diff --git a/.gitea/workflows/action.yaml b/.gitea/workflows/action.yaml index 79686358..a06a1fc3 100644 --- a/.gitea/workflows/action.yaml +++ b/.gitea/workflows/action.yaml @@ -1,24 +1,17 @@ name: Build and Publish + on: push: tags: - '*' branches: - master - - deploy - - 'feature/**' - - gitea-pages pull_request: branches: - master - - deploy pull_request_target: types: [closed] -env: - DEPLOY_BRANCH: gitea-pages - PREVIEWS_DIR: previews - jobs: build: runs-on: ubuntu-latest @@ -35,24 +28,8 @@ jobs: - name: Build the common wheel run: | - source venv/bin/activate - cd common/ - python -m build - mv dist/* ../dist - - - name: Build the GUI wheel - run: | - source venv/bin/activate - cd gui/ - python -m build - mv dist/* ../dist - - - name: Build the DAQ wheel - run: | - source venv/bin/activate - cd daq/ - python -m build - mv dist/* ../dist + source venv/bin/activate + python -m build - name: Upload Package to Gitea PyPI if: github.ref == 'refs/heads/master' && contains(github.event.head_commit.message, 'build and publish') @@ -63,146 +40,3 @@ jobs: source venv/bin/activate twine upload --repository-url https://gitea.psi.ch/api/packages/mx/pypi \ dist/* - - docs: - name: Build and Deploy Docs - runs-on: ubuntu-latest - needs: build - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 # needed for pushing branches/tags - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.12' - - - name: Build Sphinx HTML - working-directory: daq/docs - run: | - # ensure on master - git fetch origin master:master || true - git checkout master || true - - # create venv one level up and activate it - python3 -m venv ../venv - source ../venv/bin/activate - - # ensure pip and Sphinx are installed in this venv - pip install --upgrade pip - pip install "Sphinx==8.2.3" - pip install myst-parser - pip install sphinx_immaterial - pip install linkify-it-py - - if [ -f requirements.txt ]; then - pip install -r requirements.txt - elif [ -f ../docs/requirements.txt ]; then - pip install -r ../docs/requirements.txt - else - # fallback to known packages if requirements file is not present - pip install "Sphinx==8.2.3" myst-parser sphinx_immaterial linkify-it-py - fi - - - # install project editable without deps (avoid private packages) - pip install -e ../ --no-deps - - # prefer the sphinx-apidoc CLI if available; otherwise try module fallback - if command -v sphinx-apidoc > /dev/null 2>&1; then - sphinx-apidoc -o modules/ ../src --separate --module-first --force --remove-old - else - # module fallback: some Sphinx installs expose the module at sphinx.ext.apidoc - python -m sphinx.ext.apidoc -o modules/ ../src --separate --module-first --force --remove-old - fi - - - # Build HTML (source is '.' because working-directory is docs) - # Run sphinx-build and capture exit code and full output to help debugging if it fails. - sphinx-build -b html . _build/html || { - echo "=== Sphinx build failed with exit $?: showing build output and tree ===" - echo "Contents of docs/ after build attempt:" - ls -la - echo "Contents of daq/docs/_build (if any):" - ls -la _build || true - # If sphinx produced a build log file, print it - if [ -f sphinx-build.log ]; then - echo "---- sphinx-build.log ----" - cat sphinx-build.log - fi - # Exit with non-zero to fail the job (avoid deploying empty site) - exit 1 - } - - # Sanity check: ensure HTML output exists before continuing to deploy - if [ ! -d _build/html ] || [ -z "$(ls -A _build/html)" ]; then - echo "ERROR: daq/docs/_build/html does not exist or is empty after successful sphinx-build." - ls -la _build || true - exit 1 - fi - - - name: Deploy to gitea-pages branch (Gitea) - env: - GIT_USER: "Martin Appleby (Gitea)" - GIT_EMAIL: "martin.appleby@psi.ch" - DEPLOY_TOKEN: ${{ secrets.DOCS_DEPLOY_TOKEN }} - run: | - set -e - git config --global user.name "$GIT_USER" - git config --global user.email "$GIT_EMAIL" - - # Deploy strategy: create/update branch gitea-pages and replace its contents - # with the generated daq/docs/_build/html. This keeps only the documentation - # on the gitea-pages branch. - # Confirm build output exists (relative to repository root) - BUILD_DIR="daq/docs/_build/html" - echo "Checking build output at: $BUILD_DIR" - if [ ! -d "$BUILD_DIR" ] || [ -z "$(ls -A "$BUILD_DIR")" ]; then - echo "ERROR: $BUILD_DIR does not exist or is empty" - echo "Listing docs/:" - ls -la docs || true - echo "Listing daq/docs/_build:" - ls -la daq/docs/_build || true - exit 1 - fi - # Work in a temporary clone to avoid touching the runner workspace - TMPDIR=$(mktemp -d) - REPO_URL="https://$DEPLOY_TOKEN@gitea.psi.ch/${{ github.repository }}" - git clone "$REPO_URL" "$TMPDIR" - cd "$TMPDIR" - - # Create or switch to orphan branch gitea-pages - if git rev-parse --verify --quiet gitea-pages >/dev/null; then - git checkout gitea-pages - # Make sure working tree matches branch (hard reset) - git fetch --prune origin gitea-pages || true - git reset --hard origin/gitea-pages || git reset --hard - else - git checkout --orphan gitea-pages - fi - # Remove all files tracked in the branch (leave .git) - git rm -rf . || true - # Also remove untracked files to ensure clean branch state - git clean -fdx || true - - # Copy built HTML into the clone root - echo "Copying built HTML into branch root..." - (cd "${GITHUB_WORKSPACE}/${BUILD_DIR}" && tar -cf - .) | tar -xf - -C "$TMPDIR" - - # Ensure index.html exists in destination as sanity check - if [ ! -f "$TMPDIR/index.html" ] && [ ! -f "$TMPDIR/index.htm" ]; then - # If site root index is not present, try to check subfolder - echo "Warning: no index.html found at branch root after copy. Listing files:" - ls -la "$TMPDIR" || true - fi - - git add --all - if git diff --quiet --cached; then - echo "No changes to deploy" - exit 0 - fi - COMMIT_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" - git commit -m "docs: (${COMMIT_DATE}) | auto-update documentation from ${GITHUB_SHA}" - git push --force-with-lease origin gitea-pages diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3f2e470b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,69 @@ +# Changelog +## 0.3.0 +- Merge three repos into one, remove Ultralytics as dependency +- **DAQ/Server**: + - Workflow assertions to ensure scintillator is down when possible. + - Improved aerotech movement and position calculations. + - Implementation of camera auto-exposure and zoom-dependent settings. + - Added SAS-TT school demo temporary raster function. + - Enhanced status polling with robust error handling for `Tell` and `Smargon` communication. + - `ml_box` updated with beamline-specific URLs and model class types. + - Added separate authentication pathway for staff-only beamline recovery operations. + - Improved database message limits for omega (to 2 decimal places). + - Added screenshot to database from GUI; face detection sequence and beamline recovery updates. +- **GUI**: + - Major rework of `predict_subscriber` and prediction stream updates; corrected default ZMQ stream for ML box. + - Added FPS counter and sharpness monitoring for sample camera. + - Improved camera thread performance and authentication failure handling. + - Added X10SA specific camera and prediction configurations. + - New `display_status` for user-facing connection/error messages. + - Integrated `dev_help` panel with logs and error code search. + - Added framework for building GUI tutorials. + - Added alert banner for critical disconnection issues (server/Tell). + - New screenshot button and controls in sample camera GUI. + - Added SSE support for face detection panel updates during automation. + - Integrated sample position resync in recovery panel to reduce Tell polling. +- **TELL**: + - Major refactor: removed redundant code and added simulated client. + - Converted wait functions to use inbuilt pshell functionality. + - Added error handling and proxy support for connection failures. + - Fixed event names for mounting, and added missing events for gripper detection and motion sync. + - Refactored SSE connection handling for simplicity and robustness. +- **Common & Devices**: + - Added centralized `error_codes` and refactored exception handling to use FastAPI handlers. + - Expanded device support with new PVs (beamstop, scintillator, collimator, cryojet, etc.). + - Cleaned up `mx_lib` wait functions and `my_motor` class; added `clean_filename` helper. + - Improved Smargon connection exception handling. + - Updated ABR_POS_HOME configuration and added comments for cryo positions. + - Added image upload comments and improved authentication error messaging. +- **Infrastructure**: + - Updated dependencies (added `pshell`) and improved documentation autodeployment workflows. + - Refactored package structure and imports. + - Fixed `logger_config` file path expansion. + +### 0.2.69 +- check beamline state before running raster, rotation and automation +- lowered polling rate of daq status to improve GUI performance +- robot drys then parks after repeated mount failures +### 0.2.68: +- added check box to numberlineedits to switch between user input and spreadsheet +- re-enabled MLprediction +- fixed bug in gui where manual sample couldnt be created when run nubmer was negative. +- Combined beamline view now split vertically not horizontally +- New error handling in DAQ for robot mounting errors +- Error box pop ups in GUI when sample gripper detection error occurs +- Automation queue pauses if sample gripper detection error occurs multiple times to allow robot dry, if continues stops and wiats for user interverntion +- added ingest_scan to send rotation and screening result to db + +### 0.2.67: +- added run number to sampleshortinfo +- ingest raster result, including beam center to database +- aerotech goes to mount postion for manual mount +- logger config correctly expands file path for logger location. +- smart_rotiation_panel fix - but will be mvoed to DAQ in future update +- Fluoresence scan can be saved to CSV with right click +- Wait for ready before sending Tell to dry + +### 0.2.66: +- moved rastergridingestmodel and centreofmassmodel from models to raster_grid.py +- after raster load closest image to new centre diff --git a/daq/docs/README.md b/README.md similarity index 100% rename from daq/docs/README.md rename to README.md diff --git a/common/pyproject.toml b/common/pyproject.toml deleted file mode 100644 index 037a399e..00000000 --- a/common/pyproject.toml +++ /dev/null @@ -1,25 +0,0 @@ -[project] -name = "aaredaqlib" -version = "0.2.72" -description = "Libraries shared between AareDAQ and AareGUI" -readme = "README.md" -requires-python = ">=3.11" -dependencies = [ - "pydantic==2.11.4", - "numpy==2.2.5", - "jfjoch_client==1.0.0rc125", -] - -[lint] -ignore = ["F401", "F541", "W503", "W504"] - -[tool.uv.sources] -aaredb = { index = "psi"} - -[[tool.uv.index]] -name = "psi" -url = "https://gitea.psi.ch/api/packages/mx/pypi/simple" - -[build-system] -requires = ["setuptools>=75.6.0"] -build-backend = "setuptools.build_meta" diff --git a/daq/docs/CHANGELOG.md b/daq/docs/CHANGELOG.md deleted file mode 100644 index 752cc5d4..00000000 --- a/daq/docs/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# Changelog -## 0.2.70 - -### 0.2.69 -- check beamline state before running raster, rotation and automation -- lowered polling rate of daq status to improve GUI performance -- robot drys then parks after repeated mount failures -### 0.2.68: -- added check box to numberlineedits to switch between user input and spreadsheet -- re-enabled MLprediction -- fixed bug in gui where manual sample couldnt be created when run nubmer was negative. -- Combined beamline view now split vertically not horizontally -- New error handling in DAQ for robot mounting errors -- Error box pop ups in GUI when sample gripper detection error occurs -- Automation queue pauses if sample gripper detection error occurs multiple times to allow robot dry, if continues stops and wiats for user interverntion -- added ingest_scan to send rotation and screening result to db - -### 0.2.67: -- added run number to sampleshortinfo -- ingest raster result, including beam center to database -- aerotech goes to mount postion for manual mount -- logger config correctly expands file path for logger location. -- smart_rotiation_panel fix - but will be mvoed to DAQ in future update -- Fluoresence scan can be saved to CSV with right click -- Wait for ready before sending Tell to dry - -### 0.2.66: -- moved rastergridingestmodel and centreofmassmodel from models to raster_grid.py -- after raster load closest image to new centre diff --git a/daq/docs/conf.py b/daq/docs/conf.py deleted file mode 100644 index 4c0447ba..00000000 --- a/daq/docs/conf.py +++ /dev/null @@ -1,149 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -import os -import sys - -# Add project root to Python path so autodoc can import modules -sys.path.insert(0, os.path.abspath('..')) -sys.path.insert(0, os.path.abspath('../src')) # <-- ensure 'src' is on path -sys.path.insert(0, os.path.abspath('../src/aaredaq')) -sys.path.insert(0, os.path.abspath('../src/mxlibs3')) -sys.path.insert(0, os.path.abspath('../../common')) -sys.path.insert(0, os.path.abspath('../../common/src')) -sys.path.insert(0, os.path.abspath('../../common/src/aaredaqlib')) -sys.path.insert(0, os.path.abspath('../../gui')) -sys.path.insert(0, os.path.abspath('../../gui/src')) -sys.path.insert(0, os.path.abspath('../../gui/src/aaregui')) - -project = 'AareDAQ' -copyright = '2025, Paul Scherrer Institute' -author = 'M. Vears Appleby' -release = '0.2.70' -master_doc = 'index' -root_doc = 'index' -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -autodoc_mock_imports = [ - 'cv2', - 'redis', - 'jfjoch_client', - 'epics', - 'sseclient', - 'jwt', - 'aaredb', - 'aareDBclient', - 'numpy', - 'requests', - 'PyYAML', - 'loguru', - 'utility_tools', - 'extract_results', - 'testxds', - 'db_slurm_handler', - 'websocket', - 'dateutil', - 'PySide6', - 'scipy', - 'redis_lock', - 'fastapi', - 'uvicorn', - 'pydantic' -] - -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -extensions = [ - 'myst_parser', - 'sphinx_immaterial', - 'sphinx.ext.autodoc', # Add this - 'sphinx.ext.viewcode', # Optional: source code links - 'sphinx.ext.napoleon' # Optional: Google/NumPy docstring support -] - - -templates_path = ['_templates'] -exclude_patterns = [] -myst_enable_extensions = ['linkify', 'smartquotes'] - - -myst_heading_anchor = 3 - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = 'sphinx_immaterial' -# html_static_path = ['../broker/redoc-static.html'] -#html_theme_options = { -# 'sidebar_width': '300px', -# 'page_width': 'auto' -#} - -# html_theme_options = { -# 'repo_url': 'https://gitea.psi.ch/mx/aaredaq', -# 'repo_name': 'AareDaq', -# 'nav_title': 'PSI AareDaq', -# # 'html_minify': True, -# # 'css_minify': True, -# 'globaltoc_depth': 2, -# # 'repo_type': 'gitlab', -# 'color_primary': 'indigo', -# 'color_accent': 'lime', -# # 'logo_icon': '' -# } - -# html_logo = 'jfjoch.png' -# html_favicon = 'jfjoch.png' -html_theme_options = { - "icon": { - "repo": "fontawesome/brands/github", # or gitlab/gitea icon - }, - "site_url": "https://gitea.psi.ch/mx/aaredaq", - "repo_url": "https://gitea.psi.ch/mx/aaredaq", - "repo_name": "AareDAQ", - "palette": [ - { - "media": "(prefers-color-scheme: light)", - "scheme": "default", - "primary": "indigo", - "accent": "lime", - "toggle": { - "icon": "material/lightbulb-outline", - "name": "Switch to dark mode", - }, - }, - { - "media": "(prefers-color-scheme: dark)", - "scheme": "slate", - "primary": "indigo", - "accent": "lime", - "toggle": { - "icon": "material/lightbulb", - "name": "Switch to light mode", - }, - }, - ], - "features": [ - "navigation.expand", - "navigation.sections", - "navigation.top", - "search.share", - "toc.follow", - ], - "globaltoc_collapse": False, -} -html_theme_options["google_fonts"] = [] -html_sidebars = { - "**": ["logo-text.html", "globaltoc.html", "searchbox.html"] -} - - -html_show_sourcelink = False - -# language = "Python" - diff --git a/daq/docs/index.rst b/daq/docs/index.rst deleted file mode 100644 index 40f6181d..00000000 --- a/daq/docs/index.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. AareProc documentation master file, created by - sphinx-quickstart on Sun Dec 21 14:22:05 2025. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to AareDAQ's documentation! -==================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - :glob: - - README - CHANGELOG - -.. toctree:: - :maxdepth: 4 - :caption: OpenAPI Python client - - modules/src.aaredaq - modules/src.mxlibs3 - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/daq/docs/requirements.txt b/daq/docs/requirements.txt deleted file mode 100644 index 86a4ba7f..00000000 --- a/daq/docs/requirements.txt +++ /dev/null @@ -1,37 +0,0 @@ -alabaster==1.0.0 -babel==2.16.0 -beautifulsoup4==4.12.3 -certifi==2024.8.30 -charset-normalizer==3.4.0 -css-html-js-minify==2.5.5 -docutils==0.21.2 -idna==3.10 -imagesize==1.4.1 -Jinja2==3.1.4 -linkify-it-py==2.0.3 -lxml==5.3.0 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mdit-py-plugins==0.4.2 -mdurl==0.1.2 -myst-parser==4.0.0 -packaging==24.2 -Pygments==2.18.0 -python-slugify==8.0.4 -PyYAML==6.0.2 -requests==2.32.3 -snowballstemmer==2.2.0 -soupsieve==2.6 -Sphinx==8.1.3 -sphinx-material==0.0.36 -sphinxcontrib-applehelp==2.0.0 -sphinxcontrib-devhelp==2.0.0 -sphinxcontrib-htmlhelp==2.1.0 -sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==2.0.0 -sphinxcontrib-serializinghtml==2.0.0 -text-unidecode==1.3 -uc-micro-py==1.0.3 -Unidecode==1.3.8 -urllib3==2.2.3 -sphinx_immaterial==0.13.8 diff --git a/daq/src/aaredaq/best.pt b/daq/src/aaredaq/best.pt deleted file mode 100644 index ed71546a..00000000 Binary files a/daq/src/aaredaq/best.pt and /dev/null differ diff --git a/daq/src/aaredaq/devices.py b/daq/src/aaredaq/devices.py deleted file mode 100644 index cdc1afc3..00000000 --- a/daq/src/aaredaq/devices.py +++ /dev/null @@ -1,351 +0,0 @@ -import time - -from epics import PV - -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.models import SampleCameraSettings, StagePositionEnum -from mxlibs3 import aerotech, smargon -from mxlibs3.area_detector import epicsAD -from mxlibs3.enum_pv import EnumPv -from mxlibs3.filter_transmission import FilterTransmission -from mxlibs3.fluorimeter import Fluorimeter -from mxlibs3.experimental_hutch_shutter import ExperimentalHutchShutter -from mxlibs3.my_motor import MyMotor -from mxlibs3.non_standard import NonStandard -from mxlibs3.tell_client import TellClient -from mxlibs3.workflow_tools import wait_position - -class BeamlineDevices: - def __init__(self, beamline: MXBeamline): - #service_config = ServiceConfig(redis={"host": "x06da-bec-001.psi.ch", "port": 6379}) - #client = BECClient(service_config, name="Filips-Custom-Client") - #client.start() - - #self.__bec_dev = client.device_manager.devices - #self.__bec_scans = client.scans - - BEAMLINE = beamline.value.upper() - - self.tell = TellClient(beamline) - self.smargon = smargon.Smargon(beamline) - - self.__energy_pv = PV(f"{BEAMLINE}-OP-DCCM:ENERGY1") - self.__ring_current_pv = PV(f"ARS07-DPCT-0100:CURR") - self.__cryojet_temp = PV(f"{BEAMLINE}-ES-CRSM:TEMP_RBV") - - self.magnet_position_sensor = PV(f"{BEAMLINE}-ES-DF1:CBOX-CMP1") - self.magnet_position_sensor_readout = PV(f"{BEAMLINE}-ES-DF1:CBOX-USER1") - - self.dtz = MyMotor(f"{BEAMLINE}-ES-DET:TRZ1") - - # self.dty = MyMotor(f"{BEAMLINE}-MOCK-DET:TRY1") - - self.bsz = MyMotor(f"{BEAMLINE}-ES-BS:TRZ1") - - self.bsx = MyMotor(f"{BEAMLINE}-ES-BS:TRX1") - self.bsy = MyMotor(f"{BEAMLINE}-ES-BS:TRY1") - - self.__bpm = PV(f"{BEAMLINE}-OP-XBPM1:SumAll:MeanValue_RBV") - self.__anneal = PV(f"{BEAMLINE}-ES-ANN:SET_POS") - - self.aerotech = aerotech.Abr(beamline) - - self.aerotech.reload_programs() - - self.gmx = NonStandard( - name="GMX", - setpv=f"{BEAMLINE}-ES-DF1:GMX-VAL", - getpv=f"{BEAMLINE}-ES-DF1:GMX-RBV", - speed=(f"{BEAMLINE}-ES-DF1:GMX-SETV", f"{BEAMLINE}-ES-DF1:GMX-SETV"), - move_done_when=(f"{BEAMLINE}-ES-DF1:GMX-DONE", 1), - ) - - self.transmission = FilterTransmission(beamline) - - self.gmy = NonStandard( - name="GMY", - setpv=f"{BEAMLINE}-ES-DF1:GMY-VAL", - getpv=f"{BEAMLINE}-ES-DF1:GMY-RBV", - speed=(f"{BEAMLINE}-ES-DF1:GMY-SETV", f"{BEAMLINE}-ES-DF1:GMY-SETV"), - move_done_when=(f"{BEAMLINE}-ES-DF1:GMY-DONE", 1), - ) - - self.gmz = NonStandard( - name="GMZ", - setpv=f"{BEAMLINE}-ES-DF1:GMZ-VAL", - getpv=f"{BEAMLINE}-ES-DF1:GMZ-RBV", - speed=(f"{BEAMLINE}-ES-DF1:GMZ-SETV", f"{BEAMLINE}-ES-DF1:GMZ-SETV"), - move_done_when=(f"{BEAMLINE}-ES-DF1:GMZ-DONE", 1), - ) - - self.__lamp_light = NonStandard( - name="FrontLight", - setpv=f"{BEAMLINE}-ES-FL:SET-BRGHT", - getpv=f"{BEAMLINE}-ES-FL:SET-BRGHT", - tolerance=0.01, - predefs={ - "on": 2.5, - "half": 1.9, - "off": 1.0, - }, - ) - - self.cryo = NonStandard( - name="CryoJet", - setpv=f"{BEAMLINE}-ES-CJ:TRX1", - getpv=f"{BEAMLINE}-ES-CJ:TRX1.RBV", - move_done_when=(f"{BEAMLINE}-ES-CJ:TRX1.DMOV", 1), - speed=(f"{BEAMLINE}-ES-CJ:TRX1.VELO", f"{BEAMLINE}-ES-CJ:TRX1.VELO"), - ) - - self.__zoom = NonStandard( - name="Zoom", - setpv=f"{BEAMLINE}-ES-SAMCAM:ZOOM.VAL", - getpv=f"{BEAMLINE}-ES-SAMCAM:ZOOM.RBV", - move_done_when=(f"{BEAMLINE}-ES-SAMCAM:ZOOM.DMOV", 1), - stoppv=(f"{BEAMLINE}-ES-SAMCAM:ZOOM.STOP", 1), - ) - - self.__shutter_rbv = PV(f"{BEAMLINE}-ES-PH1:GET") - self.__shutter = PV(f"{BEAMLINE}-ES-PH1:SET") - - self.exp_shutter = ExperimentalHutchShutter(beamline) - - # xrf_stage = EnumPv( - # { - # "name": "KetekStage", - # "pv": f"{BEAMLINE}-MOCK-FD:SET-POS", - # "readback": f"{BEAMLINE}-MOCK-FD:GET-POS", - # "states": {"park": "park", "measure": "measure"}, - # } - # ) - - self.__reflector = EnumPv( - { - "name": "BackReflector", - "pv": f"{BEAMLINE}-ES-BL:SET-POS", - "readback": f"{BEAMLINE}-ES-BL:GET-POS", - "states": { - "park": "park", - "measure": "measure", - }, - } - ) - - self.detector_cover = PV(f"{BEAMLINE}-ES-DETCOV:SET") - - self.__beamstop_stage = EnumPv( - { - "name": "Beamstop_Stage", - "pv": f"{BEAMLINE}-ES-BS:SET-POS", - "readback": f"{BEAMLINE}-ES-BS:GET-POS", - "states": { - "park": "park", - "measure": "measure", - }, - } - ) - - self.__collimator = EnumPv( - { - "name": "Collimator", - "pv": f"{BEAMLINE}-ES-COL:SET-POS", - "readback": f"{BEAMLINE}-ES-COL:GET-POS", - "states": { - "parking": "parking", - "measure": "measure", - "down": "down", - }, - } - ) - - self.__scinti = EnumPv( - { - "name": "Scintillator", - "pv": f"{BEAMLINE}-ES-SCL:SET-POS", - "readback": f"{BEAMLINE}-ES-SCL:GET-POS", - "states": { - "parking": "parking", - "measure": "measure", - "down": "down", - }, - } - ) - - self.sample_cam = epicsAD(f"{BEAMLINE}-SAMCAM:") - - self.fluorimeter = Fluorimeter(beamline) - - - @property - def lamp_light(self) -> float: - return self.__lamp_light.value - - @lamp_light.setter - def lamp_light(self, v: float): - self.__lamp_light.move(v, wait=False) - - @property - def zoom(self) -> float: - return self.__zoom.value - - @zoom.setter - def zoom(self, value: float): - self.__zoom.move(value, wait=False) - # status = self.__bec_dev.samzoom.move(value) - # status.wait() - - def zoom_sync(self, value: float): - self.__zoom.move(value, wait=True) - - @property - def collimator(self) -> StagePositionEnum: - if self.__collimator.position_is("down"): - return StagePositionEnum.DOWN - elif self.__collimator.position_is("measure"): - return StagePositionEnum.MEASURE - elif self.__collimator.position_is("parking"): - return StagePositionEnum.PARK - else: - return StagePositionEnum.UNKNOWN - - @collimator.setter - def collimator(self, value: StagePositionEnum): - self.set_collimator(value, wait=True) - - def set_collimator(self, value: StagePositionEnum, /, wait: bool = True): - if value == StagePositionEnum.DOWN: - self.__collimator.move("down", wait=wait) - elif value == StagePositionEnum.MEASURE: - self.__collimator.move("measure", wait=wait) - elif value == StagePositionEnum.PARK: - self.__collimator.move("parking", wait=wait) - - @property - def scintillator(self) -> StagePositionEnum: - if self.__scinti.position_is("down"): - return StagePositionEnum.DOWN - elif self.__scinti.position_is("measure"): - return StagePositionEnum.MEASURE - elif self.__scinti.position_is("parking"): - return StagePositionEnum.PARK - else: - return StagePositionEnum.UNKNOWN - - @scintillator.setter - def scintillator(self, value: StagePositionEnum): - self.set_scintillator(value, wait=True) - - def set_scintillator(self, value: StagePositionEnum, /, wait: bool = True): - if value == StagePositionEnum.DOWN: - self.__scinti.move("down", wait=wait) - elif value == StagePositionEnum.MEASURE: - self.__scinti.move("measure", wait=wait) - elif value == StagePositionEnum.PARK: - self.__scinti.move("parking", wait=wait) - - @property - def reflector_up(self) -> bool: - return bool(self.__reflector.position_is("measure")) - - @reflector_up.setter - def reflector_up(self, value: bool): - if value: - self.__reflector.move("measure", wait=True) - else: - self.__reflector.move("park", wait=True) - - @property - def beamstop_stage_up(self) -> bool: - return bool(self.__beamstop_stage.position_is("measure")) - - @beamstop_stage_up.setter - def beamstop_stage_up(self, value: bool): - if value: - self.__beamstop_stage.move("measure", wait=True) - else: - self.__beamstop_stage.move("park", wait=True) - - @property - def abr_pos(self) -> Coordinate: - return Coordinate(x=self.gmx.readback, y=self.gmy.readback, z=self.gmz.readback) - - @abr_pos.setter - def abr_pos(self, pos: Coordinate): - self.gmx.move(pos.x, wait=True) - self.gmy.move(pos.y, wait=True) - self.gmz.move(pos.z, wait=True) - - wait_position(self.gmx, pos.x, 0.005) - wait_position(self.gmy, pos.y, 0.005) - wait_position(self.gmz, pos.z, 0.005) - - @property - def energy_kev(self) -> float: - return self.__energy_pv.value - - @property - def ring_current(self) -> float: - return max(0.0, self.__ring_current_pv.value) - - @property - def cryojet_temp(self) -> float: - return self.__cryojet_temp.value - - def enable_motors(self): - self.aerotech.unlock() - self.dtz.refresh() # Why ?? - self.bsz.refresh() # Why ?? - - def disable_motors(self): - self.aerotech.lock() - - @property - def shutter(self) -> bool: - return self.__shutter_rbv.value == 1 - - @shutter.setter - def shutter(self, opened: bool): - if opened: - self.__shutter.put(1) - else: - self.__shutter.put(0) - - @property - def samcam_settings(self) -> SampleCameraSettings: - return SampleCameraSettings( - gain=self.sample_cam.gain.value, - exposure=self.sample_cam.expo.value - ) - - @samcam_settings.setter - def samcam_settings(self, settings: SampleCameraSettings): - self.sample_cam.setup(settings.gain, settings.exposure) - - @property - def flux(self) -> float: - # Very approximate value - to be changed - # 2 nA -> 4e11 ph/s - if self.transmission.get() is None: - return 0.0 - return self.transmission.get() * self.full_flux - - @property - def full_flux(self) -> float: - # Very approximate value - to be changed - # 2 nA -> 4e11 ph/s - return self.__bpm.value / 2.0 * 4e11 - - @property - def dtz_low(self) -> float: - return self.dtz.get("LLM") - - @property - def dtz_high(self) -> float: - return self.dtz.get("HLM") - - def anneal(self, value: float): - self.__anneal.put(1) - time.sleep(value) - self.__anneal.put(0) diff --git a/daq/src/aaredaq/workflows.py b/daq/src/aaredaq/workflows.py deleted file mode 100644 index a75028ea..00000000 --- a/daq/src/aaredaq/workflows.py +++ /dev/null @@ -1,335 +0,0 @@ -import time - -from epics import poll - -from aaredaq.config import ABR_POS_MOUNT, ABR_OMEGA_MOUNT -from aaredaq.devices import BeamlineDevices -from aaredaq.config import BeamlineConfig -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import StagePositionEnum, SampleCameraSettings, ZoomModeEnum -from mxlibs3.mx_lib import pv_wait - -logger = setup_logger("aareDAQ") - -def move_bsz(devs: BeamlineDevices, target: float): - if abs(target - devs.bsz.position) > 0.1: - beamstop_stage_measure = devs.beamstop_stage_up - reflector_measure = devs.reflector_up - devs.reflector_up = False - devs.beamstop_stage_up = True - - devs.bsz.move(target, wait=True) - - if reflector_measure: - devs.reflector_up = True - - if not beamstop_stage_measure: - devs.beamstop_stage_up = False - - -def wait_for_dc_devices(devs: BeamlineDevices): - timeout = time.time() + 60 - timeisup = False - # devs.detector_cover.wait() - while not timeisup and ( - not devs.dtz.done_moving - ): - poll(0.1) - timeisup = timeout < time.time() - if timeisup: - if not devs.dtz.done_moving: - logger.info("DTZ still moving.") - raise RuntimeError("Timeout moving devs. Dropping to maintenance.") - - -def wait_for_se_devices(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - - _cryo = hub_cryo.cryojet_in_use - _cryopark = hub_cryo.cryojet_park_position - - if _cryo and not devs.cryo.position_is(_cryopark): - raise RuntimeError("Cryojet did not reach far position") - - -def common_2rse(devs: BeamlineDevices, cfg: BeamlineConfig): - logger.info(" moving COLLIMATOR to PARK position") - devs.collimator = StagePositionEnum.PARK - logger.info(" moving SMARGON to HOME position") - devs.smargon.move_home(wait=True) - logger.info(" moving AEROTECH to MOUNT position") - devs.aerotech.move(ABR_OMEGA_MOUNT, wait=True, direct=True) - devs.abr_pos = ABR_POS_MOUNT - logger.info(" moving REFLECTOR to DOWN position") - devs.reflector_up = False - logger.info(" LOCKING AEROTERCH") - devs.aerotech.lock() - logger.info(f" Smargon position in RSE: {devs.smargon.readback} ABS: {devs.abr_pos.x} {devs.abr_pos.y} {devs.abr_pos.z}") - - -def m2se(devs: BeamlineDevices, cfg: BeamlineConfig): - print("executing MAINTENANCE -> sample exchange") - devs.detector_cover.put(1) # Close detector cover - - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - - cfg.zoom_mode = ZoomModeEnum.User - devs.samcam_settings = cfg.zoom_settings.get_camera_settings(devs.zoom) - - devs.collimator = StagePositionEnum.PARK - devs.scintillator = StagePositionEnum.DOWN - - _dtzpark = hub.dtz_park - _cryopark = hub_cryo.cryojet_park_position - _cryo = hub_cryo.cryojet_in_use - - # devs.detector_cover.move("closed") - if not devs.aerotech.is_ready_and_willing(): - devs.aerotech.stop() - time.sleep(5.0) - raise RuntimeError("Aerotech device is not ready") - - if devs.dtz.position < _dtzpark: - devs.dtz.move(_dtzpark) - - devs.gmx.set_speed(100.0) - devs.abr_pos = ABR_POS_MOUNT - devs.aerotech.move(ABR_OMEGA_MOUNT) - - if _cryo: - devs.cryo.move(_cryopark) - - devs.reflector_up = False - - devs.bsx.move(0.0) - devs.bsy.move(0.0) - move_bsz(devs, hub.bsz) - - devs.beamstop_stage_up = False - - -def sa2se(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - logger.info(" moving cryojet to park position") - _cryopark = hub_cryo.cryojet_park_position - _dtzpark = hub.dtz_park - - devs.aerotech.move(ABR_OMEGA_MOUNT) - - if devs.cryo.position < _cryopark: - devs.cryo.move(_cryopark) - logger.info(" moving COLLIMATOR to DOWN position") - devs.collimator = StagePositionEnum.DOWN - logger.info(" moving REFLECTOR to DOWN position") - devs.reflector_up = False - devs.beamstop_stage_up = False - logger.info(" moving SMARGON to HOME position") - devs.smargon.move_home(wait=True) - logger.info(" moving DETECTOR COVER to DOWN position") - devs.detector_cover.put(1) # Close detector cover - if devs.dtz.position < _dtzpark: - logger.info(" moving DETECTOR to PARK position") - devs.dtz.move(_dtzpark) - - -def sa2rse(devs: BeamlineDevices, cfg: BeamlineConfig): - common_2rse(devs, cfg) - - -def dc2rse(devs: BeamlineDevices, cfg: BeamlineConfig): - common_2rse(devs, cfg) - - -def se2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - cfg.zoom_mode = ZoomModeEnum.User - devs.detector_cover.put(1) - devs.samcam_settings = cfg.zoom_settings.get_camera_settings(devs.zoom) - hub_cryo = cfg.cryojet_settings - _cryo = hub_cryo.cryojet_in_use - cryo_meas = hub_cryo.cryojet_measurement_position - _dtz_safety = hub.dtz_bsz_safety_margin - devs.aerotech.unlock() - logger.info("aerotech unlocked") - devs.aerotech.set_direct_mode() - logger.info("aerotech in direct mode") - logger.info(" moving reflector to up position") - devs.reflector_up = True - logger.info("moving beamstop to up position") - devs.beamstop_stage_up = True - logger.info(" setting lamp to 2.5") - devs.lamp_light = 2.5 - logger.info(" moving aerotech to measure position") - devs.abr_pos = cfg.abr_meas_pos - - if _cryo: - logger.info(" moving cryojet to measure position") - devs.cryo.move(cryo_meas) - logger.info("moving detector to measure position") - devs.dtz.move(cfg.dtz, wait=False) - -def rse2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - se2sa(devs, cfg) - -def sa2dc(devs: BeamlineDevices, cfg: BeamlineConfig): - devs.detector_cover.put(2) # Open detector cover - - devs.reflector_up = False - - #devs.reflector.wait("park") - devs.beamstop_stage_up = True - devs.dtz.move(cfg.dtz, wait=True) - devs.collimator = StagePositionEnum.MEASURE - - pv_wait(devs.dtz, None, tolerance=1.0) - wait_for_dc_devices(devs) - - -def dc2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - devs.detector_cover.put(1) # Close detector cover - devs.collimator = StagePositionEnum.PARK - devs.reflector_up = True - - # devs.gmz.move(cfg.abr_meas_pos.z, wait=True) - - -def sa2xrf(devs: BeamlineDevices, cfg: BeamlineConfig): - """sample alignment to XrfCollection""" - pass - - -def xrf2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - """XrfCollection to sample alignment""" - pass - - -def sa2ws(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - _dtzwash = hub.dtz_wash_sample_distance - devs.cryo.move(hub.cryojet_park_position) - - if devs.dtz.position < _dtzwash: - devs.dtz.move(_dtzwash) - - devs.reflector_up = False - devs.beamstop_stage_up = False - - -def ws2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - - cryo_meas = hub_cryo.cryojet_measurement_position - _cryo = hub_cryo.cryojet_in_use - - devs.dtz.move(cfg.dtz) - - if _cryo: - devs.cryo.move(cryo_meas) - - devs.reflector_up = True - devs.beamstop_stage_up = True - - -def sa2ba(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - _cryopark = hub_cryo.cryojet_park_position - _cryo = hub_cryo.cryojet_in_use - - if _cryo: - devs.cryo.move(_cryopark) - - devs.gmx.move(-38.0) - devs.lamp_light = 2.5 - devs.beamstop_stage_up = True - move_bsz(devs, 0.0) - - -def ba2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - devs.lamp_light = 2.5 - devs.beamstop_stage_up = True - move_bsz(devs, hub.bsz) - devs.reflector_up = True - devs.abr_pos = cfg.abr_meas_pos - - -def sa2bl(devs: BeamlineDevices, cfg: BeamlineConfig): - val=1000 - devs.zoom = val - cfg.zoom_mode = ZoomModeEnum.BeamLocation - devs.detector_cover.put(1) # Close detector cover - devs.samcam_settings = cfg.zoom_settings.get_camera_settings(val) - devs.lamp_light = 2.5 - devs.abr_pos = Coordinate(x=-26, y=0, z=0) - devs.cryo.move(80) - devs.set_scintillator(StagePositionEnum.MEASURE, wait=False) - devs.set_collimator(StagePositionEnum.MEASURE, wait=False) - devs.beamstop_stage_up = True - devs.reflector_up = False - devs.scintillator = StagePositionEnum.MEASURE - devs.collimator = StagePositionEnum.MEASURE - devs.shutter = True - -def bl2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - hub_cryo = cfg.cryojet_settings - cryo_meas = hub_cryo.cryojet_measurement_position - _cryo = hub_cryo.cryojet_in_use - - devs.shutter = False - - devs.set_scintillator(StagePositionEnum.DOWN, wait=False) - devs.set_collimator(StagePositionEnum.PARK, wait=False) - - devs.reflector_up = True - devs.scintillator = StagePositionEnum.DOWN - devs.collimator = StagePositionEnum.PARK - - val=1 - devs.zoom = val - cfg.zoom_mode = ZoomModeEnum.User - devs.samcam_settings = cfg.zoom_settings.get_camera_settings(val) - - if _cryo: - devs.cryo.move(cryo_meas) - - devs.abr_pos = cfg.abr_meas_pos - - -def bl2ba(devs: BeamlineDevices, cfg: BeamlineConfig): - """beam location to beamstop alignment""" - devs.gmx.move(-38) - devs.reflector_up = True - # devs.shutter.move("closed") - time.sleep(0.5) - move_bsz(devs, 0) - - -def ba2bl(devs: BeamlineDevices, cfg: BeamlineConfig): - hub = cfg.settings - move_bsz(devs, hub.bsz) - devs.abr_pos = cfg.abr_meas_pos + Coordinate(x=1) - devs.reflector_up = True - - -def sa2dh(devs: BeamlineDevices, cfg: BeamlineConfig): - logger.info("moved to dewer transfer") - if devs.tell.get_mounted_sample() is not None: - try: - # Best effort try to unmount - devs.tell.unmount(wait=True) - except Exception as e: - print(f"Error for unmounting: {e}") - devs.tell.dry(wait_cold=-1, wait=False) - - -def dh2sa(devs: BeamlineDevices, cfg: BeamlineConfig): - #devs.tell.move_cold(wait=True) - logger.info("return to sample alignment") diff --git a/daq/src/mxlibs3/aerotech.py b/daq/src/mxlibs3/aerotech.py deleted file mode 100644 index 69291d2d..00000000 --- a/daq/src/mxlibs3/aerotech.py +++ /dev/null @@ -1,1191 +0,0 @@ -""" -``Aerotech`` --- Aerotech control software -****************************************** - -This module provides an object to control the Aerotech Abr rotational stage. - -The following constants are defined. - -Measurement phases: - - Aerotech.ABR_DONE - Aerotech.ABR_READY - Aerotech.ABR_BUSY - -Axis mode - - Aerotech.DIRECT_MODE - Aerotech.MEASURING_MODE - -Shutter - - Aerotech.SHUTTER_OPEN - Aerotech.SHUTTER_CLOSE - -Methods in the Abr class -======================== - -Aerotech.is_homed() -Aerotech.do_homing(wait=True) -Aerotech.get_ready(ostart=None, orange=None, etime=None, wait=True) -Aerotech.is_done() -Aerotech.is_ready() -Aerotech.is_busy() -Aerotech.stop() -Aerotech.start_exposure() -Aerotech.wait_status(status) -Aerotech.set_mode(, value) -Aerotech.get_mode() -Aerotech.set_direct_mode() -Aerotech.set_measuring_mode() -Aerotech.move(angle, wait=False, speed=None) -Aerotech.set_shutter(state) - -Attribute Access in Abr class -============================= - -The Abr class overwrites the getattr and setattr methods to provide a pythonic -way of controlling the Abr. - -The following properties are implemented: - -velo - - Sets the velocity of rotation: ``-ES-DF1:ROTX-SETV`` - -omega - - Move the omega angle without any wait: ``-ES-DF1:ROTX-VAL`` - -exposure_time - - Sets the PV for the measurement's exposure time: ``-ES-OSC:ETIME`` - -start_angle - - Sets the PV for the measurement's starting angle: ``-ES-OSC:START-POS`` - -oscillation_angle - - Sets the PV for the measurement's oscillation angle: ``-ES-OSC:RANGE`` - -shutter - - Controls the shutter: ``-ES-PH1:SET`` and ``-ES-PH1:GET`` - -mode - - Controls the axis mode: ``-ES-DF1:AXES-MODE`` - -measurement_state - - Controls the PV for the measurement state: ``-ES-OSC:DONE`` - - -Examples -======== - - import Aerotech - abr = Aerotech.Abr() - - # move omega to 270.0 degrees - abr.omega = 270.0 - - # move omega to 180 degrees and wait for movement to finish - abr.move(180, wait=True) - - # move omega to 3000 degrees at 360 degrees/s and wait for movement to finish - abr.move(3000, speed=360, wait=True) - - # stop any movement - abr.stop() # this function only returns after the STATUS is back to OK - -""" - -import math -import time - -from epics import PV, poll -from epics.ca import pend_io - -from aaredaqlib.beamline import MXBeamline - -ABR_DONE = 0 -ABR_READY = 1 -ABR_BUSY = 2 - -GRID_SCAN_BUSY = 0 -GRID_SCAN_DONE = 1 - -DIRECT_MODE = 0 -MEASURING_MODE = 1 - -SHUTTER_CLOSE = 0 -SHUTTER_OPEN = 1 - -FULL_PERIOD = 0 -HALF_PERIOD = 1 - - -def pv_wait(pv, val, timeout=10.0): - timeout = timeout + time.time() - timeisup = False - while val != pv.get() and not timeisup: - poll(0.01) - timeisup = time.time() > timeout - if timeisup: - raise RuntimeWarning( - "timeout waiting for %s to reach %s" % (pv.pvname, str(val)) - ) - - -CMD_NONE = 0 -CMD_RASTER_SCAN_SIMPLE = 1 -CMD_MEASURE_STANDARD = 2 -CMD_VERTICAL_LINE_SCAN = 3 -CMD_SCREENING = 4 -CMD_SUPER_FAST_OMEGA = 5 -CMD_STILL_WEDGE = 6 -CMD_STILLS = 7 -CMD_REPEAT_SINGLE_OSCILLATION = 8 -CMD_SINGLE_OSCILLATION = 9 -CMD_OLD_FASHIONED = 10 -CMD_RASTER_SCAN = 11 -CMD_JET_ROTATION = 12 -CMD_X_HELICAL = 13 -CMD_X_RUNSEQ = 14 -CMD_JUNGFRAU = 15 -CMD_MSOX = 16 -CMD_SLIT_SCAN = 17 -CMD_RASTER_SCAN_STILL = 18 -CMD_SCAN_SASTT = 19 -CMD_SCAN_SASTT_V2 = 20 -CMD_SCAN_SASTT_V3 = 21 - -AXIS_OMEGA = 1 -AXIS_GMX = 2 -AXIS_GMY = 3 -AXIS_GMZ = 4 -AXIS_STY = 5 -AXIS_STZ = 6 - - -class Abr: - def __init__(self, bl: MXBeamline): - BEAMLINE = "X06DA" # FIXME - self.__pv_stop = PV(f"{BEAMLINE}-ES-AERO:TSK-STOP") - self.__pv_lock = PV(f"{BEAMLINE}-ES-DF1:LOCK") - self.__pv_direct_mode = PV(f"{BEAMLINE}-ES-DF1:MODE-DIRECT") - self.set_direct_mode = self.__set_direct_mode_v2 - self.lock_device = self.__lock_device_v2 - self.lock = self.__lock_device_v2 - - self.unlock = self.set_direct_mode - - self.__pv_shutter_set = PV(f"{BEAMLINE}-ES-PH1:SET") - self.__pv_shutter_get = PV(f"{BEAMLINE}-ES-PH1:GET") - self.__pv_axes_mode = PV(f"{BEAMLINE}-ES-DF1:AXES-MODE") - self.__pv_omega_set = PV(f"{BEAMLINE}-ES-DF1:OMEGA-VAL") - self.__pv_omega_get = PV(f"{BEAMLINE}-ES-DF1:OMEGA-RBV") - self.__pv_omega_done = PV(f"{BEAMLINE}-ES-DF1:OMEGA-DONE") - self.__pv_gmx_setp = PV(f"{BEAMLINE}-ES-DF1:GMX-SETP") - self.__pv_gmx_getp = PV(f"{BEAMLINE}-ES-DF1:GMX-GETP") - self.__pv_gmx_val = PV(f"{BEAMLINE}-ES-DF1:GMX-VAL") - self.__pv_gmx_rbv = PV(f"{BEAMLINE}-ES-DF1:GMX-RBV") - self.__pv_gmx_velo = PV(f"{BEAMLINE}-ES-DF1:GMX-SETV") - self.__pv_gmx_done = PV(f"{BEAMLINE}-ES-DF1:GMX-DONE") - self.__pv_gmy_setp = PV(f"{BEAMLINE}-ES-DF1:GMY-SETP") - self.__pv_gmy_getp = PV(f"{BEAMLINE}-ES-DF1:GMY-GETP") - self.__pv_gmy_set = PV(f"{BEAMLINE}-ES-DF1:GMY-VAL") - self.__pv_gmy_get = PV(f"{BEAMLINE}-ES-DF1:GMY-RBV") - self.__pv_gmy_done = PV(f"{BEAMLINE}-ES-DF1:GMY-DONE") - self.__pv_gmz_setp = PV(f"{BEAMLINE}-ES-DF1:GMZ-SETP") - self.__pv_gmz_getp = PV(f"{BEAMLINE}-ES-DF1:GMZ-GETP") - self.__pv_gmz_set = PV(f"{BEAMLINE}-ES-DF1:GMZ-VAL") - self.__pv_gmz_get = PV(f"{BEAMLINE}-ES-DF1:GMZ-RBV") - self.__pv_gmz_done = PV(f"{BEAMLINE}-ES-DF1:GMZ-DONE") - self.__pv_omega_velo = PV(f"{BEAMLINE}-ES-DF1:OMEGA-SETV") - self.__pv_ostart = PV(f"{BEAMLINE}-ES-OSC:START-POS") - self.__pv_orange = PV(f"{BEAMLINE}-ES-OSC:RANGE") - self.__pv_etime = PV(f"{BEAMLINE}-ES-OSC:ETIME") - self.__pv_get_ready = PV(f"{BEAMLINE}-ES-OSC:READY.PROC") - self.__pv_start = PV(f"{BEAMLINE}-ES-OSC:START") - self.__pv_phase = PV(f"{BEAMLINE}-ES-OSC:DONE") - self.__pv_stat = PV(f"{BEAMLINE}-ES-AERO:STAT") - self.__pv_ishomed = PV(f"{BEAMLINE}-ES-DF1:OMEGA-AS00") - self.__pv_dohome = PV(f"{BEAMLINE}-ES-DF1:OMEGA-HOME") - self.__pv_omega_status = PV(f"{BEAMLINE}-ES-DF1:OMEGA-STAT") - self._raster_x_start = PV(f"{BEAMLINE}-ES-GRD:GMX-START") - self._raster_x_end = PV(f"{BEAMLINE}-ES-GRD:GMX-END") - self._raster_omega = PV(f"{BEAMLINE}-ES-OSC:#M-START") - self._raster_osc = PV(f"{BEAMLINE}-ES-GRD:ANGLE") - self._raster_celltime = PV(f"{BEAMLINE}-ES-GRD:CELL-TIME") - self._raster_y_start = PV(f"{BEAMLINE}-ES-OSC:#STY-START") - self._raster_y_step = PV(f"{BEAMLINE}-ES-OSC:#STY-END") - self._raster_z_start = PV(f"{BEAMLINE}-ES-OSC:#STZ-START") - self._raster_z_step = PV(f"{BEAMLINE}-ES-OSC:#STZ-END") - self._raster_columns = PV(f"{BEAMLINE}-ES-GRD:COLUMNS") - self._raster_rows = PV(f"{BEAMLINE}-ES-GRD:ROWS") - self._raster_delay = PV(f"{BEAMLINE}-ES-GRD:RAST-DLY") - self._raster_osc_mode = PV(f"{BEAMLINE}-ES-GRD:SET-MODE") - self._raster_velo = PV(f"{BEAMLINE}-ES-GRD:#X-VEL") - self._raster_get_ready = PV(f"{BEAMLINE}-ES-GRD:READY.PROC") - self._raster_grid_start = PV(f"{BEAMLINE}-ES-GRD:START.PROC") - self._raster_grid_next = PV(f"{BEAMLINE}-ES-GRD:NEXT-ROW") - self._raster_scan_done = PV(f"{BEAMLINE}-ES-GRD:SCAN-DONE") - self._raster_row_done = PV(f"{BEAMLINE}-ES-GRD:ROW-DONE") - self._raster_grid_done = PV(f"{BEAMLINE}-ES-GRD:DONE") - self._var_1 = PV(f"{BEAMLINE}-ES-PSO:VAR-1") - self._var_2 = PV(f"{BEAMLINE}-ES-PSO:VAR-2") - self._var_3 = PV(f"{BEAMLINE}-ES-PSO:VAR-3") - self._var_4 = PV(f"{BEAMLINE}-ES-PSO:VAR-4") - self._var_5 = PV(f"{BEAMLINE}-ES-PSO:VAR-5") - self._var_6 = PV(f"{BEAMLINE}-ES-PSO:VAR-6") - self._var_7 = PV(f"{BEAMLINE}-ES-PSO:VAR-7") - self._var_8 = PV(f"{BEAMLINE}-ES-PSO:VAR-8") - self._var_9 = PV(f"{BEAMLINE}-ES-PSO:VAR-9") - self._var_10 = PV(f"{BEAMLINE}-ES-PSO:VAR-10") - self._zcmd = PV(f"{BEAMLINE}-ES-PSO:CMD") - self.__start_command = PV(f"{BEAMLINE}-ES-PSO:START-TEST.PROC") - self._cmd_2 = PV(f"{BEAMLINE}-ES-PSO:STOP-TEST.PROC") - self._gmy_done = PV(f"{BEAMLINE}-ES-DF1:GMY-DONE") - self._gmx_offset = PV(f"{BEAMLINE}-ES-DF1:GMX-OFF") - - pend_io(10) - - def raster_setup(self, positions, columns, angle, etime): - """configures parameters for a raster scan - - positions : a list of xyz indicating the positions of each cell - columns: an integer with how many columns - angle : the oscillation angle for each row - etime : the exposure time per cell - """ - self.set_direct_mode() - if columns == 1: - raise RuntimeWarning( - "Fast scans are not available with vertical line scans." - ) - - rows = len(positions) / columns - x1, y1, z1 = tuple(positions[0]) # first cell on first row - x2, y2, z2 = tuple(positions[1]) # second cell on first row - x4, y4, z4 = tuple(positions[columns - 1]) # last cell on first row - - if rows > 1: - x3, y3, z3 = tuple(positions[columns]) # first cell on second row - ystep = y3 - y1 - zstep = z3 - z1 - gmy_step = math.sqrt(pow(y3 - y1, 2) + pow(z3 - z1, 2)) - else: - ystep = 0.010 - zstep = 0.010 - gmy_step = 0.010 - - half_cell = abs(x2 - x1) / 2.0 - start_x = x1 - half_cell - end_x = x4 + half_cell - - self._raster_starting_x = start_x - self._raster_starting_y = y1 - self._raster_starting_z = z1 - self._raster_step_y = ystep - self._raster_step_z = zstep - self._raster_current_row = 0 - self._raster_num_rows = rows - - self._raster_x_start.put(start_x) - self._raster_x_end.put(end_x) - self._raster_omega.put(self.position) - self._raster_osc.put(angle) - self._raster_celltime.put(etime) - self._raster_y_start.put(y1) - self._raster_z_start.put(z1) - self._raster_y_step.put(ystep) - self._raster_z_step.put(zstep) - self._raster_columns.put(columns) - self._raster_rows.put(rows) - - def raster_next_row_yz(self): - r = self._raster_current_row - self._raster_current_row = r + 1 - - y, z = ( - r * self._raster_step_y + self._raster_starting_y, - r * self._raster_step_z + self._raster_starting_z, - ) - - if r < self._raster_num_rows: - return (y, z) - else: - return (None, None) - - def raster_get_y_step(self): - return self._raster_y_step.get() - - def raster_get_z_step(self): - return self._raster_z_step.get() - - def raster_get_ready(self): - self._raster_get_ready.put(1) - for n in range(10): - try: - pv_wait(self._raster_grid_done, ABR_READY, timeout=2) - except RuntimeWarning as e: - print(str(e), end=" ") - print(" --- trying again.") - self._raster_get_ready.put(1, wait=True) - - def raster_scan_row(self): - """start rastering a new row, either first or following rows""" - if ABR_READY == self._raster_grid_done.get(): - self._raster_grid_start.put(1) - poll(0.05) - else: - self._raster_grid_next.put(1) - - def is_scan_done(self): - return 1 == self._raster_scan_done.get() - - def wait_scan_done(self, timeout=60.0): - poll(0.05) - pv_wait(self._raster_scan_done, 1, timeout=timeout) - - def raster_is_row_scanning(self): - return 1 == self._raster_scan_done.get() - - def raster_wait_for_row(self): - poll(0.05) - pv_wait(self._raster_row_done, 1, timeout=60) - - def command(self, cmd): - self._zcmd.put(cmd) - poll(0.1) - - def start_command(self): - poll(0.1) - self.__start_command.put(1) - poll(0.1) - - def measure_standard(self, start, wedge, etime, ready_rate=500.0): - """measure a standard wedge from `start` to `start` + `wedge` during `etime` seconds""" - self.command(CMD_MEASURE_STANDARD) - self._var_1.put(start) - self._var_2.put(wedge) - self._var_3.put(etime) - self._var_4.put(ready_rate) - self.start_command() - - def measure_scan_slits(self, delta_x, delta_y, velocity): - """measure a standard wedge from `start` to `start` + `wedge` during `etime` seconds""" - self.command(CMD_SLIT_SCAN) - self._var_1.put(delta_x) - self._var_2.put(delta_y) - self._var_3.put(velocity) - self.start_command() - - def measure_raster_simple(self, etime, cell_width, cell_height, ncols, nrows): - """measures the specified grid assuming the goniometer is currently at the CENTER of TOP-LEFT CELL - - etime: a float in seconds - cell_width: a float in mm - cell_height: a float in mm - ncols: an int - nrows: an int - - """ - # self.reset() - self.command(CMD_RASTER_SCAN_SIMPLE) - self._raster_scan_done.put(0) # make SCAN DONE go into busy state - self._var_1.put(etime) - self._var_2.put(cell_width) - self._var_3.put(cell_height) - self._var_4.put(int(ncols)) - self._var_5.put(int(nrows)) - self._var_6.put(0) - self._var_7.put(0) - self._var_8.put(0) - self._raster_num_rows = nrows - self.start_command() - - def measure_sastt( - self, - etime, - cell_width, - cell_height, - ncols, - nrows, - even_tweak=0.0, - odd_tweak=0.0, - version=1, - ): - """measures the specified grid assuming the goniometer is currently at the CENTER of the required grid - - etime: a float in seconds - cell_width: a float in mm - cell_height: a float in mm - ncols: an int - nrows: an int - - odd_tweak, even_tweak: float, a distance to be added to the start of - the open shutter command. used on in the scan mode - version=3 - - - these values can be either positive/negative - - they should be small, i.e. just to tweak a trriggering event - by minor amounts - version: an int (1, 2, 3) - 1 = original snake scan, single PSO window - 2 = scan always from LEFT---RIGHT - 3 = snake scan alternating PSO window for even/odd rows - - """ - # self.reset() - if version == 1: - self.command(CMD_SCAN_SASTT) - elif version == 2: - self.command(CMD_SCAN_SASTT_V2) - elif version == 3: - self.command(CMD_SCAN_SASTT_V3) - else: - raise RuntimeError("non existing SAS-TT scan mode") - - self._raster_scan_done.put(0) # make SCAN DONE go into busy state - self._var_1.put(etime) - self._var_2.put(cell_width) - self._var_3.put(cell_height) - self._var_4.put(int(ncols)) - self._var_5.put(int(nrows)) - self._var_6.put(even_tweak) - self._var_7.put(odd_tweak) - self._var_8.put(0) - self._raster_num_rows = nrows - self.start_command() - - def measure_vertical_line(self, exposureTime, cellHeight, numCells): - """measure a vertical line using the GMY motor - - The line is nummCells * cellHeight long and the exposureTime is per cell. - - `cellHeight` in mm - `numCells` an integer - `exposureTime` in seconds / per cellHeight - """ - self.command(CMD_VERTICAL_LINE_SCAN) - self._var_1.put(cellHeight) - self._var_2.put(numCells) - self._var_3.put(exposureTime) - self.start_command() - - def measure_screening(self, start, oscangle, etime, degrees, frames, delta=0.5): - self.command(CMD_SCREENING) - self._var_1.put(start) - self._var_2.put(oscangle) - self._var_3.put(etime) - self._var_4.put(degrees) - self._var_5.put(frames) - self._var_6.put(delta) - self.start_command() - - def measure_fast_omega(self, start, wedge, etime, rate=200.0): - self.command(CMD_SUPER_FAST_OMEGA) - self._var_1.put(start) - self._var_2.put(wedge) - self._var_3.put(etime) - self._var_4.put(rate) - self.start_command() - - def measure_still_wedge( - self, start, wedge, etime, oscangle, sleep_after_shutter_close=0.010 - ): - self.command(CMD_STILL_WEDGE) - self._var_1.put(start) - self._var_2.put(wedge) - self._var_3.put(etime) - self._var_4.put(oscangle) - self._var_5.put(sleep_after_shutter_close) - self.start_command() - - def measure_stills(self, number_of_frames, exposure_time, idle=0.0): - """collect still images, i.e. no omega rotation - - number_of_frames => an integer - exposure_time => a float - idle => sleep in between each exposure - - IMPORTANT: use idle=0.0 to prevent shutter open/close - - """ - self.command(CMD_STILLS) - self._var_1.put(number_of_frames) - self._var_2.put(exposure_time) - self._var_3.put(idle) - self.start_command() - - def measure_repeat_singles(self, frames, etime, oscangle, sleep=0.0, delta=0.5): - self.command(CMD_REPEAT_SINGLE_OSCILLATION) - self._var_1.put(frames) - self._var_2.put(etime) - self._var_3.put(oscangle) - self._var_4.put(sleep) - self._var_5.put(delta) - self.start_command() - - def measure_single( - self, start_angle, oscillation_angle, exposure_time, delta=0.0, settle=0.0 - ): - self.command(CMD_SINGLE_OSCILLATION) - self._var_1.put(start_angle) - self._var_2.put(oscillation_angle) - self._var_3.put(exposure_time) - self._var_4.put(delta) - self._var_5.put(settle) - self.start_command() - - def measure_raster(self, positions, columns, angle, etime): - """raster via generic experiment interface""" - self.reset() - if len(positions) == 1: - raise RuntimeWarning("Raster scan with one cell makes no sense") - self.command(CMD_RASTER_SCAN) - - rows = len(positions) / columns - x1, y1, z1 = tuple(positions[0]) # first cell on first row - x2, y2, z2 = tuple(positions[1]) # second cell on first row - x4, y4, z4 = tuple(positions[columns - 1]) # last cell on first row - - if rows > 1: - x3, y3, z3 = tuple(positions[columns]) # first cell on second row - ystep = y3 - y1 - zstep = z3 - z1 - gmy_step = math.sqrt(pow(y3 - y1, 2) + pow(z3 - z1, 2)) - else: - ystep = 0.010 - zstep = 0.010 - gmy_step = 0.010 - - half_cell = abs(x2 - x1) / 2.0 - start_x = x1 - half_cell - end_x = x4 + half_cell - - self._raster_starting_x = start_x - self._raster_starting_y = y1 - self._raster_starting_z = z1 - self._raster_step_y = ystep - self._raster_step_z = zstep - self._raster_current_row = 0 - self._raster_num_rows = rows - - self._var_1.put(self.position) - self._var_2.put(start_x) - self._var_3.put(end_x) - self._var_4.put(columns) - self._var_5.put(rows) - self._var_6.put(angle) - self._var_7.put(etime) - self._var_8.put(HALF_PERIOD) - self._var_9.put(self._gmx_offset.get()) - self._var_10.put(gmy_step) - - self.start_command() - - def measure_raster_still(self, positions, columns, etime, delay): - """raster via generic experiment interface - - positions: list of coordinates for each cell - columns: how many columns in grid - etime: exposure time / cell_width - delay: delay configured in delay generator - to trigger detector after aerotech; - must be greater than actual shutter delay - """ - self.reset() - if len(positions) == 1: - raise RuntimeWarning("Raster scan with one cell makes no sense") - self.command(CMD_RASTER_SCAN_STILL) - - rows = len(positions) / columns - x1, y1, z1 = tuple(positions[0]) # first cell on first row - x2, y2, z2 = tuple(positions[1]) # second cell on first row - x4, y4, z4 = tuple(positions[columns - 1]) # last cell on first row - - if rows > 1: - x3, y3, z3 = tuple(positions[columns]) # first cell on second row - ystep = y3 - y1 - zstep = z3 - z1 - gmy_step = math.sqrt(pow(y3 - y1, 2) + pow(z3 - z1, 2)) - else: - ystep = 0.010 - zstep = 0.010 - gmy_step = 0.010 - - half_cell = abs(x2 - x1) / 2.0 - start_x = x1 - half_cell - end_x = x4 + half_cell - - self._raster_starting_x = start_x - self._raster_starting_y = y1 - self._raster_starting_z = z1 - self._raster_step_y = ystep - self._raster_step_z = zstep - self._raster_current_row = 0 - self._raster_num_rows = rows - - self._var_1.put(self.position) - self._var_2.put(start_x) - self._var_3.put(end_x) - self._var_4.put(columns) - self._var_5.put(rows) - self._var_6.put(delay) - self._var_7.put(etime) - self._var_8.put(HALF_PERIOD) - self._var_9.put(self._gmx_offset.get()) - self._var_10.put(gmy_step) - - self.start_command() - - def measure_jungfrau(self, columns, rows, width, height, etime, sleep=0.100): - """for Jungfrau, grid from current position""" - self.reset() - self.command(CMD_JUNGFRAU) - self._var_1.put(columns) - self._var_2.put(rows) - self._var_3.put(height) - self._var_4.put(width) - self._var_5.put(etime) - self._var_6.put(sleep) - self._var_7.put(0.0) - self._var_8.put(0.0) - self._var_9.put(0.0) - self._var_10.put(0.0) - - self.start_command() - if sleep > 0: - timeout = 5.0 + (rows * sleep) + (columns * rows * etime) - else: - timeout = None - - if timeout: - pv_wait(self._raster_scan_done, GRID_SCAN_DONE, timeout) - self.set_direct_mode() - - def measure_msox(self, start, wedge, etime, num_datasets=1, rest_time=0.0): - """for msox - start = start omega - wedge = total range to measure - etime = total time for wedge - num_datasets = how many times to repeat - rest_time = how many seconds to rest in between datasets - """ - self.reset() - self.command(CMD_MSOX) - self._var_1.put(start) - self._var_2.put(wedge) - self._var_3.put(etime) - self._var_4.put(num_datasets) - self._var_5.put(rest_time) - self._var_6.put(0) - self._var_7.put(0) - self._var_8.put(0) - self._var_9.put(0) - self._var_10.put(0) - - self.start_command() - - def next_row(self): - """start rastering a new row""" - self._raster_grid_next.put(1) - - def configure_stills(self, frames, etime, sleep=0.0): - self._var_1.put(frames) - self._var_2.put(etime) - self._var_3.put(sleep) - - def reset(self): - self.command(CMD_NONE) - self.set_direct_mode() - - def raster_2d(self): - pass - - def is_ioc_ok(self): - return 0 == self.__pv_stat.get() - - def is_ready_and_willing(self): - return self.is_ioc_ok() and self.is_homed() - - def is_omega_ok(self): - return 0 == self.__pv_omega_status.get() - - def is_homed(self): - """Are the motors homed?""" - return 1 == self.__pv_ishomed.get() - - def do_homing(self, wait=True): - """Execute the homing procedure. - - Executes the homing procedure and waits (default) until it is completed. - - PARAMETERS - `wait` true / false if the routine is to wait for the homing to finish. - """ - self.__pv_dohome.put(1, wait=True) - poll(1.0) - if not wait: - return - while not self.is_homed(): - poll(0.2) - - def __setattr__(self, name, value): - """Overwrite __setattr__ for pythonic access. - - This is in principle unnecessary but it results in clear code. - - Carefull when modifying this! - """ - if name == "velo": - self.__pv_omega_velo.put(value, wait=True) - elif name == "omega": - self.__pv_omega_set.put(value, wait=True) - elif name == "position": - self.__pv_omega_set.put(value, wait=True) - elif name == "exposure_time": - self.__pv_etime.put(value, wait=True) - elif name == "start_angle": - self.__pv_ostart.put(value, wait=True) - elif name == "oscillation_angle": - self.__pv_orange.put(value, wait=True) - elif name == "measurement_state": - self.__pv_phase.put(value, wait=True) - elif name == "shutter": - self.set_shutter(value) - elif name == "mode": - self.set_mode(value) - else: - self.__dict__[name] = value - - def __getattr__(self, name): - """Overwrite __getattr__ for pythonic access. - - This is in principle unnecessary but it results in clear code. - - Carefull when modifying this! - """ - if name == "velo": - value = self.__pv_omega_velo.get() - elif name == "omega": - value = self.__pv_omega_get.get() - elif name == "position": - value = self.__pv_omega_get.get() - elif name == "exposure_time": - value = self.__pv_etime.get() - elif name == "start_angle": - value = self.__pv_ostart.get() - elif name == "oscillation_angle": - value = self.__pv_orange.get() - elif name == "measurement_state": - value = self.__pv_phase.get() - elif name == "shutter": - value = self.__pv_shutter_get.get() - elif name == "mode": - value = self.get_mode() - else: - raise AttributeError("unknown attribute") - return value - - def get_ready(self, ostart=None, orange=None, etime=None, wait=True): - self.wait_for_movements() - if self.measurement_state == ABR_BUSY: - raise RuntimeError("ABR is not DONE!!!!") - - if self.measurement_state == ABR_READY: - self.measurement_state = ABR_DONE - - if ostart is not None: - self.__pv_ostart.put(ostart, wait=True) - if orange is not None: - self.__pv_orange.put(orange, wait=True) - if etime is not None: - self.__pv_etime.put(etime, wait=True) - - self.__pv_get_ready.put(1, wait=True) - - poll(0.1) - - if wait: - for n in range(10): - try: - self.wait_status(ABR_READY, timeout=5) - except RuntimeWarning as e: - print(str(e), end=" ") - print(" --- trying ready again.") - self.__pv_get_ready.put(1, wait=True) - - def wait_for_movements(self, timeout=60.0): - timeout = timeout + time.time() - timeisup = False - - try: - moving = self.is_moving() - except: - moving = True - - while not timeisup and moving: - poll(0.1) - try: - moving = self.is_moving() - except: - print( - "Aerotech() Failed to retrieve moving state for axes omega, gmx, gmy, gmz" - ) - moving = True - timeisup = timeout < time.time() - - if timeisup: - raise RuntimeWarning("timeout waiting for all axis to stop moving") - - def is_moving(self): - return not ( - self.__pv_omega_done.get() - and self.__pv_gmx_done.get() - and self.__pv_gmy_done.get() - and self.__pv_gmz_done.get() - ) - - def is_done(self): - """Is the measurement DONE?""" - return ABR_DONE == self.__pv_phase.get() - - def is_ready(self): - """Is the measurement READY to start?""" - return ABR_READY == self.__pv_phase.get() - - def is_busy(self): - """Is the measurement currently BUSY (executing)?""" - return ABR_BUSY == self.__pv_phase.get() - - def stop(self, wait_after_reload=1.0): - """Stops current motions; reloads aerobasic programs; goes DIRECT - - This will stop movements in both DIRECT and MEASURING modes. During the - stop the `status` temporarely goes to ERROR but reverts to OK after a - couple of seconds. - - """ - self.__pv_stop.put(1, wait=True) - poll(wait_after_reload) - self.reset() - poll(0.1) - - reload_programs = stop - - def start_exposure(self): - """Starts the previously configured exposure.""" - self.wait_for_movements() - self.__pv_start.put(1) - for n in range(10): - try: - self.wait_status(ABR_BUSY, timeout=1) - except RuntimeWarning as e: - print(str(e), end=" ") - print(" --- trying start again.") - self.__pv_start.put(1, wait=True) - - def wait_status(self, status, timeout=60.0): - """Wait for the Aertotech IOC to reach the desired `status`. - - PARAMETERS - `status` can be any the three ABR_DONE, ABR_READY or ABR_BUSY. - - NO RETURN - """ - st = self.__pv_phase.get() - timeout = timeout + time.time() - timeisup = False - while not timeisup and status != st: - poll(0.05) - st = self.__pv_phase.get() - timeisup = timeout < time.time() - - if timeisup: - raise RuntimeWarning( - "timeout waiting for abr status to change to %d: current status => %d" - % (status, st) - ) - - def get_mode(self, as_string=False): - return self.__pv_axes_mode.get(as_string=as_string) - - def is_measuring_mode(self): - return MEASURING_MODE == self.get_mode() - - def __set_direct_mode_v2(self): - """Sets the Abr to direct mode.""" - self.__pv_direct_mode.put(37, wait=True) - poll(0.1) - - def __lock_device_v1(self): - self.__pv_axes_mode.put(MEASURING_MODE, wait=True) - poll(0.1) - - def __lock_device_v2(self): - self.__pv_lock.put(1, wait=True) - poll(0.1) - - def lock_device(self): - self.__pv_lock.put(1, wait=True) - poll(0.1) - - def is_locked(self): - lpv = self.__pv_lock - if lpv is not None: - return 0 != self.get_mode() - else: - return 1 == self.get_mode() - - def velo(self, axis: int, speed: float | None = None) -> float: - """set's the speed on the given axis to speed""" - pv_velo: PV - if AXIS_GMX == axis: - velo_pv = self.__pv_gmx_velo - min, max = 0.01, 100.0 - elif AXIS_GMY == axis: - velo_pv = self.__pv_gmy_velo - min, max = 0.01, 10.0 - elif AXIS_GMZ == axis: - velo_pv = self.__pv_gmz_velo - min, max = 0.01, 10.0 - elif AXIS_OMEGA == axis: - velo_pv = self.__pv_omega_velo - min, max = 0.01, 720.0 - else: - raise Exception("unknown axis index") - - if speed is not None and velo_pv is not None: - if not (min <= speed <= max): - raise Exception( - f"requested speed {speed} outside range {min} < speed < {max}" - ) - velo_pv.put(speed) - poll(0.05) - return velo_pv.get() # type: ignore - - def select_axis(self, axis): - """returns PVs and limits for the given axis - - axis: Aerotech.AXIS_{OMEGA=1, GMX=2, GMY=3, GMZ=4} - - return (val_pv, rbv_pv, velo_pv, done_pv, velomin, velomax) - """ - - if AXIS_GMX == axis: - val_pv = self.__pv_gmx_val - rbv_pv = self.__pv_gmx_rbv - velo_pv = self.__pv_gmx_velo - done_pv = self.__pv_gmx_done - min, max = 0.01, 100.0 - elif AXIS_GMY == axis: - val_pv = self.__pv_gmy_val - rbv_pv = self.__pv_gmy_rbv - velo_pv = self.__pv_gmy_velo - done_pv = self.__pv_gmy_done - min, max = 0.01, 10.0 - elif AXIS_GMZ == axis: - val_pv = self.__pv_gmz_val - rbv_pv = self.__pv_gmz_rbv - velo_pv = self.__pv_gmz_velo - done_pv = self.__pv_gmz_done - min, max = 0.01, 10.0 - elif AXIS_OMEGA == axis: - val_pv = self.__pv_omega_set - rbv_pv = self.__pv_omega_get - velo_pv = self.__pv_omega_velo - done_pv = self.__pv_omega_done - min, max = 0.01, 720.0 - else: - raise Exception("unknown axis index") - - return (val_pv, rbv_pv, velo_pv, done_pv, min, max) - - def incr(self, axis, val, wait=False, velo=None): - (val_pv, rbv_pv, velo_pv, done_pv, min, max) = self.select_axis(axis) - cur = rbv_pv.get() # type: ignore - cv = velo_pv.get() # type: ignore - - if velo: - self.velo(axis, velo) - - val_pv.put(cur + val) - if wait: - poll(0.2) - pv_wait(done_pv, 1) - - if velo: - self.velo(axis, cv) - - def incr_x(self, val, wait=False, velo=None): - """increments GMX by val""" - self.incr(AXIS_GMX, val, wait=wait, velo=velo) - - def incr_y(self, val, wait=False, velo=None): - """increments GMY by val""" - self.incr(AXIS_GMY, val, wait=wait, velo=velo) - - def incr_z(self, val, wait=False, velo=None): - """increments GMZ by val""" - self.incr(AXIS_GMZ, val, wait=wait, velo=velo) - - def incr_omega(self, val, wait=False, velo=None): - """increments OMEGA by val""" - self.incr(AXIS_OMEGA, val, wait=wait, velo=velo) - - def move_x(self, val, wait=False, velo=None): - if velo is not None: - oldv = self.__pv_gmx_velo.get() - self.__pv_gmx_velo.put(velo) - velo = oldv - self.move_axis(AXIS_GMX, val, wait) - if velo is not None: - self.__pv_gmx_velo.put(velo) - - def move_y(self, val, wait=False): - self.move_axis(AXIS_GMY, val, wait) - - def move_z(self, val, wait=False): - self.move_axis(AXIS_GMZ, val, wait) - - def move_axis(self, axis, pos, wait=False): - axis_motor = None - if DIRECT_MODE != self.mode: - self.set_direct_mode() - if axis == AXIS_OMEGA: - self.move(pos) - else: - if axis == AXIS_GMX: - axis_motor = self.__pv_gmx_val.put - elif axis == AXIS_GMY: - axis_motor = self.__pv_gmy_set.put - elif axis == AXIS_GMZ: - axis_motor = self.__pv_gmz_set.put - if axis_motor: - axis_motor(pos) - - if wait: - self.wait_for_movements() - - def rbv(self): - x = self.__pv_gmx_rbv.get() - y = self.__pv_gmy_get.get() - z = self.__pv_gmz_get.get() - omega = self.__pv_omega_get.get() - return {"gmx": x, "gmy": y, "gmz": z, "omega": omega} - - def move(self, angle, *, wait=False, speed=None, direct=False): - """Move omega to `angle` at `speed` deg/s and `wait` (or not). - - If a `speed` is specified, it will be used for the movement but the speed - setting will be reverted to its old value afterwards. - - If `wait` is true, the routine waits until the omega position is close - to within 0.01 degrees to the target or that a timeout occured. The - timeout is the time required for the movement plus 5 seconds. - - In case of a timeout a RuntimeWarning is raised. - - PARAMETERS: - `angle` [degrees] a float specifying where to move to. - No limits. - `speed` [degrees/s] a float specifying speed to move at. - Limits: 0 - 360 - `wait` [boolean] wait or not for movement to finish. - """ - angle = float(angle) - if speed is not None: - speed = float(speed) - if DIRECT_MODE != self.mode: - if direct: - self.set_direct_mode() - else: - raise RuntimeWarning("abr is not in direct mode!") - oget = self.__pv_omega_get - oset = self.__pv_omega_set - vel = self.__pv_omega_velo - odone = self.__pv_omega_done - - cur = oget.get() - ovelo = vel.get() - if speed is not None: - vel.put(speed, wait=True) - poll(0.01) - velo = vel.get() - oset.put(angle, wait=True) - if not wait: - vel.put(ovelo, wait=True) - return - poll(0.01) - timeout = 30.0 + time.time() + abs(angle - cur) / velo # type: ignore - waited_time = timeout - 10.0 - while waited_time < timeout and abs(oget.get() - angle) > 0.01: # type: ignore - poll(0.05) - if not self.is_ioc_ok(): - raise RuntimeError("Aerotech IOC has an error status.") - if not self.is_omega_ok(): - raise RuntimeError("Aerotech OMEGA axis has an error status.") - waited_time = time.time() - if waited_time > timeout: - raise RuntimeError("Timeout on OMEGA movement.") - vel.put(ovelo, wait=True) - - def set_shutter(self, state): - if self.__pv_axes_mode.get(): - print("ABR is not in direct mode; cannot manipulate shutter") - return False - state = str(state).lower() - if state not in ["1", "0", "closed", "open"]: - print("unknown shutter state requested") - return None - elif state in ["1", "open"]: - state = 1 - elif state == ["0", "closed"]: - state = 0 - self.__pv_shutter_set.put(state, wait=True) - return state == self.__pv_shutter_get.get() - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description="aerotech client") - parser.add_argument( - "--stop", help="stop/reset/restart aerotech", action="store_true" - ) - parser.add_argument( - "--sanitize-speeds", - help="reset speeds on axis to sane defaults", - action="store_true", - ) - parser.add_argument( - "--measure-standard", help="measure a standard dataset", action="store" - ) - parser.add_argument("--omega", help="move omega to...", action="store") - parser.add_argument("--gmx", help="move gmx to...", action="store") - parser.add_argument("--gmy", help="move gmy to...", action="store") - parser.add_argument("--gmz", help="move gmz to...", action="store") - args = parser.parse_args() - - abr = Abr() - if args.stop: - abr.stop() - - elif args.sanitize_speeds: - abr.velo(AXIS_GMX, 50.0) - abr.velo(AXIS_GMY, 10.0) - abr.velo(AXIS_GMZ, 10.0) - abr.velo(AXIS_OMEGA, 180.0) - - elif args.gmx: - abr.move_x(args.gmx) - - elif args.measure_standard: - start_angle, total_range, total_time = args.measure_standard.split(",") - abr.measure_standard(start_angle, total_range, total_time) diff --git a/daq/src/mxlibs3/enum_pv.py b/daq/src/mxlibs3/enum_pv.py deleted file mode 100755 index ce500b47..00000000 --- a/daq/src/mxlibs3/enum_pv.py +++ /dev/null @@ -1,126 +0,0 @@ -from typing import cast - -from epics import PV - -from .mx_lib import ValueWaitTimeout, pv_wait - - -class EnumPv(object): - def __init__(self, args): - mandatory_args = {"pv", "readback", "states"} - supplied_args = set(args.keys()) - if not mandatory_args.issubset(supplied_args): - raise RuntimeError("Missing arguments: %s" % (", ".join(mandatory_args.difference(supplied_args)))) - - if type(args["states"]) is not dict: - raise RuntimeError("states must be a dictionary mapping put/readback for waiting purposes") - - self.val = PV(args["pv"]) - self.rbv = PV(args["readback"]) - - if "name" in args: - self.device_name = args["name"] - else: - self.device_name = self.val.pvname - - if not hasattr(self.val, "enum_strs"): - raise RuntimeError("PV %s does not have enum_strs" % self.val.pvname) - if not hasattr(self.rbv, "enum_strs"): - raise RuntimeError("PV %s does not have enum_strs" % self.rbv.pvname) - - self.__target = None - - p = args.get("move_done_when") - if p is not None: - self.__wait_pv = PV(p[0]) - self.__wait_target = p[1] - else: - self.__wait_pv = None - self.__wait_target = None - - self.states = {} - for k, v in list(args["states"].items()): - self.states[k.upper()] = v.upper() - - self.val_enums = [x.upper() for x in self.val.enum_strs] # type: ignore - self.rbv_enums = [x.upper() for x in self.rbv.enum_strs] # type: ignore - - if "timeout" not in args: - self.__timeout = 60 # seconds - else: - self.__timeout = args["timeout"] - - def __str__(self): - return f"<{self.device_name} at {self.position}>" - - def __repr__(self): - s = ( - f"<{self.device_name} at {self.position} an {self.__class__.__name__} " - f"instance at {hex(id(self))} positions = {self.positions}>" - ) - return s - - def has_position(self, position): - return position.upper() in self.states - - @property - def positions(self): - return self.rbv_enums - - def __position(self) -> str: - return self.rbv.enum_strs[self.rbv.get()] # type: ignore - - position = property(__position) - - def position_is(self, position) -> bool: - if type(position) in (int, float): - return int(position) == self.get() - else: - return str(position).upper() == str(self.__position()).upper() - - def get(self, req_type=None) -> str | int: - if req_type: - res = self.position - else: - res = cast(int, self.rbv.get()) - return res - - def put(self, value, wait=False) -> None: - self.val.put(value) - self.__target = self.rbv_enums.index(self.states[self.val_enums[value]]) - if wait: - self.wait() - - def move(self, position, wait=False) -> None: - if type(position) is not int: - if not self.has_position(position): - raise ValueError(f"Invalid position {position} for {self.device_name}") - target = self.val_enums.index(position.upper()) - else: - target = position - - self.put(target, wait=wait) - - def equal_dbr_string(self, val) -> bool: - value = self.rbv.get(as_string=True) - return cast(str, value).lower() == val.lower() - - def equal_dbr_int(self, val) -> bool: - return val == self.rbv.get() - - def wait(self, target=None): - if target is None: - target = self.__target - - if self.__wait_pv: - pv = self.__wait_pv - else: - pv = self.rbv - - if target is None: - target = self.__wait_target - - try: - pv_wait(pv, target, timeout=self.__timeout, verbose=True) - except ValueWaitTimeout: - raise ValueWaitTimeout(f"Timeout waiting for device to reach [{target}], currently at [{self.position}]") diff --git a/daq/src/mxlibs3/my_motor.py b/daq/src/mxlibs3/my_motor.py deleted file mode 100644 index 3727b3d9..00000000 --- a/daq/src/mxlibs3/my_motor.py +++ /dev/null @@ -1,53 +0,0 @@ -import time - -from epics import Motor - - -class MyMotor(Motor): - def __init__(self, name): - super().__init__(name.upper()) - - @property - def speed(self): - return self.slew_speed - - @speed.setter - def speed(self, speed): - self.slew_speed = speed - - @property - def pvname(self): - return self._prefix[:-1] - - def __readback(self): - return self.readback - - position = property(__readback) - - def __value(self): - return self.drive - - value = property(__value) - - -class BogusMotor: - def __init__(self, name, **kwargs): - self.name = name - self.readback = kwargs.get("readback", 0.0) - self.target = kwargs.get("target", 0.0) - self.velo = kwargs.get("velo", 10.0) - - @property - def position(self): - return self.readback - - def move(self, target, wait=False): - if wait: - time.sleep(abs(target - self.readback) / self.velo) - self.readback = target - - def refresh(self): - pass - - def get_position(self, *args, **kwargs): - return self.readback diff --git a/daq/src/mxlibs3/non_standard.py b/daq/src/mxlibs3/non_standard.py deleted file mode 100644 index a5b64ae2..00000000 --- a/daq/src/mxlibs3/non_standard.py +++ /dev/null @@ -1,285 +0,0 @@ -import time -from typing import Callable, cast - -from epics import PV, poll -from epics.ca import pend_io - - -def is_number(x): - return isinstance(x, (int, float)) - - -class NonStandard(object): - def __init__(self, **kwargs): - mandatory = ["name", "setpv", "getpv"] - if set(mandatory) != set(kwargs.keys()) & set(mandatory): - raise RuntimeError( - "missing mandatory argument(s): {}".format(str(list(set(mandatory) - set(kwargs.keys())))) - ) - self.name = kwargs.get("name") - self.__target_pos: float | int | str = 0 - self.device_name = self.name - self.__setpv = PV(kwargs["setpv"]) - self.__getpv = PV(kwargs["getpv"]) - self.__timeout_margin = kwargs.get("timeout", 2.0) # add this safety margin to timeout calc from speed - self.__timeout = kwargs.get("timeout", 60.0) - self.__format = kwargs.get("format") - - p = kwargs.get("speed") - if p is not None: - if is_number(p): - self.__speed_set, self.__speed_get = p, p - elif type(p) in [tuple, list] and len(p) == 2: - self.__speed_set = PV(p[0]) - self.__speed_get = PV(p[1]) - else: - raise Exception(f"{self.name} => don't know how to parse speed parameter") - else: - self.__speed_set, self.__speed_get = None, None - # - # move_done_when a tuple, first item the pv to read - # second item, the int type indicating that it is DONE - # - p = kwargs.get("move_done_when") - if p is not None: - self.__move_flag = PV(p[0]) - self.__move_flag_done = p[1] - else: - self.__move_flag = None - - # - # stoppv a tuple, first item the pv to read - # second item, the int type to put to stop the motor - # - p = kwargs.get("stoppv") - if p is not None: - self.__stoppv = PV(p[0]) - self.__stoppv_done = p[1] - else: - self.__stoppv = None - - # - # still_moving_when a tuple, first item the pv to read - # second item, the int type indicating that it is still moving. - # - p = kwargs.get("still_moving_when") - if p is not None: - self.__still_moving_flag = PV(p[0]) - self.__still_moving_flag_value = p[1] - else: - self.__still_moving_flag = None - - p = kwargs.get("predefs") - if p: - self.__predefs = p - self.positions = list(p.keys()) - else: - self.__predefs = {} - self.positions = [] - - pend_io(5.0) - - typ = self.__ret_type = self.__getpv.type - - match str(typ): - case "double" | "time_double": - self.still_moving = self.__moving_float - case "int" | "time_int": - self.still_moving = self.__moving_int - case "string" | "time_string": - self.still_moving = self.__moving_str - case _: - self.still_moving = self.__moving_unknown - - tolerance = kwargs.get("tolerance", None) - if tolerance is not None and tolerance > 0: - self.tolerance = tolerance - elif tolerance is not None and tolerance < 0: - self.still_moving = self.__moving_unknown - - if self.__move_flag: - self.still_moving = self.is_move_not_done - elif self.__still_moving_flag: - self.still_moving = self.still_moving_when - - def __str__(self): - if self.positions: - return "<{} at {}({}) Pre-defined positions {}>".format( - self.name, self.__position(predef=True), self.position, self.positions - ) - else: - return "<{} at {}>".format(self.name, self.__position()) - - def __repr__(self): - if self.positions: - return "<{} instance at {}: {} at {}({}) Pre-defined positions {}>".format( - self.__class__.__name__, - hex(id(self)), - self.name, - self.__position(predef=True), - self.position, - self.positions, - ) - else: - return "<{} instance at {}: {} at {}>".format( - self.__class__.__name__, hex(id(self)), self.name, self.__position() - ) - - def still_moving_when(self): - return self.__still_moving_flag_value == self.__still_moving_flag.get() # type: ignore - - def is_moving(self): - return not self.is_move_done() - - def is_move_done(self): - return self.__move_flag_done == self.__move_flag.get() # type: ignore - - def is_move_not_done(self): - return not self.is_move_done() - - def __moving_float(self): - if type(self.__target_pos) is not float: - raise RuntimeError("target position is not an float") - current_value = cast(float, self.__getpv.get()) - return self.tolerance < abs(cast(float, self.__target_pos) - current_value) - - def __moving_int(self): - if type(self.__target_pos) is not int: - raise RuntimeError("target position is not an integer") - return self.__target_pos != self.__getpv.get() - - def __moving_str(self): - if type(self.__target_pos) is not str: - raise RuntimeError("target position is not a string") - current_value = cast(str, self.__getpv.get()) - return self.__target_pos.upper() != current_value.upper() - - def __moving_unknown(self): - return False - - def __position(self, predef: bool = False): - """returns either a predefined position or a readback - - :rtype: Union[str, float, int] - """ - cur = self.readback - if not predef: - return cur - # loop over predefined positions, if one found and - # readback matches it's value return "position" - for pos_label, val_or_cbk in self.__predefs.items(): - if self.__ret_type is bytes: - tst = val_or_cbk == cur - elif type(val_or_cbk) is tuple: - # a tuple (Callable, arg-to-Callable) - val = val_or_cbk[0](*val_or_cbk[1]) - tst = 0.1 > abs(val - cur) # FIXME sooo bad - else: - tst = 0.1 > abs(val_or_cbk - cur) - if tst: - return pos_label - return "unknown" - - def __readback(self): - return self.__getpv.get() - - readback = property(__readback) - position = property(__position) - - def has_position(self, position: str) -> bool: - return position.lower() in [p.lower() for p in self.positions] - - def position_is(self, position, tolerance=0.1): - pos = self.__predefs.get(position, position) - cur = self.position - - print(f"position_is: {pos} == {cur}") - - if type(pos) is tuple: - pos = pos[0](*pos[1]) - - print(f"position_is: {pos} == {cur}") - - if self.__ret_type is bytes: - print("checking bytes") - return pos == cur - else: - print(f"checking numbers: abs({pos} - {cur}) < {tolerance}") - return abs(pos - cur) < tolerance - - def __value(self): - val = self.__getpv.get() - if self.__format is not None: - val = self.__format % (val,) - return val - - value = property(__value) - - def __raw_value(self): - return self.__getpv.get() - - raw_value = property(__raw_value) - - def __char_value(self): - return str(self.value) - - char_value = property(__char_value) - - def set_speed(self, speed): - if isinstance(self.__speed_set, PV): - self.__speed_set.put(speed) - elif is_number(self.__speed_set): - self.__speed_set = speed - self.__speed_get = speed - - def get_speed(self): - if is_number(self.__speed_get): - return self.__speed_get - elif isinstance(self.__speed_get, PV): - return self.__speed_get.value - else: - return None - - def get_timeout(self): - if not self.__speed_get: - timeout = self.__timeout - else: - speed = self.get_speed() - curp = self.position - if curp is None or self.__target_pos is None or speed is None: - timeout = self.__timeout_margin - raise RuntimeWarning("can't calculate timeout, ABR may be disconnected") - else: - timeout = self.__timeout_margin + (abs(curp - self.__target_pos) / speed) - return timeout - - def wait(self): - pos = self.__target_pos - timeout = time.time() + self.get_timeout() - - while time.time() < timeout and self.still_moving(): - poll(0.1) - if time.time() > timeout: - msg = "timeout occurred when moving %s to %s" % (self.name, pos) - print(msg) - raise RuntimeWarning(msg) - - def move(self, pos, relative=False, wait=False): - pos = self.__predefs.get(pos, pos) - if type(pos) is tuple: - pos = pos[0](*pos[1]) - - if relative: - pos += self.__getpv.get() - - self.__target_pos = pos - self.__setpv.put(pos) - if wait: - time.sleep(0.1) - self.wait() - - def stop(self): - if self.__stoppv: - self.__stoppv.put(self.__stoppv_done) - else: - raise RuntimeError("stop pv not configured for this motor") diff --git a/daq/src/mxlibs3/pshell_client.py b/daq/src/mxlibs3/pshell_client.py deleted file mode 100644 index e81a62c3..00000000 --- a/daq/src/mxlibs3/pshell_client.py +++ /dev/null @@ -1,794 +0,0 @@ -import threading -import time -import sys -import requests -import json - - -try: - from urllib import quote # Python 2 -except ImportError: - from urllib.parse import quote # Python 3 - - -class TimeoutException(Exception): - pass - - -try: - from sseclient import SSEClient -except: - SSEClient = None - -class SSEReceiver: - def __init__(self, url, subscribed_events): - if SSEClient is None: - raise Exception("sseclient library is not installed: server events are not available") - self.url = url - self.events = subscribed_events - self._lock = threading.Lock() - self._stop = threading.Event() - self.session = None - self.client = None - self.debug = False - self._subscribers = {} - self.thread = threading.Thread(target=self.task, kwargs={}) - self.thread.daemon = True - self.thread.start() - - def task(self): - try: - while not self._stop.is_set(): - try: - self.session = requests.Session() - self.client = SSEClient(self.url, session=self.session) - for msg in self.client: - if self.is_closed(): - break - event_name = msg.event or "message" - - if (self.events is None) or (event_name in self.events): - try: - data = json.loads(msg.data) - except: - data = str(msg.data) - #if self.debug: - # print (event_name, data) - with self._lock: - subs = list(self._subscribers.values()) - - for events, callback in subs: - if events is None or event_name in events: - try: - callback(event_name, data) - except Exception as e: - if self.debug: - print(f"[SSEManager] Error in callback {callback}: {e}") - - except IOError as e: - # print(e) - pass - except: - if self.debug: - print("Error:", sys.exc_info()[1]) - finally: - self._close_client() - if self.is_closed(): - break - else: - time.sleep(1.0) - finally: - if self.debug: - print("Exit SSE loop task") - - def subscribe(self, callback, events=None): - """ - Subscribe to SSE events. - - Args: - callback: function(event_name, data) - events: None (all events), str (one event), or list[str] (multiple events) - """ - if isinstance(events, str): - events = [events] - if events is not None: - events = set(events) - - with self._lock: - self._subscribers[id(callback)] = (events, callback) - - def unsubscribe(self, callback): - """Unsubscribe a previously subscribed callback.""" - with self._lock: - self._subscribers.pop(id(callback), None) - - def wait_events(self, events={}, timeout=-1): - """Wait any of the events matching the value (value None for any). - - Args: - events (dict event name->value) - timeout: - Returns: - (event, value) or None if timeout - """ - rx = {} - condition = threading.Condition() - def callback(name, value): - with condition: - rx[name] = value - condition.notify_all() - - self.subscribe(callback, events.keys()) - try: - start = time.time() - with condition: - while True: - for name in events.keys(): - if name in rx.keys(): - values, rx_value = events[name], rx[name] - if values is not None and type(values) is not list: - values = [values] - if values is None or rx_value in values: - return name,rx_value - - remaining = None - if timeout >= 0: - remaining = max(0, timeout - (time.time() - start)) - if remaining <= 0: - return None - condition.wait(timeout=remaining) - finally: - self.unsubscribe(callback) - - - def _close_client(self): - self.client = None - """ - if self.client is not None: - try: - if hasattr(self.client.resp, "raw"): - conn = getattr(self.client.resp.raw, "_connection", None) - if conn and hasattr(conn, "sock") and conn.sock: - conn.sock.shutdown(2) - conn.sock.close() - self.client.resp.close() - self.client = None - except: - pass - """ - if self.session is not None: - try: - self.session.close() - self.session = None - except: - pass - - def close(self): - self._stop.set() - self._close_client() - if self.debug: - print("closed") - - def is_closed(self): - return self._stop.is_set() - -class PShellClient: - def __init__(self, url): - if not url.endswith('/'): - url = url + "/" - self.url = url - self.sse_event_loop_thread = None - self.sse_client = None - self.plot_defaults = {"format": "png", "width": 600, "height": 400} - self.debug = False - self.polling_interval = 0.1 - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - def _get(self, url, stream=False): - url = self.url + url - if self.debug: - print("GET " + url) - return requests.get(url=url, stream=stream) - - def _put(self, url, json_data=None): - url = self.url + url - if self.debug: - print("PUT " + url + " -> " + json.dumps(json_data)) - return requests.put(url=url, json=json_data) - - def _del(self, url): - url = self.url + url - if self.debug: - print("DEL " + url) - return requests.delete(url=url) - - def _get_response(self, response, is_json=True): - if self.debug == True or self.debug == "rx": - print(" -> " + str(response.status_code) + ((" - " + response.text) if self.debug == "rx" else "")) - try: - response.raise_for_status() - except: - print(response.text) - raise - return json.loads(response.text) if is_json else response.text - - def _get_binary_response(self, response): - response.raise_for_status() - return response.raw.read() - - def get_plot_defaults(self): - """Return plot default properties. - - Args: - - Returns: - Dictionary - - """ - return self.plot_defaults.copy() - - def set_plot_defaults(self, defaults): - """Update plot default properties. - - Args: - Dictionary that will updated into the plot default properties. - Returns: - - """ - self.plot_defaults.update(defaults) - - def get_version(self): - """Return application version. - - Args: - - Returns: - String with application version. - - """ - return self._get_response(self._get("version"), False) - - def get_config(self): - """Return application configuration. - - Args: - - Returns: - Dictionary. - """ - return self._get_response(self._get("config")) - - def get_state(self): - """Return application state. - - Args: - - Returns: - String: Invalid, Initializing,Ready, Paused, Busy, Disabled, Closing, Fault, Offline - """ - return self._get_response(self._get("state")) - - def wait_state(self, state, timeout=-1): - """Wait application state equals. - - Args: - state (string or list of strings) - timeout(number) wait timeout in seconds. If less or equal 0 then wait forever. - Returns: - """ - if type(state) == str: - state = [state] - start = time.time() - while self.get_state() not in state: - if (timeout >= 0) and ((time.time() - start) > timeout): - raise TimeoutException(f"Timeout waiting state {state}") - time.sleep(self.polling_interval) - - def wait_state_not(self, state, timeout=-1): - """Wait application state different than. - - Args: - state (string or list of strings) - timeout(number) wait timeout in seconds. If less or equal 0 then wait forever. - Returns: - """ - if type(state) == str: - state = [state] - start = time.time() - while self.get_state() in state: - if (timeout >= 0) and ((time.time() - start) > timeout): - raise TimeoutException(f"Timeout waiting state not {state}") - time.sleep(self.polling_interval) - - def get_logs(self): - """Return application logs. - - Args: - - Returns: - List of logs. - Format of each log: [date, time, origin, level, description] - - """ - return self._get_response(self._get("logs")) - - def get_history(self, index): - """Access console command history. - - Args: - index(int): Index of history entry (0 is the most recent) - - Returns: - History entry - - """ - return self._get_response(self._get("history/" + str(index)), False) - - def get_script(self, path): - """Return script. - - Args: - path(str): Script path (absolute or relative to script folder) - - Returns: - String with file contents. - - """ - return self._get_response(self._get("script/" + str(path)), False) - - def get_devices(self): - """Return global devices. - - Args: - - Returns: - List of devices. - Format of each device record: [name, type, state, value, age] - - """ - return self._get_response(self._get("devices")) - - def abort(self, command_id=None): - """Abort execution of command - - Args: - command_id(optional, int): id of the command to be aborted. - if None (default), aborts the foreground execution. - - Returns: - - """ - if command_id is None: - self._get("abort") - else: - return self._get("abort/" + str(command_id)) - - def pause(self): - """Pause execution of command - - Args: - - Returns: - - """ - self._get("pause") - - def resume(self): - """Resume execution of command - - Args: - - Returns: - - """ - self._get("resume") - - def reinit(self): - """Reinitialize the software. - - Args: - - Returns: - - """ - self._get("reinit") - - def stop(self): - """Stop all devices implementing the 'Stoppable' interface. - - Args: - - Returns: - - """ - self._get("stop") - - def update(self): - """Update all global devices. - - Args: - - Returns: - - """ - self._get("update") - - def eval(self, statement): - """Evaluates a statement in the interpreter. - If the statement finishes by '&', it is executed in background. - Otherwise statement is executed in foreground (exclusive). - - Args: - statement(str): input statement - - Returns: - String containing the console return. - If an exception is produces in the interpretor, it is re-thrown here. - """ - statement = quote(statement) - return self._get_response(self._get("eval/" + statement), False) - - def run(self, script, pars=None, background=False): - """Executes script in the interpreter. - - Args: - script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. - pars(optional, list or dict): if a list is given, it sets sys.argv for the script. - If a dict is given, it sets global variable for the script. - background(optional, bool): if True script is executed in background. - - Returns: - Return value of the script. - If an exception is produces in the interpretor, it is re-thrown here. - """ - return self._get_response( - self._put("run", {"script": script, "pars": pars, "background": background, "async": False})) - - def start_eval(self, statement): - """Starts evaluation of a statement in the interpreter. - If the statement finishes by '&', it is executed in background. - Otherwise statement is executed in foreground (exclusive). - - Args: - statement(str): input statement - - Returns: - Command id (int), which is used to retrieve command execution status/result (get_result). - """ - statement = quote(statement) - return int(self._get_response(self._get("evalAsync/" + statement), False)) - - def eval_json(self, statement): - """Evaluates a statement in the interpreter. - Args: - statement(str): input statement - - Returns: - Return object decoded from JSON string - """ - statement = quote(statement) - return self._get_response(self._get("eval-json/" + statement), True) - - def eval_then(self, statement, on_success=True, on_exception=True): - """Set a next execution stage for the interpreter - the statement is executed - after the foreground task concludes, keeping application state busy. - - Args: - statement(str): statement for next execution stage - on_successs(bool): statement is executed if foreground task completes successfully. - on_exception(bool): statement is executed if foreground task throws exception. - """ - return self._get_response( - self._put("then", {"statement": statement, "onSuccess": on_success, "onException": on_exception})) - - def run_then(self, script, pars=None, on_success=True, on_exception=True): - """Set a next execution stage for the interpreter - the script is executed - after the foreground task concludes, keeping application state busy. - - Args: - script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. - pars(optional, list or dict): if a list is given, it sets sys.argv for the script. - If a dict is given, it sets global variable for the script. - on_successs(bool): statement is executed if foreground task completes successfully. - on_exception(bool): statement is executed if foreground task throws exception. - """ - cmd = f"run('{script}', {pars})" - return self.eval_then(cmd, on_success, on_exception) - - def set_var(self, name, value): - """Sets interpreter variable. - Args: - name(str): variable name - value(obj): value - must be JSON compatible - - Returns: - - """ - data = {} - data["name"] = name - data["value"] = value - return self._get_response(self._put("set-var", data), False) - - def start_run(self, script, pars=None, background=False): - """Starts execution of a script in the interpreter. - - Args: - script(str): name of the script (absolute or relative to the script base folder). Extension may be omitted. - pars(optional, list or dict): if a list is given, it sets sys.argv for the script. - If a dict is given, it sets global variable for the script. - background(optional, bool): if True script is executed in background. - - Returns: - Command id (int), which is used to retrieve command execution status/result (get_result). - """ - return int(self._get_response( - self._put("run", {"script": script, "pars": pars, "background": background, "async": True}))) - - def get_result(self, command_id=-1): - """Gets status/result of a command executed asynchronously (start_eval and start_run). - - Args: - command_id(optional, int): command id. If equals to -1 (default) return status/result of the foreground task. - - Returns: - Dictionary with the fields: 'id' (int): command id - 'status' (str): unlaunched, invalid, removed, running, aborted, failed or completed. - 'exception' (str): if status equals 'failed', holds exception string. - 'return' (obj): if status equals 'completed', holds return value of script (start_run) - or console return (start_eval) - """ - return self._get_response(self._get("result/" + str(command_id))) - - def help(self, input=""): - """Returns help or auto-completion strings. - - Args: - input(optional, str): - ":" for control commands - - "" for builtin functions - - "devices" for device names - - builtin function name for function help - - else contains entry for auto-completion - - Returns: - List - - """ - return self._get_response(self._get("autocompletion/" + input)) - - def get_contents(self, path=None): - """Returns contents of data path. - - Args: - path(optional, str): Path to data relative to data home path. - - Folder - - File - - File (data root) | internal path - - internal path (on currently open data root) - - Returns: - List of contents - - """ - return self._get_response(self._get("contents" + ("" if path is None else ("/" + path))), False) - - def get_data(self, path, type="txt"): - """Returns data on a given path. - - Args: - path(str): Path to data relative to data home path. - - File (data root) | internal path - - internal path (on currently open data root) - type(optional, str): txt, "json", "bin", "bs" - - Returns: - Data accordind to selected format/. - - """ - if type == "json": - return self._get_response(self._get("data-json/" + path), True) - elif type == "bin": - return self._get_binary_response(self._get("data-bin/" + path, stream=True)) - elif type == "bs": - from collections import OrderedDict - bs = self._get_binary_response(self._get("data-bs/" + path, stream=True)) - index = 0 - msg = [] - for i in range(4): - size = int.from_bytes(bs[index:index + 4], byteorder='big', signed=False) - index = index + 4 - msg.append(bs[index:index + size]) - index = index + size - [main_header, data_header, data, timestamp] = msg - main_header = json.loads(main_header, object_pairs_hook=OrderedDict) - data_header = json.loads(data_header, object_pairs_hook=OrderedDict) - channel = data_header["channels"][0] - channel["encoding"] = "<" if channel.get("encoding", "little") else ">" - from bsread.data.helpers import get_channel_reader - channel_value_reader = get_channel_reader(channel) - return channel_value_reader(data) - - return self._get_response(self._get("data" + ("" if path is None else ("/" + path))), False) - - def get_data_attrs(self, path): - return self._get_response(self._get("data-attr/" + path), True) - - def get_data_info(self, path): - return self._get_response(self._get("data-info/" + path), True) - - def get_scan_data(self, layout, path, group, device, type="txt"): - """Returns scan data of a device. - - Args: - layout(str): data layout - path(str): scan path - group(str): scan group - device(str): device name - type(optional, str): txt, "json", "bin" - - Returns: - Data accordind to selected format. - - """ - if layout is None or layout.strip() == "" or path is None: - raise Exception("Invalid scan persistence path or layout") - path = path.replace("/", "
") - path = path.replace("|", "

") - group = group.replace("/", "
") - layout = layout.replace(".", "
") - url = layout + "/" + path + "/" + group + "/" + device - if type == "json": - url = "scandata-json/" + url - return self._get_response(self._get(url), True) - elif type == "bin": - url = "scandata-bin/" + url - return self._get_binary_response(self._get(url, stream=True)) - url = "scandata/" + url - return self._get_response(self._get(url), False) - - def get_plot_contexts(self): - """Return list of plot contexts - - Args: - - Returns: - List of names - - """ - return self._get_response(self._get("plots")) - - def delete_plot_context(self, title): - """ - Delete a plotting context. - - Args: - title(str): name of the plotting context - - Returns: - - """ - return self._get_response(self._del("plots/" + title), False) - - def get_num_plots(self, title=None): - """Return number of plots in a given plotting context. - - Args: - title(str): name of the plotting context - - Returns: - Number of plots - - """ - if title is None: - title = "null" - return int(self._get_response(self._get("plots/" + title))) - - def get_plot(self, title=None, index=0, format="png", width=None, height=None): - """Return a plot as a given image type. - - Args: - title(str): name of the plotting context - index(int): plot index (0-based) - format(str): plot format ("jpg", "png", "gif", "tif") - width(int): plot width (if 0 gets plot staddard size) - height(int): plot height (if 0 gets plot staddard size) - Returns: - Image file byte array - - """ - if title is None: - title = "null" - if format is None: - format = self.plot_defaults["format"] - if width is None: - width = self.plot_defaults["width"] - if height is None: - height = self.plot_defaults["height"] - - url = "plot/" + title + "/" + str(index) + "/" + format + "/" + str(width) + "/" + str(height) - return self._get_binary_response(self._get(url, stream=True)) - - def print_logs(self): - for l in self.get_logs(): - print("%s %s %-20s %-8s %s" % tuple(l)) - - def print_devices(self): - for l in self.get_devices(): - print("%-16s %-32s %-10s %-32s %s" % tuple(l)) - - def print_help(self, input=""): - for l in self.help(input): - print(l) - - def _get_sse(self): - if self.sse_client is None: - self.sse_client = SSEReceiver(self.url + "events", None) - self.sse_client.debug = self.debug - return self.sse_client - - def subscribe(self, callback=None, events=None): - """ - Subscribe to SSE events. - - Args: - callback: function(event_name, data), If None, calls self.on_event - events: None (all events), str (one event), or list[str] (multiple events) - - Usage example: - def on_event(name, value): - if name == "state": - print ("State changed: ", value) - elif name == "record": - print ("Received scan record: ", value) - - pc.subscribe(["state", "record"], on_event) - """ - if callback == None: - callback = self.on_event - self._get_sse().subscribe(callback, events) - - def unsubscribe(self, callback): - """Unsubscribe a previously subscribed callback.""" - self._get_sse().unsubscribe(callback) - - def wait_events(self, events={}, timeout=-1): - """Wait any of the events matching the value (value None for any). - - Args: - events (dict event name->value) - timeout(number) wait timeout in seconds. If less or equal 0 then wait forever. - Returns: - (event, value) or raises TimeoutException - - Usage example: - def on_event(name, value): - if name == "state": - print ("State changed: ", value) - elif name == "record": - print ("Received scan record: ", value) - - pc.subscribe(["state", "record"], on_event) - - """ - ret = self._get_sse().wait_events(events, timeout) - if ret is None: - raise TimeoutException(f"Timeout waiting for events {events}") - return ret - - def on_event(self, name, value): - """ - Default event callback - Args: - name: event name. - value: event value. - """ - pass - - def close(self): - if self.sse_client is not None: - self.sse_client.close() - diff --git a/daq/src/mxlibs3/smargon.py b/daq/src/mxlibs3/smargon.py deleted file mode 100644 index f40789e6..00000000 --- a/daq/src/mxlibs3/smargon.py +++ /dev/null @@ -1,132 +0,0 @@ -from enum import Enum -from time import sleep, time - -import requests - -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.coordinate import SmargonCoordinate, Coordinate - - -class SmargonMode(Enum): - UNINITIALIZED = 0 - INITIALIZING = 1 - READY = 2 - ERROR = 99 - - -class Smargon(object): - SMARGON_HOME = SmargonCoordinate( - sh_mm=Coordinate(x=0, y=0, z=18), phi_deg=0, chi_deg=0 - ) - - def __init__(self, bl: MXBeamline): - if bl == MXBeamline.X06DA: - self.__simulated = False - self.__base = "http://x06da-smargopolo.psi.ch:3000" - elif bl == MXBeamline.SIMULATED: - self.__simulated = True - self.__pos = self.SMARGON_HOME - else: - raise Exception("unknown beamline") - - def gonget(self, thing: str) -> dict: - """issue a GET for some API component on the smargopolo server""" - cmd = f"{self.__base}/{thing}" - r = requests.get(cmd) - if not r.ok: - raise Exception( - f"error getting {thing}; server returned {r.status_code} => {r.reason}" - ) - return r.json() - - def gonput(self, thing: str): - cmd = f"{self.__base}/{thing}" - r = requests.put(cmd) - if not r.ok: - raise Exception( - f"error putting {thing}; server returned {r.status_code} => {r.reason}" - ) - - def move_home(self, wait=False) -> None: - self.target = self.SMARGON_HOME - if wait: - self.wait() - - @property - def mode(self) -> SmargonMode: - return SmargonMode.INITIALIZING - - @mode.setter - def mode(self, mode: SmargonMode): - if self.__simulated: - return - self.gonput(f"mode?mode={mode}") - - def initialize(self): - self.mode = SmargonMode.UNINITIALIZED - sleep(0.1) - self.mode = SmargonMode.INITIALIZING - - def enable_correction(self): - if self.__simulated: - return - - self.gonput("corr_type?corr_type=1") - - def disable_correction(self): - if self.__simulated: - return - - self.gonput("corr_type?corr_type=0") - - @property - def readback(self) -> SmargonCoordinate: - if self.__simulated: - return self.__pos - - scs = self.gonget("readbackSCS") - return SmargonCoordinate( - sh_mm=Coordinate(x=scs["SHX"], y=scs["SHY"], z=scs["SHZ"]), - phi_deg=scs["PHI"], - chi_deg=scs["CHI"], - ) - - @property - def target(self) -> SmargonCoordinate: - if self.__simulated: - return self.__pos - - scs = self.gonget("targetSCS") - return SmargonCoordinate( - sh_mm=Coordinate(x=scs["SHX"], y=scs["SHY"], z=scs["SHZ"]), - phi_deg=scs["PHI"], - chi_deg=scs["CHI"], - ) - - @target.setter - def target(self, coord: SmargonCoordinate): - if self.__simulated: - self.__pos = coord - return - - target_string = "" - if coord.sh_mm is not None: - target_string += "&SHX={:.5f}&SHY={:.5f}&SHZ={:.5f}".format( - coord.sh_mm.x, coord.sh_mm.y, coord.sh_mm.z - ) - if coord.chi_deg is not None: - target_string += "&CHI={:.5f}".format(coord.chi_deg) - if coord.phi_deg is not None: - target_string += "&PHI={:.5f}".format(coord.phi_deg) - if target_string: - self.gonput(f"targetSCS?{target_string}") - - def wait(self, timeout=60.0, tol=0.01, poll_time=0.01): - target = self.target - timeout = timeout + time() - while time() < timeout: - if target.eq(self.readback, tol): - break - if time() > timeout: - raise TimeoutError("Timed out waiting for Smargon to reach target") - sleep(poll_time) diff --git a/daq/src/mxlibs3/tell_client.py b/daq/src/mxlibs3/tell_client.py deleted file mode 100755 index 391a876d..00000000 --- a/daq/src/mxlibs3/tell_client.py +++ /dev/null @@ -1,688 +0,0 @@ -import json -import logging -import random -import re -import time -from typing import List -from urllib.parse import urlparse - -import requests - -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import ( - PuckLoadedInfo, - SampleShortInfo, - DewarAddress, - SampleDewarAddress, - #PuckInfo, -) -from aareDBclient import ( - PuckWithTellPosition, -) -from aaredaqlib.beamline import MXBeamline # noqa: F401 -from mxlibs3.pshell_client import PShellClient - -logger = setup_logger("aareDAQ") - -class ManualMountException(Exception): - pass - - -class SmartMagnetFaultException(Exception): - pass - - -class TellMountFailedException(Exception): - pass - - -class TellCommandWhileBusyException(Exception): - pass - - -class TellConnectionException(Exception): - pass - -VALID_DEWAR_POSITIONS = [f"{p}{n}" for n in "12345" for p in "ABCDEFX"] - -POSITION_PARK = "pPark" -POSITION_COLD = "pCold" -POSITION_AUX = "pAux" -POSITION_DEWAR = "pDewar" -POSITION_HOME = "pHome" -POSITION_HEATER = "pHeatB" - -#Nov 26 13:36:00 mx-x06da-queue-01.psi.ch AareDAQ[2944444]: 2025-11-26 13:36:00,388 - aareDAQ - ERROR - Error getting status: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer')) - -class TellClient: - def __init__(self, bl: MXBeamline): - self.__url = None - if bl == MXBeamline.SIMULATED: - self.__simulation = True - elif bl == MXBeamline.X06DA: - self.__simulation = False - self.__url = "http://x06da-tell.psi.ch:22222" - - if self.__simulation: - print("TELL P-Shell in SIMULATION mode") - else: - print(f"Connecting TELL p-shell service at {self.__url} ...", end="") - hostname = urlparse(self.__url).hostname - try: - requests.get(f"{self.__url}/history/0", timeout=1.0) - except ConnectionError: - print(f"...connection to {hostname} failed") - raise - except requests.ReadTimeout: - print(f"...PShell service {hostname} is down") - raise - self.pshell = PShellClient(self.__url) - self._simulated_samples_info = {} - self._simulated_detected_pucks = [] - self._simulated_mounted_sample = "" - self._simulated_current = 30.0 - self._simulated_suppress = True - self._simulated_state = "Ready" - self._simulated_offset = 0.0 - self._aborted = False - self.state = self.get_state() - self.debug = False - self._last_cmd_id = -1 - - @property - def url(self): - return self.__url - - def smc_get_current(self) -> float: - if self.__simulation: - return 30.0 - return json.loads(self.pshell.eval("smart_magnet.get_current()&")) - - def smc_set_current(self, current: float): - if self.__simulation: - return - self.pshell.eval(f"smart_magnet.set_current({current:.1f})&") - - def smc_get_suppress(self) -> bool: - if self.__simulation: - return self._simulated_suppress - return json.loads(self.pshell.eval("smart_magnet.get_supress()&")) - - def smc_set_suppress(self, state: bool): - if self.__simulation: - self._simulated_suppress = state - return - self.pshell.eval(f"smart_magnet.set_supress({state})&") - - def check_smc(self): - self.pshell.eval("smart_magnet.set_supress(False)&") - self.pshell.eval("smart_magnet.set_resting_current()&") - self.pshell.eval("smart_magnet.check_mounted(idle_time=1.0, timeout=1.0") - - def magnet_blower(self, state): - """turn on/off blower to the magnet for de-icying purposes - - state = false (blower is off) - state = true (blower is on) - """ - if X06DA: - self.pshell.eval(f"set_pin_cleaner({state})&") - else: - cmd = "true" if state else "false" - self.pshell.eval(f'robot.evaluate("doFOut1={cmd}")&') - - def get_state(self): - if self.__simulation: - return self._simulated_state - self.state = self.pshell.get_state() - return self.state - - def get_result(self, command_id=-1): - if self.__simulation: - return { - "id": self._last_cmd_id, - "status": "completed", - "exception": "", - "return": (True, "PINCODE6546"), - } - return self.pshell.get_result(command_id) - - def wait_ready(self): - if self.__simulation: - logger.info("simulated wait_ready") - time.sleep(3.0) - self._simulated_state = "Ready" - return - # Monitors event but polls every second just n case an event is missed - logger.debug(f"Waiting for robot to be ready. Current state: {self.state} Get state: {self.get_state()}") - while True: - if self.state != "Busy": - logger.debug(f"Robot is now ready...? {self.state} Get:{self.get_state()}") - break - time.sleep(0.2) - self.get_state() - if self.state != "Ready": - if self.state == "Initializing": - raise Exception("Tell reconnecting") - elif self.state == "Closing": - raise Exception("Tell is disconnecting") - raise Exception("Invalid state: " + str(self.state)) - - def set_in_mount_position(self, value): - if self.__simulation: - return - self.pshell.eval("in_mount_position = " + str(value) + "&") - - def is_in_mount_position(self): - if self.__simulation: - return True - return self.pshell.eval("in_mount_position&").lower() == "true" - - def set_simulated_mounted_sample(self, info): - self._simulated_mounted_sample = info - - def set_simulated_samples_info(self, samples): - self._simulated_samples_info = samples - - def set_simulated_detected_pucks(self, pucks): - self._simulated_detected_pucks = pucks - - def get_samples_info(self) -> List[SampleShortInfo]: - if self.__simulation: - j = self._simulated_samples_info # FIXME - else: - j = json.loads(self.pshell.eval("get_samples_info()&")) - - output: List[SampleShortInfo] = [] - for i in j: - if len(i["puckAddress"]) == 2: - dewar_location = DewarAddress( - segment=i["puckAddress"][0], pos=i["puckAddress"][1] - ) - else: - dewar_location = None - - output.append( - SampleShortInfo( - puck_name=i["puckBarcode"], - dewar_name=i["dewarName"], - sample_name=i["sampleName"], - pin=i["samplePosition"], - user=i["userName"], - location=dewar_location, - ) - ) - return output - - def set_samples_info(self, info: List[PuckWithTellPosition]): - if self.__simulation: - return - - j = [] - for x in info: - j.append( - { - "userName": x.pgroup, - "dewarName": x.dewar_name or "", - "puckName": x.puck_name, - "puckType": "Unipuck", # could use x.puck_type - "puckAddress": x.tell_position or "", - "puckBarcode": x.puck_name, - "sampleBarcode": "", - "sampleMountCount": 0, - "sampleName": "", - "samplePosition": 1, - "sampleStatus": "", - } - ) - - self.pshell.run("data/set_samples_info", pars=[json.dumps(j)], background=True) - # self.pshell.eval("set_samples_info(" + json.dumps(info) + ")&") - - def start_cmd(self, cmd, *argv): - if self.__simulation: - return 666 # FIXME should be different? - cmd = cmd + "(" - for a in argv: - cmd = cmd + (("'" + a + "'") if type(a) is str else str(a)) + ", " - cmd = cmd + ")" - ret = self.pshell.start_eval(cmd) - self.get_state() - return ret - - def wait_cmd(self, cmd): - if self.__simulation: - return {True, "BARCODE_BIGUS"} - self.wait_ready() - result = self.get_result(cmd) - # print (result) - if result["exception"] is not None: - raise Exception(result["exception"]) - return result["return"] - - def is_cmd_completed(self, cmd): - if self.__simulation: - return True - return self.get_result(cmd)["status"] != "running" - - def wait_mount_complete(self, timeout: float = 360): - if self.__simulation: - time.sleep(1.0) - return - logger.debug(f"Waiting for mount to complete. Is busy? {self.is_busy()}") - timeisup = timeout + time.time() - while time.time() < timeisup: - if not self.is_busy(): - logger.debug(f"Finished waiting for mount to complete. Is busy? {self.is_busy()}") - break - time.sleep(0.2) - - def check_command_ok(self, timeout: float = 360.0, msg: str = ""): - self.wait_mount_complete(timeout) - result = self.get_result(self._last_cmd_id) - if "completed" != result["status"]: - raise TellMountFailedException(f"{msg} {result}") - - def estimate_mounting_time(self, segment) -> int: - try: - current_mounted = self.get_mounted_sample() - gripper_in_cold = self.is_in_cold() - - if current_mounted is None: - unmount_needs_drying = 0 # might not have anything - unmount_needs_cooling = 0 - else: - segment_in_cold = current_mounted.puck.segment in "ABCDEF" - unmount_needs_drying = int(gripper_in_cold and not segment_in_cold) - unmount_needs_cooling = int(not gripper_in_cold and segment_in_cold) - - mount_needs_cooling = int(segment in "ABCDEF" and not gripper_in_cold) - mount_needs_drying = int(segment not in "ABCDEF" and gripper_in_cold) - - needs_cooling = mount_needs_cooling + unmount_needs_cooling - needs_drying = mount_needs_drying + unmount_needs_drying - return needs_cooling * 30 + needs_drying * 120 - except: - return 0 - - def mount( - self, - address: SampleDewarAddress, - force: bool = False, # kept for future - read_dm: bool = False, # read data matrix - auto_unmount: bool = False, # single command, if False it will raise exception - wait: bool = False, # blocking operation - timeout: float = 600.0, - ): - SampleDewarAddress.model_validate(address) - - segment = address.puck.segment - puck = address.puck.pos - sample = address.pin - - if self.__simulation: - self._last_cmd_id = random.randint(1000, 9999) - print( - f"simulated mount({segment}, {puck}, {sample}) -> {self._last_cmd_id}" - ) - self._simulated_mounted_sample = f"{segment}{puck}{sample}" - if random.random() < 0.1: - print("simulated failed mount") - raise TellMountFailedException(f"mount failed for {segment}{puck}") - - return self._last_cmd_id - - if self.is_busy(): - raise TellCommandWhileBusyException("mount received while robot is busy") - - logger.info(f"loading sample {sample} from segment {segment} - {puck}") - - self._last_cmd_id = self.start_cmd( - "mount", segment, puck, sample, force, read_dm, auto_unmount - ) - - wait_timeout = timeout + self.estimate_mounting_time(segment) - logger.info("waiting for mount to complete") - if wait and segment in "ABCDEF": - event, value = self.pshell.wait_events({"state": None, "motion_task": "dry", "gripper_detection" : "No Pin in Gripper"}, timeout=wait_timeout) - if event is None or event == "state": - logger.info(f"event: {event} occurred with value: {value}, checking command completed okay") - self.check_command_ok( - timeout=wait_timeout, msg=f"Mount failed for {segment}{puck}-{sample}: " - ) - return value - elif event == "gripper_detection": - logger.info(f"gripper detection: {event} occurred with value: {value}") - return value - elif event == "motion_task" and value == "dry": - logger.info(f"event: {event} occurred with value: {value}") - logger.info(" Drying occurring, releasing interface to user") - return value - else: - logger.info(f"Unexpected event: {event} occurred with value: {value}") - logger.info("Checking command completed okay anyway") - self.check_command_ok( - timeout=wait_timeout, msg=f"Mount failed for {segment}{puck}-{sample}: " - ) - elif wait and segment == "X": - logger.info("Loading an auxiliary puck") - self.check_command_ok( - timeout=wait_timeout, msg=f"Mount failed for {segment}{puck}-{sample}: " - ) - logger.info("post waiting") - return None - - def unmount(self, force=False, wait=False, timeout=360.0): - # Force has a meaning, will unmount even if smart magnet is not detecting sample - if self.__simulation: - print("simulated unmount") - return - - if self.is_busy(): - raise TellCommandWhileBusyException("mount received while robot is busy") - - self._last_cmd_id = self.start_cmd("unmount", None, None, None, force) - - if wait: - self.check_command_ok(timeout=timeout, msg="Unmount failed: ") - - return self._last_cmd_id - - def scan_pin(self, segment, puck, sample, force=False): - return self.start_cmd("scan_pin", segment, puck, sample, force) - - def scan_puck(self, segment, puck, force=False): - return self.start_cmd("scan_puck", segment, puck, force) - - def dry(self, heat_time=None, speed=None, wait_cold=None, wait=False): - if self.__simulation: - time.sleep(5.0) - self.pshell.wait_state("Ready", timeout=30.0) - self._last_cmd_id = self.start_cmd("dry", heat_time, speed, wait_cold) - if wait: - self.check_command_ok(timeout=360.0, msg=f"Dry failed") - - def move_park(self, wait=False): - if self.__simulation: - return - self._last_cmd_id = self.start_cmd("move_park") - - if wait: - self.check_command_ok(timeout=360.0, msg=f"Move to park failed") - - def move_cold(self, reset_timestamp=False, wait=False): - if self.__simulation: - return - self._last_cmd_id = self.start_cmd("move_cold", reset_timestamp) - - if wait: - self.check_command_ok(timeout=360.0, msg=f"Move to cold failed") - - def trash(self): - if self.__simulation: - return - return self.start_cmd("trash_sample") - - def abort_cmd(self): - if self.__simulation: - print("simulated abort") - return - self.pshell.abort() - self.pshell.eval("robot.stop_task()&") - - def set_gonio_mount_position(self, homing=False): - if self.__simulation: - return - if homing: - self.pshell.eval("home_fast_table()") - self.pshell.eval("set_mount_position()") - - def set_setting(self, key: str, value: str): - self.pshell.eval(f"set_setting('{key}', '{value}')&") - - def get_setting(self, key: str) -> str: - return self.pshell.eval(f"get_setting('{key}')&") - - def enable_room_temperature(self): - self.set_setting("room_temperature_enabled", "true") - - def disable_room_temperature(self): - self.set_setting("room_temperature_enabled", "false") - - def get_mounted_sample(self) -> SampleDewarAddress | None: - if self.__simulation: - ret = self._simulated_mounted_sample - else: - ret = self.pshell.eval("get_setting('mounted_sample_position')&").strip() - if not ret or len(ret) == 0: - return None - - match = re.match(r"([A-Z])(\d)(\d{1,2})", ret) - - if match: - segment, puck, sample = match.groups() - dewar_location = DewarAddress(segment=segment, pos=int(puck)) - return SampleDewarAddress(puck=dewar_location, pin=int(sample)) - else: - logger.warning(f"Failed to decode mounted sample position: {ret}") - return None - - def get_system_check(self): - if self.__simulation: - if random.random() < 0.1: - raise RuntimeError("get_system_check_failed") - return "Ok" - return self.pshell.eval("system_check_msg()&") - - def get_robot_state(self): - if self.__simulation: - return "Ready" - return self.pshell.eval("robot.state&") - - def get_robot_status(self): - if self.__simulation: - return { - "powered": True, - "settled": True, - "speed": 100, - "empty": True, - "mode": "remote", - "task": None, - "pos": "pCold", - "open": True, - "status": "move", - } - - status = self.pshell.eval("robot.take()&") - return eval(status) # FIXME ALL functions must return a valid JSON object - - def get_speed(self) -> float: - if self.__simulation: - if random.random() < 0.1: - return random.choice([1, 5, 25, 50, 75, 90]) - return 100.0 - speed = self.get_robot_status()["speed"] - return float(speed) - - def get_detected_pucks(self) -> List[PuckLoadedInfo]: - if self.__simulation: - j = self._simulated_detected_pucks - else: - j = json.loads(self.pshell.eval("get_pucks_info()&")) - - output = [] - - for i in j: - if i["puckState"] == "Present": - puck_address = i["puckAddress"] - if len(puck_address) == 2: - output.append( - PuckLoadedInfo( - puck_name=i["puckBarcode"], - location=DewarAddress( - segment=puck_address[0], pos=int(puck_address[1]) - ), - ), - ) - return output - - def set_pin_offset(self, value): - if self.__simulation: - print(f"simulated set_pin_offset {value}") - self._simulated_offset = value - return - self.pshell.eval("set_pin_offset(" + str(value) + ")&") - - def get_pin_offset(self): - if self.__simulation: - print(f"simulated get_pin_offset -> {self._simulated_offset}") - return self._simulated_offset - try: - offset = float(self.pshell.eval("get_pin_offset()&")) - except Exception: - offset = 0.0 - return offset - - def get_current(self): - if self.__simulation: - return self._simulated_current - current = self.pshell.eval("smart_magnet.get_current_rb()&") - return float(current) - - def set_current(self, current): - if self.__simulation: - self._simulated_current = current - return - self.pshell.eval("smart_magnet.set_current({:.1f})&".format(current)) - current = self.pshell.eval("smart_magnet.get_current_rb()&") - return float(current) - - def print_info(self): - print("State: " + str(self.get_state())) - print("Mounted sample: " + str(self.get_mounted_sample())) - print("System check: " + str(self.get_system_check())) - print("Robot state: " + str(self.get_robot_state())) - print("Robot status: ") - status = self.get_robot_status() - status = status - for k, v in status.items(): - print(f"{k:>10s}: {v}") - print("Pin offset: " + str(self.get_pin_offset())) - print("Mount position: " + str(self.is_in_mount_position())) - print("") - - def is_powered(self): - if self.__simulation: - return True - return self.get_robot_status()["powered"] - - def check_enable_motion(self): - if self.__simulation: - if random.random() < 0.1: - raise RuntimeError("check_enable_motion failed") - if not self.is_powered(): - self.pshell.eval("enable_motion()&") - - def is_in_park(self): - if self.__simulation: - return True - return self.is_position(POSITION_PARK) - - def is_in_home(self): - if self.__simulation: - return False - return self.is_position(POSITION_HOME) - - def is_in_cold(self): - if self.__simulation: - return False - return self.is_position(POSITION_COLD) - - def is_position(self, position: str) -> bool: - return position == self.get_robot_status()["pos"] - - def get_task(self): - """ - robot_status = { - 'powered': False, - 'settled': True, - 'speed': 10, - 'empty': True, - 'mode': 'remote', - 'task': None, - 'pos': 'pPark', - 'open': True, - 'status': 'hold' - } - :return: - """ - status = self.get_robot_status() - return status["task"] - - def is_ready(self): - return "ready" == self.get_state().lower() - - def is_busy(self): - return "busy" == self.get_state().lower() - - def check_smart_magnet_mounted(self, timeout: float = 10.0, idle_time: float = 1.0, interval: float = 0.1): - initial_state = self.pshell.eval("smart_magnet.state&") - logger.debug(f"checking smart magnet_initial state: {initial_state}") - if initial_state == "Paused": - self.pshell.eval("smart_magnet.set_supress(False)&") - self.pshell.eval("smart_magnet.set_resting_current()&") - elif initial_state == "Fault": - logger.error(f"tell smart magnet is in unknown state {initial_state}") - raise SmartMagnetFaultException - #time.sleep(1.0) - state = self.pshell.eval("smart_magnet.state&") - - try: - # sample_present = bool(self.pshell.eval( - # f"smart_magnet.check_mounted(idle_time={str(idle_time)}, timeout={str(timeout)}, interval={str(interval)})")) - #logger.debug(f"sample present: {sample_present} of type {type(sample_present)}") - #time.sleep(1.0) - if state == "Busy": - logger.debug('state busy') - self.pshell.eval("smart_magnet.set_supress(True)&") - self.pshell.eval("smart_magnet.state&") - sample_present = True - elif state == "Ready": - logger.debug('No sample detected, ready to mount') - sample_present = False - elif state == "Paused": - logger.debug("Smart magnet detection is paused") - return None - else: - self.pshell.eval("smart_magnet.set_supress(True)&") - logger.error(f"Tell smart magnet is in unknown state {state}") - raise SmartMagnetFaultException - if sample_present: - print(self.get_mounted_sample()) - if self.get_mounted_sample() is None: - logger.warning("Check mount: A manually mounted sample is detected.") - logger.warning("Remove before mounting with the robot.") - raise ManualMountException - return True - elif self.get_mounted_sample(): - logger.error("Check mount: No sample detected, but robot thinks is mounted") - raise SmartMagnetFaultException - return False - except Exception as e: - logger.error(f"check_smart_magnet_mounted failed: {e}") - raise e - #sample_present = False - - -def is_true(value): - """check if argument is semantically true""" - value = str(value).lower() - return value != "0" or value in ("true", "yes", "on", "enabled") - - -def is_false(value): - return not is_true(value) - - -def is_valid_dewar_position(position): - return position in VALID_DEWAR_POSITIONS diff --git a/gui/pyproject.toml b/gui/pyproject.toml deleted file mode 100644 index edc8531e..00000000 --- a/gui/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "aaregui" -version = "0.2.72" -description = "Beamline control GUI" -readme = "README.md" -requires-python = ">=3.11" -dependencies = [ - "pyjwt==2.10.1", - "pyzmq==26.4.0", - "opencv-python-headless==4.11.0.86", - "PySide6==6.9.0", - "aaredaqlib==0.2.72" -] - -[lint] -ignore = ["F401", "F541", "W503", "W504"] - -[build-system] -requires = ["setuptools>=75.6.0"] -build-backend = "setuptools.build_meta" - -[tool.uv.sources] -aaredb = { index = "psi"} - -[[tool.uv.index]] -name = "psi" -url = "https://gitea.psi.ch/api/packages/mx/pypi/simple" - diff --git a/gui/src/aaregui/auth.py b/gui/src/aaregui/auth.py deleted file mode 100644 index b02bdea6..00000000 --- a/gui/src/aaregui/auth.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -import jwt -import requests - -from aaredaqlib.models import TokenData - -from aaredaqlib.logger_config import setup_logger - -logger = setup_logger('aareGUI') - -def auth(base_url: str | None) -> str: - curr_user = os.getlogin() - if base_url is None: - token_data = TokenData(sub=curr_user, - staff=True, - session=15, - pgroups=["p16371", "p22233"]) - return jwt.encode(token_data.model_dump(), "ABC123") - - try: - response = requests.post( - f"{base_url}/token", - data={ - "username": curr_user, - "password": "" - }, - headers={ - "Content-Type": "application/x-www-form-urlencoded" - } - ) - - if response.status_code == 200: - response_json = response.json() - if "access_token" in response_json: - return response_json["access_token"] - - except requests.RequestException as e: - logger.error(f"Authentication request failed: {e}") - - return "" diff --git a/gui/src/aaregui/panels/illumination_panel.py b/gui/src/aaregui/panels/illumination_panel.py deleted file mode 100644 index ce441fad..00000000 --- a/gui/src/aaregui/panels/illumination_panel.py +++ /dev/null @@ -1,38 +0,0 @@ -from PySide6.QtCore import Qt, Signal, Slot -from PySide6.QtWidgets import QWidget, QGridLayout, QSlider -from aaredaqlib.models import DAQStatusModel - -from aaregui.widgets.title_label import TitleLabel - - -class IlluminationPanel(QWidget): - light = Signal(int) - - def __init__(self, parent=None): - super().__init__(parent) - grid_layout = QGridLayout(self) - - grid_layout.addWidget(TitleLabel("Front light", self), 0, 0, 1, 2) - - self.is_sliding = False - - self.slider = QSlider(orientation=Qt.Orientation.Horizontal, parent=self) - self.slider.setRange(0, 100) - self.slider.sliderPressed.connect(self.on_slider_pressed) - self.slider.sliderReleased.connect(self.on_slider_released) - - grid_layout.addWidget(self.slider, 1, 0, 1, 2) - - @Slot() - def on_slider_pressed(self): - self.is_sliding = True - - @Slot() - def on_slider_released(self): - self.is_sliding = False - self.light.emit(self.slider.value()) - - @Slot(DAQStatusModel) - def update_daq_status(self, s: DAQStatusModel): - if not self.is_sliding: # Update only if not sliding - self.slider.setValue(round(s.bl.light)) diff --git a/gui/src/aaregui/threads/camera_thread.py b/gui/src/aaregui/threads/camera_thread.py deleted file mode 100644 index 6ac9837d..00000000 --- a/gui/src/aaregui/threads/camera_thread.py +++ /dev/null @@ -1,98 +0,0 @@ -import json - -import cv2 -import numpy as np -import zmq -from PySide6.QtCore import QThread, Signal -from PySide6.QtGui import QImage, QPixmap - - -class SampleCameraThread(QThread): - # Define a signal to communicate messages from the thread to the main GUI - camera_image = Signal(QPixmap) - - def __init__(self, zmq_url: str, parent=None): - super().__init__(parent) - context = zmq.Context() - self.__socket = context.socket(zmq.SUB) - self.__socket.setsockopt(zmq.SUBSCRIBE, b"") - self.__socket.setsockopt(zmq.RCVTIMEO, 500) - self.__socket.connect(zmq_url) - - self.running = True - - def run(self): - while self.running: - try: - r = self.__socket.recv_multipart() - if len(r) != 2: - continue - meta, data = r - header = json.loads(meta) - header_shape = header["shape"] - if header["type"] == "uint8" and len(header_shape) == 2: - bayer_image = np.frombuffer(data, dtype=np.uint8) - bayer_image = bayer_image.reshape(header_shape) - rgb_image = cv2.cvtColor(bayer_image, cv2.COLOR_BAYER_RG2RGB) - #cv2.COLOR_BAYER_GB2RGB for ethernet connection - rgb_image = rgb_image[:, ::-1, :].copy() - qimage = QImage(rgb_image.data, header_shape[1], header_shape[0], #For ethernet need header_shape[0], header_shape[1], header_shape[0]*3, - QImage.Format.Format_RGB888) - self.camera_image.emit(QPixmap.fromImage(qimage)) - else: - print("Sample camera image has wrong dimensions") - except zmq.Again: # Timeout occurred - continue # Check self.running again - except Exception as e: - print(f"Error in sample camera thread {e}") - - def stop(self): - # Signal the thread to stop - self.running = False - - if self.__socket: - self.__socket.close() - self.quit() - self.wait() - -class PredictionSubscriber(QThread): - # emits parsed JSON payload (dict with keys: time, frame_id, shape, boxes) - prediction = Signal(dict) - - def __init__(self, pred_zmq_url: str, topic: bytes = b"", parent=None): - super().__init__(parent) - self._ctx = zmq.Context() - self._sock = self._ctx.socket(zmq.SUB) - if topic: - self._sock.setsockopt(zmq.SUBSCRIBE, topic) - else: - self._sock.setsockopt(zmq.SUBSCRIBE, b"") - self._sock.connect(pred_zmq_url) - self.running = True - - def run(self): - while self.running: - try: - parts = self._sock.recv_multipart() - if not parts: - continue - # publisher sends either raw JSON or [topic, json] - payload_bytes = parts[-1] - try: - payload = json.loads(payload_bytes.decode("utf-8")) - except Exception: - continue - self.prediction.emit(payload) - except Exception as e: - print("PredictionSubscriber error:", e) - break - - def stop(self): - self.running = False - try: - self._sock.close() - except Exception: - pass - self.quit() - print("Prediction thread stopped. Exiting...") - self.wait() \ No newline at end of file diff --git a/daq/pyproject.toml b/pyproject.toml similarity index 75% rename from daq/pyproject.toml rename to pyproject.toml index 4ef913dc..044818a6 100644 --- a/daq/pyproject.toml +++ b/pyproject.toml @@ -1,24 +1,28 @@ [project] name = "aaredaq" -version = "0.2.72" -description = "AareDAQ data acquisition server" +version = "0.3.0" +description = "AareDAQ (with GUI)" readme = "README.md" requires-python = ">=3.11" dependencies = [ + "pydantic==2.11.4", + "numpy==2.2.5", + "jfjoch_client==1.0.0rc126", + "pyJWT==2.10.1", + "pyzmq==26.4.0", + "opencv-python-headless==4.11.0.86", + "PySide6==6.9.0", "requests==2.32.4", "pyepics==3.5.8", "redis==6.2.0", "python-redis-lock==4.0.0", - "PyJWT==2.10.1", "fastapi==0.115.13", "uvicorn==0.34.2", - "ultralytics==8.3.133", "aaredb==0.1.1a42", - "opencv-python-headless==4.11.0.86", "python_multipart==0.0.20", "websocket-client==1.8.0", "sseclient-py==1.8.0", - "aaredaqlib==0.2.72" + "psi-pshell==2.1.0", ] [lint] diff --git a/scripts/alc_bkg_comp.ipynb b/scripts/alc_bkg_comp.ipynb deleted file mode 100644 index e8ce5627..00000000 --- a/scripts/alc_bkg_comp.ipynb +++ /dev/null @@ -1,804 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2025-09-09T06:54:20.171830792Z", - "start_time": "2025-09-03T09:37:36.977231Z" - } - }, - "source": [ - "import cv2\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns" - ], - "outputs": [], - "execution_count": 47 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-03T09:20:49.172543Z", - "start_time": "2025-09-03T09:20:49.169238Z" - } - }, - "cell_type": "code", - "source": "threshold = 5", - "id": "19360e6dda22efb5", - "outputs": [], - "execution_count": 30 - }, - { - "metadata": { - "jupyter": { - "is_executing": true - } - }, - "cell_type": "code", - "source": [ - "bkg = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/bkg1_50_50.jpg\")\n", - "curr_img = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/1002_0_1_50_50_curr_image.tiff\")" - ], - "id": "9fac6cc561e58b70", - "outputs": [], - "execution_count": null - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-05T11:27:26.501898Z", - "start_time": "2025-09-05T11:27:26.496995Z" - } - }, - "cell_type": "code", - "source": [ - "def flatfield_correction(raw_image, flat_image, dark_image=None):\n", - " \"\"\"\n", - " Apply flat-field correction to remove uneven illumination\n", - "\n", - " Args:\n", - " raw_image: Your actual image with crystal\n", - " flat_image: Image of uniform illumination (no sample)\n", - " dark_image: Dark frame (camera with no light), optional\n", - " \"\"\"\n", - " # Convert to float for calculations\n", - " raw = raw_image.astype(np.float32)\n", - " flat = flat_image.astype(np.float32)\n", - "\n", - " if dark_image is not None:\n", - " dark = dark_image.astype(np.float32)\n", - " # Subtract dark frame from both\n", - " raw_corrected = raw - dark\n", - " flat_corrected = flat - dark\n", - " else:\n", - " raw_corrected = raw\n", - " flat_corrected = flat\n", - "\n", - " # Avoid division by zero\n", - " flat_corrected[flat_corrected == 0] = 1\n", - "\n", - " # Apply correction\n", - " mean_flat = np.mean(flat_corrected)\n", - " corrected = (raw_corrected / flat_corrected) * mean_flat\n", - "\n", - " # Convert back to original dtype\n", - " return np.clip(corrected, 0, 255).astype(raw_image.dtype)" - ], - "id": "114345da7d31b16d", - "outputs": [], - "execution_count": 139 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-05T11:43:24.969687Z", - "start_time": "2025-09-05T11:43:24.954049Z" - } - }, - "cell_type": "code", - "source": [ - "def create_ring_mask(image, center=None, inner_radius=50, outer_radius=100):\n", - " \"\"\"\n", - " Create a mask to exclude a ring region\n", - "\n", - " Args:\n", - " image_shape: (height, width) of your image\n", - " center: (cx, cy) center of ring, None for image center\n", - " inner_radius: Inner radius of ring to mask out\n", - " outer_radius: Outer radius of ring to mask out\n", - "\n", - " Returns:\n", - " mask: Binary mask (0 = exclude ring, 255 = use for correction)\n", - " \"\"\"\n", - "\n", - " if len(image.shape) == 3:\n", - " h, w, _ = image.shape\n", - " else:\n", - " h, w = image.shape\n", - "\n", - "\n", - " if center is None:\n", - " center = (w // 2, h // 2)\n", - "\n", - " # Create coordinate arrays\n", - " cx, cy = center\n", - "\n", - " w = int(w)\n", - " h = int(h)\n", - "\n", - "\n", - " x = np.arange(w)\n", - " y = np.arange(h)\n", - " X, Y = np.meshgrid(x, y)\n", - "\n", - " # Calculate distances from center\n", - " distances = np.sqrt((X - cx)**2 + (Y - cy)**2)\n", - "\n", - "\n", - " # Create mask: exclude the ring region\n", - " mask = np.ones((h, w), dtype=np.uint8) * 255\n", - " ring_region = (distances >= inner_radius) & (distances <= outer_radius)\n", - " mask[ring_region] = 0\n", - "\n", - " return mask\n", - "\n", - "def flatfield_correction_with_mask(raw_image, flat_image, mask, dark_image=None):\n", - " \"\"\"\n", - " Apply flat-field correction with mask to exclude certain regions\n", - "\n", - " Args:\n", - " raw_image: Your camera image\n", - " flat_image: Flat-field reference\n", - " mask: Binary mask (0 = ignore, 255 = use)\n", - " dark_image: Dark frame (optional)\n", - " \"\"\"\n", - " # Convert to float\n", - " raw = raw_image.astype(np.float32)\n", - " flat = flat_image.astype(np.float32)\n", - "\n", - " if dark_image is not None:\n", - " dark = dark_image.astype(np.float32)\n", - " raw_corrected = raw - dark\n", - " flat_corrected = flat - dark\n", - " else:\n", - " raw_corrected = raw\n", - " flat_corrected = flat\n", - "\n", - " # Apply mask to flat field - only use unmasked regions for correction\n", - " mask_float = mask.astype(np.float32) / 255.0\n", - "\n", - " # Calculate mean only from unmasked regions\n", - " if len(flat_corrected.shape) == 3:\n", - " # Color image\n", - " mean_flat = []\n", - " for channel in range(flat_corrected.shape[2]):\n", - " masked_flat = flat_corrected[:,:,channel] * mask_float\n", - " valid_pixels = masked_flat[mask > 0]\n", - " mean_flat.append(np.mean(valid_pixels) if len(valid_pixels) > 0 else 1.0)\n", - " mean_flat = np.array(mean_flat).reshape(1, 1, -1)\n", - " else:\n", - " # Grayscale\n", - " masked_flat = flat_corrected * mask_float\n", - " valid_pixels = masked_flat[mask > 0]\n", - " mean_flat = np.mean(valid_pixels) if len(valid_pixels) > 0 else 1.0\n", - "\n", - " # Avoid division by zero\n", - " flat_corrected[flat_corrected <= 0] = 1\n", - "\n", - " # Apply correction\n", - " corrected = (raw_corrected / flat_corrected) * mean_flat\n", - "\n", - " # In masked regions, keep original values\n", - " mask_3d = mask_float\n", - " if len(corrected.shape) == 3:\n", - " mask_3d = np.stack([mask_float] * corrected.shape[2], axis=2)\n", - "\n", - " # Blend: use corrected where mask=1, original where mask=0\n", - " final_result = corrected * mask_3d + raw_corrected * (1 - mask_3d)\n", - "\n", - " return np.clip(final_result, 0, 255).astype(np.uint8)\n", - "\n", - "def create_interactive_ring_mask(image):\n", - " \"\"\"\n", - " Interactively create a ring mask by clicking on the image\n", - " Click center, then inner radius point, then outer radius point\n", - " \"\"\"\n", - " points = []\n", - "\n", - " def mouse_callback(event, x, y, flags, param):\n", - " if event == cv2.EVENT_LBUTTONDOWN:\n", - " points.append((x, y))\n", - " cv2.circle(image, (x, y), 3, (0, 255, 0), -1)\n", - " cv2.imshow('Select Ring', image)\n", - "\n", - " if len(points) == 1:\n", - " print(\"Click on inner radius of ring\")\n", - " elif len(points) == 2:\n", - " print(\"Click on outer radius of ring\")\n", - "\n", - " cv2.imshow('Select Ring', image)\n", - " print(\"Click on center of ring\")\n", - " cv2.setMouseCallback('Select Ring', mouse_callback)\n", - " cv2.waitKey(0)\n", - " cv2.destroyAllWindows()\n", - "\n", - " if len(points) == 3:\n", - " center = points[0]\n", - " inner_radius = np.sqrt((points[1][0] - center[0])**2 + (points[1][1] - center[1])**2)\n", - " outer_radius = np.sqrt((points[2][0] - center[0])**2 + (points[2][1] - center[1])**2)\n", - "\n", - " mask = create_ring_mask(image.shape, center, inner_radius, outer_radius)\n", - " return mask\n", - " else:\n", - " print(\"Need 3 points!\")\n", - " return None\n" - ], - "id": "a1ae8c16d1cb31f7", - "outputs": [], - "execution_count": 154 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-08T14:23:06.438502Z", - "start_time": "2025-09-08T14:23:02.773985Z" - } - }, - "cell_type": "code", - "source": [ - "min_contour_area = 4\n", - "mask = create_ring_mask(curr_img, inner_radius=1000,outer_radius=2000)\n", - "diff_image = cv2.absdiff(curr_img, bkg)\n", - "diff_image = cv2.cvtColor(diff_image, cv2.COLOR_RGB2GRAY)\n", - "thresh_value, binary_image = cv2.threshold(diff_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n", - "thresh_value, thresh_normal = cv2.threshold(diff_image, 50, 255, cv2.THRESH_BINARY)\n", - "ff = flatfield_correction(curr_img, bkg, dark_image=None)\n", - "ff = cv2.cvtColor(ff, cv2.COLOR_RGB2GRAY)\n", - "ff_masked = flatfield_correction_with_mask(curr_img, bkg, mask, dark_image=None)\n", - "ff_masked = cv2.cvtColor(ff_masked, cv2.COLOR_RGB2GRAY)\n", - "thresh_value, thresh_mask = cv2.threshold(ff_masked, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n", - "kernel = np.ones((3,3), np.uint8)\n", - "thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)\n", - "thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)\n", - "\n", - "contours, _ = cv2.findContours(thresh_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n", - "valid_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_contour_area]\n", - "\n", - "largest_contour = max(valid_contours, key=cv2.contourArea)\n", - "\n", - "# Step 6: Find leftmost point\n", - "leftmost_point = tuple(largest_contour[largest_contour[:,:,0].argmin()][0])\n", - "print(leftmost_point)\n", - "\n", - "leftmost_point = None\n", - "\n", - "for contour in contours:\n", - " # Loop through each point in the current contour\n", - " for point in contour:\n", - " x, y = point[0] # Point is a nested array [ [x, y] ]\n", - "\n", - " # Check if this is the leftmost point\n", - " if leftmost_point is None or x < leftmost_point[0]:\n", - " leftmost_point = (x, y)\n", - " plot_contour = contour\n", - "print(leftmost_point)\n", - "\n", - "c_img = cv2.drawContours(thresh, contours, -1, (0, 255, 0), 1)\n", - "plt.subplot(2, 2, 1)\n", - "plt.imshow(diff_image)\n", - "plt.subplot(2, 2, 2)\n", - "plt.imshow(thresh_normal)\n", - "#plt.subplot(2, 2, 4)\n", - "#plt.imshow(ff_masked)\n", - "\n", - "\n", - "result_image = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR) if len(thresh.shape) == 2 else thresh.copy()\n", - "\n", - "# Draw contour\n", - "result_image = cv2.drawContours(result_image, [largest_contour], -1, (0, 255, 0), 2)\n", - "\n", - "# Mark leftmost point\n", - "result_image = cv2.circle(result_image, leftmost_point, 100, (0, 0, 255), -1)\n", - "result_image = cv2.putText(result_image, f'Leftmost: {leftmost_point}',\n", - " (leftmost_point[0] + 10, leftmost_point[1] - 10),\n", - " cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)\n", - "\n", - "print(f'Leftmost point: {leftmost_point}')\n", - "\n", - "plt.subplot(2, 2, 3)\n", - "plt.imshow(binary_image)\n" - ], - "id": "a5363e8d3c71448", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(np.int32(24), np.int32(979))\n", - "(np.int32(24), np.int32(979))\n", - "Leftmost point: (np.int32(24), np.int32(979))\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 354, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/plain": [ - "

" - ], - "image/png": "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4pprruEHP/gB0ehwxcXatWu56aabeO211zj66KP57ne/6x1jf3R3d9PQ0MDWrVupq6vb7+0kKJFIMHPmTLZt23ZEDp0bLeHv0VpLb28vLS0tOM7kn1j0cLl26LoxenTtGB3+77GmpmbMrxsfap6Ciaww3vhIHQc+WvQ9jg59j4cH/X8aPfouR8eh/h4n/y2KiIiI7BcFBSIiIgJM4qAgHo9z2223abjRh6TvcXToezw86P/T6NF3OToO9fc4afsUiIiIyIGZtDUFIiIicmAUFIiIiAigoEBERETyFBSIiIgIMEmDgrvvvptjjjmG8vJy5s6dW/QQlSPNunXruPzyy2lpacEYw8MPPxxYb63l1ltvZcaMGVRUVDBv3jzefPPNQJquri4WLVpEbW0t9fX1XHvttfT19QXSvPzyy1x00UWUl5czc+ZM7rjjjrE+tUNq+fLlnHfeedTU1NDY2MiVV17J5s2bA2mGhoZYvHgxU6dOpbq6moULFxY9oGfr1q0sWLCAyspKGhsbufnmm8lkMoE0a9eu5eyzzyYej3PcccexYsWKsT49QdeOMF07PrzD7roxZhMoj5P777/fxmIx+6//+q9206ZN9itf+Yqtr6+3nZ2d4521cfPEE0/Yb3/72/Z//+//bQH70EMPBdb/4Ac/sHV1dfbhhx+2f/jDH+yf/dmf2Tlz5tjBwUEvzaWXXmrPPPNM+9xzz9n//M//tMcdd5y9+uqrvfU9PT22qanJLlq0yL766qv2V7/6la2oqLD/9E//dKhOc8y1tbXZ++67z7766qt248aN9pOf/KSdNWuW7evr89J89atftTNnzrSrV6+2L774or3gggvsn/zJn3jrC/P3z5s3z7700kv2iSeesNOmTSs5f//SpUvta6+9Zn/yk58c8LM/5MDp2lFM144P73C7bky6oOD888+3ixcv9j5ns1nb0tJily9fPo65mjjCf9iu69rm5mZ75513esu6u7ttPB63v/rVr6y11r722msWsC+88IKX5te//rU1xtj333/fWmvtPffcYxsaGmwymfTS3HLLLfbEE08c4zMaPzt37rSAfeqpp6y1ue+trKzMPvjgg16a119/3QK2vb3dWpu7yDqOYzs6Orw09957r62trfW+u29+85v21FNPDRzrs5/9rG1raxvrUzqi6dqxb7p2jI6Jft2YVM0HqVSKDRs2MG/ePG+Z4zjMmzeP9vb2cczZxLVlyxY6OjoC31ldXR1z5871vrP29nbq6+s599xzvTTz5s3DcRzWr1/vpbn44ouJxWJemra2NjZv3szevXsP0dkcWj09PQBMmTIFgA0bNpBOpwPf5UknncSsWbMC3+Xpp59OU1OTl6atrY1EIsGmTZu8NP59FNLod3js6Npx4HTtODgT/boxqYKC3bt3k81mA18cQFNTEx0dHeOUq4mt8L3s6zvr6Ojwnl9fEI1GmTJlSiBNqX34jzGZuK7LjTfeyMc+9jFOO+00IHeesViM+vr6QNrwd/lB39NIaRKJBIODg2NxOkc8XTsOnK4dB+5wuG5EPziJiIQtXryYV199laeffnq8syIih4nD4boxqWoKpk2bRiQSKeq12dnZGXgmuwwrfC/7+s6am5vZuXNnYH0mk6GrqyuQptQ+/MeYLJYsWcJjjz3Gk08+ydFHH+0tb25uJpVK0d3dHUgf/i4/6HsaKU1tbS0VFRWjfTqCrh0HQ9eOA3O4XDcmVVAQi8U455xzWL16tbfMdV1Wr15Na2vrOOZs4pozZw7Nzc2B7yyRSLB+/XrvO2ttbaW7u5sNGzZ4adasWYPrusydO9dLs27dOtLptJdm1apVnHjiiTQ0NByisxlb1lqWLFnCQw89xJo1a5gzZ05g/TnnnENZWVngu9y8eTNbt24NfJevvPJK4EK5atUqamtrOeWUU7w0/n0U0uh3eOzo2nHgdO3YP4fddeMgOk9OaPfff7+Nx+N2xYoV9rXXXrPXXXedra+vD/TaPNL09vbal156yb700ksWsD/60Y/sSy+9ZN99911rbW5YUX19vX3kkUfsyy+/bK+44oqSw4o++tGP2vXr19unn37aHn/88YFhRd3d3bapqcl+/vOft6+++qq9//77bWVl5aQZVmSttddff72tq6uza9eutTt27PBeAwMDXpqvfvWrdtasWXbNmjX2xRdftK2trba1tdVbXxhaNH/+fLtx40a7cuVKO3369JJDi26++Wb7+uuv27vvvltDEg8BXTuK6drx4R1u141JFxRYa+1PfvITO2vWLBuLxez5559vn3vuufHO0rh68sknLVD0uuaaa6y1uaFF3/3ud21TU5ONx+P2E5/4hN28eXNgH3v27LFXX321ra6utrW1tfZLX/qS7e3tDaT5wx/+YC+88EIbj8ftUUcdZX/wgx8cqlM8JEp9h4C97777vDSDg4P2a1/7mm1oaLCVlZX205/+tN2xY0dgP++884697LLLbEVFhZ02bZr9+te/btPpdCDNk08+ac866ywbi8XsscceGziGjB1dO4J07fjwDrfrhh6dLCIiIsAk61MgIiIiB09BgYiIiAAKCkRERCRPQYGIiIgACgpEREQkT0GBiIiIAAoKREREJE9BgYiIiAATPCi4++67OeaYYygvL2fu3Lk8//zz450lERGRSWvCBgUPPPAAS5cu5bbbbuP3v/89Z555Jm1tbUVP3BIREZHRMWGnOZ47dy7nnXce//iP/wjknlg2c+ZMbrjhBr71rW8VpU8mkySTSe+z67p0dXUxdepUjDGHLN8i+8NaS29vLy0tLTjOhI3NReQIEx3vDJSSSqXYsGEDy5Yt85Y5jsO8efNob28vuc3y5cv53ve+d6iyKDIqtm3bFni2uojIeJqQQcHu3bvJZrM0NTUFljc1NfHGG2+U3GbZsmUsXbrU+9zT08OsWbO4kE8SpWxM8ytyoDKkeZonqKmpGe+siIh4JmRQcDDi8TjxeLxoeZQyokZBgUww+UY7NW2JyEQyIRszp02bRiQSobOzM7C8s7OT5ubmccqViIjI5DYhg4JYLMY555zD6tWrvWWu67J69WpaW1vHMWciIiKT14RtPli6dCnXXHMN5557Lueffz7/8A//QH9/P1/60pfGO2siIiKT0oQNCj772c+ya9cubr31Vjo6OjjrrLNYuXJlUedDERERGR0Tdp6CDyuRSFBXV8fHuUIdDWXCydg0a3mEnp4eamtrxzs7IiLABO1TICIiIoeeggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQHGICi4/fbbMcYEXieddJK3fmhoiMWLFzN16lSqq6tZuHAhnZ2dgX1s3bqVBQsWUFlZSWNjIzfffDOZTGa0syoiIiI+0bHY6amn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SJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhInoICERERARQUiIiISJ6CAhEREQEUFIiIiEieggIREREBFBSIiIhI3gEFBcuXL+e8886jpqaGxsZGrrzySjZv3hxIMzQ0xOLFi5k6dSrV1dUsXLiQzs7OQJqtW7eyYMECKisraWxs5OabbyaTyQTSrF27lrPPPpt4PM5xxx3HihUrDu4MRUREZL8cUFDw1FNPsXjxYp577jlWrVpFOp1m/vz59Pf3e2luuukmHn30UR588EGeeuoptm/fzmc+8xlvfTabZcGCBaRSKZ599ll+/vOfs2LFCm699VYvzZYtW1iwYAGXXHIJGzdu5MYbb+TLX/4yv/nNb0bhlEVERKQUY621B7vxrl27aGxs5KmnnuLiiy+mp6eH6dOn88tf/pI///M/B+CNN97g5JNPpr29nQsuuIBf//rXfOpTn2L79u00NTUB8NOf/pRbbrmFXbt2EYvFuOWWW3j88cd59dVXvWNdddVVdHd3s3Llyv3KWyKRoK6ujo9zBVFTdrCnKDImMjbNWh6hp6eH2tra8c6OiAjwIfsU9PT0ADBlyhQANmzYQDqdZt68eV6ak046iVmzZtHe3g5Ae3s7p59+uhcQALS1tZFIJNi0aZOXxr+PQprCPkpJJpMkEonAS0RERPbfQQcFruty44038rGPfYzTTjsNgI6ODmKxGPX19YG0TU1NdHR0eGn8AUFhfWHdvtIkEgkGBwdL5mf58uXU1dV5r5kzZx7sqYmIiByRDjooWLx4Ma+++ir333//aObnoC1btoyenh7vtW3btvHOkoiIyGElejAbLVmyhMcee4x169Zx9NFHe8ubm5tJpVJ0d3cHags6Oztpbm720jz//POB/RVGJ/jThEcsdHZ2UltbS0VFRck8xeNx4vG497nQVSJDGg6614TI2MiQBoZ/T0VEJoIDCgqstdxwww089NBDrF27ljlz5gTWn3POOZSVlbF69WoWLlwIwObNm9m6dSutra0AtLa28jd/8zfs3LmTxsZGAFatWkVtbS2nnHKKl+aJJ54I7HvVqlXePvbHnj17AHiaJz4gpcj46e3tpa6ubryzISICHODog6997Wv88pe/5JFHHuHEE0/0ltfV1Xl38Ndffz1PPPEEK1asoLa2lhtuuAGAZ599FsgNSTzrrLNoaWnhjjvuoKOjg89//vN8+ctf5m//9m+B3JDE0047jcWLF/MXf/EXrFmzhr/8y7/k8ccfp62tbb/y2t3dTUNDA1u3btVF90NIJBLMnDmTbdu2qZf8hxD+Hq219Pb20tLSguNoDjERmSDsASBXEV/0uu+++7w0g4OD9mtf+5ptaGiwlZWV9tOf/rTdsWNHYD/vvPOOveyyy2xFRYWdNm2a/frXv27T6XQgzZNPPmnPOussG4vF7LHHHhs4xv7o6emxgO3p6Tmg7SRI3+Po0PcoIoeDDzVPwURWmKdA48A/HH2Po0Pfo4gcDlRvKSIiIsAkDgri8Ti33XZbYESCHDh9j6ND36OIHA4mbfOBiIiIHJhJW1MgIiIiB0ZBgYiIiAAKCkRERCRPQYGIiIgACgpEREQkb1IGBXfffTfHHHMM5eXlzJ07t+gBTEeadevWcfnll9PS0oIxhocffjiw3lrLrbfeyowZM6ioqGDevHm8+eabgTRdXV0sWrSI2tpa6uvrufbaa+nr6wukefnll7nooosoLy9n5syZ3HHHHWN9aofU8uXLOe+886ipqaGxsZErr7ySzZs3B9IMDQ2xePFipk6dSnV1NQsXLix6uNfWrVtZsGABlZWVNDY2cvPNN5PJZAJp1q5dy9lnn008Hue4445jxYoVY316IiKTLyh44IEHWLp0Kbfddhu///3vOfPMM2lra2Pnzp3jnbVx09/fz5lnnsndd99dcv0dd9zBXXfdxU9/+lPWr19PVVUVbW1tDA0NeWkWLVrEpk2bWLVqlfeEzOuuu85bn0gkmD9/PrNnz2bDhg3ceeed3H777fzsZz8b8/M7VJ566ikWL17Mc889x6pVq0in08yfP5/+/n4vzU033cSjjz7Kgw8+yFNPPcX27dv5zGc+463PZrMsWLCAVCrFs88+y89//nNWrFjBrbfe6qXZsmULCxYs4JJLLmHjxo3ceOONfPnLX+Y3v/nNIT1fETkCjesky2Pg/PPPt4sXL/Y+Z7NZ29LSYpcvXz6OuZo4APvQQw95n13Xtc3NzfbOO+/0lnV3d9t4PG5/9atfWWutfe211yxgX3jhBS/Nr3/9a2uMse+//7611tp77rnHNjQ02GQy6aW55ZZb7IknnjjGZzR+du7caQH71FNPWWtz31tZWZl98MEHvTSvv/66BWx7e7u11tonnnjCOo5jOzo6vDT33nuvra2t9b67b37zm/bUU08NHOuzn/2sbWtrG+tTEpEj3KSqKUilUmzYsIF58+Z5yxzHYd68ebS3t49jziauLVu20NHREfjO6urqmDt3rvedtbe3U19fz7nnnuulmTdvHo7jsH79ei/NxRdfTCwW89K0tbWxefNm9u7de4jO5tDq6ekBYMqUKQBs2LCBdDod+C5POukkZs2aFfguTz/9dJqamrw0bW1tJBIJNm3a5KXx76OQRr/DIjLWJlVQsHv3brLZbOCCC9DU1ERHR8c45WpiK3wv+/rOOjo6aGxsDKyPRqNMmTIlkKbUPvzHmExc1+XGG2/kYx/7GKeddhqQO89YLEZ9fX0gbfi7/KDvaaQ0iUSCwcHBsTgdEREAouOdAZHD0eLFi3n11Vd5+umnxzsrIiKjZlLVFEybNo1IJFLU27uzs5Pm5uZxytXEVvhe9vWdNTc3F3XUzGQydHV1BdKU2of/GJPFkiVLeOyxx3jyySc5+uijveXNzc2kUim6u7sD6cPf5Qd9TyOlqa2tpaKiYrRPR0TEM6mCglgsxjnnnMPq1au9Za7rsnr1alpbW8cxZxPXnDlzaG5uDnxniUSC9evXe99Za2sr3d3dbNiwwUuzZs0aXNdl7ty5Xpp169aRTqe9NKtWreLEE0+koaHhEJ3N2LLWsmTJEh566CHWrFnDnDlzAuvPOeccysrKAt/l5s2b2bp1a+C7fOWVVwJB1qpVq6itreWUU07x0vj3UUij32ERGXPj3dNxtN1///02Ho/bFStW2Ndee81ed911tr6+PtDb+0jT29trX3rpJfvSSy9ZwP7oRz+yL730kn333Xettdb+4Ac/sPX19faRRx6xL7/8sr3iiivsnDlz7ODgoLePSy+91H70ox+169evt08//bQ9/vjj7dVXX+2t7+7utk1NTfbzn/+8ffXVV+39999vKysr7T/90z8d8vMdK9dff72tq6uza9eutTt27PBeAwMDXpqvfvWrdtasWXbNmjX2xRdftK2trba1tdVbn8lk7GmnnWbnz59vN27caFeuXGmnT59uly1b5qX54x//aCsrK+3NN99sX3/9dXv33XfbSCRiV65ceUjPV0SOPJMuKLDW2p/85Cd21qxZNhaL2fPPP98+99xz452lcfXkk09aoOh1zTXXWGtzwxK/+93v2qamJhuPx+0nPvEJu3nz5sA+9uzZY6+++mpbXV1ta2tr7Ze+9CXb29sbSPOHP/zBXnjhhTYej9ujjjrK/uAHPzhUp3hIlPoOAXvfffd5aQYHB+3XvvY129DQYCsrK+2nP/1pu2PHjsB+3nnnHXvZZZfZiooKO23aNPv1r3/dptPpQJonn3zSnnXWWTYWi9ljjz02cAwRkbFirLV2fOooREREZCKZVH0KRERE5OApKBARERFAQYGIiIjkKSgQERERQEGBiIiI5CkoEBEREUBBgYiIiOQpKBARERFAQYGIiIjkKSgQERERQEGBiIiI5P3/n2VGXmeI/GAAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "execution_count": 354 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-08T14:02:01.581369Z", - "start_time": "2025-09-08T14:01:56.983788Z" - } - }, - "cell_type": "code", - "source": [ - "# Load image and convert\n", - "img = cv2.imread('/home/leonarski_f/aaredaq/daq/src/aaredaq/991_0_1_50_50_curr_image.tiff', cv2.IMREAD_COLOR)\n", - "#img = cv2.imread('/home/leonarski_f/aaredaq/daq/src/aaredaq/0_280_100_50_curr_image_colour.jpg', cv2.IMREAD_COLOR)\n", - "\n", - "bkg = cv2.imread('/home/leonarski_f/aaredaq/daq/src/aaredaq/bkg1_50_50.jpg')\n", - "# Convert to grayscale & enhance\n", - "gray_bkg = cv2.cvtColor(bkg, cv2.COLOR_BGR2GRAY)\n", - "gray = cv2.subtract(gray, gray_bkg)\n", - "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n", - "gray = cv2.GaussianBlur(gray, (5, 5), 0)\n", - "gray = cv2.equalizeHist(gray)\n", - "\n", - "# Mask out camera-case ring\n", - "#gray = cv2.subtract(gray, gray_bkg)\n", - "mask = np.zeros_like(gray, dtype=np.uint8)\n", - "h, w = gray.shape\n", - "radius = min(h, w)//2 - 20\n", - "center = (w//2, h//2)\n", - "\n", - "norm=gray\n", - "print(radius)\n", - "\n", - "#norm = flatfield_correction_with_mask(gray, gray_bkg, mask)\n", - "\n", - "#radius = 500#radius#-factor\n", - "print(gray.shape)\n", - "# # gray = cv2.bitwise_and(gray, gray, mask=mask)\n", - "# # x, y = center[0] - radius, center[1] - radius\n", - "# gray_cropped = gray[y:y+2*radius, x:x+2*radius]\n", - "# #gray_bkg_cropped = gray[y:y+2*radius, x:x+2*radius]\n", - "# #cv2.circle(mask, center, radius, 93, -1)\n", - "# print(gray_cropped.shape)\n", - "#\n", - "# #masked = cv2.bitwise_and(gray, gray, mask=mask)\n", - "# #norm = gray_cropped\n", - "# masked=gray_cropped\n", - "# background= cv2.medianBlur(masked, 51)\n", - "#\n", - "# norm = cv2.subtract(masked, background)\n", - "#norm = cv2.absdiff(masked,gray_bkg)\n", - "kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (25,25))\n", - "tophat = cv2.morphologyEx(norm, cv2.MORPH_TOPHAT, kernel)\n", - "\n", - "enhanced = cv2.addWeighted(norm, 0.7, tophat, 0.3, 0)\n", - "# Adaptive thresholding\n", - "thresh = cv2.adaptiveThreshold(enhanced, 255, cv2.ADAPTIVE_THRESH_MEAN_C,\n", - " cv2.THRESH_BINARY_INV, 41, 2)\n", - "\n", - "# Find contours\n", - "contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n", - "\n", - "best_point = None\n", - "min_x = w + 1\n", - "\n", - "print(len(contours))\n", - "for cnt in contours:\n", - " x,y,wc,hc = cv2.boundingRect(cnt)\n", - "\n", - " # Skip very large contours (likely mask boundary)\n", - " if cv2.contourArea(cnt) > 0.2 * h * w:\n", - " print(\"Skipping contour with area\", cv2.contourArea(cnt))\n", - " continue\n", - "\n", - " # Compute distance of contour centroid from image center\n", - " M = cv2.moments(cnt)\n", - " if M[\"m00\"] != 0:\n", - " cx = int(M[\"m10\"]/M[\"m00\"])\n", - " cy = int(M[\"m01\"]/M[\"m00\"])\n", - " dist = np.sqrt((cx-center[0])**2 + (cy-center[1])**2)\n", - " # If centroid is near mask radius, skip (mask edge)\n", - " #if abs(dist - radius) < 60:\n", - " # print(\"Skipping contour near mask radius\")\n", - " # continue\n", - "\n", - " # Skip vertical pin\n", - " if hc > 3*wc:\n", - " print(\"Skipping vertical pin\")\n", - " continue\n", - "\n", - " leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])\n", - " if leftmost[0] < min_x:\n", - " min_x = leftmost[0]\n", - " best_point = leftmost\n", - "\n", - "# Draw result\n", - "if best_point is not None:\n", - " print(f\"best_point = {best_point}\")\n", - " #cv2.circle(thresh, best_point, 100, (0, 0, 255), -1)\n", - " print(radius)\n", - " corrected_point = (best_point[0]+factor, best_point[1] +factor)\n", - " print(f\"corrected_point {corrected_point}\")\n", - " cv2.circle(img, corrected_point, 100, (0, 0, 255), -1)\n", - " print(\"Loop tip (leftmost point):\", best_point)\n", - "else:\n", - " print(\"No suitable contour found\")\n", - "\n", - "plt.figure(figsize=(10,8))\n", - "plt.figure(figsize=(14,10))\n", - "plt.subplot(2,4,1); plt.title(\"Original\"); plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#; plt.axis(\"off\")\n", - "plt.subplot(2,4,2); plt.title(\"Cropped\"); plt.imshow(gray_cropped, cmap=\"gray\"); plt.axis(\"off\")\n", - "plt.subplot(2,4,3); plt.title(\"Background\"); plt.imshow(norm, cmap=\"gray\"); plt.axis(\"off\")\n", - "plt.subplot(2,4,4); plt.title(\"Top-hat\"); plt.imshow(tophat, cmap=\"gray\"); plt.axis(\"off\")\n", - "plt.subplot(2,4,5); plt.title(\"Enhanced\"); plt.imshow(enhanced, cmap=\"gray\"); plt.axis(\"off\")\n", - "plt.subplot(2,4,6); plt.title(\"Threshold\"); plt.imshow(thresh, cmap=\"gray\")#; plt.axis(\"off\")\n", - "plt.subplot(2,4,7); plt.title(\"image with contours\"); #plt.imshow(img)#; plt.axis(\"off\")\n", - "contour_vis = cv2.cvtColor(masked, cv2.COLOR_GRAY2BGR)\n", - "cv2.drawContours(contour_vis, contours, -1, (0,255,0), 1)\n", - "cv2.circle(contour_vis, best_point, 100, (0, 0, 255), -1)\n", - "plt.imshow(contour_vis)\n", - "plt.show()\n", - "\n", - "cv2.imwrite('masked.tiff', enhanced)\n", - "cv2.imwrite('thresh.tiff', thresh)" - ], - "id": "d98c070865b11f36", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1003\n", - "(2046, 2046)\n", - "10291\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping contour with area 2054203.5\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "Skipping vertical pin\n", - "best_point = (np.int32(0), np.int32(1421))\n", - "1003\n", - "corrected_point (np.int32(250), np.int32(1671))\n", - "Loop tip (leftmost point): (np.int32(0), np.int32(1421))\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAABH0AAALRCAYAAADGGN8bAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsvXeUXNWVPbwr5+rKVV2dg7rViq2ABJIQEkk2JjobgxGDxwkcZjzO8xkbe/CMzTgMY/jBGINtjLFxwAZMFlFIAhRoZXUO1aGqK+f4vj96neNXpepWSwYj2W+vpaWuF+67L91377777CMTBEGABAkSJEiQIEGCBAkSJEiQIEGChL8ryN/uCkiQIEGCBAkSJEiQIEGCBAkSJEh48yGRPhIkSJAgQYIECRIkSJAgQYIECX+HkEgfCRIkSJAgQYIECRIkSJAgQYKEv0NIpI8ECRIkSJAgQYIECRIkSJAgQcLfISTSR4IECRIkSJAgQYIECRIkSJAg4e8QEukjQYIECRIkSJAgQYIECRIkSJDwdwiJ9JEgQYIECRIkSJAgQYIECRIkSPg7hET6SJAgQYIECRIkSJAgQYIECRIk/B1CIn0kSJAgQYIECRIkSJAgQYIECRL+DiGRPhLednzjG9+ATCY7pX3vu+8+yGQyDA0NvbmVEmFoaAgymQz33XffW3YMCRIkSBBDanckSDj90dzcjEsvvfTtrsbbBplMhm984xtvdzUkSJBwiti6dSuMRuPbXQ0JfwNIpI+EvwoHDx7ENddcg7q6Omg0Gni9Xnz4wx/GwYMH3+6qSZAg4e8A/f39+PjHP47W1lZotVqYzWasX78eP/rRj5BOp9/u6kmQIOE0AE0Aif+5XC5s3rwZjz/++NtdPQkSJEhgVLZVs/17/vnn3+6qnhJuvfVWPPzww293NSRUQPl2V0DCmYvf//73+NCHPgSbzYYbbrgBLS0tGBoawj333IPf/va3ePDBB3HVVVedsJx///d/x5e//OVTqsO1116LD37wg9BoNKe0vwQJEk5fPPbYY3jf+94HjUaDj3zkI1iyZAlyuRxefvllfOELX8DBgwdx9913v93VlCBBwmmCW265BS0tLRAEAVNTU7jvvvtwySWX4JFHHvmHVuRIkCDh9MEvfvGLst8///nP8fTTTx+3vKur629ZrTcNt956K9773vfiyiuvfLurIkEEifSRcEro7+/Htddei9bWVrz44otwOp287rOf/SzOPfdcXHvttejp6UFra2vVMpLJJAwGA5RKJZTKU3sUFQoFFArFKe0rQYKE0xeDg4P44Ac/iKamJmzbtg21tbW87sYbb0RfXx8ee+yxqvuWSiXkcjlotdq/VXUlSJBwGuCd73wnVq9ezb9vuOEGuN1u/OpXvzpjSR/qK0mQIOHvA9dcc03Z7507d+Lpp58+brkECW8mpPAuCaeE733ve0ilUrj77rvLCB8AcDgcuOuuu5BMJvHd734XwF98ew4dOoSrr74aVqsVGzZsKFsnRjqdxmc+8xk4HA6YTCZcfvnl8Pl8x8WPV/P0oRj7l19+GWvWrIFWq0Vrayt+/vOflx0jFArh3/7t37B06VIYjUaYzWa8853vxBtvvPEmXikJEiScCr773e8ikUjgnnvuKSN8CO3t7fjsZz8LYEYqfdNNN+GXv/wlFi9eDI1GgyeeeAIAsHfvXrzzne+E2WyG0WjEBRdcgJ07d5aVRe3Iiy++iI9//OOw2+0wm834yEc+gnA4XLYttS9PPfUUuru7odVqsWjRIvz+978/ro6RSASf+9zn0NDQAI1Gg/b2dvzXf/0XSqXScdtt3boVNTU1sFgsuO666xCJRP6ayydBggQAFosFOp2ubGLptttuw7p162C326HT6bBq1Sr89re/rbr//fffjzVr1kCv18NqtWLjxo146qmn5jzmz372MyiVSnzhC1/gZcFgENdeey3MZjO/42+88cZxvl3kr9Hf349LLrkEJpMJH/7whwHMkD+f//znuT3p7OzEbbfdBkEQeP+5vMAq+0/U9+rr68PWrVthsVhQU1OD66+/HqlUqmzfbDaLf/mXf4HT6eQ+2djY2JzXQYIECaeO+bzvQHn/p7OzE1qtFqtWrcKLL754Usfz+Xy48sorYTQa4XQ68W//9m8oFotl28yn7ZTJZEgmk/jZz37GYWpbt249pWsg4c2FpPSRcEp45JFH0NzcjHPPPbfq+o0bN6K5ufm4mfj3ve99WLBgAW699dbjGi4xtm7dit/85je49tprcfbZZ+OFF17Au971rnnXr6+vD+9973txww034LrrrsNPf/pTbN26FatWrcLixYsBAAMDA3j44Yfxvve9Dy0tLZiamsJdd92F8847D4cOHYLX65338SRIkPDm4pFH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W2655TjlbzUFTH19PZ555hmk02lcdNFFZf2iLVu2IJ/P4//+7/94WalUwo9//ON5n8cll1yCYrGI//3f/y1b/oMf/AAymYzbKLPZDIfDcVy65sr+1MmAyv6f//mfsuWUgVCCBAlvLub7vhN27NhR5qszOjqKP/7xj7j44ouhUChgtVpx4YUXlv3TarUnVaf5tp0AYDAYjiOeJbz9kJQ+Ek4JCxYswM9+9jN8+MMfxtKlS3HDDTegpaUFQ0NDuOeeezA9PY1f/epXp5Smb9WqVXjPe96DH/7whwgGg5yynWbS3ywG+dJLL8Utt9yC66+/HuvWrcP+/fvxy1/+ssz0VYIECW8P2tra8MADD+ADH/gAurq68JGPfARLlixBLpfDK6+8goceeghbt26ds4xvf/vbePrpp7FhwwZ86lOfglKpxF133YVsNovvfve7x22fy+VwwQUX4P3vfz+OHj2KO+64Axs2bMDll19etl1HRwduuOEGvPbaa3C73fjpT3+KqampshmvL3zhC/jTn/6ESy+9FFu3bsWqVauQTCaxf/9+/Pa3v8XQ0BAcDgcuu+wyrF+/Hl/+8pcxNDSERYsW4fe//z2i0eibch0lSPhHwuOPP86z4X6/Hw888AB6e3vx5S9/GWazGe9617vw/e9/H+94xztw9dVXw+/348c//jHa29vLQtbb29vxta99Dd/61rdw7rnn4t3vfjc0Gg1ee+01eL1efOc73znu2O3t7XjqqaewadMmbNmyBdu2bYPZbMaVV16JNWvW4POf/zz6+vqwcOFC/OlPf2KPjfn0aS677DJs3rwZX/va1zA0NITly5fjqaeewh//+Ed87nOfK+trffSjH8V//ud/4qMf/ShWr16NF198kftPp4Lu7m586EMfwh133IFoNIp169bh2WeffdPV1xIkSJjBybzvALBkyRJs2bKlLGU7AHzzm9980+o037YTmBnHPfPMM/j+978Pr9eLlpYWrF279k2ri4RTxNuYOUzC3wF6enqED33oQ0Jtba2gUqkEj8cjfOhDHxL2799fth2lBg0EAseVUZmyXRAEIZlMCjfeeKNgs9kEo9EoXHnllcLRo0cFAMJ//ud/8nazpWynFKpinHfeecJ5553HvzOZjPD5z39eqK2tFXQ6nbB+/Xphx44dx20npWyXIOHtw7Fjx4R//ud/FpqbmwW1Wi2YTCZh/fr1wu233y5kMhlBEGZSlt54441V99+zZ4+wZcsWwWg0Cnq9Xti8ebPwyiuvlG1D7cgLL7wgfOxjHxOsVqtgNBqFD3/4w0IwGCzbltqXJ598Uli2bJmg0WiEhQsXCg899NBxx47H48JXvvIVob29XVCr1YLD4RDWrVsn3HbbbWWp4YPBoHDttdcKZrNZqKmpEa699lph7969UrsjQcI8US1lu1arFbq7u4U777yzLM36PffcIyxYsIDf3XvvvbdqP0QQBOGnP/2psGLFCkGj0QhWq1U477zzhKeffprXV+tv7Nq1SzCZTMLGjRs5xXEgEBCuvvpqwWQyCTU1NcLWrVuF7du3CwCEBx98kPe97rrrBIPBUPUc4/G48C//8i+C1+sVVCqVsGDBAuF73/te2bkJwkxa5RtuuEGoqakRTCaT8P73v1/w+/2zpmyv7JdV61el02nhM5/5jGC32wWDwSBcdtllwujoqJSyXYKENwGVKdsFYf7vO/V/7r//fm7XVqxYITz33HPzOvZsbU61NnG+beeRI0eEjRs3CjqdTgAgpW8/TSATBMmpTcKZgX379mHFihW4//778eEPf/jtro4ECRL+TnDffffh+uuvx2uvvVaW+acampubsWTJEjz66KN/o9pJkCDh7xEPP/wwrrrqKrz88stYv379210dCRIknIGQyWS48cYbjwsFkyChEpKnj4TTEul0+rhlP/zhDyGXy7Fx48a3oUYSJEiQIEGCBAknj8o+Dfl2mc1mrFy58m2qlQQJEiRI+EeB5Okj4bTEd7/7XezevRubN2+GUqnE448/jscffxwf+9jHjsu4I0GCBAkSJEiQcLri05/+NNLpNM455xxks1n8/ve/xyuvvIJbb70VOp3u7a6eBAkSJEj4O4dE+kg4LbFu3To8/fTT+Na3voVEIoHGxkZ84xvfwNe+9rW3u2oSJEiQIEGCBAnzxvnnn4///u//xqOPPopMJoP29nbcfvvtuOmmm97uqkmQIEGChH8AnNaePj/+8Y/xve99D5OTk1i+fDluv/12rFmz5u2ulgQJEiRIkCBBggQJEiRIkCBBwmmP09bT59e//jX+9V//FTfffDP27NmD5cuXY8uWLfD7/W931SRIkCBBggQJEiRIkCBBggQJEk57nLZKn7Vr1+Kss85iN/JSqYSGhgZ8+tOfxpe/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sgSHDx+eFhysX78eFosFjY2N7/v2vxWVlZVwuVzT9svn82HXrl3T9svj8WDv3r1imZdffhmpVAqLFy8Wy2zZsgXxeFwss379etTX18Nms71Pe/P2DAwMYGJiAoWFhQA+HPspSRK+8IUv4PHHH8fLL7+MysrKafe/W6/TJUuWTFuHvMyH9b1MRERERET0vjvTnaTfbX/9618lrVYrPfTQQ9KxY8ekm266SbJardNmCfog+/d//3dp06ZNUnd3t7Rt2zbpvPPOk/Lz8yW32y1JkiR97nOfk8rKyqSXX35Z2rNnj7RkyRJpyZIl4vGJREJqbm6WVq9eLR04cEBat26d5HA4pNtvv/1M7ZIkSZLk9/ul/fv3S/v375cASD/+8Y+l/fv3S729vZIkSdL3v/99yWq1Sk8++aR06NAh6dJLL5UqKyulcDgs1rFmzRpp7ty50q5du6StW7dKtbW10ic+8Qlxv8fjkQoKCqRPfepT0pEjR6S//vWvksFgkH71q199IPbT7/dLX/nKV6QdO3ZI3d3d0oYNG6R58+ZJtbW1UiQS+dDs58033yzl5uZKmzZtkoaHh8WfUCgklnk3XqddXV2SwWCQvvrVr0otLS3S/fffL6lUKmndunXvy34SERERERF92GVd6CNJknTfffdJZWVlkkajkRYtWiTt3LnzTG/SW3b11VdLhYWFkkajkYqLi6Wrr75a6ujoEPeHw2Hp85//vGSz2SSDwSBdfvnl0vDw8LR19PT0SGvXrpX0er2Un58v/fu//7sUj8ff712ZZuPGjRKAU/5cd911kiSlp23/1re+JRUUFEharVZatWqV1NraOm0dExMT0ic+8QnJZDJJFotFuuGGGyS/3z9tmYMHD0pnn322pNVqpeLiYun73//++7WLkiS98X6GQiFp9erVksPhkHJycqTy8nLpX//1X08JJD/o+3m6/QMgPfjgg2KZd+t1unHjRmnOnDmSRqORqqqqpj0HERERERERvTGFJEnS+11dRERERERERERE762s6ulDRERERERERERpDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiIiIiIKAsx9CEiIiIiIiIiykIMfYiIiIiIiIiIshBDHyIiIiIiIiKiLMTQh4iIiIiIiIgoCzH0ISIiIiIiIiLKQgx9iIiIiIiIiIiyEEMfIiIiIiIiIqIsxNCHiIiIiIiIiCgLMfQhIiIiIiIiIspCDH2IiIiIiIiIiLIQQx8iIiIiIiIioizE0IeIiIiI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IwGQ7rjjDnHbt7/97Wn7f+DAAQmA9PnPf37ac19zzTUSAOnb3/72624f0XtN/pzQ3d0tbisvL5cASNu3bxe3vfDCCxIASa/XS729veL2X/3qVxIAaePGjeK21/7/L0mS9PDDD0sApC1btojbLr74YslgMEiDg4Pitvb2dkmtVk97D/X09EgqlUr67ne/O22dhw8fltRq9Sm3v9aFF14oLVq0SPx8xRVXSFdccYWkUqmk559/XpIkSdq3b58EQHryySfFcitXrpRWrlwpft69e/frfkaQz1d/+MMfxG3RaFRyuVzSlVde+Ybb197eLimVSunyyy+XksnktPvkzzdut1vSaDTS6tWrpy3z85//XAIg/f73v3/b2/J6+/N2znevPUay6667TiovLxc/y581LRaL5Ha7py176aWXSk1NTW9whIiISMbhXfS67r//fqxfv37an+eff37aMldffTVsNpv4Wf7Wp6ur65T1fe5zn5v28/Lly09ZTq/Xi39PTU3B6/Vi+fLl2Ldv3ynrO++881BdXS1+njVrFiwWi1hnKpXCE088gYsvvvi0vYnkbw0fffRRLF++HDabDePj4+LPeeedh2QyiS1btgAAnnvuOajV6mmVSSqVCl/84hdPWTcRvftuuOGGaX0cXu98o9VqccMNN0y77dFHH0VDQwNmzJgx7X1+7rnnAgA2btwIAOKb6CeffPKU4Z1vd3v27NkDt9uNz3/+89DpdGK5Cy+8EDNmzMCzzz77uut+7rnnAABf+tKXpt1+6623vuE2EZ1JjY2NWLJkifhZHvZ07rnnoqys7JTbT37vnvz/fyQSwfj4OM466ywAEJ8BkskkNmzYgMsuuwxFRUVi+ZqamlOqYh577DGkUilcddVV097zLpcLtbW14j3/euTPHsFgEEC6uvijH/0o5syZg1deeQVAuvpHoVDg7LPPfotH6FQmk2laLzONRoNFixad9nPUyZ544gmkUinccccdolpKJn++2bBhA2KxGG699dZpy/zrv/4rLBbLKeegd7otwP/tfPdmrrzyylMquaxWKwYGBl63pQAREZ3A4V30uhYtWvSmjZxP/hAHQARAU1NT027X6XSn/Idts9lOWe6ZZ57Bf/3Xf+HAgQPT+mycbpz+a5/7tescGxuDz+dDc3PzG+5De3s7Dh06dNrScABwu90AgN7eXhQWFsJk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" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 350, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 350 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-08T11:21:42.726663Z", - "start_time": "2025-09-08T11:21:41.711795Z" - } - }, - "cell_type": "code", - "source": [ - "x#bkg_old = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_020925.jpg\")\n", - "#bkg_new = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_03092025.jpg\")\n", - "bkg_old = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/bkg280_50_50_old.jpg\")\n", - "bkg_new = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/bkg280_50_50.jpg\")\n", - "#$bkg_newest = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/bkg280.jpg\")\n", - "grey_old = cv2.cvtColor(bkg_old, cv2.COLOR_RGB2GRAY)\n", - "grey_new = cv2.cvtColor(bkg_new, cv2.COLOR_RGB2GRAY)\n", - "#grey_newest = cv2.cvtColor(bkg_newest, cv2.COLOR_RGB2GRAY)\n", - "diff_image = cv2.absdiff(grey_old, grey_new)\n", - "_, thresh_diff = cv2.threshold(diff_image, threshold, 255, cv2.THRESH_BINARY)\n", - "\n", - "\n", - "# Simple subtraction (may result in negative values)\n", - "diff_simple = cv2.subtract(bkg_new, bkg_old)\n", - "\n", - "# Weighted difference for motion detection\n", - "diff_weighted = cv2.addWeighted(bkg_new, 0.5, bkg_old, -0.5, 128)\n", - "\n", - "# Using numpy for difference\n", - "diff_numpy = np.abs(bkg_new.astype(np.int16) - bkg_old.astype(np.int16)).astype(np.uint8)\n", - "\n", - "plt.subplot(1,2,1)\n", - "plt.imshow(bkg_old)\n", - "plt.subplot(1,2,2)\n", - "plt.imshow(bkg_new)" - ], - "id": "5c26fa11f85e6483", - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 275, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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epG/7W1v85/8yZ/0xz/+8f7v//2/f1Tr9vVf//V+6623Tv34/ve/f4rzWK3bLbfc4j/2Yz/mb3vb2/wtb3mLf9mXfZk/7WlP8w9+8IMV5+EYh//7f/9vf8ITnuDf8R3f4b/zO7/jP/RDP+Tnzp3zV73qVadavwuFs4gdlxJuuB+x4yxix1nDjUuO9HzhF36h33777fV7t9v5jTfe6K94xSsexVJdOHz3d3+3f/Znf/bBe/fee68/7nGP85/+6Z+ua7/7u7/rAPyuu+5y9xCobdv8nnvuqTg/8iM/4ldddZX/5V/+5amW/XxhFe4xht9www3+Az/wA3Xt3nvv9SuvvNJ/8id/0t3df+d3fscB+G/8xm9UnF/+5V92M/P/+3//r7u7/9t/+2/9SU960lS3l73sZf6sZz3rlGvU4STg+oqv+IoTnzkrdXN3f+973+sA/HWve527P3zj8J/+03/qn/mZnznl9TVf8zV+yy23nHaVzhvOInZcqrjhfsSONZyVuj3WceOSWt768Ic/jDe96U24+eab69q2bbj55ptx1113PYolu7jwe7/3e7jxxhvxjGc8Ay960Yvwrne9CwDwpje9CQ888MBUr0/7tE/D0572tKrXXXfdhec85zm4/vrrK84tt9yC+++/H29/+9sf2YqcJ7zzne/EPffcM9Xl6quvxnOf+9ypLtdccw0+//M/v+LcfPPN2LYNb3zjGyvOl37pl+KKK66oOLfccgvuvvtu/Omf/ukjVJvD4c4778R1112HZz3rWXjxi1+M973vfXXvLNXtvvvuAwA8+clPBvDwjcO77rprSoNxHk0ZPcvYcTngBnDEjrNSt8c6blxSpOf//b//h91uNzUcAFx//fW45557HqVSXVx47nOfi1e+8pV41atehR/5kR/BO9/5TnzJl3wJPvCBD+Cee+7BFVdcgWuuuWZ6Rut1zz33HKw37z1WAstyvj665557cN111033P+ZjPgZPfvKTH/P1vfXWW/HjP/7juOOOO/B93/d9eN3rXofbbrsNu92uynYW6jbGwLd/+7fji7/4i/HsZz+78n44xuFJce6//3586EMfOo3qXDCcVey4XHADOGLHWajbWcCNj3lINTqGUwu33XZbff+sz/osPPe5z8Unf/In47/8l/+Cxz/+8Y9iyY7hoYQXvvCF9f05z3kOPuuzPguf8imfgjvvvBPPe97zHsWSPbRw++23421vext+5Vd+5dEuyjGcJxxx49IJlwJ2nAXcuKQsPddeey3OnTu35xX+nve8BzfccMOjVKqPLFxzzTX4q3/1r+Id73gHbrjhBnz4wx/GvffeO8XRet1www0H6817j5XAspyvj2644Qa8973vne4/+OCDeP/733/m6vuMZzwD1157Ld7xjncAOBt1e8lLXoJf+IVfwGtf+1p80id9Ul1/uMbhSXGuuuqqR22ivlSw41LFDeCIHY/1up0V3LikSM8VV1yBz/u8z8Mdd9xR18YYuOOOO3DTTTc9iiV76OGDH/wgfv/3fx9PecpT8Hmf93l43OMeN9Xr7rvvxrve9a6q10033YTf/u3fnoTi1a9+Na666ip8xmd8xiNe/pPC05/+dNxwww1TXe6//3688Y1vnOpy77334k1velPFec1rXoMxBp773OdWnNe//vV44IEHKs6rX/1qPOtZz8KTnvSkR6g2Fw5/9Ed/hPe97314ylOeAuCxXTd3x0te8hL8zM/8DF7zmtfg6U9/+nT/4RqHN91005QG4zyaMnqpYMelihvAETseq3U7c7jxEThnP6bDT/3UT/mVV17pr3zlK/13fud3/Fu+5Vv8mmuumbzCH4vhO7/zO/3OO+/0d77znf6rv/qrfvPNN/u1117r733ve909tvw97WlP89e85jX+m7/5m37TTTf5TTfdVM9zy9/zn/98f8tb3uKvetWr/BM+4RMela2nH/jAB/zNb36zv/nNb3YA/oM/+IP+5je/2f/P//k/7h7bTq+55hr/uZ/7OX/rW9/qX/EVX3Fw2+lf+2t/zd/4xjf6r/zKr/infuqnTlsz7733Xr/++uv9677u6/xtb3ub/9RP/ZQ/4QlPOPVtp+er2wc+8AH/J//kn/hdd93l73znO/2///f/7p/7uZ/rn/qpn+p/8Rd/8Ziv24tf/GK/+uqr/c4775y2zf75n/95xXk4xiG3nr70pS/13/3d3/Uf/uEffsxsWT9r2HEp4Yb7ETvOInacNdy45EiPu/sP/dAP+dOe9jS/4oor/Au/8Av9DW94w6NdpAuGr/mar/GnPOUpfsUVV/gnfuIn+td8zdf4O97xjrr/oQ99yL/1W7/Vn/SkJ/kTnvAE/6qv+ip/97vfPaXxB3/wB37bbbf54x//eL/22mv9O7/zO/2BBx54pKvir33tax3A3t/Xf/3Xu3tsPf3n//yf+/XXX+9XXnmlP+95z/O77757SuN973uff+3Xfq0/8YlP9Kuuusr//t//+/6BD3xgivNbv/Vb/jf+xt/wK6+80j/xEz/Rv/d7v/dRrduf//mf+/Of/3z/hE/4BH/c4x7nn/zJn+zf/M3fvDdpPlbrdqheAPzHfuzHKs7DNQ5f+9rX+ud8zuf4FVdc4c94xjOmPB7NcNaw41LCDfcjdpxF7DhruGFZ6GM4hmM4hmM4hmM4hks6XFI+PcdwDMdwDMdwDMdwDCeFI+k5hmM4hmM4hmM4hssiHEnPMRzDMRzDMRzDMVwW4Uh6juEYjuEYjuEYjuGyCEfScwzHcAzHcAzHcAyXRTiSnmM4hmM4hmM4hmO4LMKR9BzDMRzDMRzDMRzDZRGOpOcYjuEYjuEYjuEYLotwJD3HcAzHcAzHcAzHcFmEI+k5hmM4hmM4hmM4hssiHEnPMRzDMRzDMRzDMVwW4f8HkvLKZ8ajVgwAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "execution_count": 275 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-08T08:13:17.148953Z", - "start_time": "2025-09-08T08:13:17.046977Z" - } - }, - "cell_type": "code", - "source": [ - "bkg_old_np = bkg_old.astype(np.float32)\n", - "bkg_old_np_normalized = bkg_old.astype(np.float32) / 255.0\n", - "bkg_new_np = bkg_old.astype(np.float32)\n", - "bkg_new_np_normalized = bkg_old.astype(np.float32) / 255.0\n", - "diff_np=bkg_old_np-bkg_new_np\n", - "diff_np_normalized=bkg_old_np_normalized-bkg_new_np_normalized" - ], - "id": "95a0ac65d0013e8", - "outputs": [], - "execution_count": 196 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-08T08:14:30.738697Z", - "start_time": "2025-09-08T08:14:30.671257Z" - } - }, - "cell_type": "code", - "source": [ - "print(\"mean: \", np.mean(grey_old.astype(np.float32)-grey_new.astype(np.float32)))\n", - "print(\"std: \", np.std(grey_old.astype(np.float32)-grey_new.astype(np.float32)))\n", - "diff_abs = np.abs(grey_old.astype(np.float32)-grey_new.astype(np.float32))\n", - "print(np.percentile(diff_abs, 99))" - ], - "id": "83aae96e9df6c807", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "mean: -6.184164\n", - "std: 5.93317\n", - "21.0\n" - ] - } - ], - "execution_count": 200 - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "threshold_old = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_020925.jpg\")\n", - "threshold_new = cv2.imread(\"/home/leonarski_f/aaredaq/daq/src/aaredaq/alc_test_images/bkg280_03092025.jpg\")" - ], - "id": "258a3d679516f15c" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-05T13:33:03.863166Z", - "start_time": "2025-09-05T13:33:03.839938Z" - } - }, - "cell_type": "code", - "source": [ - "import numpy as np\n", - "from scipy import ndimage\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# Example showing the difference\n", - "image = np.random.rand(50, 50) * 100\n", - "# Add a bright spot\n", - "image[20:30, 35:45] = 200\n", - "\n", - "# Without thresholding - all pixels contribute\n", - "com_no_threshold = ndimage.center_of_mass(image)\n", - "print(f\"No threshold COM: ({com_no_threshold[1]:.2f}, {com_no_threshold[0]:.2f})\")\n", - "\n", - "# With thresholding - only bright pixels contribute\n", - "threshold = 150\n", - "thresholded = image.copy()\n", - "thresholded[thresholded < threshold] = 0\n", - "com_with_threshold = ndimage.center_of_mass(thresholded)\n", - "print(f\"With threshold COM: ({com_with_threshold[1]:.2f}, {com_with_threshold[0]:.2f})\")\n" - ], - "id": "d70801a606268e76", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "No threshold COM: (26.11, 24.33)\n", - "With threshold COM: (39.50, 24.50)\n" - ] - } - ], - "execution_count": 189 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-05T13:33:18.254639Z", - "start_time": "2025-09-05T13:33:18.248074Z" - } - }, - "cell_type": "code", - "source": [ - "def center_of_mass_with_threshold(image, threshold):\n", - " \"\"\"\n", - " Apply threshold before center of mass calculation\n", - " \"\"\"\n", - " # Create binary mask\n", - " binary = (image >= threshold).astype(float)\n", - "\n", - " # Calculate center of mass on thresholded image\n", - " com = ndimage.center_of_mass(binary)\n", - "\n", - " # Return as (x, y) coordinates\n", - " return (com[1], com[0]) if com[0] is not np.nan else None\n" - ], - "id": "1ba37750a7b66b23", - "outputs": [], - "execution_count": 190 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-09-05T13:33:27.236834Z", - "start_time": "2025-09-05T13:33:27.231958Z" - } - }, - "cell_type": "code", - "source": [ - "def weighted_center_of_mass_threshold(image, threshold):\n", - " \"\"\"\n", - " Keep original intensities above threshold, zero below\n", - " \"\"\"\n", - " weighted_image = image.copy()\n", - " weighted_image[weighted_image < threshold] = 0\n", - "\n", - " com = ndimage.center_of_mass(weighted_image)\n", - " return (com[1], com[0]) if com[0] is not np.nan else None\n" - ], - "id": "59452341d64bc800", - "outputs": [], - "execution_count": 191 - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "8cf8041e736e5a43" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/scripts/knife_edge_scan.ipynb b/scripts/knife_edge_scan.ipynb deleted file mode 100644 index a05a73d7..00000000 --- a/scripts/knife_edge_scan.ipynb +++ /dev/null @@ -1,509 +0,0 @@ -{ - "cells": [ - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Import Packages**", - "id": "1e84a74bce983a48" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T15:21:27.478441Z", - "start_time": "2025-07-09T15:21:26.516951Z" - } - }, - "cell_type": "code", - "source": [ - "from aaredaq.devices import BeamlineDevices\n", - "from aaredaqlib.beamline import MXBeamline" - ], - "id": "d2efa08de2dbd46b", - "outputs": [], - "execution_count": 1 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T15:21:29.814198Z", - "start_time": "2025-07-09T15:21:28.052349Z" - } - }, - "cell_type": "code", - "source": [ - "from epics import PV\n", - "import numpy as np\n", - "import time\n", - "import matplotlib.pyplot as plt\n", - "from scipy.optimize import curve_fit\n", - "from scipy.signal import peak_widths, find_peaks" - ], - "id": "f8305237c9f98964", - "outputs": [], - "execution_count": 2 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Config**", - "id": "de33ac6389ffef80" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T15:21:33.454435Z", - "start_time": "2025-07-09T15:21:31.742983Z" - } - }, - "cell_type": "code", - "source": [ - "d = BeamlineDevices(MXBeamline.X06DA)\n", - "b = MXBeamline.X06DA\n", - "beamline = b.value.upper()" - ], - "id": "5407e46ef4c2a26d", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Connecting TELL p-shell service at http://x06da-tell.psi.ch:22222 ..." - ] - } - ], - "execution_count": 3 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Functions for fitting**", - "id": "ad205cd8366be8b5" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T15:21:35.539527Z", - "start_time": "2025-07-09T15:21:35.532072Z" - } - }, - "cell_type": "code", - "source": [ - "def gaus(x, *p):\n", - " A, mu, sigma = p\n", - " return A * np.exp(-(x-mu)**2/(2.*sigma**2))\n", - "\n", - "def sigmoid(x, *p):\n", - " L, x0, k, c = p\n", - " return L / (1 + np.exp(-k * (x -x0))) + c\n", - "\n", - "def unpack_data(data):\n", - " x_vals, y_vals = zip(*data)\n", - " x_vals = list(x_vals)\n", - " y_vals = list(y_vals)\n", - " return x_vals, y_vals\n", - "\n", - "def sigmoid_fit(x_vals, y_vals):\n", - " L_guess = np.max(y_vals)\n", - " b_guess = np.min(y_vals)\n", - " x0_guess = x_vals[np.argmin(np.abs(y_vals - (L_guess + b_guess) / 2))]\n", - " k_guess = 1 / (x_vals[-1] - x_vals[0])\n", - "\n", - " s0 = [L_guess, x0_guess, k_guess, b_guess]\n", - " parameters, params_covariance = curve_fit(sigmoid, x_vals, y_vals, p0=s0)\n", - " return parameters\n", - "\n", - "def gauss_fit(x_vals, dydx):\n", - " mean = x_vals[np.argmax(dydx)]\n", - " sigma = (np.max(x_vals) - np.min(x_vals))/4\n", - " A= np.max(dydx)\n", - " dydx[np.isnan(dydx)] = 0\n", - "\n", - " p0 = [A, mean, sigma]\n", - " parameters, covariance = curve_fit( gaus, x_vals, dydx, p0=p0)\n", - " return parameters\n", - "\n", - "def calc_fwhm(gauss_y, x_vals):\n", - " peaks = find_peaks( gauss_y )\n", - " fwhm_peak = peak_widths( gauss_y, peaks[0], rel_height=0.5 )\n", - "\n", - " fwhm_str = x_vals[int( round( fwhm_peak[2][0], 0 ))]\n", - " fwhm_end = x_vals[int( round( fwhm_peak[3][0], 0 ))]\n", - "\n", - " fwhm = fwhm_str - fwhm_end\n", - " fwhm_height = gauss_y[int( round( fwhm_peak[2][0], 0 ))]\n", - "\n", - " # find 1/e2 peak width\n", - " full_peak = peak_widths( gauss_y, peaks[0], rel_height=0.865 )\n", - " full_str = x_vals[int( round( full_peak[2][0], 0 ))]\n", - " full_end = x_vals[int( round( full_peak[3][0], 0 ))]\n", - "\n", - " full = full_str - full_end\n", - " full_height = gauss_y[int( round( full_peak[2][0], 0 ))]\n", - " return fwhm, full" - ], - "id": "d92115ec3d76d57d", - "outputs": [], - "execution_count": 4 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Function for performing knife_edge then fitting and plotting**", - "id": "323bcc0c8ba19afa" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T16:34:57.207683Z", - "start_time": "2025-07-09T16:34:57.203084Z" - } - }, - "cell_type": "code", - "source": [ - "def knife_edge(motor: str, dev: BeamlineDevices, beamline: str, steps: int = 40, start: float = 0.0, step_size: float = 0.002, offset: float = 0.0, sleep = 0.5):\n", - " diode = PV(f\"{beamline}-ES-BS:READOUT\")#X06DA-ES-BS:READOUT\n", - " dev.shutter = True\n", - " time.sleep(2.0)\n", - "\n", - " data = []\n", - "\n", - " for i in range(steps): #40\n", - " if motor == 'X':\n", - " dev.gmx.move(start-offset+step_size*i, wait=True)\n", - " time.sleep(sleep)\n", - " print(f\"{dev.gmx.value:.3f} {diode.get()}\")\n", - " data.append([dev.gmx.value, diode.get()])\n", - " else:\n", - " dev.gmy.move(start-offset+step_size*i, wait=True)\n", - " time.sleep(sleep)\n", - " print(f\"{dev.gmy.value:.3f} {diode.get()}\")\n", - " data.append([dev.gmy.value, diode.get()])\n", - "\n", - " if motor == 'X':\n", - " dev.gmx.move(start, wait=True)\n", - " #else:\n", - " # dev.gmy.move(start, wait=True)\n", - "\n", - " dev.shutter = False\n", - " return data\n" - ], - "id": "512dc280e62e4ed4", - "outputs": [], - "execution_count": 41 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T16:35:13.891315Z", - "start_time": "2025-07-09T16:35:13.885335Z" - } - }, - "cell_type": "code", - "source": [ - "def fit_knife_edge(data, motor: str):\n", - "\n", - " x_vals, y_vals = unpack_data(data)\n", - "\n", - " plt.plot(x_vals, y_vals, label = 'edge_scan')\n", - " plt.ylabel('Intensity (counts)')\n", - " plt.xlabel('Motor position (mm)')\n", - "\n", - " params=sigmoid_fit(x_vals, y_vals)\n", - "\n", - " plt.plot(x_vals, y_vals)\n", - " plt.plot(x_vals, sigmoid(x_vals, *params))\n", - " plt.show()\n", - "\n", - " y_fit = sigmoid(x_vals, *params)\n", - "\n", - " dydx = np.gradient(y_fit, x_vals)\n", - "\n", - " if motor == 'X':\n", - " dydx=-dydx\n", - "\n", - " parameters = gauss_fit(x_vals, dydx)\n", - "\n", - " x0_op = parameters[1]\n", - " sigma_op = parameters[2]\n", - " print(parameters)\n", - "\n", - " gauss_y = gaus(x_vals,*parameters)\n", - " fwhm = np.abs(2*np.sqrt(2*np.log(2))*sigma_op)\n", - " print(f\"Manually calculated FWHM to {fwhm} mm\")\n", - " plt.plot(x_vals, dydx, label = 'derivative')\n", - " plt.plot(x_vals, gauss_y,label='Gaussian fit',color ='orange')\n", - " plt.fill_between(x_vals,gauss_y,color='orange',alpha=0.5)\n", - "\n", - " try:\n", - " fwhm, full = calc_fwhm(gauss_y, x_vals)\n", - " print( \"Scipy calculated FWHM = {0} mm\".format( fwhm ) )\n", - " print( \"Scipy calculated 1/e2 = {0} mm\".format( full ) )\n", - " except:\n", - " print('scipy peak finding failed')\n", - "\n", - " plt.axvspan(x0_op+fwhm/2,x0_op-fwhm/2, color='green', alpha=0.75, lw=0, label='FWHM = {0} mm'.format(fwhm))\n", - " plt.legend()\n", - " plt.show()\n", - " #plt.savefig(output_name+filename.split('/')[-1]+'FWHM_{0}.png'.format(fwhm))\n" - ], - "id": "80460b35a33f1ecf", - "outputs": [], - "execution_count": 42 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Knife Edge scan in X**", - "id": "b063ff6432f42184" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T17:51:02.087583Z", - "start_time": "2025-07-09T17:49:59.206783Z" - } - }, - "cell_type": "code", - "source": [ - "steps_x = 50\n", - "start_pos_x = -17.94\n", - "step_size_x = 0.002\n", - "offset_x = 0.0 # offset subtracted from start position\n", - "sleep = 1 # wait after move before recording diode\n", - "x_data=knife_edge(motor='X', dev=d, beamline=beamline, steps=steps_x, start=start_pos_x, step_size=step_size_x, offset=offset_x, sleep = sleep)\n", - "fit_knife_edge(x_data, motor='X')" - ], - "id": "5454eb901526eb3", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-17.940 8.959981e-06\n", - "-17.938 8.944953e-06\n", - "-17.936 8.937235e-06\n", - "-17.934 8.946256e-06\n", - "-17.932 8.870569e-06\n", - "-17.930 8.943733e-06\n", - "-17.928 8.932527e-06\n", - "-17.926 8.931002e-06\n", - "-17.924 8.912179e-06\n", - "-17.922 8.929313e-06\n", - "-17.920 8.917321e-06\n", - "-17.918 8.937232e-06\n", - "-17.916 8.892818e-06\n", - "-17.914 8.824038e-06\n", - "-17.912 8.808735e-06\n", - "-17.910 8.837087e-06\n", - "-17.908 8.671096e-06\n", - "-17.906 8.606978e-06\n", - "-17.904 8.432655e-06\n", - "-17.902 8.189082e-06\n", - "-17.900 8.250342e-06\n", - "-17.898 7.650508e-06\n", - "-17.896 7.203671e-06\n", - "-17.894 6.735723e-06\n", - "-17.892 6.1932e-06\n", - "-17.890 6.269931e-06\n", - "-17.888 5.137038e-06\n", - "-17.886 4.552743e-06\n", - "-17.884 3.875157e-06\n", - "-17.882 3.34356e-06\n", - "-17.880 3.422219e-06\n", - "-17.878 2.437191e-06\n", - "-17.876 2.017403e-06\n", - "-17.874 1.662639e-06\n", - "-17.872 1.323577e-06\n", - "-17.870 1.346216e-06\n", - "-17.868 9.006973e-07\n", - "-17.866 7.306933e-07\n", - "-17.864 5.915996e-07\n", - "-17.862 4.870485e-07\n", - "-17.860 4.98184e-07\n", - "-17.858 3.496483e-07\n", - "-17.856 2.945638e-07\n", - "-17.854 2.461977e-07\n", - "-17.852 2.114641e-07\n", - "-17.850 2.139551e-07\n", - "-17.848 1.598115e-07\n", - "-17.846 1.397988e-07\n", - "-17.844 1.199971e-07\n", - "-17.842 1.045175e-07\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjYAAAHACAYAAACxlSKsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAXndJREFUeJzt3Xd8FHXixvHP7GbTKymEEgjd0LsUCyhFBQ/sFUEU7+zlp3eoZzsVLIcdxQrYQREroIII0nsPnVACIYH0ttnszu+PaM4I0SwkmZTn/XrNK9nZ2dlnxrJPZr47Y5imaSIiIiJSB9isDiAiIiJSWVRsREREpM5QsREREZE6Q8VGRERE6gwVGxEREakzVGxERESkzlCxERERkTpDxUZERETqDBUbERERqTNUbERERKTOqDPFZvHixVx88cU0btwYwzD48ssvq/w9k5OTuf7664mMjCQgIIBOnTqxZs2aKn9fERERObk6U2zy8vLo0qULkydPrpb3y8jIoH///jgcDubOncu2bduYNGkSERER1fL+IiIiciKjLt4E0zAMZs+ezciRI0vnOZ1OHn74YT755BMyMzPp2LEjzz77LAMGDDil9xg/fjxLly7ll19+qZzQIiIictrqzBGbv3LHHXewfPlyPv30UzZt2sQVV1zBBRdcwK5du05pfV9//TU9e/bkiiuuICYmhm7duvH2229XcmoRERHxRr04YnPgwAFatmzJgQMHaNy4celygwYNonfv3kyYMMHr9/D39wfgvvvu44orrmD16tXcfffdTJkyhdGjR1fKdoiIiIh3fKwOUB02b96M2+2mbdu2ZeY7nU4iIyMB2L59OwkJCX+6nn/9618888wzAHg8Hnr27Flairp168aWLVtUbERERCxUL4pNbm4udrudtWvXYrfbyzwXHBwMQMuWLUlMTPzT9fxWggAaNWpE+/btyzyfkJDArFmzKim1iIiIeKteFJtu3brhdrtJTU3l7LPPPukyvr6+nHHGGRVeZ//+/dmxY0eZeTt37qR58+anlVVEREROXZ0pNrm5uezevbv08b59+9iwYQMNGjSgbdu2XHfdddxwww1MmjSJbt26kZaWxoIFC+jcuTPDhg3z+v3uvfde+vXrx4QJE7jyyitZtWoVb731Fm+99VZlbpaIiIh4oc4MHv75558ZOHDgCfNHjx7NtGnTcLlc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dbH58ssvSU5O5tZbb2XGjBnEx8dz4YUX8vnnn+Nyuaoio4hIpcs/43IA+hxYRIfIDhR7ivlq91cWpxKR03VKY2yio6O577772LhxIytXrqR169aMGjWKxo0bc++997Jr167KzikiUqkSzruOQtNBc88hzgnoCpScjvKYHmuDichpOa3Bw0eOHOHHH3/kxx9/xG63c9FFF7F582bat2/Piy++WFkZRUQqXUhYA7aGngVA+x27CHYEczDnICuPrLQ4mYicDq+LjcvlYtasWQwfPpzmzZvz2Wefcc8993D48GGmT5/O/PnzmTlzJv/5z3+qIq+ISKWxd70agI6p87ko/kJAg4hFarsK3d379xo1aoTH4+Gaa65h1apVdO3a9YRlBg4cSHh4eCXEExGpOh3OvoSMX+4niky65UYyE1h4YCHHCo4RFRBldTwROQVeH7F58cUXOXz4MJMnTz5pqQEIDw9n3759p5tNRKRKOXz92Bk1GIDYLQvpEt2FYrOY2btmW5xMRE6V18Vm4cKFJ/32U15eHmPHjq2UUCIi1SWsz/UAtM9azN+aDQPg852f4/a4rYwlIqfI62Izffp0CgoKTphfUFDA+++/XymhRESqS7vuAzlkxBJoOGm65zghviEczjvMssPLrI4mIqegwsUmOzubrKwsTNMkJyeH7Ozs0ikjI4M5c+YQExNTlVlFRCqdYbNxsOnFAAQnfsmIViMADSIWqa0qPHg4PDwcwzAwDIO2bdue8LxhGDzxxBOVGk5EpDo0PXc0fPg2HQrW4GrwBB/yIYsOLSIlL4XYoFir44mIFypcbBYuXIhpmpx33nnMmjWLBg0alD7n6+tL8+bNady4cZWEFBGpSnGtO7HDpx3tinfgWrWQHg17sPboWmbvms2tXW+1Op6IeKHCxebcc88FYN++fTRr1gzDMKoslIhIdctscykkTiRy75dc2ec/rD26ls93fc64zuPwsXl9ZQwRsUiFxths2rQJj6fkMuNZWVls3ryZTZs2nXQ6Vc888wyGYXDPPfec8jpERE5Vm4GjcJl22hTvoq0zmgi/CFLzU1l8aLHV0UTECxX6M6Rr166kpKQQExND165dMQwD0zRPWM4wDNxu778iuXr1at588006d+7s9WtFRCpDg5gmbAjsRdeCFaQt/ZiR3UYydctUZuyYwXnNzrM6nohUUIWO2Ozb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ZdtaE1TF/k5LSzMjIyPNSy+91NywYYO5Y8cO8/777zcdDoe5YcMG0zRNMzEx0fTz8zNvvfVWc9u2beaWLVvM66+/3gwLCzMPHz5c5dttFav2t2ma5ogRI8wOHTqYS5cuNTdv3mwOHz7cbN++vVlUVFSl22wlK/f3753q52W9KTajR482gROmhQsXllmub9++5rXXXnvSdfy2k/ft21c6b9SoUWaDBg1MX19fs3Pnzn/6dbffr6OuFxur9vdjjz120vdt3rx5JW9hzWLlv99JSUnmhRdeaAYEBJhRUVHm//3f/5kul6syN6/Gqar9vXr1anPIkCFmgwYNzJCQELNPnz7mnDlzyrzuhx9+MPv372+GhYWZERER5nnnnWcuX768sjexRrFyf2dlZZljx441w8PDzQYNGpiXXHJJma/b10VW7u+TrcPbz0vd3VtERETqjLr31QYRERGpt1RsREREpM5QsREREZE6Q8VGRERE6gwVGxEREakzVGxERESkzlCxERERkTpDxUZERETqDBUbEamRxowZw8iRI/90mZ9//hnDMMjMzKzyPMePHycmJoakpKQqf68/2rZtG02bNiUvL6/a31uktlGxEakBxowZg2EY/OMf/zjhudtvvx3DMBgzZkyF11edH/hV5eWXX2batGmljwcMGMA999xTZpl+/fpx5MgRwsLCqjzP008/zYgRI4iPj6/y9/qj9u3b06dPH1544YVqf2+R2kbFRqSGiIuL49NPPy1zd9vCwkI+/vhjmjVrZkkm0zQpLi625L3DwsIIDw//02V8fX2JjY0tc7frqpCfn8+7777LTTfdVKXv82duvPFG3njjDcv+eYjUFio2IjVE9+7diYuL44svviid98UXX9CsWTO6detWZlmn08ldd91FTEwM/v7+nHXWWaxevRqApKQkBg4cCEBERESZoz1/9jr435GeuXPn0qNHD/z8/FiyZMkJWZOSkjAMg08//ZR+/frh7+9Px44dWbRoUZnlFi1aRO/evfHz86NRo0aMHz++zAfz559/TqdOnQgICCAyMpJBgwaVnm75/amoMWPGsGjRIl5++WUMw8AwDJKSkk56ZGrWrFl06NABPz8/4uPjmTRpUplM8fHxTJgwgbFjxxISEkKzZs146623/vSfzZw5c/Dz86NPnz4n7Kvvv/+ebt26ERAQwHnnnUdqaipz584lISGB0NBQrr32WvLz80tfN2DAAO68807uueceIiIiaNiwIW+//TZ5eXnceOONhISE0Lp1a+bOnVsmw+DBg0lPTz9hH4tIWSo2IjXI2LFjmTp1aunj9957jxtvvPGE5f75z38ya9Yspk+fzrp162jdujVDhw4lPT2duLg4Zs2aBcCOHTs4cuQIL7/88l++7vfGjx/PM888Q2JiIp07dy437wMPPMD//d//sX79evr27cvFF1/M8ePHAUhOTuaiiy6iV69ebNy4kTfeeIN3332Xp556CoAjR45wzTXXMHbsWBITE/n555+59NJLOdl9eV9++WX69u3LuHHjOHLkCEeOHCEuLu6E5dauXcuVV17J1VdfzebNm3n88cd55JFHypzSApg0aRI9e/Zk/fr13Hbbbdx6663s2LGj3O385Zdf6NGjx0mfe/zxx3nttddYtmwZBw8e5Morr+Sll17i448/5rvvvuOHH37g1VdfLfOa6dOnExUVxapVq7jzzju59dZbueKKK+jXrx/r1q1jyJAhjBo1qkwh8vX1pWvXrvzyyy/l5hQRwKt7gYtIlRg9erQ5YsQIMzU11fTz8zOTkpLMpKQk09/f30xLSzNHjBhhjh492jRN08zNzTUdDof50Ucflb6+qKjIbNy4sfncc8+ZpmmaCxcuNAEzIyOjdBlvXvfll1/+ad59+/aZgPnMM8+UznO5XGbTpk3NZ5991jRN03zooYfMdu3amR6Pp3SZyZMnm8HBwabb7TbXrl1rAmZSUtKf7pPfnHvuuebdd99dZpk/bue1115rDh48uMwyDzzwgNm+ffvSx82bNzevv/760scej8eMiYkx33jjjXK3d8SIEebYsWNP+t7z588vnTdx4kQTMPfs2VM67+9//7s5dOjQMttx1llnlT4uLi42g4KCzFGjRpXOO3LkiAmYy5cvL/Oel1xyiTlmzJhyc4qIaeqIjUgNEh0dzbBhw5g2bRpTp05l2LBhREVFlVlmz549uFwu+vfvXzrP4XDQu3dvEhMTy123N6/r2bNnhfL27du39HcfHx969uxZuq7ExET69u1bZvxL//79yc3N5dChQ3Tp0oXzzz+fTp06ccUVV/D222+TkZFRofctT2JiYpnt++09d+3ahdvtLp33+6NQhmEQGxtLampquestKCjA39//pM/9fl0NGzYkMDCQli1blpn3x3X//jV2u53IyEg6depU5jXACa8LCAgocxRHRE6kYiNSw4wdO5Zp06Yxffp0xo4da0mGoKCgKn8Pu93Ojz/+yNy5c2nfvj2vvvoq7dq1Y9++fVX+3g6Ho8xjwzDweDzlLh8VFVVu6fr9ugzDqNC6T7bMH9cDnPC69PR0oqOjy80pIio2IjXOBRdcQFFRES6Xi6FDh57wfKtWrfD19WXp0qWl81wuF6tXr6Z9+/ZAyXgMoMxRioq8zlsrVqwo/b24uJi1a9eSkJAAQEJCAsuXLy8zZmbp0qWEhITQtGlToOQDvH///jzxxBOsX78eX19fZs+efdL38vX1LbM9J5OQkFBm+357z7Zt22K3209pGwG6devGtm3bTvn1lWXLli0nDCQXkbJUbERqGLvdTmJiItu2bTvph3FQUBC33norDzzwAPPmzWPbtm2MGzeO/Pz80q8jN2/eHMMw+Pbbb0lLSyM3N7dCr/PW5MmTmT17Ntu3b+f2228nIyOj9CjTbbfdxsGDB7nzzjvZvn07X331FY899hj33XcfNpuNlStXMmHCBNasWcOBAwf44osvSEtLKy1GfxQfH8/KlStJSkri2LFjJz3C8n//938sWLCAJ598kp07dzJ9+nRee+017r///lPavt8MHTqUrVu3nvapstORlJREcnIygwYNsiyDSG2gYiNSA4WGhhIaGlru88888wyXXXYZo0aNonv37uzevZvvv/+eiIgIAJo0acITTzzB+PHjadiwIXfccUeFXuetZ555hmeeeYYuXbqwZMkSvv7669IxQU2aNGHOnDmsWrWKLl268I9//IObbrqJf//736XbuHjxYi666CLatm3Lv//9byZNmsSFF1540ve6//77sdvttG/fnujoaA4cOHDCMt27d2fmzJl8+umndOzYkUcffZT//Oc/Xl3c8GQ6depUum6rfPLJJwwZMoTmzZtblkGkNjBM8yTfrRQR+RNJSUm0aNGC9evX07VrV6vjVIvvvvuOBx54gC1btmCzVe/fhEVFRbRp04aPP/74hMHRIlKWj9UBRERqg2HDhrFr1y6Sk5NPeg2dqnTgwAEeeughlRqRCtARGxHxWn08YiMitYOKjYiIiNQZGjwsIiIidYaKjYiIiNQZKjYiIiJSZ6jYiIiISJ2hYiMiIiJ1hoqNiIiI1BkqNiIiIlJnqNiIiIhInaFiIyIiInXG/wPvujXGVKOk0AAAAABJRU5ErkJggg==" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ 2.92142522e-04 -1.78855968e+01 1.17269351e-02]\n", - "Manually calculated FWHM to 0.02761482178449844 mm\n", - "Scipy calculated FWHM = -0.02800645446777139 mm\n", - "Scipy calculated 1/e2 = -0.04800543212890318 mm\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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+XXEtefjmi9lBChJpGQJmaqqdKhvpbkbNhXqaW1EOfI8HJUQ15ckUwKA/Px8hg0bhp+fH1FRUbzzzjtu+4uLixk3bhx169bF19eXxMREli1b5tpfOsz2888/07JlS7y9vTl8+LDbMN9nn31GdHT0BQVN+/fvz/333w/Avn376N+/PxEREfj5+dGpUycWLVrkanvTTTdx6NAhnnzySedE2JLJ/ucO8+3evRtFUdi5033pkffee49GjRq5ft66dSu33XYbfn5+RERE8I9//IPTp09f1esoro4WBwac/z5yZYivWihNprIK2rDN5rxhIEE56cmQhLjuJJm6hlRVpcBi88hDVSv2l/zTTz/NH3/8wU8//cSCBQtYtmwZGzZscO0fPXo0aWlpfPPNN2zevJm77rqL3r17s2fPHlebgoIC3njjDb744gu2bdt2QU/RXXfdRVZWFkuXLnVty87OJjU1laFDhwKQl5dHnz59WLx4MRs3bqR3797069ePw4edt2DPmTOHevXq8dJLL3HixAlOnDhxwXNp2rQpCQkJzJw50237zJkzueeeewDIycnh5ptvpn379qxbt47U1FQyMzO5++67K/S6icrlWzLxvEhVsDqctdpk8nnV5qU/gkaTj0P14c8i51I/CUo5K7MKUUNI0c5rqNBqp+XE3z1y7e0vpeDjVb5fb15eHv/5z3/4+uuv6dWrFwAzZsygXr16ABw+fJgvv/ySw4cPEx3tfLMcN24cqampfPnll7z22msAWK1WPv74Y9q1a1fmdYKDg7ntttuYNWuW6zrff/89oaGh9OzZE4B27dq5Hf/yyy/z448/8vPPPzN69GhCQkLQarX4+/sTGRl50ec0dOhQPvzwQ15++WXA2Vu1fv16vv76awA+/PBD2rdv74odYNq0acTExLB7926aNm1artdOVC6fkvlSeQ4doKBgR1HkVvuqTFFUjIYd5BcksDy3I//0P1CytIwDhyJ/r4vaQf6lC/bt24fFYiExMdG1LSQkhGbNmgGwZcsW7HY7TZs2xc/Pz/X4448/2Ldvn+sYLy8v2rZte8lrDR06lB9++IHiYueE4pkzZzJ48GDX0jt5eXmMGzeOFi1aEBQUhJ+fHzt27HD1TJXX4MGDOXjwIH/++afrOh06dKB58+YA/PXXXyxdutTt+ZTuO/c5ievrbH0pZ6+UIhPPqwWj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0Wg0pKenV+QpABAfH09UVBS33HILq1atumTb4uJizGaz26M2WLNmDZs2baJVq1YUF5+dx7Jo0SJ69epF3bp18ff35x//+AdZWVnlnqQeEhLCfffdR0pKCv369eP9999369kZO3YsDzzwAMnJyfz73/9m3759Fz1XXl4e48aNo0WLFgQFBeHn58eOHTsu6Jlq27at63tFUYiMjLxoT6q4Pkqrnuc5SksiWFAUWXKkpimthr7MfAMA7bQF6GVpGVEDVahn6vTp09jtdiIiIty2R0REsHPnzjKPycjIKLN96Tyl0q+Xa3P+UJxOpyMkJKRC852ioqKYOnUqCQkJFBcX88UXX3DTTTeRnp5Ohw4dyjzm9ddf58UXXyz3NdxofZw9RJ6g9SlXs8aNG6MoygXDXg0bNgRwm/B98OBBbr/9dh5++GFeffVVQkJCWLlyJSNHjsRiseDj44NGo0E9b4jRarW6/fzll1/y+OOPk5qayuzZs3nuuedYuHAhXbp04YUXXuCee+5h/vz5/Pbbb0yaNIlvvvmGO+6444LYx40bx8KFC3n77bdp3LgxRqORv//971gs7uu6nT9MqCgKDoejXK+PqHwKKsaSxY3NUhKhRjMatpNj7sMW842cckwlTGOnLTLUJ2qeWnU3X7NmzdyGdrp27cq+fft47733+O9//1vmMRMmTGDs2LGun81mMzExMeW7oKKUa6jNk+rUqcMtt9zChx9+yGOPPXbReVMA69evx+Fw8M4776DRODs1v/32W7c2YWFhZGRkoKqqax7Upk2bLjhX+/btad++PRMmTCApKYlZs2bRpUsXAJo2bUrTpk158sknGTJkCF9++WWZydSqVau47777XPvy8vI4ePDglbwMFebl5YXdLn9hXwkf7GgAC1BkLy2JIMlUTeTtdQiNJh+Hw5e0ojD+5pNBIrK0jKh5KjTMFxoailarJTPTvfhaZmbmReeOREZGXrJ96dfLtTl/WMZms5GdnX3Vc1Y6d+7M3r17L7rf29ubgIAAt0dN8/HHH2Oz2UhISGD27Nns2LGDXbt28fXXX7Nz5060Wi3g7MWyWq188MEH7N+/n//+979MnTrV7Vw33XQTp06d4s0332Tfvn189NFH/Pbbb679Bw4cYMKECaSlpXHo0CEWLFjAnj17aNGiBYWFhYwePZply5Zx6NAhVq1axdq1a93m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" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "execution_count": 63 - }, - { - "metadata": {}, - "cell_type": "code", - "source": "fit_knife_edge(x_data, motor='X')", - "id": "41b7430b4ce4727", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "**Knife edge scan in Y**", - "id": "f6c950fbb9299d42" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2025-07-09T18:01:19.109015Z", - "start_time": "2025-07-09T18:00:32.468027Z" - } - }, - "cell_type": "code", - "source": [ - "steps_y = 40\n", - "start_pos_y = -0.20\n", - "step_size_y = 0.002\n", - "offset_y = 0.00\n", - "sleep = 1.0 # wait after move before recording diode\n", - "y_data=knife_edge(motor='Y', dev=d, beamline=beamline, steps=steps_y, start=start_pos_y, step_size=step_size_y, offset=offset_y, sleep=sleep)\n", - "fit_knife_edge(y_data, motor='Y')" - ], - "id": "f8e0541c9e92e4e6", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-0.200 2.360645e-08\n", - "-0.198 2.811506e-08\n", - "-0.196 2.810113e-08\n", - "-0.194 3.39931e-08\n", - "-0.192 4.061688e-08\n", - "-0.190 6.625245e-08\n", - "-0.188 8.658314e-08\n", - "-0.186 1.106975e-07\n", - "-0.184 1.428539e-07\n", - "-0.182 1.863939e-07\n", - "-0.180 1.863939e-07\n", - "-0.178 2.407869e-07\n", - "-0.176 2.862987e-07\n", - "-0.174 3.589597e-07\n", - "-0.172 4.629766e-07\n", - "-0.170 7.34634e-07\n", - "-0.168 9.591903e-07\n", - "-0.166 1.226978e-06\n", - "-0.164 1.638941e-06\n", - "-0.162 2.070232e-06\n", - "-0.160 2.070232e-06\n", - "-0.158 2.719557e-06\n", - "-0.156 3.40311e-06\n", - "-0.154 4.3336e-06\n", - "-0.152 5.30817e-06\n", - "-0.150 7.05408e-06\n", - "-0.148 7.882228e-06\n", - "-0.146 8.391648e-06\n", - "-0.144 8.645698e-06\n", - "-0.142 8.800723e-06\n", - "-0.140 8.833474e-06\n", - "-0.138 8.667967e-06\n", - "-0.136 8.724034e-06\n", - "-0.134 8.751249e-06\n", - "-0.132 8.949502e-06\n", - "-0.130 8.983748e-06\n", - "-0.128 8.932714e-06\n", - "-0.126 8.97258e-06\n", - "-0.124 8.960077e-06\n", - "-0.122 9.000123e-06\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjQAAAHACAYAAAC1YPKRAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAZLhJREFUeJzt3Xd8FHX+x/HXbHpPSCEEAgmd0HuzgKKg6Omd4qmIiuXUw+5Z7/ROPcVyWH7oqXieYEEsWFFBaQJKCb2HlkBIISG9l935/ZHLSqRlYTebDe+n7mOz3/3OzPubkOSTme/MGKZpmoiIiIh4MIu7A4iIiIicLhU0IiIi4vFU0IiIiIjHU0EjIiIiHk8FjYiIiHg8FTQiIiLi8VTQiIiIiMdTQSMiIiIeTwWNiIiIeDwVNCIiIuLxWkxBs2zZMi699FLi4uIwDIMvv/zS5dvMyMjguuuuIzIykoCAAHr37s3atWtdvl0RERFpqMUUNGVlZfTt25fXX3+9SbZXUFDAyJEj8fHx4fvvv2f79u1MmzaNiIiIJtm+iIiI/MpoiTenNAyDL774gssvv9zeVlVVxV//+lc++ugjCgsL6dWrF88//zyjRo06pW088sgj/Pzzzyxfvtw5oUVEROSUtZg9NCdz5513snLlSubMmcPmzZuZMGEC48aNY/fu3ae0vq+//ppBgwYxYcIEYmJi6N+/P2+//baTU4uIiEhjnBF7aA4cOEDHjh05cOAAcXFx9n5jxoxhyJAhPPvssw5vw9/fH4D777+fCRMmkJyczD333MObb77JDTfc4JRxiIiISON4uztAU9iyZQtWq5WuXbs2aK+qqiIyMhKAnTt30qNHjxOu5+GHH+a5554DwGazMWjQIHsx1L9/f7Zu3aqCRkRExA3OiIKmtLQULy8v1q1bh5eXV4P3goODAejYsSM7duw44Xrqix+ANm3akJSU1OD9Hj16MHfuXCelFhERkcY6Iwqa/v37Y7VaycnJ4eyzzz5mH19fX7p3797odY4cOZKUlJQGbbt27aJDhw6nlVVEREQc12IKmtLSUvbs2WN/nZqaysaNG2nVqhVdu3Zl4sSJXH/99UybNo3+/fuTm5vLokWL6NOnD+PHj3d4e/fddx8jRozg2Wef5aqrrmLNmjXMmDGDGTNmOHNYIiIi0ggtZlLw0qVLGT169FHtN9xwAzNnzqSmpoZ//vOfvPfee2RkZBAVFcWwYcN48skn6d279yltc968eTz66KPs3r2bxMRE7r//fm699dbTHYqIiIg4qMUUNCIiInLmOmOuQyMiIiItlwoaERER8XgePSnYZrORmZlJSEgIhmG4O46IiIg0gmmalJSUEBcXh8XinH0rHl3QZGZmEh8f7+4YIiIicgrS09Np166dU9bl0QVNSEgIUPcJCQ0NdXMaERERaYzi4mLi4+Ptv8edwaMLmvrDTKGhoSpoREREPIwzp4toUrCIiIh4PBU0IiIi4vFU0IiIiIjHU0EjIiIiHk8FjYiIiHg8FTQiIiLi8VTQiIiIiMdTQSMiIiIeTwWNiIiIeDwVNCIiIuLxVNCIiIiIx1NBIyIiIh7Po29OKSIiIo4xTRObaat7YMNqs2IzbVhN66/tR7z29/anlX8rd8c+KRU0IiIiLma1WSmrLaOytpKK2gr7c/3D3m799f1qWzU11hqqrdV1H9vqPq6x1lBtq677+H9tVtOK1Wal1qyl1lb3sJrWuucj2uuLFEdcnHgxz5/zvIs+M86jgkZERKSRamw15FXkkVueS0FVAUVVRZRUl1BcXXzs56q655KaEndHd4jFsGAxLHgZXnhbPKNU8IyUIiIiLmSaJgVVBWSVZpFTnkNuRa79Obc81/66oLIAE/OUt+NleBHgHYC/t3+D5wCvgAav/bz88PXyrXtYfPHx8sHH4mN/7ev1a5uPxQdvizc+Fh97AeJl8cLb8MbbUvewtxte9kLFYql7NjCoKi8l/2AqxYf2U314P7bCA/iUZBBcmUVBdQ2c5cRPtouooBERkTOG1WYlsyyT1KJUUotS2Ve0z/5cVFXUqHV4W7yJDogmwj+CIEsAflYLvjUmflW1+FdXElRZQWhVKa2qS2hdU0S8tYgIWy3BNhtW05eD3u0pDG6PNbo7gW1707pLf2LiEjEsJz5Px2a1kpuVxuEDKZQd2oP18D58ig/gX52H1eKL1SsAq3cgNd4B2HwCwScIwzcQwzcQi28QXv5BGIZBVV46FKXjW5pBSGUWUdZDRFBCxHG2u+Hw8d5pXlTQiIhIi2MzbaQWpbK7cDephb8WLmnFaVRZq465jIFBdEA0MYExRAf+7zkgmujA6AbtZRlZ5H92L53LlxJkVDYyj0Et3gQY1XSx7oGiPVA0H/YAP0ExgWT4JFAc2gWie+AbEUdV3gGM/FT8y9KJqMog1nqI1kYtrZ34eTpSMYEctsRQ7N+GqsA4zPB4fCMTaJXQ20VbdC4VNCIi4vFM02Rf0T7WZK8hOTuZtdlrKagqOGZfX4svHcI6kBiaSMfwjnQM60hiWCIdQjsQ4B1w3G3YrFaSP32B3jteJt6oAqOuvZhACiyRFPtEUekfQ21QLJbQNvhEtCM4Op6wmHgiW8fjZVhIT9tB7t6NVGVuxTdvJ5Hle2lnzSDUKCe0ZjvkbYe8r44dwIAa04tDlhjy/eKoCIrHjEjAO7QNZm0V1qoyzOoyjJoKqCnHqC3Hq6YcL2sFXtZKfKwVWEwrZf4xVAe1hfD2+EclENqmE1HtOhMaHkno6X4h3EgFjYiIeBzTNEktTiU5K5nkQ8kkZyeTX5nfoE+AdwBdI7qSGJZIx7BfC5e2wW3xsng5tL2MfTsonHMrQ6u3gAHbfPvgN/452nTsSWhIeKMLgfjOvYnv3HCPR1VlOel7t5CXuomarG34F+wiqPowpf5tqArpgFdkIoGtO9EqvjsxbRNp5+NLO4fSnxlU0IiIiEfYX7y/bg/M/4qYwxWHG7zv7+VPv5h+DI4dzJDYIfSM7ImPl89pbdNmtZL82Yv03v4SbY0qyk0/tiTdz+ArH8Ti5VhRdDx+/oEk9hxKYs+hTlnfmUoFjYiINAnTZqO4IJf8QwcoPXyQyvwMaouyMCoKCOlzCT1HXHzUMoWVhXyb+i1f7vmSnfk7G7zna/G1FzCDYwfTO6o3vl6+TsubmbqTgo9uZWj15v/tlelN+NVvM7RjD6dtQ5xHBY2IiDhNQW4We37+HGthBkZpNj4VOQRWHSas9jCtzELCjBrCjrVg9ockrx5H5+teISQyml8yf+HLPV+yJH0JtbZaoO7son7RvxYwfaL74Ofl5/Qx1O2V+Re9t08jrn6vTI/7GDzhIaftlRHnU0EjIiKnLfvAbtK+eZ6+OV8x2Kg+dqf/TaItJJgCSySlPpFU+sdg2GoYULyY6LKFvDX7bL6NiKTQLLcv1qNVDy7vfDnjO44nzO+Y5ZDTZKalUDD7VoZWbwIDtvv2JuzqtxjasadLtyunTwWNiIicsv071pEz/wX6Ff5IrGEFA/Z6JZIf0p3aoNZYQmLxjYgjoFVbQqPjadW6HeEBQYT/b/kaWw3z9s7juQ21pFSk1jWa5YRYDc5rdyGTBt1Kt1bdnJrZZrVSXJBL0eFMygoOUVl0iJriXGyFB+ib8TFxRhUVpi+but/LkKse0V4ZD6GCRkREHJaydjHli1+kf/kvdAAwYKtfP8yR99PrrEvpdJKLxJmmybKDy/jX2n+RVpwG1F1uv6cZzcRDO7mwvARz/7usO2ih6tp/4Ocf2Khc1tpaMlO3cXjfRiqzdmApPYRPZR5+1QUE1RYSYisizCwh3LDZi6oGDNju04vQP77FsM69HPiMiLsZpmme+jWc3ay4uJiwsDCKiooIDfXks+dFRJo/02Zj6/Ivsfz8Mj2rNwN1F4zbGHwWwef/ha4DRjVqPbsKdvFi8ousyloFQCv/VkxKmsTvOv2OmMAYMvbtIO+TO+lTuRaA/ZZ2lF04jaRh4+zrsFmtZB/YTc7eDVRkbMUnbycRZftoV5uOn1HTqBzFBFJkhFPmHU6FTzg1fq0w4ocw8LI7tVfGxVzx+1sFjYiInJC1tpaNP7xP2LrpdLbuBeou8LYhYiytxz1Ih+4DGrWevIo8Xt/4OnN3z8Vm2vCx+DApaRK39r6VYN/gBn1Nm411379DYvLTRFJ3S4K1oWOwWXwJL91Du5r9BBrHvuJvhf32Ap2oDY7DCI7GOyQav9DWBEa0JjQylrDIWHz9/E/jsyKnQwXNb6igERFxrQ0LZhG16jnizUwAyk0/Nre+nIRLHyI2vnOj1lFtrebDHR8yY/MMSmtKAbigwwXcN/A+4kPiT7hsUX4uKR/cx5D8b45er+nNQa925Ad1ojayO35xScR07k9s+254eWtGRXOmguY3VNCIiLiGabOxaubDDD8wA6g7M2lH+2vp8bsHCI+Kbdw6TJNFBxYxbe00DpYeBOrOWHp4yMMMbD3QoTw7Vi+geM1sbEEx+LVJIrJjf9p2TMLbx3nXnZGm44rf3yphRUSkgarKcrb8+3qGF/8IwKrW19D7uucYHhLe6HXsyNvBC8kvsPZQ3TyY6IBo7hlwD5d2uhSLceIJw8fSY+hYGDrW4eXkzKGCRkRE7AoPZ5P51hUMqtlKrWlhfe/HGXbl/Y1evqCygJfXvcyXe77ExMTPy48be97ITb1uItCncWcqiZwKFTQiIgJA+p4t8OFVJJmZlJgBpJ3/FkPOuazRy6cWpXLHwjvIKM0A4OLEi7l3wL20CW7jqsgidipoRESE7Su/J27BLYRTShbRVF09h949BjV6+bXZa7lnyT0UVxfTLrgdU8+eSr+Yfq4LLPIbKmhERM5wa79+gz7r/oqvYSXFuxuRt8ylTeyJzz460nf7vuNvP/+NGlsNfaL7MP286bTyb+XCxCJHU0EjInKGMm02Vr37EMPT3wYD1gefQ9KfP8I/MPjkC1N3FtM7W9/h1fWvAjCm/Rimnj0Vf29d30WangoaEZEzUN2ZTJMYXrwQgJVx1zP05lcafYXcGlsNz6x6hrm75wJwfdL1PDDogVM6g0nEGVTQiIicYQpys8iecQWDarbVXfG3zxMMv+LeRi9fWl3KX376Cz9n/ozFsPDw4Ie5tse1rgss0ggqaEREziC1NdXkvTmeHta9FBPIgTFvMuTsxp/JlF2WzZRFU9hVsIsA7wBeOOcFRsWPcl1gkUZSQSMicgZZ9/nLDLXupYggCv/4Db16NP6KvSn5Kfx50Z/JKc8h0j+S189/nZ5RPV2YVqTxdLBTROQMUXg4m+476ibw7uxxDx0cKGZ+zviZ67+/npzyHDqGdeTD8R+qmJFmRQWNiMgZImXOo4RRRqolgYF/uK/Ry3226zOmLJpCeW05Q2KH8P7F79M2uK0Lk4o4ToecRETOAPu2rmZQ7hdgQPn5zzb6po5vbnqT1ze+DsClHS/lyRFP4uPl48qoIqdEBY2ISAtn2mxUfP0XvAyT9cHnMGDk+EYtNz91vr2Yub3v7fy5758xDMOVUUVOmQ45iYi0cBsWzKJn9WYqTR/aTPhXo5bZVbCLJ355AoDJvSYzpd8UFTPSrKmgERFpwSrLS2mz+hkANrS/gTYdup10maKqIu5dci8VtRUMazOMu/vf7eqYIqdNBY2ISAu2Yc5TtCGXbKLod/U/TtrfZtp4dPmjpJekExcUx4vnvIi3RbMTpPlTQSMi0kJlH9hNv/3vApAx5DECgkJOusy/N/6b5RnL8fPy45XRrxDuH+7ilCLOoYJGRKSFyvj0QQKMarb59mbAuMkn7b/4wGLe2vwWAH8f/nd6RPZwdUQRp3FrQWO1Wnn88cdJTEwkICCATp068fTTT2OapjtjiYh4vO0rv2dgyRKspoH/pf/CsJz4x31qUSqPrXgMgGu7X8ulnS5tipgiTuPWA6PPP/88b7zxBrNmzaJnz56sXbuWyZMnExYWxt13axKaiMipsNbW4rfwUQDWRl3G0N7DTti/rKaMe5fcS1lNGQNiBvCXwX9pipgiTuXWguaXX37hsssuY/z4umsiJCQk8NFHH7FmzRp3xhIR8WhrP3+ZodZUigmi69XPnbCvaZr8bcXf2Fe0j5iAGKaNmoaPRRfOE8/j1kNOI0aMYNGiRezatQuATZs2sWLFCi666KJj9q+qqqK4uLjBQ0REflWUn0vX7XX3a9re7U4iotucsP87W99h4YGFeFu8eWn0S0QFRDVFTBGnc+semkceeYTi4mK6d++Ol5cXVquVZ555hokTJx6z/9SpU3nyySebOKWIiOfY+dEjDKWENEt7Bl154kNHv2T8wvQN0wF4bOhj9I3u2xQRRVzCrXtoPvnkEz788ENmz57N+vXrmTVrFv/617+YNWvWMfs/+uijFBUV2R/p6elNnFhEpPlK3Z7MwJzPASgd/c8T3q/pYMlBHlz2IDbTxhVdrmBC1wlNFVPEJdy6h+bBBx/kkUce4eqrrwagd+/e7N+/n6lTp3LDDTcc1d/Pzw8/P7+mjiki0uyZNhtlX/0Fb8PGhqCz6H/2ZcftW1Fbwb1L7qW4upjeUb15bOhjTZhUxDXcuoemvLwcy29OJfTy8sJms7kpkYiIZ9rw44f0qtpIlelD6yunnbDvM6ueIaUghVb+rXhp1Ev4ejXuztsizZlb99BceumlPPPMM7Rv356ePXuyYcMGXnrpJW666SZ3xhIR8SimzUb0qmcBWN/uOoYndj9u37XZa/lq71dYDAv/OvdfxAbFNlVMEZdya0Ezffp0Hn/8cf785z+Tk5NDXFwct912G0888YQ7Y4mIeJSU5IV0NzMpM/3pc4L7NVltVp5Pfh6AK7tcyeDYwU2UUMT13FrQhISE8Morr/DKK6+4M4aIiEcrWvMhANvDRzE4JPy4/b7Y8wU783cS4hvClP5TmiidSNPQvZxERDxYdVUl3fIWAuA/8Nrj9iuuLrafov3nvn+mlX+rJskn0lRU0IiIeLDtyz4nnFJyiSBpxPjj9ntr01vkV+aTGJbIH7v/sQkTijQNFTQiIh7MtmkOAHtbj8PL+9izCFKLUpm9YzYADw1+SLc2kBZJBY2IiIcqLsyjZ8kvAESNmHTcfv9a+y9qzVrOaXcOZ7U9q6niiTQpFTQiIh5q55IP8TNqSLPE06n38GP2WX5wOcsOLsPb8ObBQQ82cUKRpqOCRkTEQwXunAtAdvvfYViO/nFeY6vhheQXAJjYYyIJYQlNGU+kSamgERHxQIcO7iWpchMA7UcdfasYgDk755BWnEYr/1bc1ve2pown0uRU0IiIeKDUJbOwGCbbfXoRl9DtqPfzK/N5Y+MbANzd/25CfEOaOqJIk1JBIyLigaLTvgagpOvvj/n+axteo6SmhB6tenB558ubMJmIe6igERHxMKnbVtPJmkq16UX3844+u2ln/k4+2/UZAA8PeRgvi1dTRxRpcipoREQ8TPaKDwDYFjSMsMjWDd4zTZPn1zyPicnYhLEMbD3QHRFFmpwKGhERD2KzWknM+g4As89VR72/8MBC1h5ai5+XH/cPvL+p44m4jQoaEREPsmP1AmI5TDGBJJ07ocF7lbWVTFs7DYDJvSYTFxznjogibqGCRkTEg5Ql191Ze2fEaPwDghq8997298gozaB1YGsm95zsjngibqOCRkTEQ1RWlNG9YDEAQYMmNnjvUNkh/rPlPwDcP/B+An0CmzyfiDupoBER8RA7ln1GKOUcIpIew8Y1eO/V9a9SUVtB/5j+XJR4kZsSiriPChoREU+x+RMA9rW5CIvXr6dip5ekM2/fPAAeHvwwhmG4JZ6IO6mgERHxAEX5ufQsXQVA7FnXN3hv9o7ZmJiMjBtJz6ie7ogn4nYqaEREPEDK4vfxNWrZZ0kgsedQe3tJdQmf7/4cgOuTrj/e4iItngoaEREPELyrrmjJSfhdg/bPd39OeW05ncM7MzxuuDuiiTQLKmhERJq5rP0pJFVvwWYaJIz+9c7atbZaPtxRdxr3dT2u09wZOaOpoBERaebSls4CYIdfH2LjO9vbFx5YSFZZFq38WzG+43h3xRNpFlTQiIg0Y6bNRpv9dXfWLu9+RYP33t/+PgBXdbsKf2//Js8m0pyooBERacb2bV1Fgi2dKtOHbuddZ2/fmLORzbmb8bH48Mduf3RjQpHmQQWNiEgzlvvzewBsCxlOaHikvb1+78z4juOJCohySzaR5kQFjYhIM2WtraXjoQUAGH1+3QuTUZrBwgMLAZiUNMkt2USaGxU0IiLN1I6V3xJDPoUE0/PcK+3ts3fMxmbaGNpmKF0juroxoUjzoYJGRKSZqlj3EQApkefj61c36bespkwX0hM5BhU0IiLNkM1qpVvhMgBCBl9rb/9i9xeU1pSSEJrAWW3Pclc8kWZHBY2ISDOUtX8noZRRZfrQdeB5AFhtVj7Y8QFQN3fGYuhHuEg9fTeIiDRDh1LWAHDAJwFvH18AlqQvIaM0gzC/MC7tdKk744k0OypoRESaoaqDmwAoCOlmb7NfSK/rVQR4B7gll0hzpYJGRKQZCszfDoAZ2weArYe3sj5nPd4Wb67ufrU7o4k0SypoRESaoTYVuwEISxwAwHvb6y6wd1HCRcQExrgtl0hzpYJGRKSZyTt0kBjysZkG8T0Gk12WzY9pPwK6kJ7I8aigERFpZjJTkgHIsLQhKCSc2TtnU2vWMqj1IHpE9nBzOpHmSQWNiEgzU5a2HoCcoK6U15Tz2a7PAF1IT+REVNCIiDQz3rnbAKiO7smXe76kpLqE9iHtOTf+XDcnE2m+VNCIiDQz0WW7AAiI78+HOz4EYGKPibqQnsgJ6LtDRKQZqSgroZ31IAD7o0wOlBwgxDeEyztf7t5gIs2cChoRkWbkwI5kvAyTw4TzVdZ8AK7seiWBPoFuTibSvKmgERFpRgpT6yYEbwhKJDk7GYth4dru155kKRFRQSMi0pxkbwZgaasQAIbGDiU2KNadiUQ8ggoaEZFmJLxoJyawxq8QgEs6XeLWPCKeQgWNiEgzYa2tpX1NKtt8fcm2FuLv5c/57c93dywRj6CCRkSkmTi4ZzMBRjVfBIcCMLr9aIJ8gtycSsQzqKAREWkmcvespQaYH1x3RtMlHXW4SaSxVNCIiDQTNRmbWBXgT7EXtPJvxfC44e6OJOIxVNCIiDQTwfnbmRdcd4hpXMI4fCw+bk4k4jlU0IiINAOmzUZE9R4WBwYAOtwk4igVNCIizcDh7ANsCKql0mKhfXA8vaJ6uTuSiEdRQSMi0gxk7lzFvKC6w02XdL4UwzDcnEjEs6igERFpBjIPrGJVgD8AlyTqcJOIo1TQiIg0AxvK1mMzDDrRivjQeHfHEfE4KmhERJqBZJ88AM6JHOnmJCKeSQWNiIibbU5fzx4/C96myR8G3ODuOCIeSQWNiIibfbbpPQAGlVtJiOvm5jQinkkFjYiIG9lMG8vyVgEwqCbazWlEPJcKGhERN9qQs4E8ygiy2egR1N/dcUQ8lgoaERE3mrdvHgAXlJUTHD/IzWlEPJcKGhERN6m2VrMgdQEAl5SWEdt1sJsTiXgub3cHEBE5Uy0/uJySmhJiamvpWulFeIeu7o4k4rG0h0ZExE3qDzeNLy0n07cThkU/kkVOlcN7aFJTU1m+fDn79++nvLyc6Oho+vfvz/Dhw/H393c4QEZGBg8//DDff/895eXldO7cmXfffZdBg3QsWURarqKqIn46+BMA40vLKIjo4eZEIp6t0QXNhx9+yKuvvsratWtp3bo1cXFxBAQEkJ+fz969e/H392fixIk8/PDDdOjQoVHrLCgoYOTIkYwePZrvv/+e6Ohodu/eTURExCkPSETEE/y4/0dqbDW0r7HQraaGNW36uDuSiEdrVEHTv39/fH19ufHGG5k7dy7x8Q3vM1JVVcXKlSuZM2cOgwYN4t///jcTJkw46Xqff/554uPjeffdd+1tiYmJDg5BRMTz1B9uuqSkBIDIzpoQLHI6DNM0zZN1WrBgAWPHjm3UCvPy8khLS2PgwIEn7ZuUlMTYsWM5ePAgP/30E23btuXPf/4zt956a6O2VVxcTFhYGEVFRYSGhjZqGRERd8sszWTs3LEYGPxw4CCtaoHHMvH1c/ywvYgncsXv70bNQGtsMQMQGRnZqGIGYN++fbzxxht06dKFBQsWcMcdd3D33Xcza9asY/avqqqiuLi4wUNExNN8l/odAN1944m1Wkn37qBiRuQ0OTylfv369WzZssX++quvvuLyyy/nscceo7q62qF12Ww2BgwYwLPPPkv//v3505/+xK233sqbb755zP5Tp04lLCzM/vjtoS8RkebONE3m7a073DS4IgSAvJDu7owk0iI4XNDcdttt7Nq1C6jbw3L11VcTGBjIp59+ykMPPeTQutq0aUNSUlKDth49enDgwIFj9n/00UcpKiqyP9LT0x2NLyLiVikFKewt2ouvxZfheQUA2Fr3cnMqEc/ncEGza9cu+vXrB8Cnn37KOeecw+zZs5k5cyZz5851aF0jR44kJSXlqPUf7ywpPz8/QkNDGzxERDxJ/d6Zc+PPpXPZXgBCEwa4M5JIi+BwQWOaJjabDYCFCxdy8cUXAxAfH8/hw4cdWtd9993HqlWrePbZZ9mzZw+zZ89mxowZTJkyxdFYIiLNntVmtc+fOS/6LGLJBaBdjyHujCXSIjhc0AwaNIh//vOfvP/++/z000+MHz8eqLvgXuvWrR1a1+DBg/niiy/46KOP6NWrF08//TSvvPIKEydOdDSWiEiztyZ7DbkVuYT5hdEuv64tw2hNaHike4OJtAAOXyn45Zdf5rrrruPLL7/kr3/9K507dwbgs88+Y8SIEQ4HuOSSS7jkkkscXk5ExNPUX3tmbIexVO6rO7niUGBX2rozlEgL4XBB07dv3wZnOdV78cUX8fbWvS5FRI6loraChfsXAnBJp0uoXfUsAFVRPd0ZS6TFcPiQU8eOHcnLyzuqvbKykq5ddadYEZFjWZGxgvLactoGt6VfdD+iSupOiAho39/NyURaBocLmrS0NKxW61HtVVVVHDx40CmhRERamkUHFgEwpv0YqirLibfWXXaiTTfd8kDEGRp9jOjrr7+2f7xgwQLCwsLsr61WK4sWLdJ9mEREjqHGWsOy9GUAnN/hfNJT1tPFsFFAKDFx+rkp4gyNLmguv/xyAAzD4IYbbmjwno+PDwkJCUybNs2p4UREWoI12WsoqSkhKiCKvtF9Wbv8VQAO+nUiwuLwjnIROYZGFzT1155JTEwkOTmZqKgol4USEWlJFh6omwx8Xvx5WAwLZtZmAMoikk60mIg4wOHTklJTU12RQ0SkRbLarCw5sASA89ufD0Bo0U4AvNv2dVsukZbmlM6zXrRoEYsWLSInJ8e+56bef//7X6cEExFpCTblbiKvMo8Q3xAGxw7GZrXSvnofGBDdeZC744m0GA4XNE8++SRPPfUUgwYNok2bNhiG4YpcIiItQv3ZTee2OxcfLx/S92wh3qik0vShbefebk4n0nI4XNC8+eabzJw5k0mTJrkij4hIi2GaZoPTtQFydq0lHjjgk0hXH183phNpWRyeXl9dXX1KtzgQETnTpBSkkFGagb+XPyPa1v3crD64AYCC0O7ujCbS4jhc0Nxyyy3Mnj3bFVlERFqU+lsdjGw7kgDvAAAC87fXvRmrw00izuTwIafKykpmzJjBwoUL6dOnDz4+Pg3ef+mll5wWTkTEk9Ufbqo/uwkgrnIPAGEdB7olk0hL5XBBs3nzZvr16wfA1q1bG7ynCcIiInX2F+9nT+EevA1vzml3DgCHs9OJpgCbadC+u85wEnEmhwuaJUuWuCKHiEiLUr93ZnDsYML86m4Vk7lzDVHAQa842geHnWBpEXGUrrktIuICi/b/7+ymDmPsbWUHNgKQG9TNHZFEWjSH99CMHj36hIeWFi9efFqBREQ83aGyQ2w+vBkDg9Hxo+3tvrlbAKiO7uWuaCItlsMFTf38mXo1NTVs3LiRrVu3HnXTShGRM9Hi9Lo/7PpG9yU6MNreHl22C4Cg9v3cEUukRXO4oHn55ZeP2f6Pf/yD0tLS0w4kIuLpjnV2U3lpEe2smWBAXPch7oom0mI5bQ7Nddddp/s4icgZr7CykLXZa4GGBc2+TcuwGCa5RBAVG++ueCItltMKmpUrV+Lv7++s1YmIeKSfDv6E1bTSNaIr8aG/Fi6lm+cBkBY+zF3RRFo0hw85/eEPf2jw2jRNsrKyWLt2LY8//rjTgomIeKKFB+quDlx/7yYA02ajXc5SALx6jHdHLJEWz+GCJiys4bUTLBYL3bp146mnnuLCCy90WjAREU9TXlPOysyVAJzf4dfDTQdSNtDBzKbK9KHbiEvdFU+kRXO4oHn33XddkUNExOOtyFhBlbWK+JB4uoR3sbdnrvmcDsDOwP70DQl3Wz6RlszhgqbeunXr2LFjBwA9e/akf//+TgslIuKJ6s9uGtN+TIPrdUWk17VXdhzrllwiZwKHC5qcnByuvvpqli5dSnh4OACFhYWMHj2aOXPmEB0dfeIViIi0QNXWapYdXAbAee3Ps7cfzk6na81OMCBxxBXuiifS4jl8ltNdd91FSUkJ27ZtIz8/n/z8fLZu3UpxcTF33323KzKKiDR7q7NWU1pTSnRANH2i+9jbU3/5HIthstu7CzFtE92YUKRlc3gPzfz581m4cCE9evSwtyUlJfH6669rUrCInLHqDzed1/48LMavfyt675kPwOG259PlmEuKiDM4vIfGZrPh4+NzVLuPjw82m80poUREPInVZmVJ+hKg4cX0KstL6Va2DoCYgZe5JZvImcLhgua8887jnnvuITMz096WkZHBfffdx/nnn3+CJUVEWqaNuRvJr8wn1DeUQbGD7O0pq+YRaFSRTRQde+mCeiKu5HBB89prr1FcXExCQgKdOnWiU6dOJCYmUlxczPTp012RUUSkWVu4v+5ieqPiR+Fj+XUPduXWbwHYH3UOhsVpF2YXkWNweA5NfHw869evZ+HChezcuROAHj16MGbMmJMsKSLS8pimyeIDdXfXPvLsJpvVSsf85QAE9tbF9ERc7ZSuQ2MYBhdccAEXXHCBs/OIiHiUHfk7yCzLJMA7gBFxI+ztezatoCsFlJoBdB06zo0JRc4MDu8Dvfvuu/m///u/o9pfe+017r33XmdkEhHxGPVnN42MG0mAd4C9PW/9lwDsChmCn3+gO6KJnFEcLmjmzp3LyJEjj2ofMWIEn332mVNCiYh4ikX76wqaI+/dBNA6s+4wlK3rRU2eSeRM5HBBk5eXd9QNKgFCQ0M5fPiwU0KJiHiCtKI09hbtxdvw5px259jbM9NS6GhLo9a00GXkH9yYUOTM4XBB07lzZ+bPn39U+/fff0/Hjh2dEkpExBMsTq/bCzOkzRBCfUPt7QdWzgUgxa8nYZGt3ZJN5Ezj8KTg+++/nzvvvJPc3FzOO69uRv+iRYuYNm0ar7zyirPziYg0W/VnNx15MT2AoLQfACjpoBMnRJqKwwXNTTfdRFVVFc888wxPP/00AAkJCbzxxhtcf/31Tg8oItIc5Zbnsjl3M1B3/Zl6xYV5dK/cDAa0HarDTSJN5ZRO277jjju44447yM3NJSAggODgYGfnEhFp1pYeXIqJSZ+oPsQExtjbd//8BQMNK/st8XTo3NuNCUXOLKdU0NSLjo52Vg4REY9Sf7hpdPvRDdrNlO8ByGw9mg5NnkrkzNWoScHjxo1j1apVJ+1XUlLC888/z+uvv37awUREmqvS6lJWZ60G4Lz4X68OXFNdRdfilQBE9P+dW7KJnKkatYdmwoQJXHHFFYSFhXHppZcyaNAg4uLi8Pf3p6CggO3bt7NixQq+++47xo8fz4svvujq3CIibrMicwU1thoSQhNIDEu0t6ck/0AvysgnlC4DRp9gDSLibI0qaG6++Wauu+46Pv30Uz7++GNmzJhBUVERUHcbhKSkJMaOHUtycjI9evRwaWAREXc78nCTYRj29tJN3wCwJ/wshnif1hF9EXFQo7/j/Pz8uO6667juuusAKCoqoqKigsjISHx8fE6ytIhIy1BjrWH5wbqbTh55uMm02WiX+xMAPknj3ZJN5Ex2yn9ChIWFHfOKwSIiLVlydjKlNaVE+kfSJ7qPvf1AygY6mNlUmT50G6G7a4s0NYevFCwiciarvzrw6PajsRi//gjNXPM5ADsD+xMYrD/2RJqaChoRkUaymTaWpC8BGh5uAohIr7tJZWXHsU2eS0RU0IiINNr2vO3klOcQ6B3I0DZD7e2Hs9PpWrMTgMQRV7grnsgZTQWNiEgj1Z/ddHa7s/H18rW3p/7yORbDZLd3F2LaJh5vcRFxIYcLmhtuuIFly5a5IouISLNWX9D89nCT9575ABxue/5Ry4hI03C4oCkqKmLMmDF06dKFZ599loyMDFfkEhFpVtKK0thbtBdvizdntzvb3l5ZXkr3srUAxAz6vbviiZzxHC5ovvzySzIyMrjjjjv4+OOPSUhI4KKLLuKzzz6jpqbGFRlFRNyufjLwkNghhPiG2Nt3rpxHgFFNNtF07DnEXfFEzninNIcmOjqa+++/n02bNrF69Wo6d+7MpEmTiIuL47777mP37t3Oziki4lbHO9xUvW0eAPujzsGwaFqiiLuc1ndfVlYWP/74Iz/++CNeXl5cfPHFbNmyhaSkJF5++WVnZRQRcavDFYfZlLsJgFHxo+ztNquVjvl1Vw0O7KOL6Ym4k8MFTU1NDXPnzuWSSy6hQ4cOfPrpp9x7771kZmYya9YsFi5cyCeffMJTTz3lirwiIk1uafpSTEx6R/WmdVBre/uuDUuJopBSM4BuQy9yX0ARcfzWB23atMFms3HNNdewZs0a+vXrd1Sf0aNHEx4e7oR4IiLuZ78ZZXzDO2gXrZ4NwM6wkQzy82/yXCLyK4cLmpdffpkJEybg73/8b97w8HBSU1NPK5iISHNQVlPGqqxVAJzX/tf5M7U11XTO/REAn/5XuyWbiPzK4UNOS5YsOebZTGVlZdx0001OCSUi0lysyFhBja2GDqEd6BjW0d6+fcXXRFJEPqEkjfydGxOKCJxCQTNr1iwqKiqOaq+oqOC9995zSigRkebiyLObDMOwt1dt/BiA3VFj8PH1c0s2EflVow85FRcXY5ompmlSUlLS4JCT1Wrlu+++IyYmxiUhRUTcocZaw/KDdWcxHXm4qaKshKTCZWBA2NCJ7oonIkdodEETHh6OYRgYhkHXrl2Pet8wDJ588kmnhhMRcafkQ8mU1JQQ6R9J76je9vZtS+cwyKgk02hNt4HnnWANItJUGl3QLFmyBNM0Oe+885g7dy6tWrWyv+fr60uHDh2Ii4tzSUgREXeoP9w0Kn4UXhYve7v3trkA7I+7mDhdTE+kWWh0QXPuuecCkJqaSvv27RscSxYRaWlsps1+u4MjDzcVHs6mZ9kaMCDu7OvdFU9EfqNRf1ps3rwZm80G1N2ccsuWLWzevPmYj1P13HPPYRgG99577ymvQ0TEWbbnbSenPIdA70CGthlqb09Z/D4+hpU9Xp3o0H2AGxOKyJEatYemX79+ZGdnExMTQ79+/TAMA9M0j+pnGAZWq9XhEMnJybz11lv06dPH4WVFRFyh/nDTWW3Pws/r17OYQnZ/CcDhxEvp7I5gInJMjSpoUlNTiY6Otn/sTKWlpUycOJG3336bf/7zn05dt4jIqTrW4aas/Skk1WzFZhp0HH2jm5KJyLE0qqDp0KHDMT92hilTpjB+/HjGjBlz0oKmqqqKqqoq++vi4mKnZhERAdhfvJ89hXvwNrw5u93Z9va0pe/RBtjh14eebRPdF1BEjnJKF9b79ttv7a8feughwsPDGTFiBPv373doXXPmzGH9+vVMnTq1Uf2nTp1KWFiY/REfH+/Q9kREGmPJgbq9M4NjBxPqG2pvj93/DQBl3X7vllwicnwOFzTPPvssAQEBAKxcuZLXXnuNF154gaioKO67775Gryc9PZ177rmHDz/88IT3hTrSo48+SlFRkf2Rnp7uaHwRkZNanP6/qwMfcbgpddtqEm37qTa96XbeJHdFE5HjcPjmlOnp6XTuXDcV7ssvv+TKK6/kT3/6EyNHjmTUqFGNXs+6devIyclhwIBfzxKwWq0sW7aM1157jaqqKry8vBos4+fnh5+fLjEuIq5zuOIwG3M2AnXXn6mXveIDEoFtwcPoHxHllmwicnwOFzTBwcHk5eXRvn17fvjhB+6//34A/P39j3mPp+M5//zz2bJlS4O2yZMn0717dx5++OGjihkRkabwU/pPmJj0iuxFbFAsADarlcSs7wAwe13pzngichwOFzQXXHABt9xyC/3792fXrl1cfPHFAGzbto2EhIRGryckJIRevXo1aAsKCiIyMvKodhGRpnKsw007k38kicOUmAEkjbrKXdFE5AQcnkPz+uuvM3z4cHJzc5k7dy6RkZFA3SGka665xukBRUSaSllNGasyVwEwOn60vb0keTYAOyJG4x8Q5JZsInJiDu+hCQ8P57XXXjuq3Rk3ply6dOlpr0NE5FT9nPEz1bZq2oe0p1N4JwCqqyrplrcIgIABV7sznoicgMMFDUBhYSFr1qwhJyfHfksEqLtS8KRJmv0vIp7ph/0/AHWHm+rvV7d9+Rf0o5RcIkgaMd6d8UTkBBwuaL755hsmTpxIaWkpoaGhDW5SqYJGRDxVeU05yw4uA2Bcwjh7u3XTxwDsbT2WaO9T+htQRJqAw3NoHnjgAW666SZKS0spLCykoKDA/sjPz3dFRhERl1uWsYyK2graBbcjKTIJgNLiApKKfwYgcthEd8YTkZNwuKDJyMjg7rvvJjAw0BV5RETcYkHqAgDGJoy173nesXg2AUY16UYcnfue5c54InISDhc0Y8eOZe3ata7IIiLiFmU1ZSzPWA7AuMRfDzf57fwcgIPxl2JYHP5xKSJNyOEDwuPHj+fBBx9k+/bt9O7dGx8fnwbv/+53v3NaOBGRprA0fSlV1ioSQhPoFtENgMPZ6fSsWAcGxJ9zvXsDishJOVzQ3HrrrQA89dRTR71nGAZWq/X0U4mINKH5afMBuDDhQvvhpj1L3mOYYbLLuytdO+tinyLNncMFzZGnaYuIeLri6mJ+zqib+Hvk2U0Re78CIL/T5e6IJSIOOq2DwpWVlc7KISLiFkvTl1Jjq6FTWCe6RHQB4OCerXSrTcFqGnQerUtRiHgChwsaq9XK008/Tdu2bQkODmbfvn0APP7447zzzjtODygi4krzU+sON41NGGtvS1/2HgDbAgYQFdveLblExDEOFzTPPPMMM2fO5IUXXsDX19fe3qtXL/7zn/84NZyIiCsVVRWxMnMlAGMT6woa02aj7cF5AFR1v8Jt2UTEMQ4XNO+99x4zZsxg4sSJeHl52dv79u3Lzp07nRpORMSVFh9YTK1ZS9eIrnQM6wjAns0/096WQaXpQ/fRuuGuiKc4pQvrde7c+ah2m81GTU2NU0KJiDSF+rObjjzclLfyAwC2hYwkJKyVW3KJiOMcLmiSkpJYvnz5Ue2fffYZ/fv3d0ooERFXy6/MZ3XWauDXs5ustbV0OlR3xWCvvn90WzYRcZzDp20/8cQT3HDDDWRkZGCz2fj8889JSUnhvffeY968ea7IKCLidIsOLMJqWunRqgftQ+sm/u5Y+S29KKCIIJLO+YObE4qIIxzeQ3PZZZfxzTffsHDhQoKCgnjiiSfYsWMH33zzDRdccIErMoqION2R926qV7267kzNnZFj8PXzd0suETk1Du+hATj77LP58ccfnZ1FRKRJHK44TPKhZODXgiY7fQ99SpaDAdGjp7gznoicAof30HTs2JG8vLyj2gsLC+nYsaNTQomIuNLC/QuxmTZ6R/WmXUg7AFK/exVvw8Y23z507DXUzQlFxFEOFzRpaWnHvF9TVVUVGRkZTgklIuJKvz27qaKshKSsuQBUD7rNbblE5NQ1+pDT119/bf94wYIFhIWF2V9brVYWLVpEQkKCU8OJiDhbTnkO6w+tB34taDZ/N4OhlJFptKbPeVe7M56InKJGFzSXX345UHdH7RtuuKHBez4+PiQkJDBt2jSnhhMRcbYf9/+IiUm/6H7EBsVi2my03jETgAOdryPO+5SmFoqImzX6O7f+LtuJiYkkJycTFRXlslAiIq5Sf++mcYl1157ZuuIbetsOUGb6kzRek4FFPJXDf4qkpqa6IoeIiMtll2WzMXcjBgYXdKi7zIRt5esAbI0ez9DwSHfGE5HTcEr7VhctWsSiRYvIycmx77mp99///tcpwUREnG1BWt21Zwa0HkBMYAzpe7bQt6LuasFxY+9xZzQROU0OFzRPPvkkTz31FIMGDaJNmzYYhuGKXCIiTldf0NTf6iBzwSvEA5sChtC3S183JhOR0+VwQfPmm28yc+ZMJk2a5Io8IiIucbDkIFsOb8FiWBjTYQzFhXn0ypkHBliG3eHueCJymhy+Dk11dTUjRoxwRRYREZep3zszuPVgogKi2P7dvwkyKtlviafX2Ze7N5yInDaHC5pbbrmF2bNnuyKLiIjL1Bc0YxPHYq2tJX73+wBkd78Bw+Lwj0IRaWYcPuRUWVnJjBkzWLhwIX369MHHx6fB+y+99JLTwomIOMOB4gPsyN+Bl+HFmPZj2LLkE/qZhygiiN4X/8nd8UTECRwuaDZv3ky/fv0A2Lp1a4P3NEFYRJqj+lsdDG0zlAj/CDLWvgXA9ja/Z3hw2IkWFREP4XBBs2TJElfkEBFxmSPPbkrdtppeVRupNS0kXnSve4OJiNPowLGItGj7ivaxq2AX3oY357U/j9yFrwKwOeQsYtt3cXM6EXGWRu+h+cMf/tCofp9//vkphxERcbbv9n0HwPC44diKy+mT/wMYEHD2nW5OJiLO1OiC5si7a4uIeIJaWy1f7P4CgEs7XUrKt9MZZtSwx6sT3Qdf4OZ0IuJMjS5o3n33XVfmEBFxup8O/kRORQ6t/FtxbuzZlKb9GYCC3jfrVG2RFkbf0SLSYn2661MALut8GdsXf0QM+RwmnD7jJrs5mYg4mwoaEWmRDpYc5JeMXwCY0GUCIRv+A8Du+An4+Qe6M5qIuIAKGhFpkebunouJyfA2w6nYs5dutTupNr3oMv5ud0cTERdQQSMiLU6NtcY+GXhCtwkUL50OwKbwMUTFtndnNBFxEYcvrCci0twtTl9MXmUeUQFR9PJKJKpoCRgQcZ72zoi0VNpDIyItTv1k4N93/j1p376Kj2Flh09POvc9y83JRMRVVNCISIuyv3g/q7NWY2BwfquR9M38GICqIbqQnkhLpoJGRFqUz3Z9BsBZbc+iZP47BBpV7PbuQt/zr3ZzMhFxJRU0ItJiVFur+XLPlwCMjRlF36y6Q0/lIx/WhfREWjh9h4tIi/Hj/h8prCqkdWBrolb8SIBRTYp3d/qce4W7o4mIi6mgEZEWo34y8LjY8xl0qO607epzHtHeGZEzgL7LRaRF2Fe4j3WH1mExLPTcvA0/o4YdPj3pddZl7o4mIk1ABY2ItAj1e2eGRQ7i/JzvAbCOelR7Z0TOEPpOFxGPV1lbyVd7vwJg8IE8fI1atvn2odfIS92cTESaigoaEfF4P+z/gZLqElr7RTMxexkAxujH3JxKRJqSChoR8XifpHwCwMhCLwIMK1v8+pM0/CI3pxKRpqSCRkQ8Wkp+CptyN+FleHFHznoAfM7/q5tTiUhTU0EjIh6tfjJw/6ogYm21bPYfTPchF7g5lYg0NRU0IuKxymvK+XbftwDckrcHAP8L/+bOSCLiJipoRMRjzU+bT2lNKTFWH4ZXVrIxYBhdB4xydywRcQMVNCLiseonA19bmIsFCB73uHsDiYjbqKAREY+0LW8b2/K24W3C70tL2RA4ks59z3J3LBFxExU0IuKRPk2pmww8pqyMVjYboRc94eZEIuJOKmhExOOUVpfyXep3AFxVUsr64HPo1HuYm1OJiDupoBERj/Nd6ndU1FaQWF3DgIpqIi7W3hmRM50KGhHxKKZp2icDTygpZWPoaBKTBrs5lYi4mwoaEfEoWw5vIaUgBV+byfiScqIu+bu7I4lIM6CCRkQ8yscpHwMwtqycfSHn0aFbP/cGEpFmwdudG586dSqff/45O3fuJCAggBEjRvD888/TrVs3d8YSkSZWVVnOwd2bMW3WE/bLrDrEvL3fADChuIyoq7R3RkTquLWg+emnn5gyZQqDBw+mtraWxx57jAsvvJDt27cTFBTkzmgi0kSstbXseelCelZvOWnfGdGR2IKDOLu8gtrA0cR37t0ECUXEE7i1oJk/f36D1zNnziQmJoZ169ZxzjnnuCmViDSl5NlPMqx6C9WmF4VG2HH77fWxMD8oAIDfFwUTf+3TTRVRRDyAWwua3yoqKgKgVatWx3y/qqqKqqoq++vi4uImySUirrFv62oG7P03GLCx3z8Y8vu7j9v36cV3YaYv5cIOF3LBDdOaLqSIeIRmMynYZrNx7733MnLkSHr16nXMPlOnTiUsLMz+iI+Pb+KUIuIsVZXl8Pmf8DVq2RA4gsGX3XncvptzN7M0fSkWw8KU/lOaLqSIeIxmU9BMmTKFrVu3MmfOnOP2efTRRykqKrI/0tPTmzChiDjT+vcepqMtjQJCib9+Bobl+D+Opm+YDsClHS+lY1jHpoooIh6kWRxyuvPOO5k3bx7Lli2jXbt2x+3n5+eHn59fEyYTEVfYufoHhmS8DwakDn+WAbHH39u6JmsNq7JW4W3x5o5+dzRhShHxJG7dQ2OaJnfeeSdffPEFixcvJjEx0Z1xRKQJlJUUEjz/LrwMk+SwsQwYO+m4fU3T5P82/B8AV3a5krbBbZsqpoh4GLfuoZkyZQqzZ8/mq6++IiQkhOzsbADCwsIICAhwZzQRcZGtM+9hqJlNNlF0vfHfJ+y77OAyNuVuwt/Lnz/1+VMTJRQRT+TWPTRvvPEGRUVFjBo1ijZt2tgfH3/8sTtjiYiLbFryKUPzvgTg8PkvERYRddy+NtNmnztzTY9riA6MboqIIuKh3LqHxjRNd25eRJpQUd4h4n56EIBV0RMYdvZlJ+z/Q9oPpBSkEOwTzE09b2qKiCLiwZrNWU4i0rLtmXk70RRwwNKWvje+fMK+tbZaXt/4OgDX97yecP/wJkgoIp5MBY2IuNzab99mYMliak0LlZf8m4CgkBP2/2bvN6QVpxHuF86kHsefNCwiUk8FjYi4VE5GKl2S624imdz+JroOGHXC/tXWat7Y9AYAt/S+hWDfYFdHFJEWQAWNiLiMabOR/f4thFHGbq/ODJr07EmX+XTXp2SVZRETEMMfu/2xCVKKSEuggkZEXGbNZ9PoU7mWKtMH3wlv4+N74gtjlteU8/bmtwG4re9t+Hv7N0VMEWkBVNCIiEsc3LOV3tteBGBDt3vo0H3ASZeZvXM2eZV5tA1uy+87/97VEUWkBVFBIyJOV1lRRvmcyQQaVWzz7cOQPz520mWKq4t5d+u7AEzpNwUfLx9XxxSRFkQFjYg4lWmzsfmtW+hau4sigmg18T9YvLxOutysbbMori6mU1gnLk68uAmSikhLooJGRJxqzWf/Ykjhd1hNg/2jptOmQ7eTLpNXkcf7298H4M7+d+JlOXkBJCJyJBU0IuI0O1YvYMC25wBY0+ku+oy6olHL/WfLf6iorSApMonz25/vyogi0kKpoBERpzh0cC/R3/8JH8PKuuBRDLvuyUYtt+7QOj7c8SEA9/S/B8MwXBlTRFooFTQictoqK8oomnk1URSSakmgx+3vYVhO/uOlpLqEx5Y/honJ5Z0vZ0TbEU2QVkRaIhU0InJafjsJ2Pe6OQQGhzVq2amrp5JZlkm74HY8MuQRFycVkZZMBY2InJYjJwEfGP0abTv2aNRy81Pn882+b7AYFqaePZUgnyAXJxWRlkwFjYicst9OAu597h8atVx2WTZPrXoKgFt730q/mH6uiigiZwgVNCJySk51ErDNtPG3FX+jpLqEXpG9uK3vbS5OKiJnAhU0IuKwU50EDPD+9vdZnb2aAO8App49FR+LrggsIqdPBY2IOOR0JgGn5Kfw6vpXAXhw8IMkhCW4MKmInElU0IiIQ051EnCVtYpHlj9Cja2GUfGjuLLLlS5OKiJnEhU0ItJoR04CTnZgEjDAK+teYU/hHiL9I3lyxJO6gJ6IOJUKGhFplAaTgENGM7SRk4ABfsn8hQ92fADAUyOfopV/K1fFFJEzlAoaETmpooLDFM/8I1EUss+SQI/bZjV6EnBhZSGPr3gcgD92+yPntDvHlVFF5Azl7e4AItK85WSkUvbOZXSx7aeQYPwcmARsmiZPrXqKnIocEkITeGDQAy5OKyJnKu2hEZHj2p+yEdvbF5Bo208uEeRf+XmjJwEDfL33a37c/yPehjfPnfMcAd4BLkwrImcy7aERkWPauXYRsfOuJ5xSDlja4nPDF3Ts0K3Ry6eXpPPs6mcBmNJ/Cj0je7oqqoiIChoROdqmxXPo+tNdBBjVpHh3I+a2r4iIbtPo5Yuqirh/6f2U15YzIGYAk3tOdmFaEREVNCLyG2u++D8GbPw73oaNTf6D6XLn3EbPmYG6ScC3/ngrO/N30sq/Fc+e/SxeFi8XJhYRUUEjIv9j2mysev9vDE99HQxIDhtHvynv4ePr1+h1FFQWcOsPt5JSkEIr/1a8c+E7tA1u68LUIiJ1VNCICDarleQ3/8Tw3M8AWNnmeobd+mqjT80GyK/M55YfbmF3wW4i/SN5Z+w7dArv5KrIIiINqKAROcNVVZaz9bVrGFq6FIBVXf/C8Gsfd2gdeRV53PLDLewp3ENUQBTvjH2HjmEdXZBWROTYVNCInMGKC/NI//fvGVi9iWrTi81DnmfY+FsdWsfhisPcsuAW9hbtJTogmnfGvkNiWKKLEouIHJsKGpEzVNqOtZif3kxPWxplpj/7zp/BoHMuc2gdhysOc/OCm9lXtI+YgBjeGfuO7qAtIm6hgkbkDGOtrSV5ztP03/06fkYNeYSR//sP6d3vbIfWk1uey80/3ExqUSoxgTH8d+x/6RDawUWpRUROTAWNyBnk4J6tlHx8K8NqtoMBm/wHE3f9f+gSl+DQenLKc7h5wc2kFacRGxTLfy/8L/Gh8a4JLSLSCCpoRM4Aps3Gms/+Re9t/6KdUUWZ6c+2Po8w+Pf3OHQmE8ChskPc/MPN7C/eT5ugNrwz9h3iQ1TMiIh7qaARaeGy0/eQ+8GtDK1aDwZs8+1DxLX/YUhC429jYF9XWTY3L7iZAyUHiAuK452x79AupJ0LUouIOEYFjUgLZdpsrP36Dbpt/Ce9KafS9GFjt3sZ8sdHsXg5fuXe7LJsblpwE+kl6bQNbss7Y3XRPBFpPlTQiLRAeYcOcmDWnxhc/jMAKd7dCLhqBsO69jul9SVnJ/PXFX8lqyyLtsFt+e/Y/xIXHOfExCIip0cFjUgLs2HBLBJW/o3+FFNterE+8XYGTfwH3j6+Dq+rvKacl9e9zJyUOQC0D2nPO2PfITYo1tmxRUROiwoakRairKSQHW/fzKDihQDssyRg/v4thvUedkrrS85O5vGfHyejNAOACV0n8MCgBwjyCXJaZhERZ1FBI9ICFORmkfvW7xhUuwurabCm3Q0MmDQVP/9Ah9dVXlPOK+tf4aOdHwHQJqgNT454kuFxw50dW0TEaVTQiHi47AO7qZp5OV1tBykghEMX/5fhQy88pXX9dq/MlV2v5IGBDxDsG+zMyCIiTqeCRsSD7d+5Hv85V9KBPA4RSeXVn9G9+wCH1/PbvTKxQbE8OeJJRsSNcHZkERGXUEEj4qFS1i6m9bxJhFPKfks7/CZ/RYf4zg6vJzk7mSd+foKDpQcBuKLLFfxl0F+0V0ZEPIoKGhEPtHnpXDovuYNAo4pd3l2Juf0bwqMcO/PoYMlB3t36Lp/s+gT4316Z4U8yoq32yoiI51FBI+Jh1s6bQZ/kR/A1rGz2H0inKZ8TFBLeqGVN02RDzgbe3/4+i9MXYzNtQN1emQcGPUCIb4gLk4uIuI4KGhEPsnrOVAbveB6LYbIu5Dx63/kRvn7+J12uxlbDD2k/8P7299mWt83ePiJuBDf3upkhbYa4MraIiMupoBHxAKbNxqp3H2R4+n/AgNVRVzD4jrdPeguDoqoiPt31KR/t/Iic8hwAfC2+XNrpUq7rcR2dIxyfcyMi0hypoBFp5qy1tax942aG530JwMoOtzPshqknvEt2alEqH2z/gK/3fk2ltRKASP9Iru5+NVd1u4pW/q2aIrqISJNRQSPSjGWn7yHz4/sYWroMm2mQ3PMxhl/10DH71tpqWZO1hg92fMDyjOX29u6tujMpaRLjEsbh6+X47Q9ERDyBChqRZqYgN4tdSz4gZPeXJNVsJRaoNr3YMnQaQy+e3KBvbnkuKzJWsDxjOasyV1FSUwKAgcG58edyfdL1DGo9CMMw3DASEZGmo4JGpBkoKylkx5I5+OyYS1L5OoYaVvt723x7w6jHGDjiYmpttWzK3cSKjBWsyFjBzvydDdYT7hfORYkXMbHHRDqEdmjqYYiIuI0KGhE3qa6qZPuyz7Fu/oSk4p8ZZFTXvWHAHq9OHE68lIRzJxEdGcrPGT/z36UPsDJrJSXVJfZ1GBj0iurFWW3P4qy2Z9EzsidelhNPFBYRaYlU0Ig0EdNmI2PfdrK2LcNMW0G3gqX0o6zuTQMOGG3Y0G40pT36k+dfyc78naSsvI2cipwG6wn3C2dE3AjOansWI9uO1ARfERFU0Ii4TGlxAWmbllGydyWBh9bTvmI77SihHVAN7PH14UvfGNaFJ5AdFsSBmmzKalbA7hUN1mNg0DOyJ2e1q9sL0yuyl/bCiIj8hgoaESewWa2k79nCoe3LMNOTCSvahLeRSaGPF5ne3mT5e5EZ7EuGdywHvf3I9zIx7fN0s6G87iNfiy9dIrrQvVV3+6NLRBeCfILcNTQREY+ggkakkaprq0jLTGH//k3k5OyiqCiNioosqmvzsRrF5HmbZHp7kRXsTUGYF9DmOGsyAQjzC6srWiK6061VN3q06kFCWALeFn1biog4Sj85pUWzmTZqbDVUWauorK2kvKacstoyymvKqaitqHtdU0Z5bTnlNeWU15SRV5TD4cKDFFUcpqSmmHKzgjKjlvLfXsfOC7DfkDrgqG0HeQcSF9KWuKA42gS1IS44jjbBbYgLiiMuOI5I/0idTi0i4iQqaI6hvKacoqqiY75n/u+v68a2Q90NAU+6jHmc9v+9rl9H/Xv2PuYRbUf0OXKZI9dR/9+Ryx7Zbv/YNLGZNnvf+o9N89c+9W0209bwgc2+/JGPWrMWm82G1bRiMxs+W21We59a228e/2ursdVQa6vFarNSa9ZSba22P6psVXXP1qpf26xV1Nhqjvt1aZTfFDGGaRJigyCbF0GGP4HeIYT6RREVFkfX+L60C21vL1xCfUNPb9siItJoKmiO4aeDP/HQsmNfjVU8l4GBP97420yCrLWEWqsJMm0E2WwEmCaBNpMg04a/zcRmBmOxRODn25qgkPa0iupCfLvedOzYn8BA3ZFaRKS5UUFzDIZh4Ofl5/hyHH344GSHFI5c5si+v12X/bXR8HX9MvbXx2hv8DEGdf//2s/+n/Hrs8Ww2PvUf2xfj2HgZXhhUNfPYljqlsFif13fZlDX18vihcWw4GXUPXsb3lgsda/r2+r7eVu88Ta8qC4rp7I4D1tJAV5lefhVFRJcU0CktQh/bPiYJn7/e9R9DH6mie//Hn6/efb+9dNnV0wgB306UhLWDSOuN+GJA4jvNoCAIBUtIiKexDCPdzzEAxQXFxMWFkZRURGhodq970lsViv5uZkUZKdRmrOf6oKD2Ioy8CveT1jFAdrUZhJoVB13+SrThzLj6HkrJ1JmBJMb2JmqqCQC2vWlddeBxMZ3OeFNHkVExPlc8ftbe2jEqWqqqyjKP0RJXhZlBYeoKsqhpjATijPxKc8msPIQ4TW5RJr5RBlWoo63IgNqTQvZltbk+cdTEZKAEdmZwDZdieqQREzbTrTyduyfbysg/nQHKCIizVKzKGhef/11XnzxRbKzs+nbty/Tp09nyJAh7o51RquprqK0KJ+yojwqSvKpKi2guqyA2rJCbBWFmOV5eFXk4VNVQEBNIUG1hYSZRYRSRhQcv1CpZ4DNNDhsRFDoHUWZXwzVAa0xIxLwj+1KZPsexHboTjtfP9o1wXhFRMSzub2g+fjjj7n//vt58803GTp0KK+88gpjx44lJSWFmJgYd8fzeLU11RTl51Caf4iywhyqinOoLj6MWZYHFXl4VebjW12IX20p/tYSAm1lBJtlBBpVRAARp7BNm2lQZIRQbAmjzDucCr8oagJjIawtvhHtCIyKJzw2gcjW8cT4+qGvsoiInC63z6EZOnQogwcP5rXXXgPAZrMRHx/PXXfdxSOPPHLCZV01h6a8tIiivGxsVhs2azU2qxWbtabu2WbFVluDabNis9Zis9ViWmsxrdYTnrp9LGb9umqrsNVWg7UGW201prXu4/pnrNUY1hqw1WLY6p9rsdiq657NWvuzxazFx1pJoLWYULOIsPp7BZ2iMtOfUiOIckswlV7BVHsHU+MTQq1fBGZgJJagKHxCo/EPa01QRGtCI9sQGhGNl4OHg0RE5MzR4ubQVFdXs27dOh599FF7m8ViYcyYMaxcudJtubYvmcOgdS3rtO1CgikxQuv2mPiEU+MbjjWgFUZgJF5BkXgFtcI3OBz/4AgCQiIJDmtFUGgEQT6+6KL7IiLS3Lm1oDl8+DBWq5XWrVs3aG/dujU7d+48qn9VVRVVVb+e+VJcXOySXBZvXypNH6x4YTUs2LBgxevXZ8OC7chnLNgML8xjnLZ9QoZBreGDzfDGavHBZvhgs/hgWrz/91z3wOJd97GXD8b/nrF4Y3j5gJcPhpcvhpdP3cPbB4tPAP5h0QSFxxDSqjWhEdGE+/gS7pLPloiIiPt51HGBqVOn8uSTT7p8OwMumgwXTXb5dkRERMQ53HoBjqioKLy8vDh06FCD9kOHDhEbG3tU/0cffZSioiL7Iz09vamiioiISDPm1oLG19eXgQMHsmjRInubzWZj0aJFDB8+/Kj+fn5+hIaGNniIiIiIuP2Q0/33388NN9zAoEGDGDJkCK+88gplZWVMnqxDPiIiItI4bi9o/vjHP5Kbm8sTTzxBdnY2/fr1Y/78+UdNFBYRERE5Hrdfh+Z06F5OIiIinscVv791Vz4RERHxeCpoRERExOOpoBERERGPp4JGREREPJ4KGhEREfF4KmhERETE46mgEREREY+ngkZEREQ8ngoaERER8Xhuv/XB6ai/yHFxcbGbk4iIiEhj1f/edubNCjy6oCkpKQEgPj7ezUlERETEUSUlJYSFhTllXR59LyebzUZmZiYhISEYhuHUdRcXFxMfH096enqLvU/UmTBG0DhbGo2z5TgTxgga57GYpklJSQlxcXFYLM6Z/eLRe2gsFgvt2rVz6TZCQ0Nb9D9AODPGCBpnS6NxthxnwhhB4/wtZ+2ZqadJwSIiIuLxVNCIiIiIx1NBcxx+fn78/e9/x8/Pz91RXOZMGCNonC2NxtlynAljBI2zqXj0pGARERER0B4aERERaQFU0IiIiIjHU0EjIiIiHu+MLWjy8/OZOHEioaGhhIeHc/PNN1NaWnrC/nfddRfdunUjICCA9u3bc/fdd1NUVNSg34EDBxg/fjyBgYHExMTw4IMPUltb6+rhHJej4wSYMWMGo0aNIjQ0FMMwKCwsPKrP+vXrueCCCwgPDycyMpI//elPJ12vq7hqjLt27eKyyy4jKiqK0NBQzjrrLJYsWeKiUZycK8a5dOlSDMM45iM5OdmFozk+V309Ab799luGDh1KQEAAERERXH755c4fQCO5apwJCQlHfS2fe+45F43i5Fz59QSoqqqiX79+GIbBxo0bnRveAa4a5+9+9zvat2+Pv78/bdq0YdKkSWRmZrpoFCfmijGmpaVx8803k5iYSEBAAJ06deLvf/871dXVDuc7YwuaiRMnsm3bNn788UfmzZvHsmXL+NOf/nTc/pmZmWRmZvKvf/2LrVu3MnPmTObPn8/NN99s72O1Whk/fjzV1dX88ssvzJo1i5kzZ/LEE080xZCOydFxApSXlzNu3Dgee+yxY76fmZnJmDFj6Ny5M6tXr2b+/Pls27aNG2+80QUjODlXjBHgkksuoba2lsWLF7Nu3Tr69u3LJZdcQnZ2trOH0CiuGOeIESPIyspq8LjllltITExk0KBBrhjGSbnq6zl37lwmTZrE5MmT2bRpEz///DPXXnuts+M3mqvGCfDUU081+JreddddzozuEFeOE+Chhx4iLi7OWXFPmavGOXr0aD755BNSUlKYO3cue/fu5corr3R2/EZxxRh37tyJzWbjrbfeYtu2bbz88su8+eabjfraH8U8A23fvt0EzOTkZHvb999/bxqGYWZkZDR6PZ988onp6+tr1tTUmKZpmt99951psVjM7Oxse5833njDDA0NNauqqpw3gEY63XEuWbLEBMyCgoIG7W+99ZYZExNjWq1We9vmzZtNwNy9e7fT8jeGq8aYm5trAuayZcvsbcXFxSZg/vjjj07L31iuGudvVVdXm9HR0eZTTz11upFPiavGWVNTY7Zt29b8z3/+4+zIp8SVX88OHTqYL7/8shPTnjpX/7v97rvvzO7du5vbtm0zAXPDhg1OSu6Ypvr+NE3T/Oqrr0zDMMzq6urTieywphzjCy+8YCYmJjqc8YzcQ7Ny5UrCw8Mb/AU6ZswYLBYLq1evbvR6ioqKCA0Nxdvb277e3r1707p1a3ufsWPHUlxczLZt25w3gEZy1jh/q6qqCl9f3wb33wgICABgxYoVpx74FLhqjJGRkXTr1o333nuPsrIyamtreeutt4iJiWHgwIHOiO4QV43zt77++mvy8vKYPHmy09bpCFeNc/369WRkZGCxWOjfvz9t2rThoosuYuvWrc6I7TBXfz2fe+45IiMj6d+/Py+++KLbDnu7cpyHDh3i1ltv5f333ycwMPB0o56Wpvr+zM/P58MPP2TEiBH4+Pg4bb2N0VRjhLrfra1atXJ4uTOyoMnOziYmJqZBm7e3N61atWr04YTDhw/z9NNPN9jdlp2d3aCYAeyv3XGYwhnjPJbzzjuP7OxsXnzxRaqrqykoKOCRRx4BICsr67QyO8pVYzQMg4ULF7JhwwZCQkLw9/fnpZdeYv78+URERJxubIe5apy/9c477zB27FiX3yPteFw1zn379gHwj3/8g7/97W/MmzePiIgIRo0aRX5+/mllPhWu/HrefffdzJkzhyVLlnDbbbfx7LPP8tBDD53WOk+Vq8ZpmiY33ngjt99+u9sOjR7J1d+fDz/8MEFBQURGRnLgwAG++uqr016no5rqZ9CePXuYPn06t912m8PLtqiC5pFHHjnuBMf6x86dO097O8XFxYwfP56kpCT+8Y9/nH5wBzXVOI+nZ8+ezJo1i2nTphEYGEhsbCyJiYm0bt3aaXdNdfcYTdNkypQpxMTEsHz5ctasWcPll1/OpZde6tSizd3jPNLBgwdZsGBBg3lhzuLucdpsNgD++te/csUVVzBw4EDeffddDMPg008/ddp23D1OgPvvv59Ro0bRp08fbr/9dqZNm8b06dOpqqpy2jbcPc7p06dTUlLCo48+6rJtgPvHWe/BBx9kw4YN/PDDD3h5eXH99ddjOumauM1ljAAZGRmMGzeOCRMmcOuttzq8vEffbfu3HnjggZNOTO3YsSOxsbHk5OQ0aK+trSU/P5/Y2NgTLl9SUsK4ceMICQnhiy++aLDbLzY2ljVr1jTof+jQIft7ztIU4zyZa6+9lmuvvZZDhw4RFBSEYRi89NJLdOzY8bTWW8/dY1y8eDHz5s2joKDAftfYf//73/z444/MmjXLvkfqdLl7nEd69913iYyM5He/+51T1nckd4+zTZs2ACQlJdnb/Pz86NixIwcOHDjl9f6Wu8d5LEOHDqW2tpa0tDS6devmlHW6e5yLFy9m5cqVR11if9CgQUycOJFZs2ad8rqP5O5x1ouKiiIqKoquXbvSo0cP4uPjWbVqFcOHDz/tdTeXMWZmZjJ69GhGjBjBjBkzTm0lDs+6aQHqJzetXbvW3rZgwYKTTm4qKioyhw0bZp577rlmWVnZUe/XTwo+dOiQve2tt94yQ0NDzcrKSucOohFOdZz1HJnE9c4775iBgYGN6utMrhrj119/bVosFrOkpKRBe9euXc1nnnnGKdkd4eqvpc1mMxMTE80HHnjAWZFPiavGWVRUZPr5+TWYFFxdXW3GxMSYb731ltPyN1ZTfm9+8MEHpsViMfPz808n8ilx1Tj3799vbtmyxf5YsGCBCZifffaZmZ6e7uxhnFRTfj33799vAuaSJUtOI7HjXDnGgwcPml26dDGvvvpqs7a29pQznpEFjWma5rhx48z+/fubq1evNlesWGF26dLFvOaaa+zvHzx40OzWrZu5evVq0zTrfiAOHTrU7N27t7lnzx4zKyvL/qj/AtTW1pq9evUyL7zwQnPjxo3m/PnzzejoaPPRRx91yxhN0/FxmqZpZmVlmRs2bDDffvtt+5k+GzZsMPPy8ux9pk+fbq5bt85MSUkxX3vtNTMgIMB89dVXm3Rs9VwxxtzcXDMyMtL8wx/+YG7cuNFMSUkx//KXv5g+Pj7mxo0bm3yMpum6r6VpmubChQtNwNyxY0eTjed4XDXOe+65x2zbtq25YMECc+fOnebNN99sxsTEuOUXvWm6Zpy//PKL+fLLL5sbN2409+7da37wwQdmdHS0ef311zf5+Oq58t9tvdTUVLee5WSarhnnqlWrzOnTp5sbNmww09LSzEWLFpkjRowwO3Xq5JY/kl0xxoMHD5qdO3c2zz//fPPgwYMNfrc66owtaPLy8sxrrrnGDA4ONkNDQ83Jkyc3+Gu8/hukvgqury6P9UhNTbUvl5aWZl500UVmQECAGRUVZT7wwAP207rdwdFxmqZp/v3vfz/mON999117n0mTJpmtWrUyfX19zT59+pjvvfdeE46qIVeNMTk52bzwwgvNVq1amSEhIeawYcPM7777rglH1pCrxmmapnnNNdeYI0aMaKKRnJirxlldXW0+8MADZkxMjBkSEmKOGTPG3Lp1axOOrCFXjHPdunXm0KFDzbCwMNPf39/s0aOH+eyzz7rll189V/67/e063FnQuGKcmzdvNkePHm22atXK9PPzMxMSEszbb7/dPHjwYBOPro4rxvjuu+8e93ero3S3bREREfF4LeosJxERETkzqaARERERj6eCRkRERDyeChoRERHxeCpoRERExOOpoBERERGPp4JGREREPJ4KGhEREfF4KmhEpFm68cYbufzyy0/YZ+nSpRiGQWFhocvz5OXlERMTQ1pamsu39Vvbt2+nXbt2lJWVNfm2RTyFChqRZuDGG2/EMAxuv/32o96bMmUKhmGc9I64R2rKX/Su8uqrrzJz5kz761GjRnHvvfc26DNixAiysrIICwtzeZ5nnnmGyy67jISEBJdv67eSkpIYNmwYL730UpNvW8RTqKARaSbi4+OZM2cOFRUV9rbKykpmz55N+/bt3ZLJNE1qa2vdsu2wsDDCw8NP2MfX15fY2FgMw3BplvLyct555x1uvvlml27nRCZPnswbb7zhtq+HSHOngkakmRgwYADx8fF8/vnn9rbPP/+c9u3b079//wZ9q6qquPvuu4mJicHf35+zzjqL5ORkANLS0hg9ejQAERERDfbunGg5+HXPzvfff8/AgQPx8/NjxYoVR2VNS0vDMAzmzJnDiBEj8Pf3p1evXvz0008N+v30008MGTIEPz8/2rRpwyOPPNLgF/Jnn31G7969CQgIIDIykjFjxtgPqxx5yOnGG2/kp59+4tVXX8UwDAzDIC0t7Zh7oubOnUvPnj3x8/MjISGBadOmNciUkJDAs88+y0033URISAjt27dnxowZJ/zafPfdd/j5+TFs2LCjPlcLFiygf//+BAQEcN5555GTk8P3339Pjx49CA0N5dprr6W8vNy+3KhRo7jrrru49957iYiIoHXr1rz99tuUlZUxefJkQkJC6Ny5M99//32DDBdccAH5+flHfY5FpI4KGpFm5KabbuLdd9+1v/7vf//L5MmTj+r30EMPMXfuXGbNmsX69evp3LkzY8eOJT8/n/j4eObOnQtASkoKWVlZvPrqqydd7kiPPPIIzz33HDt27KBPnz7Hzfvggw/ywAMPsGHDBoYPH86ll15KXl4eABkZGVx88cUMHjyYTZs2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" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ 0.00048058 -0.15422773 0.00713343]\n", - "Manually calculated FWHM to 0.016797947350266428 mm\n", - "Scipy calculated FWHM = -0.015900000000000247 mm\n", - "Scipy calculated 1/e2 = -0.02798400000000001 mm\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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NlD7/A43RiNEw9C5OwDRsI4dO8aVV15JYGAgL774In369MFgMLBnzx4++OAD2rZty8033+zuMPHy8sLLy6vBr3P06FEiIyMZPny4c1twcHCDX1c0MFUtlyB5ASoaucW/wWg1hWi159lV0s2xoeAI2O0gi0GLFkT+Nbdwf/vb39DpdGzbto0//elP9OjRg06dOnHLLbfw3XffcdNNNznLvvbaa/Tp0wcfHx+io6P529/+RmFhoXP/s88+S//+/V3O/8Ybb9CxY0fn8/Xr13PFFVfg4+NDYGAgV155JSdPOhaz3LVrF6NHj8bPzw9/f38GDRrEtm3bgMpdbEePHuWWW24hPDwcX19fhgwZws8//+xy7Y4dO/Liiy9yzz334OfnR/v27fnggw+qfS2mTJnCAw88QGpqKoqiOOMu38U2atQoTp48ycMPP4yiKCiKUtOXWriTzQiqDRUFo90gE0Q2AoP+JPtKOmFXNWArhtxd7g5JiHolCVJdlX1jdcejhrfUnjt3jp9++on7778fHx+fKsuUTwA0Gg0LFy5k3759LFmyhLVr1/LYY4/V+CWxWq2MGzeOkSNHsnv3bpKSkpgxY4bzGpMmTaJdu3Zs3bqVlJQUnnjiCTw8PKo8V2FhITfccANr1qxhx44djBkzhptuuonU1FSXcgsWLGDw4MHs2LGDv/3tb9x3330cPHiwynO++eabzJs3j3bt2pGens7WrVsrlfn6669p164d8+bNIz09nfT09BrXX7iRc4C2HhVkgHYjMOhPYlINpNmiHRsy17o3ICHqmXSx1ZWtGL70dc+1/1QIuqoTnvKOHDmCqqp069bNZXtISAhGoxGA+++/n5deegnAZaByx44deeGFF7j33nt59913axRWfn4+eXl53HjjjXTu7FjMskePHs79qampPProo3Tv3h2A2NjYas/Vr18/+vXr53z+/PPP89///pdvv/2WmTNnOrffcMMN/O1vfwPg8ccf5/XXX2fdunWV6gwQEBCAn58fWq2WiIiIKq8bHByMVqvFz8+v2jKiCSqdILKodIJIGaDd8Ax6R8vwjqKutA84Cdmb3RyREPVLWpBaoS1btrBz50569eqFyXThg+Tnn3/m2muvpW3btvj5+XHXXXdx7ty5Gg/kDg4OZsqUKSQkJHDTTTfx5ptvurTAzJo1i7/85S/Ex8fzr3/9i6NH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saht27ZVP/roo/oOuU4a8u/ZoUMH9fXXX6/HaOuuof/dfv/992r37t3Vffv2qYC6Y8eOeoq85hrr/6aqquo333yjKoqims3mywm5Thqzni+//LIaExNT6xilBakeJCUlERgY6PINOT4+Ho1GQ3Jyco3Pk5eXh7+/PzqdznnePn36EB4e7iyTkJBAfn4++/btq78K1EB91bEik8mEXq93WVzQy8sLgN9++63uAddRQ9WzTZs2dOvWjc8++4yioiKsVivvv/8+YWFhDBo0qD5Cr5WGqmdF3377LefOnWPq1Kn1ds7aaKh6bt++ndOnT6PRaBgwYACRkZFcf/317N27tz7CrrWG/nv+61//ok2bNgwYMIBXXnnFbd38DVnPzMxMpk+fzv/93//h7e19uaHWWWP938zJyWHp0qUMHz4cDw+PejtvTTVWPcHx2RocHFzr4yRBqgcZGRmEhYW5bNPpdAQHB9e4+yQ7O5vnn3/epXkxIyPDJTkCnM8bu1umPupYlWuuuYaMjAxeeeUVzGYz58+f54knngAgPT39smKui4aqp6Io/Pzzz+zYsQM/Pz88PT157bXXSExMJCgo6HLDrrWGqmdFH3/8MQkJCQ26CPTFNFQ9jx07BsCzzz7LU089xapVqwgKCmLUqFHk5ORcVsx10ZB/z7///e8sX76cdevW8de//pUXX3yRxx577LLOWVcNVU9VVZkyZQr33nuv27qCyzT0/83HH38cHx8f2rRpQ2pqKt98881ln7MuGus96MiRI7z11lv89a9/rfWxkiBdxBNPPFHtgNOyx4EDBy77Ovn5+YwdO5aePXvy7LPPXn7gtdBYdaxOr169WLJkCQsWLMDb25uIiAhiYmIIDw93aVW6XO6up6qq3H///YSFhfHrr7+yZcsWxo0bx0033VSviaC761leWloaP/74o8u4uvri7nra7XYA/vGPf3D77bczaNAgPv30UxRFYcWKFfV2HXfXE2DWrFmMGjWKvn37cu+997JgwQLeeustTCZTvV3D3fV86623KCgoYM6cOQ12DXfXscyjjz7Kjh07+Omnn9BqtUyePBm1HhfUaCr1BDh9+jRjxozhj3/8I9OnT6/18boGiKnFeOSRRy45WLhTp05ERERw9uxZl+1Wq5WcnBwiIiIuenxBQQFjxozBz8+P//73vy5NnREREWzZssWlfGZmpnNffWiMOl7KxIkTmThxIpmZmfj4+KAoCq+99hqdOnW6rPOW5+56rl27llWrVnH+/Hn8/f0BePfdd1m9ejVLlixxtppdLnfXs7xPP/2UNm3acPPNN9fL+cpzdz0jIyMB6Nmzp3ObwWCgU6dOpKam1vm8Fbm7nlWJi4vDarVy4sQJunXrVi/ndHc9165dS1JSUqU1vwYPHsykSZNYsmRJnc9dxt11LBMSEkJISAhdu3alR48eREdHs3nzZoYNG3bZ54amU88zZ84wevRohg8fzgcffFC3k9R61JKopGyw2bZt25zbfvzxx0sONsvLy1OHDh2qjhw5Ui0qKqq0v2yQdmZmpnPb+++/r/r7+6tGo7F+K3EJda1jmdoMqPv4449Vb2/vGpWtbw1Vz2+//VbVaDRqQUGBy/auXbuq//znP+sl9tpo6L+n3W5XY2Ji1EceeaS+Qq6ThqpnXl6eajAYXAZpm81mNSwsTH3//ffrLf6aasz/n59//rmq0WjUnJycywm5ThqqnidPnlT37NnjfPz4448qoP7nP/9RT506Vd/VuKjG/FuePHlSBdR169ZdRsR105D1TEtLU2NjY9UJEyaoVqu1zjFKglRPxowZow4YMEBNTk5Wf/vtNzU2Nla98847nfvT0tLUbt26qcnJyaqqOt5g4+Li1D59+qhHjhxR09PTnY+yP6jValV79+6tXnfdderOnTvVxMRENTQ0VJ0zZ06zqKOqqmp6erq6Y8cO9cMPP3TexbVjxw713LlzzjJvvfWWmpKSoh48eFB9++23VS8vL/XNN99s1LqV1xD1zMrKUtu0aaPedttt6s6dO9WDBw+qs2fPVj08PNSdO3c2eh1VteH+nqqqqj///LMKqPv372+0+lSnoer54IMPqm3btlV//PFH9cCBA+q0adPUsLAwtyQOqtow9dy0aZP6+uuvqzt37lSPHj2qfv7552poaKg6efLkRq9fmYb8d1vm+PHjbruLTVUbpo6bN29W33rrLXXHjh3qiRMn1DVr1qjDhw9XO3fu3OhfuMs0RD3T0tLULl26qNdee62alpbm8tlaW5Ig1ZNz586pd955p+rr66v6+/urU6dOdWktKPsPV5apl2W/VT2OHz/uPO7EiRPq9ddfr3p5eakhISHqI4884pwGoLHVto6qqqrPPPNMlXX89NNPnWXuuusuNTg4WNXr9Wrfvn3Vzz77rBFrVVlD1XPr1q3qddddpwYHB6t+fn7q0KFD1e+//74Ra+aqoeqpqqp65513qsOHD2+kmlxcQ9XTbDarjzzyiBoWFqb6+fmp8fHx6t69exuxZq4aop4pKSlqXFycGhAQoHp6eqo9evRQX3zxRbd9oKpqw/67rXgOdyVIDVHH3bt3q6NHj1aDg4NVg8GgduzYUb333nvVtLS0Rq7dBQ1Rz08//bTaz9baUlS1HkdnCSGEEEK0AHIXmxBCCCFEBZIgCSGEEEJUIAmSEEIIIUQFkiAJIYQQQlQgCZIQQgghRAWSIAkhhBBCVCAJkhBCCCFEBZIgCSGEEEJUIAmSEEIIIUQFkiAJIYQQQlQgCZIQQgghRAWSIAkhhBBCVPD/BusWBBOLl4cAAAAASUVORK5CYII=" - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "execution_count": 68 - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "fit_knife_edge(y_data, motor='Y')", - "id": "d6dd221d89d3b71a" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/common/src/aaredaqlib/__init__.py b/src/__init__.py similarity index 100% rename from common/src/aaredaqlib/__init__.py rename to src/__init__.py diff --git a/daq/src/aaredaq/__init__.py b/src/aare/__init__.py similarity index 100% rename from daq/src/aaredaq/__init__.py rename to src/aare/__init__.py diff --git a/daq/src/mxlibs3/__init__.py b/src/aare/common/__init__.py similarity index 100% rename from daq/src/mxlibs3/__init__.py rename to src/aare/common/__init__.py diff --git a/src/aare/common/autofocus_tools.py b/src/aare/common/autofocus_tools.py new file mode 100644 index 00000000..6b60795a --- /dev/null +++ b/src/aare/common/autofocus_tools.py @@ -0,0 +1,59 @@ +import cv2 +import numpy as np + +def focus_measure_edges(gray: np.ndarray, mask: np.ndarray | None = None, verbose: bool = False) -> float: + # mild denoise (optional but usually stabilizes the curve) + gray = cv2.GaussianBlur(gray, (3, 3), 0) + + gx = cv2.Scharr(gray, cv2.CV_64F, 1, 0) + gy = cv2.Scharr(gray, cv2.CV_64F, 0, 1) + g2 = gx * gx + gy * gy + + roi = g2[mask] if mask is not None else g2.reshape(-1) + if roi.size == 0: + return 0.0 + + # threshold relative to median -> knocks out noise floor + t = float(np.median(roi) * 3.0) + strong = roi[roi > t] + + if strong.size == 0: + return 0.0 + if verbose: + print(f"mask pixels: {mask.sum()}, " + f"focus={strong.mean():.2f}" + f"strong_size={strong.size}") + + return float(strong.mean()) # higher = sharper + +def focus_measure_blob_size(gray: np.ndarray, mask: np.ndarray | None = None) -> float: + """ + Measures sharpness for a single bright blob. + Higher = sharper (smaller blob). + """ + g = gray.astype(np.float64) + + if mask is not None: + g = np.where(mask, g, 0.0) + + # Background subtraction is crucial for blob metrics + # Use a large-ish blur as background estimate (tune ksize to your scale) + bg = cv2.GaussianBlur(g, (0, 0), sigmaX=10.0, sigmaY=10.0) + s = g - bg + s[s < 0] = 0.0 + + total = float(s.sum()) + if total <= 0: + return 0.0 + + h, w = s.shape + y, x = np.mgrid[0:h, 0:w] + + cx = float((s * x).sum() / total) + cy = float((s * y).sum() / total) + + # intensity-weighted second central moment (variance) + var = float((s * ((x - cx) ** 2 + (y - cy) ** 2)).sum() / total) + + # smaller var => sharper, so invert + return float(1.0 / (var + 1e-9)) \ No newline at end of file diff --git a/common/src/aaredaqlib/beamline.py b/src/aare/common/beamline.py similarity index 73% rename from common/src/aaredaqlib/beamline.py rename to src/aare/common/beamline.py index 51d4f693..7c402bb8 100644 --- a/common/src/aaredaqlib/beamline.py +++ b/src/aare/common/beamline.py @@ -10,8 +10,6 @@ class MXBeamline(Enum): def mx_beamline() -> MXBeamline: - name = os.getenv("BEAMLINE_XNAME") - if name is None: - name = os.getenv("BEAMLINE", "SIMULATED") + name = os.getenv("BEAMLINE") name=name.strip().upper() return MXBeamline[name] if name in MXBeamline.__members__ else MXBeamline.SIMULATED diff --git a/common/src/aaredaqlib/coordinate.py b/src/aare/common/coordinate.py similarity index 86% rename from common/src/aaredaqlib/coordinate.py rename to src/aare/common/coordinate.py index edbdebc4..76da6e25 100644 --- a/common/src/aaredaqlib/coordinate.py +++ b/src/aare/common/coordinate.py @@ -102,3 +102,21 @@ def positive_coords(value: Coordinate) -> Coordinate: if value.x <= 0 or value.y <= 0: raise ValueError("Coordinates must be positive") return value + + +class AerotechCoordinate(BaseModel): + at_mm: Optional[Coordinate] = None + omega_deg: Optional[float] = None + + def eq(self, other: "AerotechCoordinate", tol: float) -> bool: + return ( + abs(self.at_mm.x - other.at_mm.x) < tol + and abs(self.at_mm.y - other.at_mm.y) < tol + and abs(self.at_mm.z - other.at_mm.z) < tol + and abs(self.omega_deg - other.omega_deg) < tol + ) + + def __eq__(self, other: object) -> bool: + if isinstance(other, AerotechCoordinate): + return self.eq(other, tol=0.01) + return NotImplemented \ No newline at end of file diff --git a/common/src/aaredaqlib/diffraction_geometry.py b/src/aare/common/diffraction_geometry.py similarity index 95% rename from common/src/aaredaqlib/diffraction_geometry.py rename to src/aare/common/diffraction_geometry.py index d91e9846..92f29a97 100644 --- a/common/src/aaredaqlib/diffraction_geometry.py +++ b/src/aare/common/diffraction_geometry.py @@ -36,7 +36,7 @@ class DiffractionGeometry(BaseModel): def resolution_angstrom(self, exp_dtz_mm: float) -> float: if exp_dtz_mm <= 0: - raise ValueError("Detector distance must be positive") + raise ValueError(f"Detector distance must be positive {exp_dtz_mm}") theta = math.atan(self.detector_radius_mm / exp_dtz_mm)*0.5 return self.wavelength_angstrom / (2 * math.sin(theta)) diff --git a/src/aare/common/error_codes.py b/src/aare/common/error_codes.py new file mode 100644 index 00000000..d4247300 --- /dev/null +++ b/src/aare/common/error_codes.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from enum import StrEnum + +class AuthErrorCode(StrEnum): + """ + Stable, machine-readable error codes used across the API. + + Rules: + - never rename an existing value (treat as public API) + - only add new values + """ + + # Generic / defaults + AUTHENTICATION_ERROR = "AUTHENTICATION_ERROR" + AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED" + FORBIDDEN = "FORBIDDEN" + HTTP_ERROR = "HTTP_ERROR" + INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR" + + # Auth/JWT + INVALID_TOKEN = "INVALID_TOKEN" + SESSION_ALREADY_ACTIVE = "SESSION_ALREADY_ACTIVE" + + # Authorization + NOT_STAFF = "NOT_STAFF" + NOT_IN_ACTIVE_PGROUP = "NOT_IN_ACTIVE_PGROUP" + + +class DAQErrorCode(StrEnum): + BEAMLINE_BUSY = "BEAMLINE_BUSY" + +_ERROR_CODE_HELP: dict[str, str] = { + # Auth/JWT + AuthErrorCode.AUTHENTICATION_ERROR: ( + "Generic authentication problem. Usually means the request lacked valid credentials " + "(expired/invalid token, missing Authorization header, etc.)." + ), + AuthErrorCode.AUTHENTICATION_FAILED: ( + "Authentication failed during login/token creation. Typically incorrect credentials " + "or an inability to validate the user." + ), + AuthErrorCode.INVALID_TOKEN: ( + "The provided token could not be decoded/validated (bad signature, expired, malformed). " + "Re-authenticate to obtain a new token." + ), + AuthErrorCode.SESSION_ALREADY_ACTIVE: ( + "A different session currently owns control. Use “force current session” (if allowed) " + "or wait for the active session to expire/end." + ), + # Authorization + AuthErrorCode.FORBIDDEN: ( + "Generic permissions failure. The user is authenticated but not allowed to perform this action." + ), + AuthErrorCode.NOT_STAFF: ( + "This action requires staff privileges. Log in with a staff account or ask staff to perform it." + ), + AuthErrorCode.NOT_IN_ACTIVE_PGROUP: ( + "You are not a member of the currently active p-group. Change p-group or use an account " + "that belongs to the active group." + ), + # Generic + AuthErrorCode.HTTP_ERROR: ( + "Generic HTTP error wrapper. The server returned an HTTPException that wasn’t mapped to a more specific code." + ), + AuthErrorCode.INTERNAL_SERVER_ERROR: ( + "Unhandled server error. Check server logs for a stack trace and context." + ), + DAQErrorCode.BEAMLINE_BUSY: ( + "Beamline state is set to Busy by prior action. If this state persists an additional error may have occurred, " + "preventing the state from being released, this should timeout within 10 minutes." + "If this occurs please seek assistance from your local contact." + ) +} + +def error_code_help(code: str) -> str | None: + """ + Return a human help message for a code string, if known. + Accepts either enum value strings or raw strings. + """ + if not code: + return None + return _ERROR_CODE_HELP.get(str(code)) + + +def export_error_code_help() -> dict[str, str]: + """ + Export help text as {"CODE": "help text", ...} + """ + return {str(k): str(v) for k, v in _ERROR_CODE_HELP.items()} + +def export_error_codes_grouped() -> dict[str, dict[str, str]]: + """ + Export codes grouped by enum class name: + + { + "AuthErrorCode": {"INVALID_TOKEN": "INVALID_TOKEN", ...}, + "DAQErrorCode": {"BEAMLINE_BUSY": "BEAMLINE_BUSY", ...} + } + """ + enums: tuple[type[StrEnum], ...] = (AuthErrorCode, DAQErrorCode) + return {e.__name__: {c.name: str(c.value) for c in e} for e in enums} + +def export_error_codes() -> dict[str, str]: + """ + Backwards-compatible, flat export used by older clients/tests/docs: + + {"INVALID_TOKEN": "INVALID_TOKEN", ...} + + NOTE: This intentionally exports only AuthErrorCode to avoid breaking + existing consumers that assume a flat map and/or specific keys. + """ + return {c.name: str(c.value) for c in AuthErrorCode} \ No newline at end of file diff --git a/src/aare/common/exception_handler.py b/src/aare/common/exception_handler.py new file mode 100644 index 00000000..7098c362 --- /dev/null +++ b/src/aare/common/exception_handler.py @@ -0,0 +1,190 @@ +from __future__ import annotations + +from aare.common.logger_config import setup_logger +from aare.common.error_codes import AuthErrorCode, DAQErrorCode + +logger = setup_logger("aareDAQ") + +class TransformationInvalidException(Exception): + def __init__(self, message: str = "Transformation is not implemented"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class LoopCenteringFailed(Exception): + def __init__(self, message: str = "Loop Centering did not detect a sample"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class MountingFailed(Exception): + def __init__(self, message: str = "A sample was not mounted"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class WarningTellException(Exception): + def __init__(self, message: str = "Warning error in TELL"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class CriticalTellException(Exception): + def __init__(self, message: str = "Critical error in TELL"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class AXCFailed(Exception): + def __init__(self, message: str = "Auto X-ray centering failed"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class BeamlineBusyException(Exception): + def __init__(self, message: str = "Beamline is in busy state"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class SampleException(Exception): + def __init__(self, message: str = "Sample not found"): + super().__init__(message) + self.message = message + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class AuthenticationException(Exception): + def __init__(self, + message: str = "Authentication failed.", + *, + status_code: int = 401, + headers: dict[str, str] | None = None, + code: AuthErrorCode = AuthErrorCode.AUTHENTICATION_FAILED): + super().__init__(message) + self.message = message + self.status_code = status_code + self.headers = headers + self.code = code + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class UserRightsException(Exception): + def __init__(self, + message: str = "User does not have rights to perform this action.", + *, + status_code: int = 403, + headers: dict[str, str] | None = None, + code: AuthErrorCode = AuthErrorCode.FORBIDDEN): + super().__init__(message) + self.message = message + self.status_code = status_code + self.headers = headers + self.code = code + logger.error(message, extra={"exception:": Exception}) + + def __str__(self) -> str: + return self.message + + +class SmargonCommunicationError(Exception): + """ + Raised when Smargon HTTP communication fails (connection refused, timeout, bad HTTP status, etc). + Keep the original exception in `__cause__` by using `raise ... from e`. + """ + + def __init__( + self, + message: str = "Smargon communication error", + *, + endpoint: str | None = None, + base_url: str | None = None, + operation: str | None = None, # e.g. "GET" / "PUT" + status_code: int | None = None, + ): + super().__init__(message) + self.message = message + self.endpoint = endpoint + self.base_url = base_url + self.operation = operation + self.status_code = status_code + logger.error( + message, + extra={ + "device": "smargon", + "operation": operation, + "endpoint": endpoint, + "base_url": base_url, + "status_code": status_code, + }, + ) + + def __str__(self) -> str: + return self.message + + +class TellCommunicationError(Exception): + """ + Raised when TELL HTTP/PShell communication fails (timeouts, connection refused, etc). + Intended to be caught centrally by FastAPI exception handlers. + """ + + def __init__( + self, + message: str = "TELL communication error", + *, + endpoint: str | None = None, + base_url: str | None = None, + operation: str | None = None, # e.g. "GET" + ): + super().__init__(message) + self.message = message + self.endpoint = endpoint + self.base_url = base_url + self.operation = operation + logger.error( + message, + extra={ + "device": "tell", + "operation": operation, + "endpoint": endpoint, + "base_url": base_url, + }, + ) + + def __str__(self) -> str: + return self.message \ No newline at end of file diff --git a/common/src/aaredaqlib/face_detection.py b/src/aare/common/face_detection.py similarity index 97% rename from common/src/aaredaqlib/face_detection.py rename to src/aare/common/face_detection.py index af36e59d..363977bf 100644 --- a/common/src/aaredaqlib/face_detection.py +++ b/src/aare/common/face_detection.py @@ -1,12 +1,11 @@ import json import time -from typing import Tuple, Dict, List, Iterable, Optional +from typing import Tuple, Dict, List, Optional import numpy as np from scipy.optimize import curve_fit import statistics import math -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import MLBoxModel, MLOutputModel +from aare.common.logger_config import setup_logger logger = setup_logger("aareDAQ") diff --git a/common/src/aaredaqlib/find_xtal.py b/src/aare/common/find_xtal.py similarity index 98% rename from common/src/aaredaqlib/find_xtal.py rename to src/aare/common/find_xtal.py index a3328ac1..23468175 100644 --- a/common/src/aaredaqlib/find_xtal.py +++ b/src/aare/common/find_xtal.py @@ -3,10 +3,9 @@ from typing import List, Optional, Callable import numpy as np from scipy import ndimage -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.models import CrystalSize -from aaredaqlib.raster_grid import RasterGridRequest, CenterOfMassModel -from aaredaqlib.logger_config import setup_logger +from aare.common.models import CrystalSize +from aare.common.raster_grid import RasterGridRequest, CenterOfMassModel +from aare.common.logger_config import setup_logger logger = setup_logger('aareDAQ') diff --git a/common/src/aaredaqlib/logger_config.py b/src/aare/common/logger_config.py similarity index 98% rename from common/src/aaredaqlib/logger_config.py rename to src/aare/common/logger_config.py index 87583343..372d26be 100644 --- a/common/src/aaredaqlib/logger_config.py +++ b/src/aare/common/logger_config.py @@ -63,7 +63,7 @@ def setup_logger(name="aareDAQ", base_dir: str | None = '~/tmp/mxlogs', config_p h["filename"] = abs_filename log_dir = os.path.dirname(abs_filename) if log_dir and not os.path.exists(log_dir): - os.makedirs(log_dir, exist_ok=True) + os.makedirs(log_dir, exist_ok=True) logging.config.dictConfig(config) logging.getLogger("redis_lock").setLevel(logging.WARNING) diff --git a/common/src/aaredaqlib/models.py b/src/aare/common/models.py similarity index 97% rename from common/src/aaredaqlib/models.py rename to src/aare/common/models.py index f11b6ac6..f90ad14d 100644 --- a/common/src/aaredaqlib/models.py +++ b/src/aare/common/models.py @@ -3,16 +3,14 @@ import re from enum import Enum from typing import Annotated, Literal, Tuple, List, Optional -import numpy as np - from pydantic import BaseModel, Field, field_validator, AfterValidator -from aaredaqlib.coordinate import Coordinate, positive_coords -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.coordinate import Coordinate, positive_coords +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.sample_geometry import SampleGeometryModel from jfjoch_client.models.scan_result import ScanResult -from aaredaqlib.beamline import MXBeamline +from aare.common.beamline import MXBeamline class StagePositionEnum(Enum): MEASURE = 0 @@ -651,7 +649,8 @@ def def_loop_centering_zoom(beamline) -> ZoomModel: if beamline == MXBeamline.X06DA: return ZoomModel(z={1: SampleCameraSettings(gain=0, exposure=0.05)}) elif beamline == MXBeamline.X10SA: - return ZoomModel(z={1: SampleCameraSettings(gain=0, exposure=0.05)}) + return ZoomModel(z={1: SampleCameraSettings(gain=0, exposure=0.002), + 280: SampleCameraSettings(gain=0, exposure=0.002)}) elif beamline == MXBeamline.X06SA: return ZoomModel(z={1: SampleCameraSettings(gain=0, exposure=0.05)}) elif beamline == MXBeamline.SIMULATED: @@ -675,8 +674,8 @@ def zoom_manager(mode: ZoomModeEnum = ZoomModeEnum.User, beamline: MXBeamline = class AutofocusSettings(BaseModel): - center_x_pxl: float - center_y_pxl: float + center_x_pxl: float | None # Use beam center + center_y_pxl: float | None # Use beam center radius_pxl: float z_range_um: float z_steps: int @@ -684,7 +683,8 @@ class AutofocusSettings(BaseModel): class BeamlineStatus(BaseModel): name: str ring_current_mA: float - light: Annotated[float, Field(ge=0.0, le=100.0)] + front_light: Annotated[float, Field(ge=0.0, le=100.0)] + back_light: Annotated[float, Field(ge=0.0, le=100.0)] cryojet_K: float shutter_open: bool exp_shutter_open: bool | None @@ -719,6 +719,12 @@ class DAQStatusModel(BaseModel): last_best_b_factor: float | None = None crystal_size: CrystalSize = CrystalSize(x=0,y=0,z=0) + tell_connected: bool = True + tell_error: str | None = None + + smargon_connected: bool = True + smargon_error: str | None = None + class BeamlineSettingsModel(BaseModel): dtz_max: float | None = 1600.0 dtz_min: float | None = 120.0 @@ -731,7 +737,7 @@ class BeamlineSettingsModel(BaseModel): camera_max_magnification: float | None = 1.0 camera_min_magnification: float | None = 500.0 camera_translation_factor_a: float | None = 0.00253 - camera_translation_factor_b: float | None = 255.0 + camera_translation_factor_b: float | None = 512.0 class CryojetSettingsModel(BaseModel): cryojet_park_position: float | None = 12.0 @@ -777,4 +783,7 @@ class ScanResultPayloadModel(BaseModel): sample_id: int attach_image: bool = True beam_mark_pxl: tuple[float, float] - beam_size_mm: Annotated[Coordinate, AfterValidator(positive_coords)] \ No newline at end of file + beam_size_mm: Annotated[Coordinate, AfterValidator(positive_coords)] + +class RecoveryActionRequest(BaseModel): + confirmation_code: str \ No newline at end of file diff --git a/common/src/aaredaqlib/raster_grid.py b/src/aare/common/raster_grid.py similarity index 95% rename from common/src/aaredaqlib/raster_grid.py rename to src/aare/common/raster_grid.py index 05d32d80..7c4327ff 100644 --- a/common/src/aaredaqlib/raster_grid.py +++ b/src/aare/common/raster_grid.py @@ -5,8 +5,8 @@ import numpy as np from jfjoch_client.models.scan_result import ScanResult from pydantic import Field, AfterValidator, BaseModel -from aaredaqlib.coordinate import Coordinate, positive_coords, SmargonCoordinate -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.coordinate import Coordinate, positive_coords, SmargonCoordinate +from aare.common.sample_geometry import SampleGeometryModel class RasterGridRequest(BaseModel): diff --git a/common/src/aaredaqlib/rotation_scan.py b/src/aare/common/rotation_scan.py similarity index 91% rename from common/src/aaredaqlib/rotation_scan.py rename to src/aare/common/rotation_scan.py index 13885d12..471e7a9a 100644 --- a/common/src/aaredaqlib/rotation_scan.py +++ b/src/aare/common/rotation_scan.py @@ -1,7 +1,7 @@ from jfjoch_client.models.scan_result import ScanResult from pydantic import BaseModel -from aaredaqlib.coordinate import SmargonCoordinate +from aare.common.coordinate import SmargonCoordinate class RotationScanRequest(BaseModel): diff --git a/common/src/aaredaqlib/sample_geometry.py b/src/aare/common/sample_geometry.py similarity index 97% rename from common/src/aaredaqlib/sample_geometry.py rename to src/aare/common/sample_geometry.py index 2e27d56b..c9a4a473 100644 --- a/common/src/aaredaqlib/sample_geometry.py +++ b/src/aare/common/sample_geometry.py @@ -3,7 +3,7 @@ from typing import Annotated import numpy as np from pydantic import BaseModel, Field, AfterValidator -from aaredaqlib.coordinate import Coordinate, SmargonCoordinate, positive_coords +from aare.common.coordinate import Coordinate, SmargonCoordinate, positive_coords class SampleGeometryModel(BaseModel): diff --git a/gui/src/aaregui/__init__.py b/src/aare/daq/__init__.py similarity index 100% rename from gui/src/aaregui/__init__.py rename to src/aare/daq/__init__.py diff --git a/daq/src/aaredaq/aaredb.py b/src/aare/daq/aaredb.py similarity index 92% rename from daq/src/aaredaq/aaredb.py rename to src/aare/daq/aaredb.py index d432e180..e165f7b1 100644 --- a/daq/src/aaredaq/aaredb.py +++ b/src/aare/daq/aaredb.py @@ -4,11 +4,11 @@ import json import os from typing import List, Optional -import aareDBclient +import aareDB import cv2 import numpy as np import requests -from aareDBclient import ( +from aareDB import ( SetTellPosition, SampleEventCreate, SampleEventType, @@ -21,21 +21,18 @@ from aareDBclient import ( BeamlineParametersInput, ExperimentParametersCreate) -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import ( +from aare.common.coordinate import Coordinate +from aare.common.logger_config import setup_logger +from aare.common.models import ( SampleShortInfo, PuckLoadedInfo, - DewarAddress, - SampleShortInfoList, - DAQStatusModel, SessionStatus, ScanResultPayloadModel, + DAQStatusModel, ScanResultPayloadModel, ) -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.raster_grid import RasterGridRequest, RasterPayloadModel, CenterOfMassModel -from aaredaqlib.rotation_scan import RotationScanRequest -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.beamline import MXBeamline +from aare.common.raster_grid import RasterGridRequest, RasterPayloadModel, CenterOfMassModel +from aare.common.rotation_scan import RotationScanRequest +from aare.common.sample_geometry import SampleGeometryModel from jfjoch_client.models import ScanResult @@ -47,16 +44,16 @@ class AareWrapper: bl: MXBeamline, host: str = "https://mx-db-01.psi.ch/dispatcher", ): - configuration = aareDBclient.Configuration(host=host) + configuration = aareDB.Configuration(host=host) configuration.verify_ssl = False # Disable SSL verification - self.client = aareDBclient.ApiClient(configuration) + self.client = aareDB.ApiClient(configuration) self.client.default_headers["X-Shared-Password"] = os.getenv("AAREDB_SHARED_PASSWORD") self.__host = host - self.__tell_api = aareDBclient.TellsRunnerApi(self.client) - self.__sample_api = aareDBclient.SamplesRunnerApi(self.client) - self.__proc_api = aareDBclient.ProcessingsRunnerApi(self.client) - self.__raster_api = aareDBclient.GridscanRunnerApi(self.client) + self.__tell_api = aareDB.TellsRunnerApi(self.client) + self.__sample_api = aareDB.SamplesRunnerApi(self.client) + self.__proc_api = aareDB.ProcessingsRunnerApi(self.client) + self.__raster_api = aareDB.GridscanRunnerApi(self.client) self.__bl = bl def set_pucks_beamline(self, input_list: List[PuckLoadedInfo]): @@ -76,7 +73,7 @@ class AareWrapper: print(ret) def create_manual_sample(self, s: SampleShortInfo): - from aareDBclient.models import ManualSampleCreate + from aareDB.models import ManualSampleCreate manual_sample = ManualSampleCreate( pgroup=s.user, @@ -188,7 +185,7 @@ class AareWrapper: except Exception as e: logger.error(f"Error sending message to db: {e}") - def upload_image(self, sample_id: int, filename: str, bgr_image: np.ndarray): + def upload_image(self, sample_id: int, filename: str, bgr_image: np.ndarray, message: str | None = None): _, buffer = cv2.imencode('.jpg', bgr_image) jpeg_bytes = io.BytesIO(buffer) url = f"{self.__host}/protected_router/sample_runner/{sample_id}/upload-images" @@ -196,9 +193,16 @@ class AareWrapper: "accept": "application/json", "X-Shared-Password": os.getenv("AAREDB_SHARED_PASSWORD") } - response = requests.post(url, - files={'uploaded_file': (filename + ".jpg", jpeg_bytes, "image/jpeg")}, - verify=False, headers=headers) + + request_kwargs = { + "files": {'uploaded_file': (filename + ".jpg", jpeg_bytes, "image/jpeg")}, + "verify": False, + "headers": headers, + } + if message is not None: + request_kwargs["data"] = {"comment": message} + + response = requests.post(url, **request_kwargs) logger.debug(f"Response status code: {response.status_code}") def upload_jpg(self, sample_id: int, filename: str, jpg_image): diff --git a/daq/src/aaredaq/auth.py b/src/aare/daq/auth.py similarity index 72% rename from daq/src/aaredaq/auth.py rename to src/aare/daq/auth.py index e293f9ae..3af7f247 100644 --- a/daq/src/aaredaq/auth.py +++ b/src/aare/daq/auth.py @@ -9,7 +9,9 @@ from fastapi import HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from pydantic import BaseModel -from aaredaq.config import BeamlineConfig +from aare.daq.config import BeamlineConfig + +from aare.common.exception_handler import AuthenticationException, UserRightsException, AuthErrorCode if os.environ.get("JWT_AAREDAQ_KEY") is None: raise Exception("JWT_AAREDAQ_KEY environment variable not set, cannot guarantee safe authentication.") @@ -58,20 +60,21 @@ def parse_token(token: str) -> TokenData: token = TokenData(**payload) return token except jwt.PyJWTError as e: - print(f"JWT error {e}") - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid token", - ) + raise AuthenticationException( + message="Invalid token", + status_code=401, + headers={"WWW-Authenticate": "Bearer"}, + code=AuthErrorCode.INVALID_TOKEN, + ) from e def check_jwt_ro(cfg: BeamlineConfig, data: TokenData) -> None: active_pgroup = cfg.pgroup if not data.staff and (active_pgroup is None or active_pgroup not in data.pgroups): - print("Not member of a currently active p-group.") - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not member of a currently active p-group.", + raise UserRightsException( + message="Not member of a currently active p-group.", + status_code=403, + code=AuthErrorCode.NOT_IN_ACTIVE_PGROUP, ) @@ -81,30 +84,32 @@ def check_jwt_rw(cfg: BeamlineConfig, data: TokenData) -> None: try: cfg.try_set_active_session(data.session, SESSION_EXPIRE_SECONDS) except Exception as e: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Another session is active.", + raise AuthenticationException( + message="Another session is active.", + status_code=401, headers={"WWW-Authenticate": "Bearer"}, - ) + code=AuthErrorCode.SESSION_ALREADY_ACTIVE, + ) from e +def check_jwt_staff_only(data: TokenData) -> None: + if not data.staff: + raise UserRightsException( + message="Not member of the MX staff.", + status_code=403, + code=AuthErrorCode.NOT_STAFF, + ) def check_jwt_staff(cfg: BeamlineConfig, data: TokenData) -> None: - if not data.staff: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not member of the MX staff.", - headers={"WWW-Authenticate": "Bearer"}, - ) - + check_jwt_staff_only(data) try: cfg.try_set_active_session(data.session, SESSION_EXPIRE_SECONDS) except Exception as e: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Another session is active.", + raise AuthenticationException( + message="Another session is active.", + status_code=401, headers={"WWW-Authenticate": "Bearer"}, - ) - + code=AuthErrorCode.SESSION_ALREADY_ACTIVE, + ) from e def force_current_sesion(cfg: BeamlineConfig, data: TokenData) -> None: cfg.force_set_active_session(data.session, SESSION_EXPIRE_SECONDS) diff --git a/daq/src/aaredaq/autofocus.py b/src/aare/daq/autofocus.py similarity index 100% rename from daq/src/aaredaq/autofocus.py rename to src/aare/daq/autofocus.py diff --git a/daq/src/aaredaq/beamcenterfit.py b/src/aare/daq/beamcenterfit.py similarity index 100% rename from daq/src/aaredaq/beamcenterfit.py rename to src/aare/daq/beamcenterfit.py diff --git a/daq/src/aaredaq/config.py b/src/aare/daq/config.py similarity index 93% rename from daq/src/aaredaq/config.py rename to src/aare/daq/config.py index 8ca1743e..61196563 100644 --- a/daq/src/aaredaq/config.py +++ b/src/aare/daq/config.py @@ -6,8 +6,8 @@ from typing import Tuple, List import numpy as np import redis import redis_lock -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.models import ( +from aare.common.coordinate import Coordinate +from aare.common.models import ( BeamlineSettingsModel, BeamMarkCoeffModel, ZoomModeEnum, @@ -18,11 +18,13 @@ from aaredaqlib.models import ( FluorescenceSpectrumOutputModel, CrystalSize, SimpleStrategyInputModel, SimpleScanParameters ) -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.logger_config import setup_logger +from aare.common.beamline import MXBeamline +from aare.common.logger_config import setup_logger + +from aare.common.exception_handler import BeamlineBusyException ABR_POS_ALIGN_DEF = Coordinate(x=-18, y=-0.266, z=0) -ABR_POS_MOUNT = Coordinate(x=-18, y=0, z=0) +ABR_POS_MOUNT = Coordinate(x=0, y=0, z=0)#Coordinate(x=-18, y=0, z=0) ABR_OMEGA_MOUNT = 0.0 logger = setup_logger("aareDAQ") @@ -47,10 +49,6 @@ def base64_to_numpy(encoded_str: str | None) -> np.ndarray | None: return np.load(buffer) # Load buffer as a NumPy array -class BeamlineBusyException(Exception): - pass - - class BeamlineConfig: """ Manages the configuration and state of a beamline system by interacting with a Redis @@ -84,10 +82,23 @@ class BeamlineConfig: @property def active_session(self) -> int | None: - tmp = self.__client.get(f"{self.__bl}:active_session") - if tmp is None: + """ + Read active_session from Redis and convert to int. + + Returns: + int if present and valid, otherwise None. + """ + raw = self.__client.get(f"{self.__bl}:active_session") + if raw is None: + return None + try: + return int(raw) + except (TypeError, ValueError): + logger.warning( + "Invalid active_session value in redis; treating as missing", + extra={"beamline": self.__bl, "raw": raw}, + ) return None - return int(tmp) def session_status(self, session: int) -> SessionStatus: return SessionStatus(session=self.session_state(session), @@ -104,12 +115,12 @@ class BeamlineConfig: def try_set_active_session(self, session: int, expiry_sec: int) -> None: with redis_lock.Lock( - self.__client, f"{self.__bl}:active_session_lock", expire=10 + self.__client, f"{self.__bl}:active_session_lock", expire=10 ): - tmp = self.__client.get(f"{self.__bl}:active_session") - if tmp is None: + active = self.active_session + if active is None: self.__client.set(f"{self.__bl}:active_session", session) - elif int(tmp) != session: + elif active != session: raise Exception( "There is already active session with different id. Try again later." ) @@ -118,26 +129,28 @@ class BeamlineConfig: #TODO finish setting this up! def try_extend_active_session(self, session: int, expiry_sec: int) -> None: with redis_lock.Lock( - self.__client, f"{self.__bl}:active_session_lock", expire=10 + self.__client, f"{self.__bl}:active_session_lock", expire=10 ): - tmp = self.__client.get(f"{self.__bl}:active_session") - if tmp == session: - self.__client.expire(f"{self.__bl}:active_session", expiry_sec, gt=True) - elif int(tmp) != session: - raise Exception( - "There is already active session with different id. Try again later." - ) - else: + active = self.active_session + if active is None: raise Exception( "There is no active session with given id. Try again later." ) - + if active == session: + self.__client.expire(f"{self.__bl}:active_session", expiry_sec, gt=True) + else: + raise Exception( + "There is already active session with different id. Try again later." + ) def end_active_session(self, session: int) -> None: with redis_lock.Lock( self.__client, f"{self.__bl}:active_session_lock", expire=10 ): - if int(self.__client.get(f"{self.__bl}:active_session")) == session: + active = self.active_session + if active is None: + return + if active == session: self.__client.delete(f"{self.__bl}:active_session") def force_set_active_session(self, session: int, expiry_sec: int) -> None: @@ -554,12 +567,6 @@ class BeamlineConfig: else: self.__client.set(f"{self.__bl}:last_best_b_factor", last_best_b_factor) - - - @crystal_size.setter - def crystal_size(self, xtal_size: CrystalSize): - self.__client.set(f"{self.__bl}:crystal_size", xtal_size.model_dump_json()) - @property def simple_input_parameters(self) -> SimpleStrategyInputModel | None: tmp = self.__client.get(f"{self.__bl}:simple_input_params") @@ -600,7 +607,14 @@ class BeamlineConfig: tmp = self.__client.get(f"{self.__bl}:failed_mount_count") if tmp is None: return 0 - return tmp + try: + return int(tmp) + except (TypeError, ValueError): + logger.warning( + "Failed Mount Count is not an integer, resetting to 0.", + extra={"beamline": self.__bl, "tmp": tmp}, + ) + return 0 @failed_mount_count.setter def failed_mount_count(self, count:int): diff --git a/daq/src/aaredaq/daq.py b/src/aare/daq/daq.py similarity index 56% rename from daq/src/aaredaq/daq.py rename to src/aare/daq/daq.py index 7e53518f..9a72ec0e 100644 --- a/daq/src/aaredaq/daq.py +++ b/src/aare/daq/daq.py @@ -1,98 +1,54 @@ -import copy -import json + import secrets import time +import traceback + from datetime import datetime from math import ceil -from typing import List, Tuple, Optional +from pathlib import Path +from typing import List, Tuple, Optional, Callable import cv2 import numpy as np -import redis -import aaredaqlib.face_detection as fd -from aaredaq import workflows -from aaredaq.aaredb import AareWrapper -from aaredaq.autofocus import calculate_focus_measure -from aaredaq.config import BeamlineConfig, ABR_POS_MOUNT -from aaredaq.config import BeamlineStateEnum -from aaredaq.devices import BeamlineDevices -from aaredaq.mlbox import MlBox -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.coordinate import Coordinate, SmargonCoordinate -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.find_xtal import raster_centre_of_mass, create_quality_filtered_array, identify_crystal_raster, \ - get_result_list_from_com, get_best_b_factor, get_best_res, get_xtal_size, has_sufficient_low_res_spots -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import ( + +import aare.common.face_detection as fd +from aare.daq import workflows +from aare.daq.aaredb import AareWrapper +from aare.common.autofocus_tools import focus_measure_edges +from aare.daq.config import BeamlineConfig, ABR_POS_MOUNT, ABR_OMEGA_MOUNT +from aare.daq.config import BeamlineStateEnum +from aare.daq.devices import BeamlineDevices +from aare.daq.mlbox import MlBox +from aare.common.beamline import MXBeamline +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.logger_config import setup_logger +from aare.common.models import ( SampleShortInfo, PuckLoadedInfo, - SampleShortInfoList, - DAQStatusModel, BeamlineStatus, SessionStatus, SampleCameraSettings, AutofocusSettings, ZoomModeEnum, CrystalSize, + SampleShortInfoList, AutofocusSettings, + DAQStatusModel, BeamlineStatus, SessionStatus, SampleCameraSettings, ZoomModeEnum, SimpleScanParameters, MLBoxModel, FluorescenceSpectrumParameterModel, FluorescenceSpectrumOutputModel) -from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem -from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan -from aaredaqlib.sample_geometry import SampleGeometryModel -from mxlibs3.jfjoch import JFJochWrapper +from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem +from aare.common.rotation_scan import RotationScanRequest, CompletedRotationScan +from aare.common.sample_geometry import SampleGeometryModel +from aare.devices.area_detector import AutoEnum +from aare.devices.jfjoch import JFJochWrapper +from aare.devices.mx_lib import clean_filename + +from aare.common.exception_handler import ( + TransformationInvalidException, + LoopCenteringFailed, + MountingFailed, + WarningTellException, + CriticalTellException, + AXCFailed, SmargonCommunicationError, TellCommunicationError, +) logger = setup_logger("aareDAQ") -class TransformationInvalidException(Exception): - def __init__(self, message="Transformation is not implemented"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:" : Exception}) - - def __str__(self): - return self.message - - -class LoopCenteringFailed(Exception): - def __init__(self, message="Loop Centering did not detect a sample"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:" : Exception}) - - def __str__(self): - return self.message - -class MountingFailed(Exception): - def __init__(self, message="A sample was not mounted"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:" : Exception}) - - def __str__(self): - return self.message - -class WarningTellException(Exception): - def __init__(self, message="Warning error in TELL"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:": Exception}) - - def __str__(self): - return self.message - -class CriticalTellException(Exception): - def __init__(self, message="Critical error in TELL"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:": Exception}) - - def __str__(self): - return self.message - -class AXCFailed(Exception): - def __init__(self, message="Auto X-ray centering failed"): - super().__init__(message) - self.message = message - logger.error(f"{message}", extra={"exception:": Exception}) - - def __str__(self): - return self.message - class AareDAQ: MIN_SPOTS_LOW_RES_THRESHOLD = 10.0 @@ -101,11 +57,133 @@ class AareDAQ: self.last_time = 0.0 self.__cfg = cfg self.__devs = BeamlineDevices(bl) - self.__mlbox = MlBox() + self.__mlbox = MlBox(bl) self.__jfjoch = JFJochWrapper(bl) self.__bl = bl.value.upper() self.__aare = AareWrapper(bl) self.__saved_box = None + self._smargon_trace_path = Path("logs") / "smargon_trace.csv" + self._face_detection_progress_cb: Callable[[dict], None] | None = None + self._last_sample_sync_ts = 0.0 + self._sample_sync_min_interval_s = 2.0 + + def set_face_detection_progress_callback(self, cb: Callable[[dict], None] | None) -> None: + self._face_detection_progress_cb = cb + + def _emit_face_detection_progress(self, payload: dict) -> None: + if self._face_detection_progress_cb is None: + return + try: + self._face_detection_progress_cb(payload) + except Exception as e: + logger.warning(f"Failed to emit face detection progress: {e}") + + def _append_smargon_trace(self, *, sample_id: int | None, event: str) -> None: + try: + path = self._smargon_trace_path + path.parent.mkdir(parents=True, exist_ok=True) + + is_new_file = not path.exists() or path.stat().st_size == 0 + pos = self.smargon + sh = pos.sh_mm + + with path.open("a", encoding="utf-8", buffering=1) as f: + if is_new_file: + f.write( + "timestamp,event,sample_id,omega_deg,zoom," + "shx_mm,shy_mm,shz_mm,phi_deg,chi_deg\n" + ) + + f.write( + f"{datetime.now().isoformat(timespec='milliseconds')}," + f"{event}," + f"{'' if sample_id is None else sample_id}," + f"{self.omega:.3f}," + f"{self.zoom:.3f}," + f"{sh.x:.5f}," + f"{sh.y:.5f}," + f"{sh.z:.5f}," + f"{pos.phi_deg:.5f}," + f"{pos.chi_deg:.5f}\n" + ) + f.flush() + + except Exception as e: + logger.warning(f"Failed to append smargon trace: {e}") + + def _sample_matches_mounted_address( + self, + sample: SampleShortInfo | None, + mounted_address, + ) -> bool: + if sample is None or sample.location is None or mounted_address is None: + return False + return ( + sample.location.segment == mounted_address.puck.segment + and sample.location.pos == mounted_address.puck.pos + and sample.pin == mounted_address.pin + ) + + def _find_sample_by_mounted_address(self, mounted_address) -> SampleShortInfo | None: + for sample in self.__cfg.spreadsheet.s: + if self._sample_matches_mounted_address(sample, mounted_address): + return sample + + for sample in self.__cfg.reference_tools.s: + if self._sample_matches_mounted_address(sample, mounted_address): + return sample + + return None + + def _placeholder_sample_from_mounted_address(self, mounted_address) -> SampleShortInfo: + return SampleShortInfo( + db_id=-1, + puck_name="", + dewar_name="", + sample_name=f"Mounted sample {mounted_address.puck.segment}{mounted_address.puck.pos}-{mounted_address.pin}", + run_number=0, + user="", + pin=mounted_address.pin, + location=mounted_address.puck, + ) + + def sync_current_sample_from_tell(self, force: bool = False) -> SampleShortInfo | None: + current_sample = self.__cfg.current_sample + + if current_sample is not None and current_sample.location is None: + return current_sample + + now = time.monotonic() + if not force and (now - self._last_sample_sync_ts) < self._sample_sync_min_interval_s: + return current_sample + + self._last_sample_sync_ts = now + mounted_address = self.__devs.tell.get_mounted_sample() + + if mounted_address is None: + if current_sample is not None and current_sample.location is not None: + logger.warning("TELL reports no mounted sample; clearing cached current_sample") + self.__cfg.current_sample = None + return self.__cfg.current_sample + + if self._sample_matches_mounted_address(current_sample, mounted_address): + return current_sample + + resolved_sample = self._find_sample_by_mounted_address(mounted_address) + if resolved_sample is None: + resolved_sample = self._placeholder_sample_from_mounted_address(mounted_address) + logger.warning( + "Mounted sample from TELL was not found in known sample lists; using placeholder", + extra={"mounted_address": str(mounted_address)}, + ) + else: + logger.info( + f"Reconciled cached sample from TELL to {resolved_sample.sample_name}", + extra={"db_id": resolved_sample.db_id}, + ) + + self.__cfg.current_sample = resolved_sample + return resolved_sample @property def state(self) -> BeamlineStateEnum: @@ -196,15 +274,14 @@ class AareDAQ: @property def omega(self) -> float: - return self.__devs.aerotech.omega + return self.__devs.aerotech_omega - @omega.setter - def omega(self, val: float): - self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) + def __omega(self, val: float): self.__saved_box = None + print(f"Set omega to {val}") if -2000 < val < 2000: try: - self.__devs.aerotech.move(val, wait=True, speed=180.0, direct=True) + self.__devs.aerotech_omega = val self.__cfg.state_busy = False except Exception as e: logger.error(f"Omega error: {e}") @@ -215,6 +292,16 @@ class AareDAQ: logger.error("Omega has to be between -2000 and 2000 degrees") raise ValueError("Omega has to be between -2000 and 2000 degrees (for now)") + @omega.setter + def omega(self, val: float): + self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) + self.__omega(val) + + def omega_rel(self, val: float): + self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) + curr_omega = self.__devs.aerotech_omega + self.__omega(curr_omega + val) + @property def zoom(self) -> float: return self.__devs.zoom @@ -222,19 +309,13 @@ class AareDAQ: @zoom.setter def zoom(self, val: float): self.__saved_box = None + self.__devs.samcam_auto(AutoEnum.AUTO) self.__devs.zoom = val - print(f"{self.__cfg.state}") - if self.__cfg.state == BeamlineStateEnum.BeamLocation: - self.__cfg.zoom_mode = ZoomModeEnum.BeamLocation - else: - self.__cfg.zoom_mode = ZoomModeEnum.User - zoom_settings = self.__cfg.zoom_settings.get_camera_settings(val) - print(f"Setting zoom {val} {zoom_settings}") - self.samcam_settings = zoom_settings - #elf.__cfg.state_busy = False + time.sleep(0.2) + self.__devs.samcam_auto(AutoEnum.ONCE) @property - def light(self) -> float: + def front_light(self) -> float: val = self.__devs.lamp_light if val <= 1.0: return 0 @@ -243,18 +324,30 @@ class AareDAQ: else: return (val - 1.0) / 1.5 * 100.0 - @light.setter - def light(self, f: float): + @front_light.setter + def front_light(self, f: float): conv = (f / 100.0 * 1.5) + 1.0 print(f"Light {f} -> {conv}") self.__devs.lamp_light = conv + @property + def back_light(self) -> float: + val = self.__devs.back_light + if val <= 0.0: + return 0.0 + elif val <= 3.0: + return val / 3.0 * 100.0 + else: + return 100.0 + + @back_light.setter + def back_light(self, f: float): + conv = f / 100.0 * 3.0 + print(f"Backlight {f} -> {conv}") + self.__devs.back_light = conv + @property def sample(self) -> SampleShortInfo | None: - if self.__cfg.current_sample is not None and self.__cfg.current_sample.location is None: - return self.__cfg.current_sample - if self.__devs.tell.get_mounted_sample() is None: - return None return self.__cfg.current_sample @property @@ -265,34 +358,12 @@ class AareDAQ: def samcam_settings(self, s: SampleCameraSettings): self.__devs.samcam_settings = s - def autofocus(self, f: AutofocusSettings): - pos = self.__cfg.abr_meas_pos - - z_min = pos.z - f.z_range_um / 2.0 - z_max = pos.z + f.z_range_um / 2.0 - - measures = [] - - for i in range(f.z_steps): - pos.z = z_min + i * (z_max - z_min) / f.z_steps - self.__devs.abr_pos = pos - self.__devs.sample_cam.get_single_image() - image = self.__devs.sample_cam.get_image(gray=True) - val = calculate_focus_measure(image, f.center_x_pxl, f.center_y_pxl, f.radius_pxl) - measures.append((pos.z, val)) - best_pos, _ = max(measures, key=lambda x: x[1]) - - pos.z = best_pos - self.__devs.abr_pos = pos - self.__cfg.abr_meas_pos = pos - self.__devs.sample_cam.collect_auto() - def tweak_abr_meas_pos(self, c: Coordinate): self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) try: new_meas_pos = self.__cfg.abr_meas_pos + c self.__cfg.abr_meas_pos = new_meas_pos - self.__devs.abr_pos = new_meas_pos + self.__devs.aerotech_pos = new_meas_pos self.__saved_box = None self.__cfg.state_busy = False except: @@ -302,7 +373,7 @@ class AareDAQ: def save_abr_meas_pos(self): self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) try: - self.__cfg.abr_meas_pos = self.__devs.abr_pos + self.__cfg.abr_meas_pos = self.__devs.aerotech_pos self.__cfg.state_busy = False except: self.__cfg.state_busy = False @@ -311,7 +382,7 @@ class AareDAQ: def goto_abr_meas_pos(self): self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) try: - self.__devs.abr_pos = self.__cfg.abr_meas_pos + self.__devs.aerotech_pos = self.__cfg.abr_meas_pos self.__cfg.state_busy = False except: self.__cfg.state_busy = False @@ -335,198 +406,232 @@ class AareDAQ: raise def __mount_failure_handler(self, mount_error): - failed = self.__cfg.increment_failed_mount_count() - if failed >=4: - #TODO move park does not dry, need to change this!!! - self.__devs.tell.dry(wait=False, wait_cold=-1) - raise CriticalTellException(f"Repeated drying failure, moved to park" - f"\nThere either really is no sample or " - f"a critical failure.\nPlease check the dewar and if a sample, " - f"please contact the MX team") - elif failed >=3: - self.__devs.tell.dry(wait=False, wait_cold=-1) - raise WarningTellException(f"Continued to not find a sample, drying robot in park for 10 minutes. " - f"\n Please get a cup of coffee.\nAfter the robot has dried, " - f"check the sample positions that have been missed, if no samples continue!" - f"\nOtherwise there may be a critical error so please let your local " - f"contact for support") - elif failed == 2: - self.__devs.tell.dry(wait=False) - raise MountingFailed(f"Drying gripper: repeated error: {mount_error}") - else: - raise MountingFailed(f"{mount_error}") + pass def __mount(self, target: SampleShortInfo | None): - self.__set_state(BeamlineStateEnum.RobotSampleExchange) - self.__saved_box = None - logger.info("Moving smargon to home") - self.__devs.smargon.move_home(wait=True) - logger.info("moving aerotech to mount position") - self.__devs.abr_pos = ABR_POS_MOUNT - time.sleep(0.1) - logger.info("checking beamstop") - if self.__devs.bsz.value < 24.0: - raise Exception("Beamstop Z below 24.0 mm - potentially unsafe with mounting") - logger.info(f"Checking magnet postion sensor positon: {self.__devs.magnet_position_sensor_readout.value}") - logger.info(f"Checking smargon position: {self.__devs.smargon.readback}") - logger.info(f"Checking abr position: {self.__devs.abr_pos}") - if self.__devs.magnet_position_sensor.value != 0: - time.sleep(1) - logger.warning("!!!!!!!!!!!!!!!!!!!!!MAGNET CONTROLLER BROKE AGAIN!!!!!!!!!!!!!!!!!!") - logger.debug(f"Checking magnet position sensor positon: {self.__devs.magnet_position_sensor_readout.value}") - logger.debug(f"Checking smargon position: {self.__devs.smargon.readback}") - logger.debug(f"Checking abr position: {self.__devs.abr_pos}") - if self.__devs.magnet_position_sensor.value != 0: - start = time.time() - end = start + 360 - while self.__devs.magnet_position_sensor.value != 0: - time.sleep(1) - logger.debug(f"Checking magnet position sensor positon: {self.__devs.magnet_position_sensor_readout.value}") - logger.debug(f"Checking smargon position: {self.__devs.smargon.readback}") - logger.debug(f"Checking abr position: {self.__devs.abr_pos}") - if time.time() > end: - raise Exception(f"Magnet position sensor is not in position: {self.__devs.magnet_position_sensor_readout.value}") - - #Reenable TELL after doors locked - logger.info("enable tell motion after doors locked") + self.__devs.smargon_move_home() + self.__devs.aerotech_pos = ABR_POS_MOUNT + self.__devs.aerotech_omega = ABR_OMEGA_MOUNT + #collimator should be down!!! self.__devs.tell.check_enable_motion() - logger.info("Waiting for tell to be ready") - self.__devs.tell.wait_ready() - self.__devs.tell.wait_mount_complete() - - logger.debug("Moving tell to mount position") + self.__devs.tell.wait_not_busy() self.__devs.tell.set_in_mount_position(True) - curr_sample = self.__cfg.current_sample - - if curr_sample is not None and curr_sample.location is None: - logger.info(f"Unmounting current sample") - # TODO: Smarter way to know manual sample has be removed from goniometer - self.__aare.sample_unmounted(curr_sample) - self.__cfg.current_sample = None - elif target is None: - logger.info(f"Moving tell to unmount with no target") - self.__devs.tell.unmount(wait=True, timeout=360) - self.__aare.sample_unmounted(curr_sample) + if target is None: + self.__devs.tell.unmount(wait=True, timeout=60.0) self.__cfg.current_sample = None else: - # reset zoom - self.zoom = 1 - # mount sample - self.__aare.sample_unmounted(curr_sample) - logger.info(f"Moving tell to mount") - value = self.__devs.tell.mount( - address=target.tell_address(), - force=True, - auto_unmount=True, - read_dm=False, - wait=True, - timeout=360, - ) - logger.debug(f"Post tell mount, pre db input") - if value is not None: - if value == "No Pin in Gripper": - mount_error = "No sample was detected in gripper" - logger.error(mount_error) - self.__aare.sample_failed(target, failed_comment = mount_error) - self.__mount_failure_handler(mount_error=mount_error) - self.__cfg.current_sample = None - logger.debug(f"setting current sample to None as previous unmount succeeded but mount failed") - raise MountingFailed(f"{mount_error}: drying gripper {target.sample_name} {target.location} {target.pin}") - elif value == "dry": - logger.info("Robot is drying") - else: - logger.info(f"Event detected from robot: {value}") - - mounted = self.__devs.tell.get_mounted_sample() - logger.info(f"response from tell {mounted}") - if not mounted: - mount_error = "Failed to mount target" - logger.error(f"{mount_error}: {target.db_id} {target.location} {target.pin}") - self.__aare.sample_failed(target, failed_comment = mount_error) - #self.__mount_failure_handler(mount_error=mount_error) - self.__cfg.current_sample = None - logger.debug(f"setting current sample to None but not sure if unmount succeeded") - raise MountingFailed(f"No Sample detected on smart magent: {target.sample_name} {target.location} {target.pin}") - - if target is not None: - self.__aare.sample_mounted(target) - logger.info(f"Target mounted: {target.db_id} {target.location} {target.pin}") - self.__cfg.failed_mount_count = 0 - self.save_screenshot_db(target.db_id, f"sample_mounted") - else: - self.__cfg.failed_mount_count = 0 - logger.info(f"Target is None: {target}") + value = self.__devs.tell.mount(address=target.tell_address(), force=True, auto_unmount=True, read_dm=False, + wait=True, timeout=360.0) + logger.info(f"Mount result: {value}") self.__cfg.current_sample = target + #self.__mount_failure_handler(value) - - # TODO: Need to know if dry needs to happen + def recovery_unmount_sample(self) -> None: + self.__cfg.try_set_busy(timeout=360) + try: + self.__set_state(BeamlineStateEnum.RobotSampleExchange) + self.__devs.tell.check_enable_motion() + self.__devs.tell.wait_not_busy() + self.__devs.tell.set_in_mount_position(True) + self.__devs.tell.unmount(wait=True, timeout=360.0) + self.__cfg.current_sample = None + self.__set_state(BeamlineStateEnum.SampleAlignment) + self.__cfg.state_busy = False + except Exception: + self.__cfg.state_busy = False + raise @sample.setter def sample(self, target: SampleShortInfo | None): - # This will set internally state to SampleExchange, but will return to SampleAlignment - # before exiting - self.__cfg.try_set_busy(timeout=360) - + curr_sample_is_manual=False try: curr_sample = self.__cfg.current_sample - curr_sample_is_manual = False - logger.info(f"current sample: {curr_sample}") - logger.info(f"new target is: {target}") - self.__cfg.crystal_size = CrystalSize(x=0, y=0, z=0) - self.__cfg.last_best_b_factor = None - self.__cfg.last_best_res = None - self.__cfg.xrf = None - - if curr_sample is not None and curr_sample.location is None: - self.__cfg.current_sample = None - curr_sample_is_manual = True - - if target is not None or not curr_sample_is_manual: - self.__mount(target) - if target is not None and target.db_id is not None: - #self.__aare.sample_mounted(self.__cfg.current_sample) - logger.info(f"post_mount_{target.db_id}_{self.__devs.zoom}") - self.save_screenshot_db(target.db_id , f"post_mount_{target.db_id }_{self.__devs.zoom}") + workflows.common_2rse(devs=self.__devs, cfg=self.__cfg) + #if curr_sample is not None and curr_sample.location is None: + # self.__cfg.current_sample = None + # curr_sample_is_manual = True + #if target is not None or not curr_sample_is_manual: + logger.debug(target) + self.__mount(target) + logger.info(f"Sample mounted: {target}") except Exception as e: self.__cfg.state_busy = False - # If unmount succeeded, but mount failed - mounted_sample = self.__devs.tell.get_mounted_sample() - #TODO check the following error logic - # if target is not None: - # print(f"TELL: Error mounting, TELL believes current sample is {mounted_sample}, while expected {target.location}") - if mounted_sample is None: - logger.error("TELL: After mounting there is no sample on gonio according to TELL") - self.__cfg.current_sample = None - if target is not None: - raise e - elif target is not None and (target.location is not None - and mounted_sample.puck.pos == target.location.pos - and mounted_sample.puck.segment == target.location.segment - and mounted_sample.pin == target.pin): - logger.info("TELL: Actually mounting was correct according to TELL, so setting current sample to target") - self.__cfg.current_sample = target - else: - raise e - - self.__set_state(BeamlineStateEnum.SampleAlignment) + logger.debug(f"Failed to mount sample: {e}") + self.__aare.sample_failed(target, f"Mount failed due to {e}") + raise e + workflows.rse2sa(devs=self.__devs, cfg=self.__cfg) self.__cfg.state_busy = False + if target is not None: + if target.db_id is not None: + self.__aare.sample_mounted(target) + self.save_screenshot_db(target.db_id, f"{target.db_id}_mounted") - #if target is not None and target.location is not None: - # self.__loop_center_sequence(target.db_id) @property def camera_image(self) -> np.ndarray | None: - image = self.__devs.sample_cam.get_image(gray=False) + image = self.__devs.samcam_get_image(gray=False) return image @property def camera_image_gray(self) -> np.ndarray | None: - image = self.__devs.sample_cam.get_image(gray=True) + image = self.__devs.samcam_get_image(gray=True) return image def list_loaded_pucks(self) -> List[PuckLoadedInfo]: - return self.__devs.tell.get_detected_pucks() + return [] + + def __auto_focus(self, settings: AutofocusSettings, settle_time_s: float = 1.0) -> float: + """ + Scan smargon Z and find the position with maximum focus measure. + + Args: + settings: AutofocusSettings with center, radius, range, and steps + settle_time_s: Time to wait after each move before capturing image + + Returns: + Best Z position (mm) found during the scan + """ + geom = self.sample_geometry + current_smargon = self.__devs.smargon_pos + + # Get center for the mask (use beam center if not specified) + center_x = geom.beam_location_pxl.x + center_y = geom.beam_location_pxl.y + radius_pxl = 30 + + # Convert z_range from um to mm + z_range_mm = settings.z_range_um / 1000.0 + n_steps = settings.z_steps + + # Starting Z position (current sh_mm) + z_start = 0.0 + z_min = z_start - z_range_mm / 2.0 + z_max = z_start + z_range_mm / 2.0 + z_step = z_range_mm / (n_steps - 1) if n_steps > 1 else 0.0 + + # Pre-compute mask (will be created on first image) + focus_mask: np.ndarray | None = None + + # Collect focus measures at each Z position + z_positions: list[float] = [] + focus_values: list[float] = [] + + print(f"Starting autofocus: z_range={z_range_mm * 1000:.1f}um, steps={n_steps}, " + f"center=({center_x:.1f}, {center_y:.1f}), radius={radius_pxl:.1f}px") + + + for i in range(n_steps): + z_pos = z_min + i * z_step + + # Move to position + target = SmargonCoordinate( + chi_deg=current_smargon.chi_deg, + phi_deg=current_smargon.phi_deg, + sh_mm=geom.beamline_to_smargon(Coordinate(z=z_pos)) + ) + self.__devs.smargon_pos = target + self.__devs.smargon_wait(timeout=30) + + # Wait for mechanical settling and image stabilization + time.sleep(settle_time_s) + + # Capture image + gray = self.camera_image_gray + + if gray is None: + logger.warning(f"Failed to get image at z={z_pos:.4f}") + continue + + # Create mask on first valid image + if focus_mask is None or focus_mask.shape != gray.shape: + h, w = gray.shape + y, x = np.ogrid[:h, :w] + focus_mask = (x - center_x) ** 2 + (y - center_y) ** 2 <= radius_pxl ** 2 + + print(focus_mask.shape) + print(gray.shape) + + # Calculate focus measure + fm = focus_measure_edges(gray, focus_mask) + + z_positions.append(z_pos) + focus_values.append(fm) + logger.debug(f"Autofocus step {i + 1}/{n_steps}: z={z_pos:.4f}mm, focus={fm:.2f}") + print(f"Autofocus step {i + 1}/{n_steps}: z={z_pos:.4f}mm, focus={fm:.2f}") + if len(z_positions) < 3: + logger.error("Autofocus failed: not enough valid measurements") + # Return to original position + self.__devs.smargon_pos = current_smargon + self.__devs.smargon_wait(timeout=30) + return z_start + + # Find best position - use parabolic fit around the peak for sub-step precision + z_arr = np.array(z_positions) + fm_arr = np.array(focus_values) + + # Find index of maximum + peak_idx = int(np.argmax(fm_arr)) + + # Try parabolic fit if peak is not at the edge + if 0 < peak_idx < len(fm_arr) - 1: + # Fit parabola to 3 points around peak: f(z) = a*z^2 + b*z + c + z_fit = z_arr[peak_idx - 1: peak_idx + 2] + fm_fit = fm_arr[peak_idx - 1: peak_idx + 2] + try: + coeffs = np.polyfit(z_fit, fm_fit, 2) + a, b, c = coeffs + if a < 0: # Parabola opens downward (valid peak) + best_z = -b / (2 * a) + # Sanity check: best_z should be within the fitted range + if z_fit[0] <= best_z <= z_fit[2]: + logger.info(f"Autofocus: parabolic fit found peak at z={best_z:.4f}mm") + else: + best_z = z_arr[peak_idx] + logger.info(f"Autofocus: parabolic fit out of range, using sample peak z={best_z:.4f}mm") + else: + best_z = z_arr[peak_idx] + logger.info(f"Autofocus: invalid parabola, using sample peak z={best_z:.4f}mm") + except Exception as e: + logger.warning(f"Parabolic fit failed: {e}, using sample peak") + best_z = z_arr[peak_idx] + else: + best_z = z_arr[peak_idx] + logger.warning(f"Autofocus: peak at edge of scan range, z={best_z:.4f}mm") + + # Move to best position + best_target = SmargonCoordinate( + chi_deg=current_smargon.chi_deg, + phi_deg=current_smargon.phi_deg, + sh_mm=geom.beamline_to_smargon(Coordinate(z=best_z)), + ) + self.__devs.smargon_pos = best_target + self.__devs.smargon_wait(timeout=30) + + logger.warning(f"Autofocus complete: best_z={best_z:.4f}mm, " + f"focus_range=[{min(fm_arr):.2f}, {max(fm_arr):.2f}]") + + return best_z + + def auto_focus(self, settings: AutofocusSettings) -> float: + """ + Public autofocus method. Only allowed in SampleAlignment state. + + Args: + settings: AutofocusSettings with center, radius, range, and steps + + Returns: + Best Z position (mm) found during the scan + """ + self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) + try: + best_z = self.__auto_focus(settings) + self.__cfg.state_busy = False + return best_z + except Exception as e: + logger.error(f"Autofocus failed: {e}") + self.__cfg.state_busy = False + raise def __auto_center(self, grid: RasterGridRequest) -> CompletedRasterGrid | None: @@ -540,7 +645,7 @@ class AareDAQ: r = self.__ml_bounding_box(sample.db_id, f"ml_{geom.omega_deg:.2f}deg") if r is None: - self.__devs.aerotech.move(geom.omega_deg + 90.0, wait=True) + self.__devs.aerotech_omega = geom.omega_deg + 90.0 time.sleep(0.2) r = self.__ml_bounding_box(sample.db_id, f"ml_{geom.omega_deg + 90.0:.2f}deg") @@ -554,7 +659,7 @@ class AareDAQ: grid.omega_deg = geom.omega_deg res1 = self.__raster(grid) grid.omega_deg += 90 - self.__devs.aerotech.move(grid.omega_deg, wait=True) + self.__devs.aerotech_omega = grid.omega_deg grid.n_x = 1 #TODO generate y scan rather than had code for 1x50 @@ -572,119 +677,29 @@ class AareDAQ: return None - def __raster(self, r: RasterGridRequest) -> CompletedRasterGridElem: - #TODO more sensible max_time adding, for large gridscans may fail. - max_time = r.exp_time_s * r.n_y * r.n_x + 60 - - if r.dtz is not None: - self.__cfg.dtz = r.dtz - + def __raster(self, r: RasterGridRequest):# -> CompletedRasterGridElem: + max_time = r.exp_time_s * r.n_x * r.n_y + 60 + row_time = r.exp_time_s * r.n_x + row_width_mm = r.grid_size_mm.x * r.n_x self.__set_state(BeamlineStateEnum.DataCollection) - - save_smargon_position = self.__devs.smargon.readback + save_smargon_position = self.__devs.smargon_pos if r.smargon_top_left is not None: delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=r.grid_size_mm.x / 2, y=r.grid_size_mm.y / 2)) - - self.__devs.smargon.target = SmargonCoordinate(sh_mm=r.smargon_top_left.sh_mm + delta_mm, + self.__devs.set_smargon_pos(SmargonCoordinate(sh_mm=r.smargon_top_left.sh_mm + delta_mm, phi_deg=r.smargon_top_left.phi_deg, - chi_deg=r.smargon_top_left.chi_deg) - if r.transmission is not None: - self.__devs.transmission.set(r.transmission, wait=False) - self.__devs.aerotech.move(r.omega_deg, wait=True, speed=360.0) - self.__devs.transmission.wait() - self.__devs.smargon.wait() - + chi_deg=r.smargon_top_left.chi_deg)) + self.__devs.aerotech_omega = r.omega_deg + self.__devs.smargon_wait(timeout=180) status = self.status - logger.info(f"raster status: {status}") - logger.info(f"raster grid request: {r}") - self.__jfjoch.measure_raster(r, status) - self.__aare.create_gridscan_run(self.sample, r, status) - - if self.sample is not None and self.sample.db_id is not None: - self.save_screenshot_db(self.sample.db_id, "before_raster") - - if r.n_x == 1: - self.__devs.aerotech.measure_vertical_line(r.exp_time_s, r.grid_size_mm.y, r.n_y) - else: - self.__devs.aerotech.measure_raster_simple( - r.exp_time_s, r.grid_size_mm.x, r.grid_size_mm.y, r.n_x, r.n_y - ) - self.__devs.aerotech.wait_scan_done(max_time) - self.__devs.aerotech.reset() - self.__devs.abr_pos = self.__cfg.abr_meas_pos - result = self.__jfjoch.wait_till_done(60) - - images = result.images - - result_array = create_quality_filtered_array(images, - 'spots_low_res', min_spots=None, - min_efficiency=1.0, min_background=None, - min_low_res_spots=None) - - #if not has_sufficient_low_res_spots(result_array, self.MIN_SPOTS_LOW_RES_THRESHOLD): - # logger.error("Auto X-ray centering failed: insufficient low-resolution spots " - # f"(threshold={self.MIN_SPOTS_LOW_RES_THRESHOLD})") - # self.__aare.ingest_gridscan(sample=self.sample, raster_result=result, - # raster_request=r, geom=self.sample_geometry, - # com=None, beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom)) - # raise AXCFailed("Auto X-ray centering failed: insufficient low-resolution spots") - - self.__cfg.crystal_size = get_xtal_size(self.__cfg.crystal_size, result_array, r) - com = raster_centre_of_mass(result_array, images) - if com is None: - logger.debug(f"using old method as COM is disabled") - com = identify_crystal_raster(result, r) - if com: - com_mm = com.get_com_mm(r) - grid_mm_x = com_mm.x - grid_mm_y = com_mm.y - else: - grid_mm_x = None - grid_mm_y = None - - if grid_mm_x or grid_mm_y: - - new_delta_mm = self.sample_geometry.smargon_nudge(Coordinate(x=grid_mm_x, y=grid_mm_y)) - - if r.n_x != 1: - result_list = get_result_list_from_com(images, com) - self.__cfg.last_best_b_factor = get_best_b_factor(result_list) - self.__cfg.last_best_res = get_best_res(result_list) - logger.debug(f"b_factor: {self.__cfg.last_best_b_factor}, best_res: {self.__cfg.last_best_res}") - - else: - new_delta_mm = None - - if new_delta_mm is not None: - if r.smargon_top_left: - new_target = r.smargon_top_left - else: - new_target = save_smargon_position - - logger.debug(f'moving SMARGON to target new delta mm {new_target.sh_mm + new_delta_mm} mm') - self.__devs.smargon.target = SmargonCoordinate(sh_mm=new_target.sh_mm + new_delta_mm, - phi_deg=new_target.phi_deg, - chi_deg=new_target.chi_deg) - else: - logger.error("Auto finding optimal image failed. Using previous position.") - self.__devs.smargon.target = save_smargon_position - - if self.sample is not None and self.sample.db_id is not None and result is not None: - self.__devs.reflector_up = True - time.sleep(0.1) - self.save_screenshot_db(self.sample.db_id, f"post_raster_{r.omega_deg}deg") - if com and hasattr(com, "max_image"): - diffraction_image_filename = f"{self.sample.db_id}_best_diffraction_from_raster_image_{com.max_image}" - diffraction_image = self.__jfjoch.get_diffraction_image(com.max_image) - self.__aare.upload_jpg(self.sample.db_id, diffraction_image_filename, diffraction_image) - try: - self.__aare.ingest_gridscan(sample = self.sample, raster_result =result, - raster_request = r, geom = self.sample_geometry, - com = com, beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom)) - except Exception as e: - logger.error(f"Exception ingesting grid scan: {e}") - self.__devs.reflector_up = False - return CompletedRasterGridElem(request=copy.deepcopy(r), result=result, centre_of_mass=com) + print(f"raster status {status}") + print(f'raster grid request: {r}') + #self.__jfjoch.measure_raster(r, status) + self.__devs.aerotech.run_grid_scan(cell_height_mm=r.grid_size_mm.y, num_rows=r.n_x, + row_width_mm=row_width_mm, time_per_row_s=row_time, task_id=3) + self.__devs.aerotech_pos = self.__cfg.abr_meas_pos + #result = self.__jfjoch.wait_till_done(60) + return None + #return CompletedRasterGridElem(request=copy.deepcopy(r), result=, centre_of_mass=None) def measure_raster(self, r: RasterGridRequest, auto: bool) -> CompletedRasterGrid: self.__cfg.try_set_busy(timeout=ceil(360)) @@ -693,10 +708,11 @@ class AareDAQ: result = self.__auto_center(r) else: raster_result = self.__raster(r) - result = CompletedRasterGrid(r=[raster_result]) + #result = CompletedRasterGrid(r=[raster_result]) self.__set_state(BeamlineStateEnum.SampleAlignment) self.__cfg.state_busy = False - return result + return CompletedRasterGrid(r=[]) + #return result except Exception as e: try: self.__aare.axc_failed(self.sample) @@ -707,76 +723,7 @@ class AareDAQ: raise e def __rotation(self, request: RotationScanRequest) -> CompletedRotationScan: - if request.dtz is not None: - logger.info(f'requesting dtz to move to {request.dtz}') - self.__cfg.dtz = request.dtz - if self.sample is not None and self.sample.db_id is not None: - self.save_screenshot_db(self.sample.db_id, f"pre_rotation{self.sample.db_id}_{self.__devs.zoom}") - self.__set_state(BeamlineStateEnum.DataCollection) - - if request.transmission is not None: - logger.info(f'requesting transmission to move to {request.transmission}') - self.__devs.transmission.set(request.transmission, wait=False) - - if request.start is not None: - self.__devs.smargon.target = request.start - - omega_start = self.omega - - self.__devs.transmission.wait() - if request.start is not None: - self.__devs.smargon.wait() - - status = self.status - self.__jfjoch.measure_rotation(request, status, self.__cfg.xrf) - self.__aare.create_rotation_run(self.sample, request, status) - - if self.sample is not None and self.sample.db_id is not None: - self.save_screenshot_db(self.sample.db_id, "before_dc") - - if request.screening: - self.__devs.aerotech.measure_screening(request.start_omega_deg, - request.wedge_omega_deg, - request.exp_time_s, - request.incr_omega_deg, - request.steps) - self.__devs.aerotech.wait_scan_done(request.exp_time_s * request.steps + 60) - else: - - total_omega = request.incr_omega_deg * request.steps - total_time = request.exp_time_s * request.steps - - self.__devs.aerotech.measure_standard( - request.start_omega_deg, total_omega, total_time - ) - - if request.start is not None and request.end is not None: - smargon_time_step = request.time_sec / float(request.steps) - pos_step = (request.end.sh_mm - request.start.sh_mm) * (1.0 / float(request.steps)) - - for i in range(request.steps): - self.__devs.smargon.target = SmargonCoordinate( - sh_mm=request.start.sh_mm + pos_step * i - ) - time.sleep(smargon_time_step) - - self.__devs.aerotech.wait_scan_done(total_time + 60) - - self.__devs.aerotech.reset() - self.__devs.aerotech.move(omega_start, wait=False, speed=180.0, direct=True) - result = self.__jfjoch.wait_till_done(60) - self.__aare.sample_collected(self.sample) - self.__devs.aerotech.move(omega_start, wait=True, speed=180.0, direct=True) - - if self.sample is not None and self.sample.db_id is not None: - self.save_screenshot_db(self.sample.db_id, "after_dc") - try: - self.__aare.ingest_scan(sample=self.sample, result=result, - geom=self.sample_geometry, beam_mark_pxl=self.__cfg.get_beam_mark(self.zoom)) - - except Exception as e: - logger.error(f"Exception ingesting scan: {e}") - return CompletedRotationScan(request=copy.deepcopy(request), result=result) + return None def measure_rotation(self, request: RotationScanRequest) -> CompletedRotationScan: total_time = request.exp_time_s * request.steps @@ -806,14 +753,13 @@ class AareDAQ: exposure = zoom_settings[zoom_value].exposure gain = zoom_settings[zoom_value].gain self.__devs.samcam_settings = SampleCameraSettings(exposure=exposure, gain=gain) - self.__devs.zoom_sync(zoom_value) + self.__devs.set_zoom(zoom_value, wait=True) time.sleep(5.0) # Wait for settings to stabilize - image = self.__devs.sample_cam.get_image(gray=False) + image = self.__devs.samcam_get_image(gray=False) self.__cfg.put_alc_bkg(zoom_value, exposure, gain, image) bgr_array = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) cv2.imwrite(f"bkg{zoom_value:.0f}_{exposure*1000:.0f}_{gain:.0f}.jpg", bgr_array) self.__cfg.state_busy = False - self.__devs.sample_cam.set_auto() except Exception as e: self.__cfg.state_busy = False raise e @@ -839,21 +785,21 @@ class AareDAQ: self.__cfg.state_busy = False raise RuntimeError("Cannot set dtz during data collection") elif state == BeamlineStateEnum.SampleAlignment: - self.__devs.dtz.move(val, wait=False) + self.__devs.set_dtz(val, wait=False) self.__cfg.dtz = val self.__cfg.state_busy = False @property def smargon(self) -> SmargonCoordinate: - return self.__devs.smargon.readback + return self.__devs.smargon_pos @smargon.setter def smargon(self, sc: SmargonCoordinate): self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) try: self.__saved_box = None - self.__devs.smargon.target = sc - self.__devs.smargon.wait() + self.__devs.smargon_pos = sc + self.__devs.smargon_wait() self.__cfg.state_busy = False except Exception as e: self.__cfg.state_busy = False @@ -877,48 +823,18 @@ class AareDAQ: @property def sample_geometry(self) -> SampleGeometryModel: zoom = self.__devs.zoom - abr_pos = self.__cfg.abr_meas_pos - try: - aerotech_coord = Coordinate( - x=self.__devs.gmx.value - abr_pos.x, - y=self.__devs.gmy.value - abr_pos.y, - z=self.__devs.gmz.value - abr_pos.z, - ) - sample_geom = SampleGeometryModel( - beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom), - pixel_in_mm=self.__cfg.pixel_to_mm(zoom), - omega_deg=self.__devs.aerotech.omega, - smargon=self.__devs.smargon.readback, - beam_size_mm=self.__cfg.beam_size_mm, - aerotech=aerotech_coord, - aerotech_meas=self.__devs.abr_pos - ) - return sample_geom - - except Exception as e: - - try: - test_x = self.__devs.gmx.value - abr_pos.x - print(f"Error creating sample geometry model: {e}") - print(f"Error not ABR, check smargon then restart server") - raise Exception(f"Error getting sample geometry {e}") - - except: - print(f"Error getting sample geometry: {e}") - print(f"!!!!! ABR MAY HAVE DISCONNECTED !!!!!") - print(f"!!!!! CHECK ABR EPICS PANEL FOR ERRORS!!!!!") - print("!!!!! IF NOT RESTART GUI !!!!!") - print("CLOSING EXPERIMENTAL HUCTH FOR SAFETY") - self.__devs.exp_shutter.close() - return SampleGeometryModel( - beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom), - pixel_in_mm=self.__cfg.pixel_to_mm(zoom), - omega_deg=self.__devs.aerotech.omega, - smargon=self.__devs.smargon.readback, - beam_size_mm=self.__cfg.beam_size_mm, - aerotech=Coordinate(x=0.0, y=0.0, z=0.0), - aerotech_meas=self.__devs.abr_pos - ) + aerotech_pos_ref = self.__cfg.abr_meas_pos + aerotech_pos = self.__devs.aerotech_pos + sample_geom = SampleGeometryModel( + beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom), + pixel_in_mm=self.__cfg.pixel_to_mm(zoom), + omega_deg=self.__devs.aerotech_omega, + smargon=self.__devs.smargon_pos, + beam_size_mm=self.__cfg.beam_size_mm, + aerotech=aerotech_pos - aerotech_pos_ref, + aerotech_meas=aerotech_pos + ) + return sample_geom @property def beam_center(self) -> Tuple[float, float]: @@ -939,9 +855,6 @@ class AareDAQ: def get_beam_mark(self): return self.__cfg.get_beam_mark(self.__devs.zoom) - def listen_changes(self) -> redis.client.PubSub: - return self.__cfg.listen_changes() - def __ml_bounding_box(self, sample_id: int | None = None, filename: str | None = None) -> RasterGridRequest | None: time.sleep(0.2) # Just to be sure image is stable #curr_image = self.camera_image @@ -1065,10 +978,12 @@ class AareDAQ: except Exception as e: logger.error(f"error in face detection sequence {e}") result = { - "samples": None, - "height_fit": None, - "area_fit": None, + "running": False, + "samples": [], + "height_fit": {}, + "area_fit": {}, } + self._emit_face_detection_progress(result) self.__cfg.state_busy = False return result @@ -1086,8 +1001,8 @@ class AareDAQ: if beam_y !=0 and abs(centre_y-beam_y)/abs(beam_y) > tolerance: coord = geom.picture_to_smargon(Coordinate(x=beam_x, y=centre_y)) - self.__devs.smargon.target = SmargonCoordinate(sh_mm=coord) - self.__devs.smargon.wait(60) + self.__devs.smargon = SmargonCoordinate(sh_mm=coord) + self.__devs.smargon_wait(60) return @@ -1100,13 +1015,10 @@ class AareDAQ: zoom_value = self.__devs.zoom logger.info('face detection sequence') - self.__devs.samcam_settings = SampleCameraSettings( - exposure=zoom_settings[zoom_value].exposure, - gain=zoom_settings[zoom_value].gain) - self.__devs.zoom_sync(zoom_value) + self.__devs.set_zoom(zoom_value, wait=True) boxes: dict[int, tuple[float, float, float, float]] = {} - curr_angle = int(self.__devs.aerotech.omega) + curr_angle = int(self.__devs.aerotech_omega) total_range = steps * step_size + 1 start_angle = curr_angle if curr_angle + total_range < 720 else 0 end_angle = curr_angle + total_range @@ -1114,16 +1026,23 @@ class AareDAQ: for angle in range(start_angle, end_angle, step_size): logger.debug(f'moving to angle: {angle}') rotate_time = time.perf_counter() - self.__devs.aerotech.move(angle, wait=True) + self.__devs.aerotech_omega = angle logger.info(f"time to rotate 15 degrees: {time.perf_counter() - rotate_time}") curr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR) box_time = time.perf_counter() - m = self.__mlbox.predict(curr_image, filename=None, preferred_class = (3,0)) + m = self.__mlbox.predict(curr_image, filename=None, preferred_class=(3, 0)) logger.info(f"time to predict: {time.perf_counter() - box_time}") if not m or not m.box: logger.info(f"no box found for angle {angle}") + self._emit_face_detection_progress({ + "running": True, + "current_angle_deg": angle, + "samples": fd.get_samples_out(boxes), + "height_fit": {}, + "area_fit": {}, + }) continue cls_id = int(m.cls.value) @@ -1137,42 +1056,60 @@ class AareDAQ: else: logger.debug(f"ignoring class {cls_id} (pin/crystal) at angle {angle}") - if not boxes: - logger.info("no boxes found") - return {"samples": None, "height_fit": None, "area_fit": None} + self._emit_face_detection_progress({ + "running": True, + "current_angle_deg": angle, + "samples": fd.get_samples_out(boxes), + "height_fit": {}, + "area_fit": {}, + }) + + if not boxes: + logger.info("no boxes found") + result = {"running": False, "samples": [], "height_fit": {}, "area_fit": {}} + self._emit_face_detection_progress(result) + return result best_fit_angle_area, area_params = fd.get_flat_face(boxes, start_angle, end_angle, True) best_fit_angle_height, height_params = fd.get_flat_face(boxes, start_angle, end_angle, False) - fit_results = {"Area":{"angle":best_fit_angle_area, "params":area_params}, "Height": {"angle":best_fit_angle_height, "params":height_params}} + fit_results = { + "Area": {"angle": best_fit_angle_area, "params": area_params}, + "Height": {"angle": best_fit_angle_height, "params": height_params}, + } logger.info(f"best angle by area: {best_fit_angle_area}") logger.info(f"best angle by height: {best_fit_angle_height}") flat_face_angle, best_params, best_name = fd.choose_best_fit(fit_results) logger.info(f"best params: {best_params}") logger.info(f"chosen fit: {best_name}") logger.info(f"best angle: {flat_face_angle}") - self.__devs.aerotech.move(flat_face_angle, wait=True) + self.__devs.aerotech_omega = flat_face_angle samples_out = fd.get_samples_out(boxes) logger.info(f"face detection sequence done, samples: {samples_out}") - return { + result = { + "running": False, "samples": samples_out, - "height_fit": {"A": height_params["A"], - "B": height_params["B"], - "phi_rad": height_params["phi_rad"], - "C": height_params["C"], - "best_angle_deg": best_fit_angle_height + "height_fit": { + "A": height_params["A"], + "B": height_params["B"], + "phi_rad": height_params["phi_rad"], + "C": height_params["C"], + "best_angle_deg": best_fit_angle_height, }, - "area_fit": {"A": area_params["A"], - "B": area_params["B"], - "phi_rad": area_params["phi_rad"], - "C": height_params["C"], - "best_angle_deg": best_fit_angle_area + "area_fit": { + "A": area_params["A"], + "B": area_params["B"], + "phi_rad": area_params["phi_rad"], + "C": area_params["C"], + "best_angle_deg": best_fit_angle_area, }, } + self._emit_face_detection_progress(result) + return result - def __loop_center_sequence(self, sample_id: int | None = None) -> bool: + def __loop_center_sequence(self, sample_id: int | None = None, trace_all_alc_moves: bool = False) -> bool: self.__set_state(BeamlineStateEnum.SampleAlignment) self.__devs.lamp_light = 2.5 @@ -1180,24 +1117,24 @@ class AareDAQ: try: self.__cfg.zoom_mode = ZoomModeEnum.LoopCenter - zoom_settings = self.__cfg.zoom_settings.z + #zoom_settings = self.__cfg.zoom_settings.z - for zoom_iter, zoom_value in enumerate(zoom_settings): - exposure = zoom_settings[zoom_value].exposure - gain = zoom_settings[zoom_value].gain + for zoom_iter, zoom_value in enumerate([200]): + #exposure = zoom_settings[zoom_value].exposure + #gain = zoom_settings[zoom_value].gain max_attempt = 2 attempt = 0 - base_angles = (0, 45, 90) if (zoom_iter % 2 == 0) else (90, 45, 0) + base_angles = (0, 90) if (zoom_iter % 2 == 0) else (90, 0) if sample_id is not None: + logger.info(f"submitting to db loop center sequence for sample {sample_id}, zoom={zoom_value}") self.save_screenshot_db(sample_id, f"pre_alc") while attempt < max_attempt: - self.__devs.samcam_settings = SampleCameraSettings(exposure=exposure, gain=gain) - exp = int(exposure * 1000) - gn = int(gain) - self.__devs.zoom_sync(zoom_value) - logger.debug(f'zoom={zoom_value},gain={gn}, exp={exp}ms') + #self.__devs.samcam_settings = SampleCameraSettings(exposure=exposure, gain=gain) + #exp = int(exposure * 1000) + #gn = int(gain) + self.zoom = zoom_value found_flag = False found_angle: int | None = None @@ -1206,10 +1143,10 @@ class AareDAQ: for angle in base_angles: logger.debug(f"Moving to new omega: {angle}") time_to_move_aerotech= time.perf_counter() - self.__devs.aerotech.move(angle, wait=True) + self.__devs.aerotech_omega = angle logger.info(f"time to move: {time.perf_counter()-time_to_move_aerotech}") - filename = f"{sample_id}_{angle}_{zoom_value:.0f}_{exp}_{gn}" if sample_id is not None else None + filename = f"{sample_id}_{angle}_{zoom_value:.0f}" if sample_id is not None else None try: target, cls, classes = self.__ml_loop_centre_box(sample_id, filename) @@ -1233,9 +1170,16 @@ class AareDAQ: found_angle = angle time_to_move_smargon = time.perf_counter() - self.__devs.smargon.target = target - self.__devs.smargon.wait(60) + self.__devs.smargon_pos = target + self.__devs.smargon_wait(60) logger.info(f"time to move smargon: {time.perf_counter() - time_to_move_smargon}") + if sample_id is not None: + if trace_all_alc_moves: + self._append_smargon_trace( + sample_id=sample_id, + event=f"alc_move_zoom_{zoom_value:.0f}_angle_{angle}" + ) + self.save_screenshot_db(sample_id, f"{sample_id}_{angle}_{zoom_value:.0f}") if targets_found_this_attempt == 0: logger.error(f"No targets found in this attempt {attempt}") @@ -1247,7 +1191,7 @@ class AareDAQ: break if found_flag is not None and found_angle is not None: logger.debug(f"found a target at angle {found_angle} in attempt {attempt + 1}") - base_angles = (found_angle, found_angle + 45, found_angle + 90) + base_angles = (found_angle, found_angle + 45) logger.debug(f"new base angles: {base_angles}") attempt += 1 logger.debug(f"attempt {attempt} of {max_attempt}") @@ -1259,7 +1203,9 @@ class AareDAQ: logger.debug("alc success") self.__aare.sample_centered(self.__cfg.current_sample) if sample_id is not None: + logger.info(f"sample {sample_id} centered") self.save_screenshot_db(sample_id, f"{sample_id}_centered") + self._append_smargon_trace(sample_id=sample_id, event="alc_success") return True except Exception as e: @@ -1283,29 +1229,45 @@ class AareDAQ: f"Loop_face: {found_classes_count.get(3,0)}, " f"Loop_all: {found_classes_count.get(0,0)}, " f"Pin: {found_classes_count.get(1,0)}") - logger.info(f"Error in loop centering: {e}") + logger.error(traceback.format_exc()) + + logger.error(f"Error in loop centering: {e}") return False def auto_loop_center(self, sample_id: int | None = None) -> float: start = time.perf_counter() try: self.__cfg.try_set_busy(timeout=360) + if sample_id is None: + sample_id = self.__cfg.current_sample.db_id if not self.__loop_center_sequence(sample_id): raise LoopCenteringFailed self.__cfg.state_busy = False except Exception: self.__cfg.zoom_mode = ZoomModeEnum.User - self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) + #self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) self.__cfg.state_busy = False raise self.__cfg.zoom_mode = ZoomModeEnum.User - self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) + #self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) end = time.perf_counter() return end - start + def _default_screenshot_message(self, sample_id: int) -> str: + omega_value = self.omega + zoom_value = self.zoom + samcam = self.samcam_settings + return ( + f"sample_id: {sample_id} " + f"zoom: {zoom_value} " + f"exp:{samcam.exposure} " + f"gain:{samcam.gain} " + f"omega:{omega_value:.2f}" + ) + def save_screenshot(self, filename: str): #time.sleep(0.2) # Wait 200 ms to ensure camera image is stable bgr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR) @@ -1316,6 +1278,31 @@ class AareDAQ: bgr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR) self.__aare.upload_image(sample_id, filename, bgr_image) + def send_screenshot_db(self, filename: str | None = None, message: str | None = None) -> None: + sample = self.sample + if sample is None or sample.db_id is None or sample.db_id < 0: + raise ValueError("No sample with a valid sample_id is mounted.") + + sample_id = sample.db_id + bgr_image = cv2.cvtColor(self.camera_image, cv2.COLOR_RGB2BGR) + + if filename: + filename = clean_filename(filename) + pgroup = self.__cfg.pgroup + if not pgroup: + raise ValueError("No active pgroup set; cannot save screenshot to photos directory.") + + photos_dir = Path("/sls/mx/data") / pgroup / "raw" / "photos" + photos_dir = photos_dir / str(sample_id) + photos_dir.mkdir(parents=True, exist_ok=True) + photo_path = photos_dir / f"{filename}.jpeg" + cv2.imwrite(str(photo_path), bgr_image) + + upload_name = filename or f"{sample_id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}" + final_message = (message or "").strip() or self._default_screenshot_message(sample_id) + self.__aare.upload_image(sample_id, upload_name, bgr_image, message=final_message) + + @property def sample_spreadsheet(self) -> SampleShortInfoList: return self.__cfg.spreadsheet @@ -1405,7 +1392,6 @@ class AareDAQ: return default_params, "defaults" - def measure(self, sample: SampleShortInfo) -> float: start = time.perf_counter() formatted_date = datetime.now().strftime('%Y%m%d') @@ -1424,7 +1410,12 @@ class AareDAQ: start_mount=time.perf_counter() logger.info(f"starting mount {sample.db_id} at {time.ctime()}") self.__mount(sample) + if sample.db_id is not None: + self.__aare.sample_mounted(sample) + self.save_screenshot_db(sample.db_id, f"{sample.db_id}_mounted") logger.info(f"mounting done at {time.perf_counter() - start_mount}, total time: {time.perf_counter() - start}") + #self.__devs.smargon_pos + #self.__devs.aerotech_pos = alc_time = time.perf_counter() - start logger.info(f"starting alc at {alc_time}") if not self.__loop_center_sequence(sample.db_id): @@ -1435,51 +1426,52 @@ class AareDAQ: return end - start #raise LoopCenteringFailed logger.info(f"alc done at {time.perf_counter() - start}") - self.__face_detection_sequence() + + result = self.__face_detection_sequence(steps=7, step_size=30) + self._emit_face_detection_progress(result) logger.info(f"face_detection done at {time.perf_counter() - start}") - self.zoom = 500 + #self.zoom = 500 hex_string = secrets.token_hex(3) # 3 bytes = 6 hex characters print(hex_string.upper()) - raster_params = self.get_auto_raster_params() - if self.__auto_center(RasterGridRequest( - exp_time_s=raster_params.exp_time_s, - file_prefix=sample_prefix + f"_{hex_string}", - smargon_top_left= SmargonCoordinate(), - n_x=1, - n_y=1, - dtz=raster_params.dtz, - grid_size_mm=Coordinate(x=geom.beam_size_mm.x * 0.5, y=geom.beam_size_mm.y * 0.5), - omega_deg=self.omega, - transmission = raster_params.transmission, - )): - logger.info(f"raster scans done at {time.perf_counter() - start}") - params, source = self.get_collection_params(prefer_smart=False) - logger.info(f"Using {source} for data collection: {params}") - - self.__cfg.zoom_mode = ZoomModeEnum.User - self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) - self.__devs.dtz.move(params.dtz, wait=True) - if self.omega + 180 < 720: - start_omega = self.omega - else: - start_omega = params.start_omega_deg - self.__rotation( RotationScanRequest(start_omega_deg=start_omega, - dtz=params.dtz, - file_prefix="data/" + sample_prefix + f"_{hex_string}", - exp_time_s=params.exp_time_s, - incr_omega_deg=params.incr_omega_deg, - steps=params.steps, - transmission=params.transmission, - )) - logger.info(f"rotation done at {time.perf_counter() - start}") - else: - logger.error("auto center failed") - self.__aare.axc_failed(sample) + # raster_params = self.get_auto_raster_params() + # if self.__auto_center(RasterGridRequest( + # exp_time_s=raster_params.exp_time_s, + # file_prefix=sample_prefix + f"_{hex_string}", + # smargon_top_left= SmargonCoordinate(), + # n_x=1, + # n_y=1, + # dtz=raster_params.dtz, + # grid_size_mm=Coordinate(x=geom.beam_size_mm.x * 0.5, y=geom.beam_size_mm.y * 0.5), + # omega_deg=self.omega, + # transmission = raster_params.transmission, + # )): + # logger.info(f"raster scans done at {time.perf_counter() - start}") + # params, source = self.get_collection_params(prefer_smart=False) + # logger.info(f"Using {source} for data collection: {params}") + # + # self.__cfg.zoom_mode = ZoomModeEnum.User + # self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) + # self.__devs.dtz = params.dtz + # if self.omega + 180 < 720: + # start_omega = self.omega + # else: + # start_omega = params.start_omega_deg + # # self.__rotation( RotationScanRequest(start_omega_deg=start_omega, + # # dtz=params.dtz, + # # file_prefix="data/" + sample_prefix + f"_{hex_string}", + # # exp_time_s=params.exp_time_s, + # # incr_omega_deg=params.incr_omega_deg, + # # steps=params.steps, + # # transmission=params.transmission, + # # )) + # logger.info(f"rotation done at {time.perf_counter() - start}") + # else: + # logger.error("auto center failed") + # self.__aare.axc_failed(sample) self.zoom = 1 self.__cfg.zoom_mode = ZoomModeEnum.User - self.__devs.samcam_settings = self.__cfg.zoom_settings.get_camera_settings(self.zoom) self.__cfg.state_busy = False except Exception as e: logger.error(f"Error in measure: {e}") @@ -1496,17 +1488,17 @@ class AareDAQ: return end - start def __set_state(self, target: BeamlineStateEnum): - # __set_state assumes that beamline is already in busy state - # it will apply a proper transformation and change state afterward - # specifically: - # 1. If target state is maintenance, just go there - # 2. If target state is same as current, nothing will happen - # 3. If target state cannot be reached, exception is raised and current state is kept - # 4. If exception is raised during transformation, state is set to maintenance - # 5. If transformation goes OK, target state is set - # - # Busy state will be cleared only, if exception is raised. - # + """__set_state assumes that beamline is already in busy state + it will apply a proper transformation and change state afterward + specifically: + 1. If target state is maintenance, just go there + 2. If target state is same as current, nothing will happen + 3. If target state cannot be reached, exception is raised and current state is kept + 4. If exception is raised during transformation, state is set to maintenance + 5. If transformation goes OK, target state is set + + Busy state will be cleared only, if exception is raised. """ + curr_state = self.__cfg.state if not self.__cfg.state_busy: @@ -1599,7 +1591,7 @@ class AareDAQ: det_cfg = self.__jfjoch.detector() return DiffractionGeometry( energy_keV=self.__devs.energy_kev, - dtz_mm=self.__devs.dtz.value, + dtz_mm=self.__devs.dtz, detector_size_pxl=(det_cfg.width, det_cfg.height), pixel_size_mm=det_cfg.pixel_size_mm, beam_center_pxl=self.__cfg.beam_center, @@ -1613,40 +1605,137 @@ class AareDAQ: def beamline_status(self) -> BeamlineStatus: return BeamlineStatus( ring_current_mA=self.__devs.ring_current, - light=self.light, + front_light=self.front_light, + back_light=self.back_light, cryojet_K=self.__devs.cryojet_temp, shutter_open=self.__devs.shutter, - exp_shutter_open=self.__devs.exp_shutter.state(), + exp_shutter_open=self.__devs.shutter, flux_ph_s=self.__devs.full_flux, sample_camera=self.__devs.samcam_settings, name=self.__bl, - transmission=self.__devs.transmission.get(), + transmission=self.__devs.transmission, zoom=self.__devs.zoom, commissioning_mode=self.__cfg.commissioning_mode, - dtz_min=self.__devs.dtz_low, - dtz_max=self.__devs.dtz_high, + dtz_min=20, + dtz_max=1000, ) + def _safe_sample(self) -> tuple[SampleShortInfo | None, bool, str | None]: + """ + Return (sample, tell_connected, tell_error) without raising. + """ + try: + return self.sync_current_sample_from_tell(), True, None + except TellCommunicationError as e: + return self.__cfg.current_sample, False, str(e) + except Exception as e: + # Keep status flowing even if Tell code throws something unexpected + return self.__cfg.current_sample, False, f"TELL unavailable: {e}" + + def _safe_geom(self) -> tuple[SampleGeometryModel, bool, str | None]: + """ + Return (geom, smargon_connected, smargon_error) without raising. + Uses a conservative fallback geometry if Smargon access fails. + """ + try: + return self.sample_geometry, True, None + except SmargonCommunicationError as e: + zoom = self.__devs.zoom + fallback = SampleGeometryModel( + beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom), + pixel_in_mm=self.__cfg.pixel_to_mm(zoom), + omega_deg=self.__devs.aerotech_omega, + smargon=SmargonCoordinate( + sh_mm=Coordinate(x=0.0, y=0.0, z=0.0), + phi_deg=0.0, + chi_deg=0.0, + ), + beam_size_mm=self.__cfg.beam_size_mm, + aerotech=Coordinate(x=0.0, y=0.0, z=0.0), + aerotech_meas=Coordinate(x=0.0, y=0.0, z=0.0), + ) + return fallback, False, str(e) + except Exception as e: + zoom = self.__devs.zoom + fallback = SampleGeometryModel( + beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom), + pixel_in_mm=self.__cfg.pixel_to_mm(zoom), + omega_deg=self.__devs.aerotech_omega, + smargon=SmargonCoordinate( + sh_mm=Coordinate(x=0.0, y=0.0, z=0.0), + phi_deg=0.0, + chi_deg=0.0, + ), + beam_size_mm=self.__cfg.beam_size_mm, + aerotech=Coordinate(x=0.0, y=0.0, z=0.0), + aerotech_meas=Coordinate(x=0.0, y=0.0, z=0.0), + ) + return fallback, False, f"Smargon unavailable: {e}" + + def _safe_beamline_status(self) -> BeamlineStatus: + try: + return self.beamline_status + except Exception: + return BeamlineStatus( + name=self.__bl, + ring_current_mA=0.0, + front_light=0.0, + back_light=0.0, + cryojet_K=0.0, + shutter_open=False, + exp_shutter_open=None, + flux_ph_s=0.0, + sample_camera=SampleCameraSettings(gain=0.0, exposure=0.0), + transmission=None, + zoom=self.__devs.zoom, + commissioning_mode=self.__cfg.commissioning_mode, + dtz_min=20, + dtz_max=1000, + ) + + def _safe_diffraction_geometry(self) -> DiffractionGeometry: + try: + return self.diffraction_geometry + except Exception: + # Must satisfy pydantic constraints in DiffractionGeometry + return DiffractionGeometry( + energy_keV=12.4, + dtz_mm=150.0, + detector_size_pxl=(1, 1), + pixel_size_mm=0.15, + beam_center_pxl=(0.0, 0.0), + detector_description="unavailable", + detector_serial_number="unavailable", + poni_rot1_rad=0.0, + poni_rot2_rad=0.0, + ) + @property def status(self) -> DAQStatusModel: - # session should be set by FastAPI server + safe_sample, tell_ok, tell_err = self._safe_sample() + safe_geom, smargon_ok, smargon_err = self._safe_geom() + return DAQStatusModel( state=self.state, busy=self.busy, - geom=self.sample_geometry, - bl=self.beamline_status, - sample=self.sample, + geom=safe_geom, + bl=self._safe_beamline_status(), + sample=safe_sample, session=SessionStatus(), - diffraction=self.diffraction_geometry, + diffraction=self._safe_diffraction_geometry(), box=self.__saved_box, - last_best_res = self.__cfg.last_best_res, - last_best_b_factor = self.__cfg.last_best_b_factor, - crystal_size = self.__cfg.crystal_size + last_best_res=self.__cfg.last_best_res, + last_best_b_factor=self.__cfg.last_best_b_factor, + crystal_size=self.__cfg.crystal_size, + tell_connected=tell_ok, + tell_error=tell_err, + smargon_connected=smargon_ok, + smargon_error=smargon_err, ) def cancel(self): if self.__cfg.state == BeamlineStateEnum.DataCollection: - self.__devs.aerotech.stop() + self.__devs.aerotech_stop() self.__jfjoch.cancel() def anneal(self, time_s: float): @@ -1663,47 +1752,14 @@ class AareDAQ: self.__set_state(BeamlineStateEnum.XrayFluorescence) if fm.transmission is not None: - self.__devs.transmission.set(fm.transmission, wait=True) + self.__devs.transmission = fm.transmission - self.__devs.fluorimeter.start_acquisition(erase=fm.erase) - self.__devs.aerotech.set_shutter(1) - time.sleep(fm.acq_time_s) - self.__devs.aerotech.set_shutter(0) - self.__devs.fluorimeter.stop_acquisition() - time.sleep(0.2) - spectrum = self.__devs.fluorimeter.get_current_data() - - offset = self.__devs.fluorimeter.offset - slope = self.__devs.fluorimeter.slope # slope is in keV! - energy = [slope * 1000.0 * i + offset for i in range(len(spectrum))] - fluo_output = FluorescenceSpectrumOutputModel(spectrum=spectrum, - bkg=self.__devs.fluorimeter.get_current_background(), - energy_eV=energy, - average_dead_time=self.__devs.fluorimeter.average_dead_time() / 100.0) - if self.sample is not None: - self.__cfg.xrf = fluo_output + # TODO: Fill self.__set_state(BeamlineStateEnum.SampleAlignment) self.__cfg.state_busy = False - return fluo_output + return None except Exception as e: self.__set_state(BeamlineStateEnum.SampleAlignment) self.__cfg.state_busy = False raise e - - def fluorimeter_start(self, erase: bool = False): - self.__devs.aerotech.set_shutter(1) - self.__devs.fluorimeter.start_acquisition(erase=erase) - - def fluorimeter_stop(self): - self.__devs.fluorimeter.stop_acquisition() - self.__devs.aerotech.set_shutter(0) - - def fluorimeter_status(self) -> int | None: - return self.__devs.fluorimeter.check_status() - - def fluorimeter_data(self): - return self.__devs.fluorimeter.get_current_data() - - def fluorimeter_background(self): - return self.__devs.fluorimeter.get_current_background() \ No newline at end of file diff --git a/src/aare/daq/devices.py b/src/aare/daq/devices.py new file mode 100644 index 00000000..0455beea --- /dev/null +++ b/src/aare/daq/devices.py @@ -0,0 +1,355 @@ +# Abstractions of devices for beamline + +# Each "standard" device needs three elements: +# - property to read device value +# - setter with option to do sync/async move +# - property setter, which assumes that sync move is done (excl. zoom, which is async by default) + +import time +from enum import Enum + +import numpy as np +from epics import PV +from fontTools.feaLib.ast import deviceToString + +from aare.common.beamline import MXBeamline +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.models import SampleCameraSettings, StagePositionEnum +from aare.devices import smargon, aerotech +from aare.devices.area_detector import epicsAD, AutoEnum +from aare.devices.enum_pv import EnumPV +from aare.devices.my_motor import MyMotor + +from aare.devices.set_get_pv import SetGetPV, PredefinedPV +from aare.devices.tell_client import make_tell_client + +class BeamlineDevices: + def __init__(self, beamline: MXBeamline): + BEAMLINE = beamline.value.upper() + self.tell = make_tell_client(beamline) + self.__aerotech = aerotech.AerotechControllerEpics(beamline) + self.aerotech = aerotech.AerotechController(controller_ip="129.129.118.96") + self.__smargon = smargon.Smargon(beamline) + + self.__ring_current_pv = PV(f"ARS07-DPCT-0100:CURR") + + self.__dtz = MyMotor(f"{BEAMLINE}-ES-DET:TRZ") + self.__dty = MyMotor(f"{BEAMLINE}-ES-DET:TRY") + + self.__det_cov = EnumPV(name="det_cov", + setpv=f"{BEAMLINE}-ES-DETCOV:SET", + getpv=f"{BEAMLINE}-ES-DETCOV:GET") + + self.__sample_cam = epicsAD(f"{BEAMLINE}-ES-MS:") + + self.__front_light = PredefinedPV(name='front_light', + setpv=f"{BEAMLINE}-ES-FL:SET", + getpv=f"{BEAMLINE}-ES-FL:SET", + predefs={"off":1.49, + 'half':2.0, + 'max':3.0}, + timeout=10.0 + ) + self.__back_light = PredefinedPV(name='back_light', + setpv =f"{BEAMLINE}-ES-BL:SET", + getpv=f"{BEAMLINE}-ES-BL:SET", + predefs={"off": 0, + 'half': 0.98, + 'max': 1.2}, + timeout=10.0 + ) + + self.__back_light_pos = EnumPV(name = "back_light_pos", + setpv = f"{BEAMLINE}-ES-BL:POS-SET", + getpv = f"{BEAMLINE}-ES-BL:POS-GET", + timeout = 10.0) + + self.__collimator_pos = MyMotor(f"{BEAMLINE}-ES-COL:TRY") + self.__collimator_X = MyMotor(f"{BEAMLINE}-ES-COL:TRX") # HOW TO HANDLE!!! + + self.__scintillator_pos = PV(f"{BEAMLINE}-ES-SCL:TRY") # how to handle!!! + self.__scintillator_z = PV(f"{BEAMLINE}-ES-SCL:TRZ") + + self.__beamstop_pos = EnumPV(name = "beamstop_pos", + setpv = f"{BEAMLINE}-ES-BS:POS-SET", + getpv = f"{BEAMLINE}-ES-BS:POS-GET", + timeout = 10.0) + + self.__beamstop_x = MyMotor(f"{BEAMLINE}-ES-BS:TRX") + self.__beamstop_y = MyMotor(f"{BEAMLINE}-ES-BS:TRY") + self.__beamstop_z = MyMotor(f"{BEAMLINE}-ES-BS:TRZ") + + + self.__zoom = SetGetPV(name = f"zoom", + setpv = f"{BEAMLINE}-ES-MS:ZOOM.VAL", + getpv = f"{BEAMLINE}-ES-MS:ZOOM.RBV") + + self.__cryojet_pos = EnumPV(name='cryojet_pos', + setpv = f"{BEAMLINE}-ES-CS:POS-SET", + getpv = f"{BEAMLINE}-ES-CS:POS-GET", + timeout = 10.0) + + self.__cryojet_x = MyMotor(f"{BEAMLINE}-ES-CS:TRX") #currently in is 5 out is 15? + + + +# Transmission + @property + def transmission(self) -> float: + return 1.0 + def set_transmission(self, value: float, /, wait: bool = True): + pass + + @transmission.setter + def transmission(self, value: float): + self.set_transmission(value, wait=False) + +# Lamp light + @property + def lamp_light(self) -> float: + return self.__front_light.value + + @lamp_light.setter + def lamp_light(self, v: float): + self.set_front_light(v, wait=False) + + def set_front_light(self, v: float, /, wait: bool = True): + self.__front_light.move(v, wait=wait) + + # Back light + @property + def back_light(self) -> float: + return self.__back_light.value + + @back_light.setter + def back_light(self, v: float): + self.set_back_light(v, wait=False) + + def set_back_light(self, v: float, /, wait: bool = True): + self.__back_light.move(v, wait=wait) + +# Zoom + @property + def zoom(self) -> float: + return self.__zoom.value + + @zoom.setter + def zoom(self, value: float): + self.set_zoom(value, wait=True) + + def set_zoom(self, value: float, /, wait: bool = True): + self.__zoom.move(value, wait=wait) + +# Collimator + @property + def collimator(self) -> float: + return self.__collimator_pos.get() + + @collimator.setter + def collimator(self, value: float): + self.set_collimator(value, wait=True) + + def set_collimator(self, value: float, /, wait: bool = True): + self.__collimator_pos.move(value, wait=wait) + +# Scintillator + @property + def scintillator(self) -> float: + return self.__scintillator_pos.get() + + @scintillator.setter + def scintillator(self, value: float): + self.set_scintillator(value, wait=True) + + def set_scintillator(self, value: float, /, wait: bool = True): + self.__scintillator_pos.put(value, wait=wait) + +# Reflector (backlight?) + @property + def reflector_up(self) -> bool: + return self.__back_light_pos.position.upper() == StagePositionEnum.MEASURE.name + + @reflector_up.setter + def reflector_up(self, value: StagePositionEnum): + self.set_reflector_up(value, wait=True) + + def set_reflector_up(self, value: StagePositionEnum, /, wait: bool = True): + self.__back_light_pos.move(value, wait=wait) + +# Beamstop + @property + def beamstop_stage_up(self) -> bool: + return False + + @beamstop_stage_up.setter + def beamstop_stage_up(self, value: bool): + pass + + @property + def beamstop_z(self) -> float: + return 35.0 + + @beamstop_z.setter + def beamstop_z(self, value: float): + pass + +# Optics + @property + def energy_kev(self) -> float: + return 12.4 + + @property + def ring_current(self) -> float: + return max(0.0, 0.0) + + @property + def flux(self) -> float: + return 0 + + @property + def full_flux(self) -> float: + return 0 + +# Cryojet + @property + def cryojet_temp(self) -> float: + return 100 + + def anneal(self, time: float): + pass + + @property + def cryojet_pos(self) -> StagePositionEnum: + return StagePositionEnum(self.__cryojet_pos.position.upper()) + + @cryojet_pos.setter + def cryojet_pos(self, value: StagePositionEnum): + self.cryojet_pos_setter(value, wait=True) + + def cryojet_pos_setter(self, value: StagePositionEnum, wait:bool=False): + self.__cryojet_pos.move(value, wait=wait) + + # Shutter + @property + def shutter(self) -> bool: + return False + + @shutter.setter + def shutter(self, opened: bool): + pass + +# Sample camera + @property + def samcam_settings(self) -> SampleCameraSettings: + return SampleCameraSettings( + gain=self.__sample_cam.gain_rbv.value, + exposure=self.__sample_cam.expo_rbv.value + ) + + @samcam_settings.setter + def samcam_settings(self, settings: SampleCameraSettings): + self.__sample_cam.setup(settings.gain, settings.exposure) + + def samcam_get_image(self, /, gray: bool = False) -> np.ndarray: + return self.__sample_cam.get_image(gray=gray) + + def samcam_auto(self, state: AutoEnum): + self.__sample_cam.set_auto(state) + + def samcam_frame_id(self) -> int: + """ + Camera UniqueId for the last produced frame (monotonic counter from AreaDetector). + """ + return int(self.__sample_cam.uid.get()) + + + +# Detector Z + @property + def dtz(self) -> float: + return self.__dtz.readback + + @dtz.setter + def dtz(self, value: float): + self.set_dtz(value, wait=True) + + def set_dtz(self, value: float, /, wait: bool = True): + self.__dtz.move(value, wait=wait) + + @property + def dtz_low(self) -> float: + return self.__dtz.get("LLM") + + @property + def dtz_high(self) -> float: + return self.__dtz.get("HLM") + +# Aertoech Automation1 + @property + def aerotech_pos(self) -> Coordinate: + return Coordinate(x=self.__aerotech.gmx.readback, + y=self.__aerotech.gmy.readback, z=self.__aerotech.gmz.readback) + + @aerotech_pos.setter + def aerotech_pos(self, pos: Coordinate): + # self.__aerotech.gmx.move(pos.x, wait=False) + # self.__aerotech.gmy.move(pos.y, wait=False) + # self.__aerotech.gmz.move(pos.z, wait=False) + self.__aerotech.gmx.move(pos.x, wait=True) + self.__aerotech.gmy.move(pos.y, wait=True) + self.__aerotech.gmz.move(pos.z, wait=True) + #TODO add wait pos? + + @property + def aerotech_omega(self) -> float: + return self.__aerotech.omega.readback + + @aerotech_omega.setter + def aerotech_omega(self, val: float): + self.set_aerotech_omega(val, wait=True) + + def set_aerotech_omega(self, val: float, /, wait: bool = True): + self.__aerotech.omega.move(val, wait=wait) + + @property + def aerotech_lock(self) -> bool: + return False + + @aerotech_lock.setter + def aerotech_lock(self, val: bool): + pass + + def aerotech_stop(self): + pass + +# Smargon goniometer + @property + def smargon_pos(self) -> SmargonCoordinate: + return self.__smargon.readback + + def set_smargon_pos(self, pos: SmargonCoordinate, /, wait: bool = True): + self.__smargon.target = pos + + @smargon_pos.setter + def smargon_pos(self, pos: SmargonCoordinate): + self.set_smargon_pos(pos, wait=True) + + def smargon_wait(self, timeout: float = 10.0): + self.__smargon.wait(timeout=timeout) + + def smargon_move_home(self): + self.__smargon.move_home(wait=True) + + def smargon_aerotech_wait(self): + self.__smargon.wait_aerotech(timeout=10.0) + +if __name__ == "__main__": + from aare.common.beamline import mx_beamline + beamline = mx_beamline() + devs = BeamlineDevices(beamline) + print(devs.aerotech_pos) + # devs.aerotech_pos = Coordinate(x=124.0, y=1.0, z=1.0) + # print(devs.aerotech_pos) + # devs.aerotech_omega = 0.0 + print(devs.reflector_up) + devs.reflector_up = StagePositionEnum.MEASURE \ No newline at end of file diff --git a/daq/src/aaredaq/mlbox.py b/src/aare/daq/mlbox.py similarity index 88% rename from daq/src/aaredaq/mlbox.py rename to src/aare/daq/mlbox.py index 997cfe1f..094233c2 100644 --- a/daq/src/aaredaq/mlbox.py +++ b/src/aare/daq/mlbox.py @@ -1,24 +1,41 @@ - -from typing import Tuple, Optional, Iterable +from enum import Enum +from typing import Optional, Iterable import cv2 import requests -from aaredaqlib.models import MLBoxModel, MLOutputModel, MLBoxType, BoundingBoxModel -from aaredaqlib.logger_config import setup_logger +from aare.common.beamline import MXBeamline +from aare.common.models import MLBoxModel, MLOutputModel, MLBoxType, BoundingBoxModel +from aare.common.logger_config import setup_logger logger=setup_logger("aareDAQ") +class BoxClassEnum(Enum): + """Enum for MLBoxType values, should be updated if model changes + Loop_all = 0. Green box on camera + Pin = 1. Red box on camera + Crystal = 2. Blue box on camera + Loop_face = 3. Yellow box on camera + """ + Loop_all = 0 + Pin = 1 + Crystal = 2 + Loop_face = 3 + class MlBox: - def __init__(self, url="http://mx-aare-test.psi.ch:8002/predict/?model=best_v8_20102025.pt"): #mx-aare-test.psi.ch, mx-ml.psi.ch - self.__url = url - # self.class_info = [ - # ["loop_all", (255, 0, 0)], # class 0: Blue for loop_all - # ["pin", (0, 255, 0)], # class 1: Green for pin - # ["crystal", (0, 0, 255)], # class 2: Red for crystal - # ["loop_face", (255, 255, 0)] # class 3: Yellow for loop_face - # ] + def __init__(self, bl:MXBeamline, url="http://mx-aare-test.psi.ch:8002/predict/?model=best_v8_20102025.pt"): #mx-aare-test.psi.ch, mx-ml.psi.ch + if bl == MXBeamline.SIMULATED: + self.__url = None + elif bl == MXBeamline.X06DA: + self.__url = "http://mx-aare-test.psi.ch:8002/predict/?model=best_v8_20102025.pt" + elif bl == MXBeamline.X10SA: + self.__url = "http://x10sa-spark-01.psi.ch:8002/predict/?model=best_v12_22092025.engine" + elif bl == MXBeamline.X06SA: + self.__url = "" + raise NotImplemented(f"MLBox not implemente for {bl}") + else: + raise Exception(f"unknown beamline {bl}") def get_response(self, image): ok, buf = cv2.imencode(".jpg", image) diff --git a/daq/src/aaredaq/server.py b/src/aare/daq/server.py similarity index 66% rename from daq/src/aaredaq/server.py rename to src/aare/daq/server.py index 60c3729e..45f57d4f 100644 --- a/daq/src/aaredaq/server.py +++ b/src/aare/daq/server.py @@ -1,34 +1,42 @@ import asyncio +import hmac import io import os, time -from typing import Tuple, AsyncGenerator +from typing import AsyncGenerator import json import cv2 import urllib3 import uvicorn -from aaredaqlib.coordinate import SmargonCoordinate, Coordinate -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import SampleShortInfo, DAQStatusModel, BeamlineStateEnum, BeamlineSettingsModel, \ +from aare.common.coordinate import SmargonCoordinate, Coordinate +from aare.common.error_codes import export_error_codes, export_error_codes_grouped +from aare.common.logger_config import setup_logger +from aare.common.models import SampleShortInfo, DAQStatusModel, BeamlineStateEnum, BeamlineSettingsModel, \ SampleShortInfoList, SessionStatus, SampleCameraSettings, AutofocusSettings, TokenData, \ CryojetSettingsModel, SimpleScanParameters, CrystalSize, FluorescenceSpectrumParameterModel, \ - FluorescenceSpectrumOutputModel -from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid -from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan -from aaredaqlib.sample_geometry import SampleGeometryModel + FluorescenceSpectrumOutputModel, RecoveryActionRequest +from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid +from aare.common.rotation_scan import RotationScanRequest, CompletedRotationScan +from aare.common.sample_geometry import SampleGeometryModel from fastapi import FastAPI, Depends from fastapi import HTTPException from fastapi import status as api_status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from starlette.responses import StreamingResponse -from urllib3.exceptions import InsecureRequestWarning -from aaredaq import auth -from aaredaqlib.beamline import mx_beamline -from aaredaq.config import BeamlineConfig -from aaredaq.daq import (AareDAQ, LoopCenteringFailed, TransformationInvalidException, - MountingFailed, WarningTellException, CriticalTellException) +from aare.daq import auth +from aare.common.beamline import mx_beamline +from aare.daq.config import BeamlineConfig +from aare.daq.daq import AareDAQ +from aare.daq.server_exception_handler import register_exception_handlers + +from aare.common.exception_handler import ( + SampleException, + UserRightsException, + ) +logger = setup_logger("aareDAQ") app = FastAPI() +register_exception_handlers(app) # OAuth2 setup oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -37,56 +45,119 @@ bl = mx_beamline() cfg = BeamlineConfig(bl) daq = AareDAQ(cfg, bl) +try: + daq.sync_current_sample_from_tell(force=True) +except Exception as e: + logger.warning(f"Initial sample sync from TELL failed: {e}") + _all_pgroups_cache: dict[str, tuple[list[str], float]] = {} _ALL_PGROUPS_TTL_S = 60.0 # adjust TTL as needed -logger = setup_logger("aareDAQ") +_face_detection_state: dict = { + "seq": 0, + "running": False, + "samples": [], + "height_fit": {}, + "area_fit": {}, +} +_face_detection_state_lock = asyncio.Lock() + +def _required_recovery_code() -> str: + code = os.getenv("AARE_RECOVERY_CODE", "").strip() + if not code: + logger.error("AARE_RECOVERY_CODE is not configured.") + raise HTTPException( + status_code=api_status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Recovery confirmation code is not configured on the server.", + ) + return code + +def _validate_recovery_code(confirmation_code: str) -> None: + expected = _required_recovery_code() + provided = str(confirmation_code or "").strip() + if not hmac.compare_digest(provided, expected): + logger.warning("Invalid recovery confirmation code.") + raise HTTPException( + status_code=api_status.HTTP_403_FORBIDDEN, + detail="Invalid confirmation code.", + ) + +def _sample_is_mounted() -> bool: + try: + return daq.sample is not None + except Exception: + return False + +def _push_face_detection_progress(payload: dict) -> None: + global _face_detection_state + try: + next_seq = int(_face_detection_state.get("seq", 0)) + 1 + _face_detection_state = { + "seq": next_seq, + **payload, + } + except Exception as e: + logger.warning(f"Failed to update face detection progress: {e}") + + +async def face_detection_event_stream() -> AsyncGenerator[str, None]: + last_seq = -1 + try: + while True: + state = dict(_face_detection_state) + seq = int(state.get("seq", 0)) + if seq != last_seq: + last_seq = seq + yield f"data: {json.dumps(state, separators=(',', ':'))}\n\n" + await asyncio.sleep(0.15) + except asyncio.CancelledError: + return + +daq.set_face_detection_progress_callback(_push_face_detection_progress) @app.post("/token") async def login(form_data: OAuth2PasswordRequestForm = Depends()): data = auth.authenticate_user(cfg, form_data) return {"access_token": data, "token_type": "bearer"} +@app.get("/meta/error-codes") +async def meta_error_codes() -> dict[str, dict[str, str]]: + """ + Public, stable registry of machine-readable error codes. + Useful for GUIs, tests, and diagnostics. + """ + return export_error_codes_grouped() @app.get("/status") async def status(token: str = Depends(oauth2_scheme)) -> DAQStatusModel: data = auth.parse_token(token) - try: - full = daq.status - active_pgroup = cfg.pgroup - is_staff = data.staff - in_allowed_groups = (active_pgroup is not None and active_pgroup in data.pgroups) - in_ro = is_staff or in_allowed_groups - sample_pgroup = full.sample.user if full.sample is not None else None - sample_view_allowed = sample_pgroup in data.pgroups or is_staff - - full.sample = full.sample if in_ro and sample_view_allowed else None - full.box = full.box if in_ro else None - full.last_best_res = full.last_best_res if in_ro else None - full.last_best_b_factor = full.last_best_b_factor if in_ro else None - full.crystal_size = full.crystal_size if in_ro else CrystalSize(x=0,y=0,z=0) - full.session = SessionStatus( - current_pgroup=cfg.pgroup, - session=cfg.session_state(data.session), - staff=data.staff - ) - return full - - except Exception as e: - logger.error(f"Error getting status: {e}") - raise HTTPException( - status_code=api_status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Error getting status: {e}" - ) + full = daq.status + active_pgroup = cfg.pgroup + is_staff = data.staff + in_allowed_groups = (active_pgroup is not None and active_pgroup in data.pgroups) + in_ro = is_staff or in_allowed_groups + sample_pgroup = full.sample.user if full.sample is not None else None + sample_view_allowed = sample_pgroup in data.pgroups or is_staff + full.sample = full.sample if in_ro and sample_view_allowed else None + full.box = full.box if in_ro else None + full.last_best_res = full.last_best_res if in_ro else None + full.last_best_b_factor = full.last_best_b_factor if in_ro else None + full.crystal_size = full.crystal_size if in_ro else CrystalSize(x=0,y=0,z=0) + full.session = SessionStatus( + current_pgroup=cfg.pgroup, + session=cfg.session_state(data.session), + staff=data.staff + ) + return full @app.get("/beamline/geometry") async def sample_geometry( token: str = Depends(oauth2_scheme), ) -> SampleGeometryModel: auth.check_jwt_ro(cfg, auth.parse_token(token)) - return daq.sample_geometry + return daq.status.geom @app.put("/beamline/omega") @@ -96,14 +167,26 @@ async def omega(val: float, token: str = Depends(oauth2_scheme)): daq.omega = val return "OK" - -@app.put("/beamline/light") -async def light(val: float, token: str = Depends(oauth2_scheme)): - logger.debug(f"Setting light to {val}") +@app.put("/beamline/omega_rel") +async def omega(val: float, token: str = Depends(oauth2_scheme)): + logger.debug(f"Moving omega by {val}") auth.check_jwt_rw(cfg, auth.parse_token(token)) - daq.light = val + daq.omega_rel(val) return "OK" +@app.put("/beamline/front_light") +async def front_light(val: float, token: str = Depends(oauth2_scheme)): + logger.debug(f"Setting light to {val}") + auth.check_jwt_rw(cfg, auth.parse_token(token)) + daq.front_light = val + return "OK" + +@app.put("/beamline/back_light") +async def back_light(val: float, token: str = Depends(oauth2_scheme)): + logger.debug(f"Setting back light to {val}") + auth.check_jwt_rw(cfg, auth.parse_token(token)) + daq.back_light = val + return "OK" @app.put("/beamline/zoom") async def zoom(val: float, token: str = Depends(oauth2_scheme)): @@ -190,7 +273,7 @@ async def samcam_settings(s: SampleCameraSettings, token: str = Depends(oauth2_s async def samcam_autofocus(s: AutofocusSettings, token: str = Depends(oauth2_scheme)): logger.debug(f"SamCam AutoFocus") auth.check_jwt_rw(cfg, auth.parse_token(token)) - daq.autofocus(s) + daq.auto_focus(s) return "OK" @app.post("/beamline/shutter") @@ -251,41 +334,14 @@ async def mount(dbid: int, token: str = Depends(oauth2_scheme), reference: bool index = i if index == -1: - raise HTTPException( - status_code=api_status.HTTP_404_NOT_FOUND, - detail="Sample not found", - ) - if token_data.staff or st.s[index].user in token_data.pgroups: - try: - daq.sample = st.s[index] - except MountingFailed as e: - raise HTTPException( - status_code=api_status.HTTP_404_NOT_FOUND, - detail=f"{e}", - ) - except WarningTellException as e: - raise HTTPException( - status_code=api_status.HTTP_410_GONE, - detail=f"{e}", - ) - except CriticalTellException as e: - raise HTTPException( - status_code=api_status.HTTP_417_EXPECTATION_FAILED, - detail=f"{e}" - ) - except Exception as e: - raise HTTPException( - status_code=api_status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"{e}" - ) - return "OK" - else: - raise HTTPException( - status_code=api_status.HTTP_401_UNAUTHORIZED, - detail="Sample belongs to a different user.", - headers={"WWW-Authenticate": "Bearer"}, - ) + raise SampleException(message="Sample not found") + if not (token_data.staff or st.s[index].user in token_data.pgroups): + raise UserRightsException(message="Sample belongs to a different user.") + + daq.sample = st.s[index] + + return "OK" @app.post("/sample/unmount") async def unmount(token: str = Depends(oauth2_scheme)): @@ -303,6 +359,16 @@ async def manual(s: SampleShortInfo, token: str = Depends(oauth2_scheme)): daq.create_sample(s) print(f"DB ID after creating {s.db_id}") +@app.post("/sample/resync") +async def sample_resync(token: str = Depends(oauth2_scheme)) -> dict: + auth.check_jwt_rw(cfg, auth.parse_token(token)) + daq.sync_current_sample_from_tell(force=True) + logger.info("TELL sample cache resynced via API request.") + return { + "ok": True, + "message": "TELL sample cache resynced.", + } + def get_spreadsheet(data: TokenData) -> SampleShortInfoList: if data.staff: @@ -392,6 +458,116 @@ async def beam_location(token: str = Depends(oauth2_scheme)): auth.check_jwt_staff(cfg, auth.parse_token(token)) daq.state = BeamlineStateEnum.BeamLocation +@app.post("/state/maintenance") +async def maintenance(token: str = Depends(oauth2_scheme)) -> str: + auth.check_jwt_staff(cfg, auth.parse_token(token)) + cfg.state = BeamlineStateEnum.Maintenance + logger.warning("Beamline state set to Maintenance via protected endpoint.") + return "OK" + +@app.post("/access/take_over_beamline") +async def take_over_beamline(payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme)) -> str: + data = auth.parse_token(token) + auth.check_jwt_staff_only(data) + _validate_recovery_code(payload.confirmation_code) + auth.force_current_sesion(cfg, data) + logger.warning( + "Beamline session forcefully taken over.", + extra={"session": getattr(data, "session", None)}, + ) + return "OK" + +@app.post("/state/free_beamline") +async def free_beamline(payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme)) -> str: + data = auth.parse_token(token) + auth.check_jwt_staff_only(data) + _validate_recovery_code(payload.confirmation_code) + cfg.state_busy = False + logger.warning( + "Beamline busy flag cleared via protected endpoint.", + extra={"session": getattr(data, "session", None)}, + ) + return "OK" + +@app.post("/recovery/recover_beamline") +async def recover_beamline(payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme)) -> dict: + data = auth.parse_token(token) + auth.check_jwt_staff_only(data) + _validate_recovery_code(payload.confirmation_code) + + sample_mounted = _sample_is_mounted() + prev_state = cfg.state + prev_busy = cfg.state_busy + + auth.force_current_sesion(cfg, data) + cfg.state_busy = False + cfg.state = BeamlineStateEnum.Maintenance + + logger.warning( + "Beamline recovery action executed.", + extra={ + "session": getattr(data, "session", None), + "previous_state": getattr(prev_state, "name", str(prev_state)), + "previous_busy": prev_busy, + "sample_mounted": sample_mounted, + }, + ) + + return { + "ok": True, + "sample_mounted": sample_mounted, + "previous_state": getattr(prev_state, "name", str(prev_state)), + "previous_busy": prev_busy, + "new_state": BeamlineStateEnum.Maintenance.name, + } +@app.post("/recovery/unmount_sample") +async def recovery_unmount_sample(payload: RecoveryActionRequest, token: str = Depends(oauth2_scheme)) -> dict: + data = auth.parse_token(token) + auth.check_jwt_staff_only(data) + _validate_recovery_code(payload.confirmation_code) + + auth.force_current_sesion(cfg, data) + + if cfg.state_busy: + raise HTTPException( + status_code=api_status.HTTP_409_CONFLICT, + detail="Beamline is busy. Clear or recover the beamline before attempting recovery unmount.", + ) + + status = daq.status + if not getattr(status, "tell_connected", False): + raise HTTPException( + status_code=api_status.HTTP_409_CONFLICT, + detail=f"TELL is not connected: {getattr(status, 'tell_error', 'unknown error')}", + ) + + sample_mounted = _sample_is_mounted() + if not sample_mounted: + return { + "ok": True, + "sample_mounted": False, + "message": "No sample appears to be mounted.", + } + + prev_state = cfg.state + daq.recovery_unmount_sample() + + logger.warning( + "Recovery sample unmount executed.", + extra={ + "session": getattr(data, "session", None), + "previous_state": getattr(prev_state, "name", str(prev_state)), + }, + ) + + return { + "ok": True, + "sample_mounted": True, + "previous_state": getattr(prev_state, "name", str(prev_state)), + "new_state": getattr(cfg.state, "name", str(cfg.state)), + "message": "Recovery unmount completed.", + } + # Scans @app.post("/scan/raster") async def raster(val: RasterGridRequest, auto: bool = False, token: str = Depends(oauth2_scheme)) -> CompletedRasterGrid: @@ -407,40 +583,7 @@ async def rotation(val: RotationScanRequest, token: str = Depends(oauth2_scheme) @app.post("/scan/auto") async def auto(s: SampleShortInfo, token: str = Depends(oauth2_scheme)): auth.check_jwt_rw(cfg, auth.parse_token(token)) - try: - runtime = daq.measure(s) - return f"{runtime:0.3f}" - except LoopCenteringFailed as e: - raise HTTPException( - status_code=api_status.HTTP_404_NOT_FOUND, - detail=f"Loop centering failed: {e}", - ) - except TransformationInvalidException as e: - raise HTTPException( - status_code=api_status.HTTP_400_BAD_REQUEST, - detail=f"Transformation invalid: {e}", - ) - except MountingFailed as e: - raise HTTPException( - status_code=api_status.HTTP_404_NOT_FOUND, - detail=f"{e}", - ) - except WarningTellException as e: - raise HTTPException( - status_code=api_status.HTTP_410_GONE, - detail=f"{e}", - ) - except CriticalTellException as e: - raise HTTPException( - status_code=api_status.HTTP_417_EXPECTATION_FAILED, - detail=f"{e}" - ) - except Exception as e: - logger.error(f"Exception in auto: {e}") - raise HTTPException( - status_code=api_status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"error {e}" - ) + runtime = daq.measure(s) return f"{runtime:0.3f}" @@ -479,14 +622,34 @@ async def alc_ml_bounding_box(token: str = Depends(oauth2_scheme)) -> RasterGrid auth.check_jwt_rw(cfg, auth.parse_token(token)) return daq.ml_bounding_box() - @app.post("/face_detection/run") async def face_detection_run(steps: int, step_size: int, token: str = Depends(oauth2_scheme)) -> dict: logger.debug(f"Face detection run: {steps} steps, {step_size} step size") auth.check_jwt_rw(cfg, auth.parse_token(token)) + _push_face_detection_progress({ + "running": True, + "status": "starting", + "samples": [], + "height_fit": {}, + "area_fit": {}, + }) result = daq.face_detection(steps=steps, step_size=step_size) return result +@app.get("/sse/face_detection") +async def sse_face_detection(token: str = Depends(oauth2_scheme)): + auth.check_jwt_ro(cfg, auth.parse_token(token)) + return StreamingResponse( + face_detection_event_stream(), + media_type="text/event-stream", + headers={ + "Cache-Control": "no-cache", + "Connection": "keep-alive", + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Cache-Control" + } + ) + # Access management @app.get("/access/pgroup") async def pgroup(token: str = Depends(oauth2_scheme)) -> str: @@ -670,6 +833,17 @@ async def sse_fluorimeter(token: str = Depends(oauth2_scheme)): } ) +@app.post("/samcam/send_screenshot_db") +async def send_screenshot_db( + filename: str | None = None, + message: str | None = None, + token: str = Depends(oauth2_scheme), +) -> str: + data = auth.parse_token(token) + auth.check_jwt_rw(cfg, data) + daq.send_screenshot_db(filename=filename, message=message) + return "OK" + LOGGING_CONFIG = { "version": 1, @@ -708,7 +882,7 @@ def main(): urllib3.disable_warnings() # Run the application using uvicorn - uvicorn.run("aaredaq.server:app", host="0.0.0.0", port=5210, workers=4, log_config=LOGGING_CONFIG) + uvicorn.run("aare.daq.server:app", host="0.0.0.0", port=5210, workers=4, log_config=LOGGING_CONFIG) if __name__ == "__main__": diff --git a/src/aare/daq/server_exception_handler.py b/src/aare/daq/server_exception_handler.py new file mode 100644 index 00000000..530864db --- /dev/null +++ b/src/aare/daq/server_exception_handler.py @@ -0,0 +1,154 @@ +# aare/common/server_error_handler.py +from __future__ import annotations + +from fastapi import HTTPException +from fastapi import status as api_status +from starlette.requests import Request +from starlette.responses import JSONResponse + +from aare.common.logger_config import setup_logger +from aare.common.exception_handler import ( + MountingFailed, + WarningTellException, + CriticalTellException, + LoopCenteringFailed, + TransformationInvalidException, + BeamlineBusyException, + AuthenticationException, + SampleException, + UserRightsException, + SmargonCommunicationError, TellCommunicationError +) + +logger = setup_logger("aareDAQ") + + +def _error_payload(*, code: str, message: str, extra: dict | None = None) -> dict: + payload = {"code": code, "message": message} + if extra: + payload["extra"] = extra + return payload + + +def register_exception_handlers(app) -> None: + """ + Register server-wide exception handlers on the given FastAPI app. + Call once right after `app = FastAPI()`. + """ + + @app.exception_handler(HTTPException) + async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse: + # Keep explicit HTTP errors, but normalize response shape + detail = exc.detail + if isinstance(detail, dict) and "code" in detail and "message" in detail: + body = detail + else: + body = _error_payload(code="HTTP_ERROR", message=str(detail)) + return JSONResponse(status_code=exc.status_code, content=body, headers=exc.headers) + + @app.exception_handler(MountingFailed) + async def mounting_failed_handler(request: Request, exc: MountingFailed) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_404_NOT_FOUND, + content=_error_payload(code="MOUNTING_FAILED", message=str(exc)), + ) + + @app.exception_handler(WarningTellException) + async def warning_tell_handler(request: Request, exc: WarningTellException) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_410_GONE, + content=_error_payload(code="TELL_WARNING", message=str(exc)), + ) + + @app.exception_handler(CriticalTellException) + async def critical_tell_handler(request: Request, exc: CriticalTellException) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_417_EXPECTATION_FAILED, + content=_error_payload(code="TELL_CRITICAL", message=str(exc)), + ) + + @app.exception_handler(LoopCenteringFailed) + async def loop_centering_failed_handler(request: Request, exc: LoopCenteringFailed) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_404_NOT_FOUND, + content=_error_payload(code="LOOP_CENTERING_FAILED", message=str(exc)), + ) + + @app.exception_handler(TransformationInvalidException) + async def transformation_invalid_handler(request: Request, exc: TransformationInvalidException) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_400_BAD_REQUEST, + content=_error_payload(code="TRANSFORMATION_INVALID", message=str(exc)), + ) + + @app.exception_handler(BeamlineBusyException) + async def beamline_busy_handler(request: Request, exc: BeamlineBusyException) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_423_LOCKED, + content=_error_payload(code="BEAMLINE_BUSY", message=str(exc) or "Beamline is busy"), + ) + + @app.exception_handler(AuthenticationException) + async def authentication_exception_handler(request: Request, exc: AuthenticationException) -> JSONResponse: + return JSONResponse( + status_code=getattr(exc, "status_code", api_status.HTTP_401_UNAUTHORIZED), + content=_error_payload( + code=str(getattr(exc, "code", "AUTHENTICATION_ERROR")), + message=str(exc) or "Invalid authentication", + ), + headers=getattr(exc, "headers", None), + ) + + @app.exception_handler(UserRightsException) + async def user_rights_exception_handler(request: Request, exc: UserRightsException) -> JSONResponse: + return JSONResponse( + status_code=getattr(exc, "status_code", api_status.HTTP_403_FORBIDDEN), + content=_error_payload( + code=str(getattr(exc, "code", "FORBIDDEN")), + message=str(exc) or "Forbidden", + ), + headers=getattr(exc, "headers", None), + ) + + @app.exception_handler(SampleException) + async def sample_exception_handler(request: Request, exc: SampleException) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_404_NOT_FOUND, + content=_error_payload(code="SAMPLE_NOT_FOUND", message=str(exc) or "Sample not found"), + ) + + @app.exception_handler(SmargonCommunicationError) + async def smargon_comm_handler(request: Request, exc: SmargonCommunicationError) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_503_SERVICE_UNAVAILABLE, + content=_error_payload( + code="SMARGON_UNAVAILABLE", + message=str(exc) or "Smargon is unavailable", + extra={ + "operation": getattr(exc, "operation", None), + "endpoint": getattr(exc, "endpoint", None), + }, + ), + ) + + @app.exception_handler(TellCommunicationError) + async def tell_comm_handler(request: Request, exc: TellCommunicationError) -> JSONResponse: + return JSONResponse( + status_code=api_status.HTTP_503_SERVICE_UNAVAILABLE, + content=_error_payload( + code="TELL_UNAVAILABLE", + message=str(exc) or "TELL is unavailable", + extra={ + "operation": getattr(exc, "operation", None), + "endpoint": getattr(exc, "endpoint", None), + }, + ), + ) + + @app.exception_handler(Exception) + async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse: + logger.exception("Unhandled server exception") + return JSONResponse( + status_code=api_status.HTTP_500_INTERNAL_SERVER_ERROR, + content=_error_payload(code="INTERNAL_SERVER_ERROR", message=str(exc) or "Internal server error"), + ) diff --git a/daq/src/aaredaq/spreadsheetupdater.py b/src/aare/daq/spreadsheetupdater.py similarity index 95% rename from daq/src/aaredaq/spreadsheetupdater.py rename to src/aare/daq/spreadsheetupdater.py index 110e0002..4f7c65f8 100644 --- a/daq/src/aaredaq/spreadsheetupdater.py +++ b/src/aare/daq/spreadsheetupdater.py @@ -2,12 +2,13 @@ import os import json import websocket import time -from aareDBclient.models import PuckWithTellPosition -from aaredaqlib.models import SampleShortInfoList, SampleShortInfo, DewarAddress +from aareDB.models import PuckWithTellPosition +from aare.common.models import SampleShortInfoList, SampleShortInfo, DewarAddress from config import BeamlineConfig -from aaredaqlib.beamline import MXBeamline +from aare.common.beamline import MXBeamline, mx_beamline -SLOT_IDENTIFIER = "X10SA" +beamline = mx_beamline() +SLOT_IDENTIFIER = beamline.value.upper() WS_URL = f"wss://mx-db-01.psi.ch/dispatcher/protected_router/tell_runner/ws/samples-spreadsheet/{SLOT_IDENTIFIER}" # Ensure the environment variable for the shared password is set @@ -16,9 +17,8 @@ if not password: raise ValueError("The AAREDB_SHARED_PASSWORD environment variable is not set.") WS_HEADERS = [f"X-Shared-Password: {password}"] -beamline = MXBeamline.X10SA -config = BeamlineConfig(bl=beamline) +config = BeamlineConfig(bl=beamline) # Cache the current spreadsheet for change detection current_spreadsheet = None diff --git a/daq/src/aaredaq/tellupdater.py b/src/aare/daq/tellupdater.py similarity index 76% rename from daq/src/aaredaq/tellupdater.py rename to src/aare/daq/tellupdater.py index b38b5231..e9815dec 100644 --- a/daq/src/aaredaq/tellupdater.py +++ b/src/aare/daq/tellupdater.py @@ -1,25 +1,33 @@ import os import json +import threading + import websocket import sseclient import requests import time -from aareDBclient.models import PuckWithTellPosition -#from mxlibs3.tell_client import TellClient -#from aaredb import AareWrapper # Make sure the import path fits your project -#from aaredaqlib.beamline import MXBeamline +from aareDB.models import PuckWithTellPosition + +from aare.devices.tell_client import TellClient + +from aare.common.logger_config import setup_logger +from aaredb import AareWrapper # Make sure the import path fits your project +from aare.common.beamline import MXBeamline, mx_beamline + +logger = setup_logger("aareDAQ") # Configuration -SLOT_IDENTIFIER = "X10SA" -#WS_URL = f"wss://mx-db-01.psi.ch/dispatcher/protected_router/wstell/ws/slot/{SLOT_IDENTIFIER}" -WS_URL = f"wss://localhost:8001/protected_router/wstell/ws/slot/{SLOT_IDENTIFIER}" +beamline = mx_beamline() +SLOT_IDENTIFIER = beamline.value.upper() +WS_URL = f"wss://mx-db-01.psi.ch/dispatcher/protected_router/wstell/ws/slot/{SLOT_IDENTIFIER}" +#WS_URL = f"wss://localhost:8001/protected_router/wstell/ws/slot/{SLOT_IDENTIFIER}" WS_HEADERS = [f"X-Shared-Password: {os.getenv('AAREDB_SHARED_PASSWORD')}"] print(WS_HEADERS) # Initialize TELL client and DB wrapper -beamline = None #MXBeamline.X06DA # Use your beamline enum/value -tell_client = None #TellClient(bl=beamline) -aare_db = None #AareWrapper(bl=beamline) + # Use your beamline enum/value +tell_client = TellClient(bl=beamline) +aare_db = AareWrapper(bl=beamline) # Track current state current_pucks = [] @@ -32,22 +40,17 @@ def listen_to_sse(): return sse_url = tell_client.url + "/events" try: - response = requests.get(sse_url, stream=True) - client = sseclient.SSEClient(response) + #response = requests.get(sse_url, stream=True) + client = sseclient.SSEClient(sse_url) - # Immediately fetch current detected pucks once on connect so the system starts with - # up-to-date state (instead of waiting for the first DewarContentUpdate event). - try: - print("[SSE][listen_to_sse] Initial detected pucks fetch on connect") - handle_tell_change_event() - except Exception as exc: - print(f"[SSE][listen_to_sse][WARN] Initial fetch failed: {exc}") + print("[SSE][listen_to_sse] Initial detected pucks fetch on connect") + handle_tell_change_event() for event in client.events(): + print(f"event = {event.event} with data: {event.data}") if event.event == "DewarContentUpdate": - print(f"[SSE][listen_to_sse] event: {event.event}, data: {event.data}") on_sse_event(event) - except requests.exceptions.RequestException as exc: + except Exception as exc: print(f"[SSE][listen_to_sse][ERROR] Failed to connect to {sse_url}: {exc}") def compare_and_report_change(old, new, key_func): @@ -69,8 +72,8 @@ def compare_and_report_change(old, new, key_func): def ws_update_samples_info(pucks): """Send sample info to TELL robot.""" - #tell_client.set_samples_info(pucks) - print(pucks) + tell_client.set_samples_info(pucks) + logger.info(f"Payload sent to TELL: {pucks}") def handle_tell_change_event(): """Fetch the latest detected pucks from TELL and update the database.""" @@ -139,8 +142,8 @@ def on_open(ws): def main(): # Start SSE listener in a separate background thread - #sse_thread = threading.Thread(target=listen_to_sse, daemon=True) - #sse_thread.start() + sse_thread = threading.Thread(target=listen_to_sse, daemon=True) + sse_thread.start() # Main thread runs websocket client loop while True: diff --git a/src/aare/daq/workflows.py b/src/aare/daq/workflows.py new file mode 100644 index 00000000..04addece --- /dev/null +++ b/src/aare/daq/workflows.py @@ -0,0 +1,144 @@ +from aare.common.coordinate import Coordinate +from aare.common.models import StagePositionEnum +from aare.daq.devices import BeamlineDevices +from aare.daq.config import BeamlineConfig, ABR_POS_MOUNT + + +def move_bsz(devs: BeamlineDevices, target: float): + if abs(target - devs.bsz.position) > 0.1: + beamstop_stage_measure = devs.beamstop_stage_up + reflector_measure = devs.reflector_up + devs.reflector_up = False + devs.beamstop_stage_up = True + devs.beamstop_z = target + + if reflector_measure: + devs.reflector_up = True + + if not beamstop_stage_measure: + devs.beamstop_stage_up = False + + +def wait_for_dc_devices(devs: BeamlineDevices): + # Should wait for DTZ + pass + +def wait_for_se_devices(devs: BeamlineDevices, cfg: BeamlineConfig): + # Should wait for Cryojet go far + pass + +def common_2rse(devs: BeamlineDevices, cfg: BeamlineConfig): + print('move collimator and scintillator to 20') + devs.collimator = 20.0 + devs.scintillator = 20.0 + print('move smargon home') + devs.smargon_move_home() + print('try to move aerotech') + devs.aerotech_pos = Coordinate(x=0.0, y=0.0, z=0.0) + devs.aerotech_omega = 0.0 + #print('move bl to park') + #devs.reflector_up = StagePositionEnum.PARK + print('move bs to park') + devs.beamstop_stage_up = StagePositionEnum.PARK + #print('move cryo to park') + #devs.__cryojet_pos = StagePositionEnum.PARK + +def m2se(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + +def sa2se(devs: BeamlineDevices, cfg: BeamlineConfig): + print('move collimator and scintillator to 20') + devs.collimator = 20.0 + devs.scintillator = 20.0 + print('move smargon home') + devs.smargon_move_home() + print('try to move aerotech') + devs.aerotech_pos = Coordinate(x=0.0, y=0.0, z=0.0) + devs.aerotech_omega = 0.0 + print('move bl to park') + devs.reflector_up = StagePositionEnum.PARK + print('move bs to park') + devs.beamstop_stage_up = StagePositionEnum.PARK + #print('move cryo to park') + #devs.__cryojet_pos = StagePositionEnum.PARK + +def sa2rse(devs: BeamlineDevices, cfg: BeamlineConfig): + common_2rse(devs, cfg) + +def dc2rse(devs: BeamlineDevices, cfg: BeamlineConfig): + common_2rse(devs, cfg) + +def se2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.reflector_up = StagePositionEnum.MEASURE + devs.aerotech_pos = cfg.abr_meas_pos + +def rse2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + se2sa(devs, cfg) + +def sa2dc(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + +def dc2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + +def sa2xrf(devs: BeamlineDevices, cfg: BeamlineConfig): + """sample alignment to XrfCollection""" + pass + + +def xrf2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + """XrfCollection to sample alignment""" + pass + + +def sa2ws(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + + +def ws2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + + +def sa2ba(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + + +def ba2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + pass + +def sa2bl(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + +def bl2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + + +def bl2ba(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + +def ba2bl(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + +def sa2dh(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + if devs.tell.get_mounted_sample() is not None: + try: + # Best effort try to unmount + devs.tell.unmount(wait=True) + except Exception as e: + print(f"Error for unmounting: {e}") + devs.tell.dry(wait_cold=-1, wait=False) + +def dh2sa(devs: BeamlineDevices, cfg: BeamlineConfig): + devs.scintillator = 20.0 + devs.reflector_up = StagePositionEnum.MEASURE + +if __name__ == "__main__": + from aare.common.beamline import mx_beamline + import time + bl = mx_beamline() + cfg = BeamlineConfig(bl) + devs = BeamlineDevices(bl) + common_2rse(devs, cfg) + time.sleep(10.0) + rse2sa(devs, cfg) \ No newline at end of file diff --git a/gui/src/aaregui/models/__init__.py b/src/aare/devices/__init__.py similarity index 100% rename from gui/src/aaregui/models/__init__.py rename to src/aare/devices/__init__.py diff --git a/src/aare/devices/aerotech.py b/src/aare/devices/aerotech.py new file mode 100644 index 00000000..5884e40b --- /dev/null +++ b/src/aare/devices/aerotech.py @@ -0,0 +1,386 @@ +import os +import sys +import threading +import time +from enum import Enum +from typing import Union + +import automation1 as a1 +from epics import PV, Motor, caput, caget + +from aare.common.beamline import MXBeamline, mx_beamline +from aare.devices.my_motor import MyMotor + +class TaskEnum(Enum): + TASK_0 = 0 + TASK_1 = 1 + TASK_2 = 2 + TASK_3 = 3 + TASK_4 = 4 + +class AxisEnum(Enum): + X = "gmx" + Y = "gmy" + Z = "gmz" + OMEGA = "Omega" + +class AerotechRunEnum(Enum): + STOP = 0 + START = 1 + RUN = 2 + LOAD = 3 + PAUSE = 4 + RESET = 5 + +class VariableTypeEnum(Enum): + INT = 0 + REAL = 1 + STRING = 2 + +class AerotechControllerEpics: + def __init__(self, beamline: MXBeamline): + BEAMLINE = beamline.value.upper() + self.aerotech_pv_prefix = f"{BEAMLINE}-ES-DF1" + trx_prefix = f"{self.aerotech_pv_prefix}:TRX1" + try_prefix = f"{self.aerotech_pv_prefix}:TRY1" + trz_prefix = f"{self.aerotech_pv_prefix}:TRZ1" + rotu_prefix = f"{self.aerotech_pv_prefix}:ROTU" + self.gmx = MyMotor(trx_prefix) + self.gmy = MyMotor(try_prefix) + self.gmz = MyMotor(trz_prefix) + self.omega = MyMotor(rotu_prefix) + self.__enable_all = PV(f"{self.aerotech_pv_prefix}:EnableAll") + self.__disable_all = PV(f"{self.aerotech_pv_prefix}:DisableAll") + self.__acknowledge_all = PV(f"{self.aerotech_pv_prefix}:AckAll") + self.__stop_all = PV(f"{self.aerotech_pv_prefix}:StopAll") + self.__task_filename = PV(f"{self.aerotech_pv_prefix}:TASK:FILENAME") + self.__task_id = PV(f"{self.aerotech_pv_prefix}:TASK:TASKIDX") # values can be 1 to 4 DO NOT USE 0!!!! + self.__task_run_enum = PV(f"{self.aerotech_pv_prefix}:TASK:SWITCH") # 0 Stop, 1 Start, 2 Run, + # 3 Load, 4 Pause, 5 Reset + self.enable_all() + + def enable_all(self): + self.__enable_all.put(1) + self.__enable_all.put(0) + + def acknowledge_all(self): + self.__acknowledge_all.put(1) + self.__acknowledge_all.put(0) + + def _disable_all(self): + self.__disable_all.put(1) + self.__disable_all.put(0) + + def stop_all(self): + self.__stop_all.put(1) + self.__stop_all.put(0) + + def __task_stop(self): + self.__task_run_enum.put(0) + + def __task_start(self): + self.__task_run_enum.put(1) + + def __task_run(self): + self.__task_run_enum.put(2) + + def __task_pause(self): + self.__task_run_enum.put(4) + + def __task_load(self): + self.__task_run_enum.put(3) + + def __task_reset(self): + self.__task_run_enum.put(5) + + def __set_task_id(self, task_id: int): + if task_id not in range(1, 5): + raise ValueError(f"Invalid task id {task_id}") + self.__task_id.put(task_id) + + def __put(self, axis: MyMotor, attr: str, value: float): + try: + axis.put(attr=attr, value=value) + except Exception as e: + raise ValueError(f"Error setting {axis.name} {attr} to {value}: {e}") + + def set_offset(self, axis: MyMotor, offset: float): + self.__put(axis=axis, attr="OFF", value=offset) + + def home_all(self, task_id: int = 3): + #self.__task_id.put(2) + self.__task_reset() + time.sleep(0.2) + self.__task_id.put(task_id) + print(self.__task_id.get()) + time.sleep(0.2) + self.__task_filename.put("home_all.a1exe") + print(self.__task_filename.get()) + # self.__task_load() + #time.sleep(0.2) + #print(self.__task_run_enum.get()) + time.sleep(1.0) + self.__task_run() + print(self.__task_run_enum.get()) + + def get_tast_status(self, task_id: int = 3): + task_status = PV(f"{self.aerotech_pv_prefix}:TASK:T{task_id}:STATUS") + return task_status.get(as_string=True) + + + def __set_global(self, index:int, value: Union[int, float, str], + timeout:float=10.0): + """Set a global variable in aerotech, it takes ~200 ms for the value to be set + :param index: select a variable to change. an integer between 0..256 for int and real variable for 0..31 for strings + :param value: the value to set can be int, float (REAL) or string + :param timeout: timeout for vairable change, default 10.0 seconds """ + var_type = self.__get_var_type(value) + caput(f"{self.aerotech_pv_prefix}:VAR:{var_type.upper()}-ADDR", index) + if var_type == 'STRING': + var_type = 'STRING-SHORT' + caput(f"{self.aerotech_pv_prefix}:VAR:{var_type.upper()}", value) + start = time.perf_counter() + while time.perf_counter() - start < timeout: + rbv = self.__read_global_from_index(index, var_type) + if rbv == str(value): + return + time.sleep(0.1) + + raise TimeoutError(f"Timeout setting global variable {index} to {value}") + + + def __read_global_feedback(self, index, var_type: str): + caput(f"{self.aerotech_pv_prefix}:VAR:{var_type.upper()}-RBV.PROC", 1) + time.sleep(0.5) + return caget(f"{self.aerotech_pv_prefix}:VAR:{var_type.upper()}-RBV", as_string=True) + + def __read_global_from_index(self, index, var_type: str): + return caget(f"{self.aerotech_pv_prefix}:VAR:{var_type.upper()}{index}_RBV", as_string=True) + + def __get_var_type(self, value): + if type(value) is int: + return VariableTypeEnum.INT.name + elif type(value) is float: + return VariableTypeEnum.REAL.name + elif type(value) is str: + return VariableTypeEnum.STRING.name + else: + raise ValueError(f"Invalid type {type(value)} for global variable") + + def get_global_variable(self, index: int, var_type:VariableTypeEnum): + return self.__read_global_from_index(index, var_type.name) + + def set_global_variable(self, index: int, value: Union[int, float, str]): + self.__set_global(index, value) + + +class AerotechController: + def __init__(self, controller_ip: str): + if controller_ip is None: + self.controller = None + else: + self.controller = a1.Controller.connect(controller_ip) + + self.status_item_configuration = a1.StatusItemConfiguration() + self.start_controller() + + def start_controller(self): + self.controller.start() + + def disconnect(self): + self.controller.disconnect() + + def enable_motion(self, axis: str): + self.controller.runtime.commands.motion.enable(axis.upper()) + + def home_motor(self, axis: str): + self.__configure_axis_status(axis, a1.AxisStatusItem.AxisEnabled) + result = self.get_status_via_status_items(name=axis, status_item=a1.AxisStatusItem.AxisEnabled) + if not result == a1.AxisStatusItem.AxisEnabled: + self.enable_motion(axis) + self.controller.runtime.commands.motion.home(axis.upper()) + + def __configure_axis_status(self, axis_name: str, axis_status_item: a1.AxisStatusItem): + self.status_item_configuration.axis.add(axis_status_item=axis_status_item, axis=axis_name) + + def __configure_task_status(self, task_id:int, task_status_item: a1.TaskStatusItem): + self.status_item_configuration.task.add(task_status_item=task_status_item, task=f"Task {task_id}") + + def get_status_via_status_items(self, name: str | int, status_item: a1.TaskStatusItem | a1.AxisStatusItem): + result = self.controller.runtime.status.get_status_items(self.status_item_configuration) + if int(name): + return result.task.get(status_item, f"Task {name}").value + elif str(name): + return result.axis.get(status_item, name).value + else: + raise ValueError(f"Invalid status item {status_item} for task {name}") + + def set_global_variable(self, index:int, value: Union[int, float, str]): + if type(value) is int: + self.controller.runtime.variables.global_.set_integer(index, value) + elif type(value) is float: + self.controller.runtime.variables.global_.set_real(index, value) + elif type(value) is str: + self.controller.runtime.variables.global_.set_string(index, value) + else: + raise ValueError(f"Invalid type {type(value)} for global variable") + + def get_axis_status_via_status_items(self, axis_name:str, status_item: a1.AxisStatusItem): + result = self.controller.runtime.status.get_status_items(self.status_item_configuration) + return result.task.get(status_item, axis_name).value + + def wait_for_status_to_change(self, name: str | int, status_item:a1.TaskStatusItem | a1.AxisStatusItem, enum, timeout: float = 60.0): + start = time.perf_counter() + while self.get_status_via_status_items(name, status_item) == enum: + time.sleep(0.1) + if time.perf_counter() - start > timeout: + print(self.get_status_via_status_items(name, status_item)) + raise TimeoutError(f"Timeout waiting for task {name} to finish") + return + + def wait_program_finish(self, task_id:int=3, timeout:float=60.0): + start = time.perf_counter() + status_item = a1.TaskStatusItem.TaskState + while True: + status = self.get_status_via_status_items(task_id, status_item) + if status != a1.TaskState.ProgramRunning: + if status == a1.TaskState.Idle: + return + elif status == a1.TaskState.ProgramComplete: + print(f"Program completed on Task {task_id}") + return + elif status == a1.TaskState.Error: + raise RuntimeError(f"Task {task_id} failed to start") + elif status == a1.TaskState.ProgramPaused: + print(f"Program paused on Task {task_id}, not sure how") + else: + raise RuntimeError(f"Unknown status {status} for task {task_id}") + if time.perf_counter() - start > timeout: + print(self.get_status_via_status_items(task_id, status_item)) + raise TimeoutError(f"Timeout waiting for task {task_id} to finish") + time.sleep(0.05) + print(f"Task {task_id} finished with status {status}") + + def __run_program(self, script_name:str, task_id:int=3, timeout:float=60.0): + self.__configure_task_status(task_id, a1.TaskStatusItem.TaskState) + state = self.get_status_via_status_items(task_id, a1.TaskStatusItem.TaskState) + print(f"Task {task_id} is in state {state}: {a1.TaskState(state).name}") + if state != a1.TaskState.ProgramComplete and state != a1.TaskState.Idle: + if a1.TaskState.ProgramRunning == state: + self.wait_for_status_to_change(task_id, a1.TaskStatusItem.TaskState, state, timeout) + elif a1.TaskState.ProgramComplete == state: + print('can continue') + else: + print(f"Task {task_id} is not Idle: {a1.TaskState(state).name} , aborting") + return + try: + print(f"Running script {script_name} on task {task_id}") + self.controller.runtime.tasks[task_id].program.run(script_name) + self.wait_program_finish(task_id, timeout) + except Exception as e: + print(f"Error executing script {script_name}: {e}") + + def run_grid_scan(self, cell_height_mm:float, num_rows:int, + row_width_mm:float, time_per_row_s: float, task_id:int =3): + self.set_global_variable(0, cell_height_mm) + self.set_global_variable(1, row_width_mm) + self.set_global_variable(2, time_per_row_s) + self.set_global_variable(1, num_rows) + self.set_global_variable(0, 1) + #self.__run_program(script_name="grid_scan.a1exe", task_id=task_id, timeout=120.0) + def home_all(self, task_id:int = 3): + self.__run_program(script_name="home_all.a1exe", task_id=task_id, timeout=120.0) + + def rotation_scan(self, task_id = 3, start_angle:float = 0.0, end_angle:float = 360.0, step_size:float = 1.0, num_steps:int = 10): + self.__run_program(script_name="rotation_scan.a1exe", task_id=task_id, timeout=90.0) + + def move_motor_absolute(self, axis:str, position:float, speed:float=1.0): + self.controller.runtime.commands.motion.moveabsolute(axis.upper(), [position], [speed]) + + def move_motor_linear(self, axis: str, position: float, speed: float = 1.0): + self.controller.runtime.commands.motion.movelinear(axis.upper(), [position], speed) + +if __name__ == "__main__": + beamline = mx_beamline() + print(beamline) + ### test on 10S + aerotech = AerotechController(controller_ip="129.129.118.96") + #aerotech.enable_motion("X") + #aerotech.home_all() + rw = 0.320 + ch = 0.010 + nr = 10 + tpr_s = rw / ch * 0.02 + #aerotech.run_grid_scan(cell_height_mm=ch, num_rows=nr, + # row_width_mm=rw, time_per_row_s=tpr_s) + st = time.perf_counter() + aerotech.move_motor_absolute("Z", 0, 10000) + print(f"time to move: {time.perf_counter() - st}") + aerotech.disconnect() + + #aerotech_epics = AerotechControllerEpics(beamline) + #aerotech_epics.omega.speed = 80.0 + #print(aerotech_epics.get_global_variable(0, VariableTypeEnum.REAL)) + #aerotech_epics.set_global_variable(0, 100.0) + #print(aerotech_epics.get_global_variable(0, VariableTypeEnum.REAL)) + # print('enable all motors') + # aerotech_epics.enable_all() + # print('home_all') + # aerotech_epics.home_all() + # print('wait for home to finish') + # start = time.perf_counter() + # status = aerotech_epics.get_tast_status(2) + # print(f'current status: {status}') + # if status == 'Idle': + # time.sleep(0.2) + # test_counter = 0 + # while status != 'Ready': + # time.sleep(0.1) + # if time.perf_counter() - start > 360.0: + # raise TimeoutError("Timeout waiting for home all task to finish") + # elif status == 'Idle': + # time.sleep(0.5) + # if test_counter == 1: + # raise RuntimeError("Home all task failed to start") + # time.sleep(1.0) + # print('restarting home all') + # aerotech_epics.home_all() + # time.sleep(1.0) + # test_counter = 1 + # + # status = arotech_epics.get_tast_status(2) + # for i in range(10): + # print(f'moving to {(i+1)*90}') + # aerotech_epics.omega.move(90.0, relative=True, wait=True) + # time.sleep(1.0) + # if i == 5: + # print('simulating disable') + # aerotech_epics._disable_all() + # time.sleep(10.0) + # print('re-enabling') + # aerotech_epics.enable_all() + # time.sleep(1.0) + # print('home all') + # aerotech_epics.home_all() + # print('wait for home to finish') + # start = time.perf_counter() + # status = aerotech_epics.get_tast_status(2) + # print(f'current status: {status}') + # test_counter = 0 + # while status != 'Ready': + # time.sleep(0.1) + # if time.perf_counter() - start > 360.0: + # raise TimeoutError("Timeout waiting for home all task to finish") + # status = aerotech_epics.get_tast_status(2) + # time.sleep(0.5) + # if test_counter == 1: + # raise RuntimeError("Home all task failed to start") + # time.sleep(1.0) + # print('restarting home all') + # aerotech_epics.home_all() + # time.sleep(1.0) + # test_counter = 1 + + + #aerotech_epics.home_all() + diff --git a/daq/src/mxlibs3/area_detector.py b/src/aare/devices/area_detector.py similarity index 82% rename from daq/src/mxlibs3/area_detector.py rename to src/aare/devices/area_detector.py index 082f8cb1..1f6ac594 100644 --- a/daq/src/mxlibs3/area_detector.py +++ b/src/aare/devices/area_detector.py @@ -1,6 +1,12 @@ +from enum import Enum + import epics import numpy as np +class AutoEnum(Enum): + MANUAL = 0 + ONCE = 1 + AUTO = 2 class epicsAD(object): def __init__(self, prefix, cam="cam1:", image="image1:"): @@ -12,10 +18,15 @@ class epicsAD(object): self.acquire = epics.PV(prefix + cam + "Acquire") self.color = epics.PV(prefix + cam + "ColorMode") self.gain_mode = epics.PV(prefix + cam + "GainAuto") + self.gain_mode_rbv = epics.PV(prefix + cam + "GainAuto_RBV") # 0 - manual, GainMode, 2 - auto GainAuto self.expo_mode = epics.PV(prefix + cam + "ExposureAuto") - # 0 - manual, ExposureMode, 2 - auto ExposureAutoself.gain = epics.PV(prefix + cam + "Gain") + self.expo_mode_rbv = epics.PV(prefix + cam + "ExposureAuto_RBV") + # 0 - manual, ExposureMode, 1 - once 2 - auto ExposureAuto + self.gain = epics.PV(prefix + cam + "Gain") + self.gain_rbv = epics.PV(prefix + cam + "Gain_RBV") self.expo = epics.PV(prefix + cam + "AcquireTime") + self.expo_rbv = epics.PV(prefix + cam + "AcquireTime_RBV") self.ndim = epics.PV(prefix + image + "NDimensions_RBV") self.dim0 = epics.PV(prefix + image + "ArraySize0_RBV") @@ -128,10 +139,20 @@ class epicsAD(object): self.expo.put(expo) # 20 hz acquisition self.acquire.put(1) - def set_auto(self): + def set_auto(self, state: AutoEnum): self.acquire.put(0, wait=True) - self.gain_mode.put(2) # automatic gain control - self.expo_mode.put(2) # automatic exposure control + self.gain_mode.put(state.value) # automatic gain control + self.expo_mode.put(state.value) # automatic exposure control + self.acquire.put(1) + + def set_auto_once(self): + self.expo_mode.put(1) + self.gain_mode.put(1) + + def set_manual(self): + self.acquire.put(0, wait=True) + self.gain_mode.put(0) # automatic gain control + self.expo_mode.put(0) # automatic exposure control self.acquire.put(1) def restore(self, gain: float = 5, expo: float = 0.025): diff --git a/src/aare/devices/bec_worker.py b/src/aare/devices/bec_worker.py new file mode 100644 index 00000000..7772595e --- /dev/null +++ b/src/aare/devices/bec_worker.py @@ -0,0 +1,259 @@ +from bec_lib.client import BECClient +from bec_ipython_client import BECIPythonClient +from bec_lib.service_config import ServiceConfig +from bec_lib.procedures.helper import FrontendProcedureHelper, BackendProcedureHelper + +from aare.common.beamline import MXBeamline, mx_beamline + + +#from pxii_bec.macros.pxii_guards import GuardViolation + + +#specify up to 10 queue to runs in parallel, request more if needed! +# st = client.proc.request_new("sleep", ((), {"time_s":5}), queue="test") + +#to see all deevices +#devs.show_all + +#helper fucntions +# helper.get.active_and_pending_queue_names() +# helper.get.running_procedures() +# helper.request.abort_queue() + +def bec_exception_handler(exception: Exception): + print(f"Exception: {exception}") + + +class MultiPositionDevice: + """inherits from the MultiPositionDevice BEC class + can move in and out + :param device is inisitialised with initialise_PD_devices() and can be called with PD.device_name + :states is a dictionary of str, float from bec.dev.device_name.user_parameter + """ + + def __init__(self, device, states: dict[str, float] | None = None): + self.device = device + self.states = states + + def move_to(self, position: str): + self.device.move_to(position) + + @property + def actual(self) -> float: + return self.device.actual + + @property + def state(self) -> str: + """returns the current state of the device as a string or unknown if out of a valid state position""" + return self.device.state + + @property + def is_at(self, state:str) -> bool: + return self.device.is_at("state") + + @property + def is_clear(self) -> bool: + return self.device.is_clear() + + +class PositionedDevice: + """inherits from the PositionedDevice BEC class + can move in and out + :param device is inisitialised with initialise_PD_devices() and can be called with PD.device_name + """ + + def __init__(self, device): + self.device = device + self.states = ["in", "out"] + + def move_in(self): + self.device.mvin() + + + def move_out(self): + self.device.mvout() + + @property + def is_in(self) -> bool: + return self.device.is_in() + + @property + def is_out(self) -> bool: + return self.device.is_out() + + +class GuardedPositionedDevice: + """inherits from the GuardedAxis BEC class + :param device is inisitialised with initialise_PD_devices() and can be called with PD.device_name + allowed functions are move(float) and actual which returns the feedback""" + + def __init__(self, device): + self.device = device + + def move(self, position: float): + self.device.move(position) + + @property + def actual(self) -> float: + return self.device.actual + + + +class OurBECDevices: + def __init__(self, BECDevices): + print("initialising devices") + init_positioned_devices() + dev = BECDevices + print("devices initialised") + self.coll_y = MultiPositionDevice(device = PD.coll_y, + states = dev.coll_y.user_parameter) + self.scintillator_diode_y = MultiPositionDevice(device = PD.diag_y, + states = dev.diag_y.user_parameter) + self.backlight_pos = PositionedDevice(device = PD.bl_pos) + #self.beamstop_pos = PositionedDevice(device = PD.bs_pos) + self.beamstop_z = GuardedPositionedDevice(device = PD.bs_z) + + self.goniometer_x = GuardedPositionedDevice(device = PD.gon_x) # may get deprecated with the IOC + +class BECClientWorker: + def __init__(self, beamline:MXBeamline, name:str = "default"): + BEAMLINE = beamline.value.lower() + service_config = ServiceConfig(redis={"host": f"{BEAMLINE}-bec-001.psi.ch", "port": 6379}) + print(service_config.config) + service_config.config["log_writer"]["base_path"]='./logs' + print(service_config.config) + self.client = BECIPythonClient(config=service_config) + #self.client.config.update_session_with_file("/sls/x10sa/config/bec/production/bec/bec_lib/bec_lib/config_helper.py") + self.client.start() + self.dev = self.client.device_manager.devices + self.scans = self.client.scans + self.macros = self.client.macros + self.load_user_macros() + self.helper = FrontendProcedureHelper(self.client.connector) + self.ProtectedDevices = OurBECDevices(BECDevices=self.dev) + + + def run_macro(self, macro_name:str, *args, queue:str = "default", **kwargs): + return self.client.proc.run_macro(macro_name, *args, queue=queue) + + def run_macro_blocked(self, macro_name:str, *args, queue:str = "default", **kwargs): + try: + status = self.run_macro(macro_name, *args, queue=queue) + print(status) + status.wait() + print(status) + return status + except Exception as e: + print(f"Error: {e}") + return None + + def show_all_devices(self): + return self.dev.show_all + + def list_all_macros(self): + return self.macros.list_user_macros() + + def load_user_macros(self): + self.macros.load_all_user_macros() + + def shutdown_client(self): + self.client.shutdown() + + def common2rse(self): + status = self.scans.umv(self.dev.blight_pos, 0, relative=False) + try: + SE.blpos.checkpos() + except NotImplemented as e: + print(f"Backlight position not checked: {e}") + print(f"Moved backlight to position {self.dev.blight_pos.read()} with status {status.status}") + self.scans.umv(self.dev.bs_z, 72.0, self.dev.coll_y, 20.0, self.dev.scin_y, 20.0, self.dev.cryo_pos, 1, relative=False) + self.scans.umv(self.dev.bs_pos, 0, relative=False) + print(f"Moved everything else to park position with status {status.status}") + + if self.dev.bs_z.read().value != 72.0:# or self.dev.coll_y.read() != 20.0 or self.dev.scin_y.read() != 20.0: + print(f"is bs_z correct: {self.dev.bs_z.read().value != 72.0}")# is coll_y correct {self.dev.coll_y.read() != 20.0}, is scin_y correct {self.dev.scin_y.read() != 20.0}") + raise Exception("Error: something went wrong") + + def rse2sa(self): + self.scans.umv(self.dev.blight_pos, 1, relative=False) + self.scans.umv(self.dev.bs_pos, 1, relative = False) + + def mono_pitch_scan_runner(self): + print('this is a print statement from inside DAQ not BEC') + try: + self.macros.mono_pitch_scan(False) + except Exception as e: + print(f"Error: {e}") + + # not implemented yet + # self.cryo_pos = PD.cryo_pos + # self.xrf_pos = PD.xrf_po + +if __name__ == "__main__": + import time + print('starting BEC Client') + beamline = mx_beamline() + try: + + client = BECClientWorker(beamline) + except Exception as e: + print(f"Error: {e}") + import sys + sys.exit(1) + + client.show_all_devices() + client.list_all_macros() + try: + # a=client.a2e_runner(160, "iln") + # print(a) + # print(convert_from_energy(12)) + # energy = get_current_energy() + # pos = get_dcm_motors_positions(energy) + # print(energy, pos) + print(bs_z_policy(15.0)) + #client.scans.umv(client.dev.xeye_x, 0, relative=False) + #client.mono_pitch_scan_runner() + #client.mono_pitch_scan_runner() + #b=client.run_macro_blocked("a2e", 160, "iln", queue="test") + #b = client.run_macro_blocked("mono_pitch_scan", False, queue="default") + + #status = client.mono_pitch_scan_runner + #print(status) + + #client.rse2sa() + #time.sleep(10.0) + #time.sleep(10.0) + #print(status) + #client.common2rse() + #print(status) + except GuardViolation as e: + print(f"GuardViolation: {e}") + except RuntimeError as e: + print(f"RuntimeError: {e}") + except Exception as e: + print(f"Error: {e}") + client.shutdown_client() + +# +# try: +# st = client.proc.run_macro("a2e", 160, "iln", queue="test") +# print(st) +# st.wait() +# print(st) +# status_1 = scans.umv(bec_dev.bs_x, -1.0, bec_dev.bs_y, -1.0, relative = True) # blocking +# print( +# f"Moved to position {bec_dev.bs_x.position} with status {status.status}" +# ) +# status = scans.mv(bec_dev.bs_x, 1.0, bec_dev.bs_y, 1.0, relative=True) # none blocking +# status.wait() +# print( +# f"Moved to position {bec_dev.bs_x.position} with status {status.status}" +# ) +# except Exception as e: +# print(f"Error: {e}") +# +# client.shutdown() + + +#backend wont work unless bec server will work, frontend anywehre with user access + diff --git a/src/aare/devices/enum_pv.py b/src/aare/devices/enum_pv.py new file mode 100755 index 00000000..118fe26f --- /dev/null +++ b/src/aare/devices/enum_pv.py @@ -0,0 +1,35 @@ +from enum import Enum +from typing import Any + +from aare.devices.set_get_pv import SetGetPV, MoveResult + +class EnumPV(SetGetPV): + def __init__(self, name: str, setpv: str, getpv: str, **kwargs): + super().__init__(name, setpv, getpv, **kwargs) + if not self.setpoint_pv.enum_strs: + raise RuntimeError(f"{setpv} is not an ENUM PV") + + @property + def position(self) -> str: + return self.readback_pv.get(as_string=True) + + def _resolve(self, x: Any) -> MoveResult: + # accept Enum member + if isinstance(x, Enum): + x = x.name + + # accept index + if isinstance(x, int): + try: + return MoveResult(target=self.setpoint_pv.enum_strs[x], name=None) + except Exception as e: + raise ValueError(f"Bad enum index {x}") from e + + # accept name -> match against enum strings (case-insensitive) + if isinstance(x, str): + for s in self.setpoint_pv.enum_strs: + if s.strip().lower() == x.strip().lower(): + return MoveResult(target=s, name=s) + raise ValueError(f"'{x}' not in {list(self.setpoint_pv.enum_strs)}") + + raise TypeError(f"Unsupported enum command type: {type(x).__name__}") \ No newline at end of file diff --git a/daq/src/mxlibs3/experimental_hutch_shutter.py b/src/aare/devices/experimental_hutch_shutter.py similarity index 95% rename from daq/src/mxlibs3/experimental_hutch_shutter.py rename to src/aare/devices/experimental_hutch_shutter.py index 8800fc14..83526763 100644 --- a/daq/src/mxlibs3/experimental_hutch_shutter.py +++ b/src/aare/devices/experimental_hutch_shutter.py @@ -1,4 +1,4 @@ -from aaredaqlib.beamline import MXBeamline +from aare.common.beamline import MXBeamline from epics import PV class ExperimentalHutchShutter: diff --git a/daq/src/mxlibs3/filter_transmission.py b/src/aare/devices/filter_transmission.py similarity index 97% rename from daq/src/mxlibs3/filter_transmission.py rename to src/aare/devices/filter_transmission.py index 3c9c9e17..46dee47f 100644 --- a/daq/src/mxlibs3/filter_transmission.py +++ b/src/aare/devices/filter_transmission.py @@ -2,7 +2,7 @@ import time from epics import PV, poll -from aaredaqlib.beamline import MXBeamline +from aare.common.beamline import MXBeamline class FilterTransmission: diff --git a/daq/src/mxlibs3/fluorimeter.py b/src/aare/devices/fluorimeter.py similarity index 97% rename from daq/src/mxlibs3/fluorimeter.py rename to src/aare/devices/fluorimeter.py index 7b664729..ca5b298c 100644 --- a/daq/src/mxlibs3/fluorimeter.py +++ b/src/aare/devices/fluorimeter.py @@ -1,12 +1,10 @@ import time -from typing import Callable, cast from epics import PV, poll -from epics.ca import pend_io -from aaredaqlib.beamline import MXBeamline +from aare.common.beamline import MXBeamline -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareaDAQ") diff --git a/daq/src/mxlibs3/jfjoch.py b/src/aare/devices/jfjoch.py similarity index 94% rename from daq/src/mxlibs3/jfjoch.py rename to src/aare/devices/jfjoch.py index 6d106d19..964cd761 100644 --- a/daq/src/mxlibs3/jfjoch.py +++ b/src/aare/devices/jfjoch.py @@ -2,11 +2,10 @@ import math import jfjoch_client -from aaredaqlib.beamline import MXBeamline -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.models import SampleShortInfo, DAQStatusModel, FluorescenceSpectrumOutputModel -from aaredaqlib.raster_grid import RasterGridRequest -from aaredaqlib.rotation_scan import RotationScanRequest +from aare.common.beamline import MXBeamline +from aare.common.models import DAQStatusModel, FluorescenceSpectrumOutputModel +from aare.common.raster_grid import RasterGridRequest +from aare.common.rotation_scan import RotationScanRequest class JFJochWrapper: @@ -14,6 +13,8 @@ class JFJochWrapper: match bl: case MXBeamline.X06DA: self.__url = "http://sls-gpu-001:8080" + case MXBeamline.X10SA: + self.__url = "http://sls-gpu-002:8080" case MXBeamline.SIMULATED: self.__url = "http://localhost:8080" case _: diff --git a/daq/src/mxlibs3/mx_lib.py b/src/aare/devices/mx_lib.py similarity index 69% rename from daq/src/mxlibs3/mx_lib.py rename to src/aare/devices/mx_lib.py index 9a0e30cc..1f40ed06 100644 --- a/daq/src/mxlibs3/mx_lib.py +++ b/src/aare/devices/mx_lib.py @@ -1,44 +1,9 @@ -import datetime import re import time -from typing import Callable, Union +from typing import Callable, Union, Any from epics import PV, Motor, poll - -def timestamp(): - """ - Returns a fixed width string (15 characters) with a timestamp - in the format (24Hour:Minute:Second.Microsecond). - - Example: 13:09:43.009508 - """ - x = datetime.datetime(1, 1, 1).now() - return "%4d-%02d-%02d %02d:%02d:%02d,%03d" % ( - x.year, - x.month, - x.day, - x.hour, - x.minute, - x.second, - x.microsecond / 1000, - ) - - -def itoa(x, base=10): - is_negative = x < 0 - if is_negative: - x = -x - digits = [] - while x > 0: - x, last_digit = divmod(x, base) - digits.append("0123456789abcdefghijklmnopqrstuvwxyz"[last_digit]) - if is_negative: - digits.append("-") - digits.reverse() - return "".join(digits) - - def wait_for_movement_to_finish(*motors): """ Wait for all {motors} passed in argument to finish movement. @@ -51,10 +16,6 @@ def wait_for_movement_to_finish(*motors): Returns: nothing """ - # timeout = 1.5 * max([abs(motor.get_position(readback=True) - - # motor.get_position()) / motor.slew_speed - # for motor in motors]) - # poll(0.3) longest = 0.0 for motor in motors: @@ -77,15 +38,31 @@ class ValueWaitTimeout(Exception): pass -def pv_wait(pv, value, *, timeout=30.0, polling=0.2, tolerance=None, verbose=False): - if not (isinstance(pv, PV) or isinstance(pv, Motor)): - raise ValueError("wait what!? what pv?!") - +def pv_wait(pv: PV | Motor, value: Any, *, timeout: float = 60.0, + polling: float = 0.1, tolerance: float | None=None, verbose: bool =False): + """wait until an epics.PV reaches a value + pv: epics.PV | epics.Motor + the PV on which you want to wait on + value/target: any + this value depends on the PV type: str, enum, double, ... + :timeout: float default = 60.0 + timeout in seconds + :polling: float default = 0.1 + polling interval in seconds + tolerance: float or None + provide a tolerance to accept when comparing values, currently None by default, however certain PVs and motors + have inbuilt tolerances that can be used instead + verbose: bool default = False + NotImplemented + """ if isinstance(pv, Motor): def checker(m, target=None, tolerance=None): if tolerance is None: tolerance = m.get("RDBD") + if tolerance is None: + print(f"WARNING: motor {m._prefix[:-1]} has no RDBD, using 0.001") + tolerance = 0.001 #FIXME if target is None: target = m.drive @@ -107,14 +84,25 @@ def pv_wait(pv, value, *, timeout=30.0, polling=0.2, tolerance=None, verbose=Fal def is_epics_type(pv: PV, pv_type: str) -> bool: + """Check to see if a PV is of a certain type such as double, enum, string, ...""" if isinstance(pv_type, type): pv_type = pv_type.__name__ return pv_type == pv.type -def wait_string_condition(pv, target: Union[str, re.Pattern], *, timeout=60.0, polling=0.1): - if not (isinstance(pv, PV) or "string" not in pv.type): +def wait_string_condition(pv: PV, target: Union[str, re.Pattern], *, timeout: float = 60.0, polling: float = 0.1): + """wait until an epics.PV of type string reaches target + :pv: epics.PV + PV should be of type string + :target: str or re.Pattern + :timeout: float default = 60.0 + timeout in seconds + :polling: float default = 0.1 + polling interval in seconds + """ + + if not (isinstance(pv, PV) and "string" not in pv.type): raise AttributeError("argument 'pv' must be an epics.PV of type string") if not isinstance(target, re.Pattern): @@ -131,7 +119,8 @@ def wait_string_condition(pv, target: Union[str, re.Pattern], *, timeout=60.0, p raise TimeoutError(f"timeout waiting for string {pv.pvname} == {target}; actual value == {pv.char_value}") -def wait_float_condition(pv: PV, value, *, timeout: float = 60.0, **kwargs): +def wait_float_condition(pv: PV, value:float, *, timeout: float = 60.0, + polling: float = 0.1, tolerance: float| None = None): """wait until an epics.PV of type double reaches value pv: epics.PV the PV enum on which you want to wait on @@ -139,30 +128,37 @@ def wait_float_condition(pv: PV, value, *, timeout: float = 60.0, **kwargs): value: float the target value + polling: float + how often pv is checked during wait loop + tolerance: float or None the tolerance to accept when comparing values, if None (default) we try to figure an appropriate value - timeout: double + timeout: float default = 60.0 a timeout in seconds return: nothing raises: TimeoutError if a timeout occurs """ - if not (isinstance(pv, PV) or "double" not in pv.type): - raise AttributeError("argument 'pv' must be an epics.PV of type double") try: value = float(value) except ValueError: raise AttributeError("argument 'value' must be a number") - tolerance = kwargs.get("tolerance", pow(10, -(pv.precision - 1))) # type: ignore - polling = kwargs.get("polling", 0.1) + if tolerance is None: + # If pv.precision is missing/None, fall back to a default + precision = getattr(pv, "precision", None) + if precision is None: + tolerance = 1e-6 + else: + tolerance = pow(10, -(precision - 1)) tout = time.time() + timeout + while time.time() < tout: if abs(pv.value - value) < tolerance: return @@ -190,13 +186,13 @@ def wait_motor_position(motor: Motor, tester: Callable, *, timeout: float = 50.0 raises: TimeoutError if a timeout occurs """ - if not isinstance(tester, Callable): + if not callable(tester): raise RuntimeError("argument 'tester' must be a function") try: move_time = abs(motor.drive - motor.readback) / motor.speed except Exception: - move_time = 1.0 # in case we're dealing with weird motor record + move_time = 1.0 # in case of unusual motor record tout = move_time + time.time() + timeout @@ -209,7 +205,7 @@ def wait_motor_position(motor: Motor, tester: Callable, *, timeout: float = 50.0 raise TimeoutError(f"timeout waiting for a condition on {motor} {motor.drive} != {motor.readback}") -def wait_enum_condition(pv: PV, value: Union[str, int, re.Pattern], *, timeout: float = 60.0, polling=0.1, **kwargs): +def wait_enum_condition(pv: PV, value: Union[str, int, re.Pattern], *, timeout: float = 60.0, polling=0.1): """wait until an epics.PV enum reaches value pv: epics.PV the PV enum on which you want to wait on @@ -224,7 +220,7 @@ def wait_enum_condition(pv: PV, value: Union[str, int, re.Pattern], *, timeout: raises: TimeoutError if a timeout occurs """ - if not (isinstance(pv, PV) or "enum" != pv.type[-4:].lower()): + if not (isinstance(pv, PV) and pv.type.lower().endswith("enum")): raise AttributeError("argument 'pv' must be an epics.PV of type enum") if not (isinstance(value, str) or isinstance(value, int) or isinstance(value, re.Pattern)): @@ -248,4 +244,12 @@ def wait_enum_condition(pv: PV, value: Union[str, int, re.Pattern], *, timeout: poll(polling) if time.time() > tout: - raise TimeoutError(f"timeout waiting for enum {pv.pvname} == {value}") + raise TimeoutError(f"timeout waiting for enum {pv.pvname} == {value}," + f"current value is {pv.get(as_string=True)}") + +def clean_filename(self, filename: str) -> str: + cleaned = re.sub(r"[^A-Za-z0-9._-]", "_", filename.strip()) + cleaned = cleaned.strip("._-") + if not cleaned: + raise ValueError("Filename is empty after sanitization.") + return cleaned \ No newline at end of file diff --git a/src/aare/devices/my_motor.py b/src/aare/devices/my_motor.py new file mode 100644 index 00000000..d7938948 --- /dev/null +++ b/src/aare/devices/my_motor.py @@ -0,0 +1,102 @@ +import time + +from epics import Motor + + +class MyMotor(Motor): + """Wrapper for the EPICS motor PV.""" + def __init__(self, name, timeout=5.0): + super().__init__(name.upper(), timeout=timeout) + + @property + def speed(self): + """Gets the current motor.slew_speed value""" + return self.get('VELO') + + @speed.setter + def speed(self, v): + """Sets the motor slew speed""" + self.put('VELO', v) + + @property + def position(self): + """Gets the current motor readback value""" + return self.readback + + @property + def value(self): + """Gets the current motor.drive value""" + return self.drive + + @value.setter + def value(self, v): + """Sets motor.drive to a set value""" + self.drive = v + + def stop(self): + """Stops the motor""" + self.stop_motor() + + @property + def moving(self): + """Returns True if the motor is moving""" + return bool(self.moving_flag) + + @property + def units(self): + """Returns the units of the motor as a string""" + return self.get("EGU", as_string=True) + + @property + def limits(self): + """Returns (low_limit, high_limit)""" + return self.get('HLM'), self.get('LLM') + + @limits.setter + def limits(self, limits): + """Sets (low_limit, high_limit)""" + low, high = limits + self.put('LLM', low) + self.put('HLM', high) + + def move_motor(self, val, relative=False, wait=False, timeout=300.0): + """ + Moves the motor to an absolute or relative position. + :param val: Position to move to + :param relative: If True, moves relative to current position + :param wait: If True, waits for completion (synchronous) + :param timeout: Maximum time to wait for completion + """ + + return self.move(val, relative=relative, wait=wait, timeout=timeout) + + def home(self, direction='forward', wait=False): + """ + Homes the motor. + :param direction: 'forward' or 'reverse' + """ + field = 'HOMF' if direction == 'forward' else 'HOMR' + self.put(field, 1) + if wait: + self.wait_for_stop() + + def wait_for_stop(self, timeout=300.0, poll_rate=0.01): + """ + Synchronous wait until the motor stops moving. + """ + start_time = time.time() + while self.moving: + time.sleep(poll_rate) + if time.time() - start_time > timeout: + raise RuntimeError(f"Timeout waiting for motor {self.name} to stop") + + async def wait_for_stop_async(self, timeout=300.0, poll_rate=0.01): + """ + Asynchronous wait until the motor stops moving. + """ + import asyncio + start_time = time.time() + while self.moving: + await asyncio.sleep(poll_rate) + if time.time() - start_time > timeout: + raise RuntimeError(f"Timeout waiting for motor {self.name} to stop") diff --git a/src/aare/devices/set_get_pv.py b/src/aare/devices/set_get_pv.py new file mode 100644 index 00000000..c3784fe2 --- /dev/null +++ b/src/aare/devices/set_get_pv.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Mapping, Optional, Union, Callable + +from epics import PV, poll +from aare.devices.mx_lib import pv_wait + +RawValue = Union[str, float, int] +ResolverValue = Union[ + RawValue, + tuple[Callable[..., RawValue], tuple[Any, ...]], # (func, args) pattern you already use +] + +@dataclass +class MoveResult: + target: RawValue + name: Optional[str] = None + + +class SetGetPV: + def __init__(self, name: str, setpv: str, getpv: str, *, timeout: float = 60.0, tolerance: float | None = None): + self.name = name + self.setpoint_pv = PV(setpv) + self.readback_pv = PV(getpv) + self.default_timeout = timeout + self.tolerance = tolerance + self._last_target: RawValue | None = None + + @property + def value(self) -> Any: + return self.readback_pv.get() + + def _resolve(self, x: Any) -> MoveResult: + # Default: treat input as raw value + return MoveResult(target=x, name=None) + + def move(self, x: Any, *, wait: bool = False, timeout: float | None = None) -> MoveResult: + res = self._resolve(x) + self._last_target = res.target + self.setpoint_pv.put(res.target) + if wait: + self.wait(timeout=timeout) + return res + + def wait(self, *, timeout: float | None = None): + if self._last_target is None: + return + pv_wait(self.readback_pv, self._last_target, timeout=timeout or self.default_timeout, tolerance=self.tolerance) + +class PredefinedPV(SetGetPV): + def __init__(self, name: str, setpv: str, getpv: str, predefs: Mapping[str, ResolverValue], **kwargs): + super().__init__(name, setpv, getpv, **kwargs) + self._predefs = dict(predefs) + + @property + def positions(self) -> list[str]: + return list(self._predefs.keys()) + + def _resolve(self, x: Any) -> MoveResult: + if isinstance(x, str) and x in self._predefs: + v = self._predefs[x] + if isinstance(v, tuple) and callable(v[0]): + v = v[0](*v[1]) + return MoveResult(target=v, name=x) + return MoveResult(target=x, name=None) diff --git a/src/aare/devices/smargon.py b/src/aare/devices/smargon.py new file mode 100644 index 00000000..9a7951d3 --- /dev/null +++ b/src/aare/devices/smargon.py @@ -0,0 +1,234 @@ +from enum import Enum +from time import sleep, time + +import requests + +from aare.common.beamline import MXBeamline +from aare.common.coordinate import SmargonCoordinate, Coordinate, AerotechCoordinate +from aare.common.exception_handler import SmargonCommunicationError + + +class SmargonMode(Enum): + UNINITIALIZED = 0 + INITIALIZING = 1 + READY = 2 + ERROR = 99 + + +class Smargon(object): + SMARGON_HOME = SmargonCoordinate( + sh_mm=Coordinate(x=0, y=0, z=18), phi_deg=0, chi_deg=0 + ) + AERO_HOME = AerotechCoordinate(x=0, y=0, z=0, omega=0) + + def __init__(self, bl: MXBeamline): + if bl == MXBeamline.X06DA: + self.__simulated = False + self.__base = "http://x06da-smargopolo.psi.ch:3000" + elif bl == MXBeamline.X10SA: + self.__simulated = False + self.__base = "http://x10sa-smargopolo.psi.ch:3000" + elif bl == MXBeamline.SIMULATED: + self.__simulated = True + self.__pos = self.SMARGON_HOME + self.__pos_aero = self.AERO_HOME + else: + raise Exception("unknown beamline") + + def gonget(self, thing: str) -> dict: + """issue a GET for some API component on the smargopolo server + short hand for goniometer get""" + cmd = f"{self.__base}/{thing}" + try: + r = requests.get(cmd, timeout=2.0) + except requests.exceptions.RequestException as e: + raise SmargonCommunicationError( + f"Smargon GET failed for '{thing}'", + endpoint=thing, + base_url=self.__base, + operation="GET", + ) from e + + if not r.ok: + raise SmargonCommunicationError( + f"Smargon GET returned HTTP {r.status_code} for '{thing}': {r.reason}", + endpoint=thing, + base_url=self.__base, + operation="GET", + status_code=r.status_code, + ) + + try: + return r.json() + except ValueError as e: + raise SmargonCommunicationError( + f"Smargon GET returned invalid JSON for '{thing}'", + endpoint=thing, + base_url=self.__base, + operation="GET", + status_code=r.status_code, + ) from e + + def gonput(self, thing: str): + """issue a PUT command for some API component on the smargopolo server + short hand for goniometer put""" + cmd = f"{self.__base}/{thing}" + try: + r = requests.put(cmd, timeout=2.0) + except requests.exceptions.RequestException as e: + raise SmargonCommunicationError( + f"Smargon PUT failed for '{thing}'", + endpoint=thing, + base_url=self.__base, + operation="PUT", + ) from e + + if not r.ok: + raise SmargonCommunicationError( + f"Smargon PUT returned HTTP {r.status_code} for '{thing}': {r.reason}", + endpoint=thing, + base_url=self.__base, + operation="PUT", + status_code=r.status_code, + ) + + def move_home(self, wait=False) -> None: + self.target = self.SMARGON_HOME + if wait: + self.wait() + + @property + def mode(self) -> SmargonMode: + return SmargonMode.INITIALIZING + + @mode.setter + def mode(self, mode: SmargonMode): + if self.__simulated: + return + self.gonput(f"mode?mode={mode}") + + def initialize(self): + self.mode = SmargonMode.UNINITIALIZED + sleep(0.1) + self.mode = SmargonMode.INITIALIZING + + def enable_correction(self): + if self.__simulated: + return + + self.gonput("corr_type?corr_type=1") + + def disable_correction(self): + if self.__simulated: + return + + self.gonput("corr_type?corr_type=0") + + @property + def readback(self) -> SmargonCoordinate: + if self.__simulated: + return self.__pos + + scs = self.gonget("readbackSCS") + return SmargonCoordinate( + sh_mm=Coordinate(x=scs["SHX"], y=scs["SHY"], z=scs["SHZ"]), + phi_deg=scs["PHI"], + chi_deg=scs["CHI"], + ) + + @property + def readback_aerotech(self) -> AerotechCoordinate: + if self.__simulated: + return self.__pos_aero + + acs = self.gonget("readbackAEROTECH") + return AerotechCoordinate(at_mm = Coordinate(x=acs["GMX"], y = acs["GMY"], z = acs["GMZ"]), + omega_deg = acs["GMU"]) + + @property + def target(self) -> SmargonCoordinate: + if self.__simulated: + return self.__pos + + scs = self.gonget("targetSCS") #targetAEROTECH, #targetOMEGA + return SmargonCoordinate( + sh_mm=Coordinate(x=scs["SHX"], y=scs["SHY"], z=scs["SHZ"]), + phi_deg=scs["PHI"], + chi_deg=scs["CHI"], + ) + + @target.setter + def target(self, coord: SmargonCoordinate): + if self.__simulated: + self.__pos = coord + return + + target_string = "" + if coord.sh_mm is not None: + target_string += "&SHX={:.5f}&SHY={:.5f}&SHZ={:.5f}".format( + coord.sh_mm.x, coord.sh_mm.y, coord.sh_mm.z + ) + if coord.chi_deg is not None: + target_string += "&CHI={:.5f}".format(coord.chi_deg) + if coord.phi_deg is not None: + target_string += "&PHI={:.5f}".format(coord.phi_deg) + if target_string: + self.gonput(f"targetSCS?{target_string}") + + @property + def target_aerotech(self) -> AerotechCoordinate: + if self.__simulated: + return self.__pos_aero + + acs = self.gonget("targetAEROTECH") #targetAEROTECH, #targetOMEGA + return AerotechCoordinate(at_mm = Coordinate(x=acs["GMX"], y = acs["GMY"], z = acs["GMZ"]), + omega_deg = acs["GMU"]) + + @target_aerotech.setter + def target_aerotech(self, coord: AerotechCoordinate): + if self.__simulated: + self.__pos_aero = coord + return + + target_string = "" + if coord.at_mm is not None: + target_string += "&GMX={:.5f}&GMY={:.5f}&GMZ={:.5f}".format( + coord.at_mm.x, coord.at_mm.y, coord.at_mm.z + ) + if coord.omega_deg is not None: + target_string += "&GMU={:.5f}".format(coord.omega_deg) + if target_string: + self.gonput(f"targetAEROTECH?{target_string}") + + + def wait(self, timeout=60.0, tol=0.01, poll_time=0.01): + target = self.target + timeout = timeout + time() + while time() < timeout: + if target.eq(self.readback, tol): + break + if time() > timeout: + raise TimeoutError("Timed out waiting for Smargon to reach target") + sleep(poll_time) + + def wait_aerotech(self, timeout=60.0, tol=0.01, poll_time=0.01): + target = self.target + timeout = timeout + time() + while time() < timeout: + if self.target_aerotech.eq(self.readback_aerotech, tol): + break + if time() > timeout: + raise TimeoutError("Timed out waiting for Aerotech to reach target") + sleep(poll_time) + + +if __name__ == "__main__": + smargon = Smargon(MXBeamline.X10SA) + x = smargon.readback_aerotech + print(x) + y = smargon.target_aerotech + smargon.target_aerotech = AerotechCoordinate(at_mm=Coordinate(x=0, y=0, z=0)) + print(y) + smargon.wait_aerotech() + print(f"aerotech reached {smargon.readback_aerotech}") + diff --git a/src/aare/devices/tell_client.py b/src/aare/devices/tell_client.py new file mode 100755 index 00000000..9ff31f99 --- /dev/null +++ b/src/aare/devices/tell_client.py @@ -0,0 +1,664 @@ +import json +import random +import re +import time +from typing import List +from urllib.parse import urlparse + +import requests + +from aare.common.exception_handler import TellCommunicationError +from aare.common.logger_config import setup_logger +from aare.common.models import ( + PuckLoadedInfo, + DewarAddress, + SampleDewarAddress, +) +from aareDB import PuckWithTellPosition + +from aare.common.beamline import MXBeamline # noqa: F401 +from pshell import PShellClient + +logger = setup_logger("aareDAQ") + +class ManualMountException(Exception): + """Custom exception for manual mounting""" + pass + + +class SmartMagnetFaultException(Exception): + """Custom exception for smart magnet fault""" + pass + + +class TellMountFailedException(Exception): + """Custom exception for mount failure""" + pass + + +class TellCommandWhileBusyException(Exception): + """Custom exception for trying to move Tell when it is busy""" + pass + + +class TellConnectionException(Exception): + """Custom exception for connection problems""" + pass + +VALID_DEWAR_POSITIONS = [f"{p}{n}" for n in "12345" for p in "ABCDEFX"] + +def is_valid_dewar_position(position): + """check if argument is a valid dewar position""" + return position in VALID_DEWAR_POSITIONS + +POSITION_PARK = "pPark" +POSITION_COLD = "pCold" +POSITION_AUX = "pAux" +POSITION_DEWAR = "pDewar" +POSITION_HOME = "pHome" +POSITION_HEATER = "pHeatB" + +#Nov 26 13:36:00 mx-x06da-queue-01.psi.ch AareDAQ[2944444]: 2025-11-26 13:36:00,388 - aareDAQ - ERROR - Error getting status: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer')) + +class TellClient: + """High-level Tell robot API using PShellClient""" + def __init__(self, bl: MXBeamline): + self.__url = None + beamline = bl.value.lower() + self.__beamline = bl + if bl == MXBeamline.X06DA: + self.__url = f"http://{beamline}-tell.psi.ch:22222" + + elif bl == MXBeamline.X10SA: + self.__url = f"http://PC17488:22222" + + elif bl == MXBeamline.X06SA: + self.__url = f"" + raise NotImplemented(f"TellClient not implemente for {beamline}") + elif bl == MXBeamline.SIMULATED: + raise NotImplemented(f"Use SimClient, generate tell client using" + f"make_tell_client(beamline)") + else: + raise ValueError(f"Unknown beamline {beamline}") + + print(f"Connecting TELL p-shell service at {self.__url} ...", end="") + hostname = urlparse(self.__url).hostname + try: + requests.get(f"{self.__url}/history/0", timeout=1.0) + except requests.exceptions.RequestException as e: + print(f"...connection to {hostname} failed") + raise TellCommunicationError( + f"TELL connection failed ({hostname})", + base_url=self.__url, + endpoint="history/0", + operation="GET", + ) from e + except requests.ReadTimeout as e: + print(f"...PShell service {hostname} is down") + raise TellCommunicationError( + f"TELL connection timedout ({hostname})", + base_url=self.__url, + endpoint="history/0", + operation="GET", + ) from e + + self.pshell = PShellClient(self.__url) + + self._aborted = False + self.state = self.get_state() + self.debug = False + self._last_cmd_id = -1 + + @property + def url(self): + """returns the configured base url for the Tell robot""" + return self.__url + + def get_state(self): + """returns the current state of the robot""" + self.state = self.pshell.get_state() + return self.state + + def get_result(self, command_id=-1): + """returns the result of the last command issued to the robot""" + return self.pshell.get_result(command_id) + + def wait_ready(self, timeout: float = 360.0): + """waits until the robot is ready to accept commands returns None if simulation + and raises an exception if the robot is not ready""" + self.pshell.wait_state("Ready", timeout=timeout) + + def wait_not_busy(self, timeout: float = 360.0): + """waits until the robot is not busy and returns None if simulation + and raises an exception if the robot is busy""" + self.pshell.wait_state_not("Busy", timeout=timeout) + state = self.get_state() + if state != "Ready": + if state == "Initializing": + raise TellConnectionException("Tell reconnecting") + elif state == "Closing": + raise TellConnectionException("Tell is disconnecting") + raise Exception("Invalid state: " + str(state)) + + def set_in_mount_position(self, value): + """tells the robot that the beamlien is safe and to set the in mount position flag allowing mounting + :param value """ + self.pshell.eval("in_mount_position = " + str(value) + "&") + + def is_in_mount_position(self) -> bool: + """checks to see if the robot is in the mount position and returns a boolean""" + return self.pshell.eval("in_mount_position&").lower() == "true" + + def set_samples_info(self, info: List[PuckWithTellPosition]): + """sets the samples in the robot dewar based on the given list of PuckWithTellPosition objects + and runs set_sample_info in the background""" + + j = [] + for x in info: + j.append( + { + "userName": x.pgroup, + "dewarName": x.dewar_name or "", + "puckName": x.puck_name, + "puckType": "Unipuck", # could use x.puck_type + "puckAddress": x.tell_position or "", + "puckBarcode": x.puck_name, + "sampleBarcode": "", + "sampleMountCount": 0, + "sampleName": "", + "samplePosition": 1, + "sampleStatus": "", + } + ) + + self.pshell.run("data/set_samples_info", pars=[json.dumps(j)], background=True) + # self.pshell.eval("set_samples_info(" + json.dumps(info) + ")&") + + def start_cmd(self, cmd, *argv): + """starts a command on the robot and returns the command id""" + cmd = cmd + "(" + for a in argv: + cmd = cmd + (("'" + a + "'") if type(a) is str else str(a)) + ", " + cmd = cmd + ")" + ret = self.pshell.start_eval(cmd) + self.get_state() + return ret + + def check_command_ok(self, timeout: float = 360.0, msg: str = ""): + """checks to see if the last command issued to the robot was completed and returns the result + Returns an exception if the command result doesnt return completed or removed""" + self.wait_not_busy(timeout) + result = self.get_result(self._last_cmd_id) + logger.debug(f"{msg} {result}") + status = result["status"] + if "completed" != status: #FIXME this is very limiting and depends on tell reporting statuses + if "removed" != status: + raise TellMountFailedException(f"{msg} {result}") + else: + return f"{msg} {result}" + + def estimate_mounting_time(self, segment) -> int: + """Adds additional time if cooling/drying is expected based on requested segment, + current sample segment and gripper position. + :param segment: any - however valid segment ABCDEFX """ + try: + current_mounted = self.get_mounted_sample() + gripper_in_cold = self.is_in_cold() + + if current_mounted is None: + unmount_needs_drying = 0 # might not have anything + unmount_needs_cooling = 0 + else: + segment_in_cold = current_mounted.puck.segment in "ABCDEF" + unmount_needs_drying = int(gripper_in_cold and not segment_in_cold) + unmount_needs_cooling = int(not gripper_in_cold and segment_in_cold) + + mount_needs_cooling = int(segment in "ABCDEF" and not gripper_in_cold) + mount_needs_drying = int(segment not in "ABCDEF" and gripper_in_cold) + + needs_cooling = mount_needs_cooling + unmount_needs_cooling + needs_drying = mount_needs_drying + unmount_needs_drying + return needs_cooling * 30 + needs_drying * 120 + except: + return 0 + + def mount( + self, + address: SampleDewarAddress, + force: bool = False, # kept for future + read_dm: bool = False, # read data matrix + auto_unmount: bool = False, # single command, if False it will raise exception + wait: bool = False, # blocking operation + timeout: float = 600.0, + ): + """send api request to mount sample from dewer after validating dewer address returns None or repsonse. + If the robot is busy, mount will raise an exception. + :param address: SampleDewarAddress + :param force: bool + :param read_dm: bool + :param auto_unmount: bool + :param wait: bool + :param timeout: float + """ + SampleDewarAddress.model_validate(address) + + segment = address.puck.segment + puck = address.puck.pos + sample = address.pin + + if self.is_busy(): + raise TellCommandWhileBusyException("mount received while robot is busy") + + logger.info(f"loading sample {sample} from segment {segment} - {puck}") + + self._last_cmd_id = self.start_cmd( + "mount", segment, puck, sample, force, read_dm, auto_unmount + ) + + wait_timeout = timeout + self.estimate_mounting_time(segment) + logger.info("waiting for mount to complete") + if wait and segment in "ABCDEF": + event, value = self.pshell.wait_events({"state": None, "Motion Task": "dry", + "Gripper detection" : None, + "Motion Sync": "Robot Clear after mount"}, timeout=wait_timeout) + if event is None or event == "state": + logger.info(f"event: {event} occurred with value: {value}, checking command completed okay") + self.check_command_ok( + timeout=wait_timeout, msg=f"Mount {segment}{puck}-{sample}: " + ) + return value + elif event == "Gripper detection" and value == "No Pin in Gripper": + logger.info(f"gripper detection: {event} occurred with value: {value}") + return value + elif event == "Gripper detection" and value == "Pin still in Gripper": + logger.info(f"gripper detection: {event} occurred with value: {value}") + return value + elif event == "Gripper detection" and value == "Pin is lost": + logger.info(f"gripper detection: {event} occurred with value: {value}") + return value + elif event == "Motion Task" and value == "dry": + logger.info(f"event: {event} occurred with value: {value}") + logger.info(" Drying occurring, releasing interface to user") + return value + elif event == "Motion Sync" and value == "Robot Clear after mount": + logger.info(f"event: {event} occurred with value: {value}") + logger.info(" Mounting complete, releasing interface to user") + return value + else: + logger.info(f"Unexpected event: {event} occurred with value: {value}") + logger.info("Checking command completed okay anyway") + self.check_command_ok( + timeout=wait_timeout, msg=f"Mount {segment}{puck}-{sample}: " + ) + elif wait and segment == "X": + logger.info("Loading an auxiliary puck") + self.check_command_ok( + timeout=wait_timeout, msg=f"Mount {segment}{puck}-{sample}: " + ) + logger.info("post waiting") + return None + + def unmount(self, force=False, wait=False, timeout=360.0): + """send api request to unmount sample from dewer returns None or repsonse. + :param force: bool Force has a meaning, will unmount even if smart magnet is not detecting sample + :param wait: bool If true will wait until unmount is completed + :timeout: float""" + + if self.is_busy(): + raise TellCommandWhileBusyException("mount received while robot is busy") + + self._last_cmd_id = self.start_cmd("unmount", None, None, None, force) + + if wait: + self.check_command_ok(timeout=timeout, msg="Unmount message: ") + + return self._last_cmd_id + + def dry(self, heat_time=None, speed=None, wait_cold=None, wait=False): + """send api request to dry tell gripper. + :param: heat_time float if None Tell will use default for drying time + :param: speed float if None Tell will use default for drying speed + :param: wait_cold bool if -1 to go to park after dry. if None Tell will use default time to wait_cold. + :param wait: bool If true will wait until drying is completed + """ + self.pshell.wait_state("Ready", timeout=30.0) + self._last_cmd_id = self.start_cmd("dry", heat_time, speed, wait_cold) + if wait: + self.check_command_ok(timeout=360.0, msg=f"Dry failed") + + def move_park(self, wait=False): + """send api request to move robot to park position""" + self._last_cmd_id = self.start_cmd("move_park") + + if wait: + self.check_command_ok(timeout=360.0, msg=f"Move to park failed") + + def move_cold(self, reset_timestamp=False, wait=False): + """send api request to move robot to cold position""" + self._last_cmd_id = self.start_cmd("move_cold", reset_timestamp) + + if wait: + self.check_command_ok(timeout=360.0, msg=f"Move to cold failed") + + def abort_cmd(self): + """sends an abort pshell requesst and a robot stop task command""" + self.pshell.abort() + self.pshell.eval("robot.stop_task()&") + + def set_setting(self, key: str, value: str): + """wrapper for pshell eval set_setting command + :param key str, name of a setting in tell + :param value str, the new value of the setting as a string""" + self.pshell.eval(f"set_setting('{key}', '{value}')&") + + def get_setting(self, key: str) -> str: + """wrapper for pshell eval get_setting command, returns the current value for key as a string + :param key str, name of a setting in tell""" + return self.pshell.eval(f"get_setting('{key}')&") + + def get_mounted_sample(self) -> SampleDewarAddress | None: + """get the current mounted sample and return a SampleDewarAddress object or None if no sample is mounted""" + ret = self.get_setting('mounted_sample_position').strip() + if not ret or len(ret) == 0: + return None + + match = re.match(r"([A-Z])(\d)(\d{1,2})", ret) + + if match: + segment, puck, sample = match.groups() + dewar_location = DewarAddress(segment=segment, pos=int(puck)) + return SampleDewarAddress(puck=dewar_location, pin=int(sample)) + else: + logger.warning(f"Failed to decode mounted sample position: {ret}") + return None + + def get_system_check(self): + """returns the current system check status""" + return self.pshell.eval("system_check_msg()&") + + def get_robot_state(self): + """returns the current robot state""" + return self.pshell.eval("robot.state&") + + def get_robot_status(self): + """returns the current robot status""" + status = self.pshell.eval("robot.take()&") + return eval(status) # FIXME ALL functions must return a valid JSON object + + def get_detected_pucks(self) -> List[PuckLoadedInfo]: + """returns a list of detected pucks as PuckLoadedInfo objects""" + j = json.loads(self.pshell.eval("get_pucks_info()&")) + + output = [] + + for i in j: + if i["puckState"] == "Present": + puck_address = i["puckAddress"] + if len(puck_address) == 2: + output.append( + PuckLoadedInfo( + puck_name=i["puckBarcode"], + location=DewarAddress( + segment=puck_address[0], pos=int(puck_address[1]) + ), + ), + ) + return output + + def get_pin_offset(self): + """get the pin offset for the smart magnet, returns offset as a float""" + try: + offset = float(self.pshell.eval("get_pin_offset()&")) + except Exception: + offset = 0.0 + return offset + + def get_current(self): + """get the current drawn by the smart magnet, returns current as a float in mA""" + current = self.pshell.eval("smart_magnet.get_current_rb()&") + return float(current) + + def set_current(self, current: float) -> float: + """set the current drawn by the smart magnet, returns current as a float in mA""" + self.pshell.eval("smart_magnet.set_current({:.1f})&".format(current)) + current = self.pshell.eval("smart_magnet.get_current_rb()&") + return float(current) + + def is_powered(self): + """returns True if the robot is powered on""" + return self.get_robot_status()["powered"] + + def check_enable_motion(self): + """check if the robot is powered on and enable motion if not""" + if not self.is_powered(): + self.pshell.eval("enable_motion()&") + + def is_in_cold(self): + """Compare current robot position to the set cold position. Returns True if in cold position, False otherwise.""" + return self.is_position(POSITION_COLD) + + def is_position(self, position: str) -> bool: + """Compare current robot position to a given position. Returns True if in position, False otherwise.""" + return position == self.get_robot_status()["pos"] + + def is_ready(self): + """returns True if the robot is ready to receive commands""" + return "ready" == self.get_state().lower() + + def is_busy(self): + """returns True if the robot is busy""" + return "busy" == self.get_state().lower() + + def check_smart_magnet_mounted(self, timeout: float = 10.0, idle_time: float = 1.0, interval: float = 0.1): + """Reads smart_magent state and tries to infer if a sample is present + Handles: PAUSED, Fault, Busy and Ready states. + Raises a ManualMountException is the amgnet indicates a sample is present but get_mounted_sample is None. + Raises a SmartMagnetFaultException if the magnet detects no sample but the robot thinks a sample is mounted""" + #TODO tidy up + initial_state = self.pshell.eval("smart_magnet.state&") + + logger.debug(f"checking smart magnet_initial state: {initial_state}") + + if initial_state == "Paused": + self.pshell.eval("smart_magnet.set_supress(False)&") + self.pshell.eval("smart_magnet.set_resting_current()&") + + elif initial_state == "Fault": + logger.error(f"tell smart magnet is in unknown state {initial_state}") + raise SmartMagnetFaultException + + state = self.pshell.eval("smart_magnet.state&") + + try: + if state == "Busy": + logger.debug('state busy') + self.pshell.eval("smart_magnet.set_supress(True)&") + self.pshell.eval("smart_magnet.state&") + sample_present = True + if self.get_mounted_sample() is None: + logger.warning("Check mount: A manually mounted sample is detected.") + logger.warning("Remove before mounting with the robot.") + raise ManualMountException + return True + elif state == "Ready": + logger.debug('No sample detected, ready to mount') + sample_present = False + if self.get_mounted_sample(): + logger.error("Check mount: No sample detected, but robot thinks is mounted") + raise SmartMagnetFaultException + return False + elif state == "Paused": + logger.debug("Smart magnet detection is paused") + return None + else: + self.pshell.eval("smart_magnet.set_supress(True)&") + logger.error(f"Tell smart magnet is in unknown state {state}") + raise SmartMagnetFaultException + + except Exception as e: + logger.error(f"check_smart_magnet_mounted failed: {e}") + raise e + +class SimTellClient: + """ + Simulation-only Tell client. + + Keeps behavior deterministic-ish and stateful without needing PShellClient. + Implement more methods as your callers need them. + """ + def __init__(self): + self._state = "Ready" + self._last_cmd_id = 1000 + self._mounted_sample: str = "" + self._simulated_samples_info = {} + self._simulated_detected_pucks = [] + self._simulated_current = 30.0 + self._simulated_suppress = True + self._simulated_offset = 0.0 + + @property + def url(self): + return None + + def _next_cmd_id(self) -> int: + self._last_cmd_id += 1 + return self._last_cmd_id + + def get_state(self) -> str: + return self._state + + def is_ready(self) -> bool: + return self._state.lower() == "ready" + + def is_busy(self) -> bool: + return self._state.lower() == "busy" + + def wait_ready(self, timeout: float = 360.0): + # Keep it simple: flip to Ready quickly. + time.sleep(0.05) + self._state = "Ready" + + def mount( + self, + address: SampleDewarAddress, + force: bool = False, + read_dm: bool = False, + auto_unmount: bool = False, + wait: bool = False, + timeout: float = 600.0, + ): + SampleDewarAddress.model_validate(address) + if self.is_busy(): + raise TellCommandWhileBusyException("mount received while robot is busy") + + cmd_id = self._next_cmd_id() + self._state = "Busy" + + segment = address.puck.segment + puck = address.puck.pos + sample = address.pin + self._mounted_sample = f"{segment}{puck}{sample}" + + if wait: + self.wait_ready(timeout=timeout) + else: + # quickly become ready anyway, but asynchronously-ish + time.sleep(0.01) + self._state = "Ready" + + return cmd_id + + def unmount(self, force: bool = False, wait: bool = False, timeout: float = 360.0): + if self.is_busy(): + raise TellCommandWhileBusyException("unmount received while robot is busy") + + cmd_id = self._next_cmd_id() + self._state = "Busy" + self._mounted_sample = "" + if wait: + self.wait_ready(timeout=timeout) + else: + time.sleep(0.01) + self._state = "Ready" + return cmd_id + + def get_mounted_sample(self) -> SampleDewarAddress | None: + ret = self._mounted_sample + if not ret: + return None + match = re.match(r"([A-Z])(\d)(\d{1,2})", ret) + if not match: + return None + segment, puck, sample = match.groups() + return SampleDewarAddress(puck=DewarAddress(segment=segment, pos=int(puck)), pin=int(sample)) + +class TellClientProxy: + """ + Lazy-connecting Tell client proxy that retries periodically. + - Server can start even if TELL is down. + - First use triggers connect; failures raise TellCommunicationError. + """ + def __init__(self, bl: MXBeamline, *, retry_interval_s: float = 2.0): + self._bl = bl + self._client: TellClient | None = None + self._retry_interval_s = float(retry_interval_s) + self._last_attempt_ts = 0.0 + self._last_error: Exception | None = None + + def _get_client(self) -> TellClient: + if self._client is not None: + return self._client + + now = time.monotonic() + if now - self._last_attempt_ts < self._retry_interval_s and self._last_error is not None: + raise self._last_error + + self._last_attempt_ts = now + try: + self._client = TellClient(self._bl) + self._last_error = None + return self._client + except TellCommunicationError as e: + self._last_error = e + raise + except Exception as e: + wrapped = TellCommunicationError( + "TELL connection failed", + operation="CONNECT", + ) + self._last_error = wrapped + raise wrapped from e + + @property + def url(self): + return self._get_client().url + + # Delegate methods used by DAQ; add more as needed + def get_mounted_sample(self) -> SampleDewarAddress | None: + return self._get_client().get_mounted_sample() + + def get_state(self): + return self._get_client().get_state() + + def wait_not_busy(self, timeout: float = 360.0): + return self._get_client().wait_not_busy(timeout=timeout) + + def check_enable_motion(self): + return self._get_client().check_enable_motion() + + def set_in_mount_position(self, value): + return self._get_client().set_in_mount_position(value) + + def mount(self, *args, **kwargs): + return self._get_client().mount(*args, **kwargs) + + def unmount(self, *args, **kwargs): + return self._get_client().unmount(*args, **kwargs) + + def abort_cmd(self): + return self._get_client().abort_cmd() + +def make_tell_client(bl: MXBeamline) -> TellClient | SimTellClient | TellClientProxy: + if bl == MXBeamline.SIMULATED: + return SimTellClient() + return TellClientProxy(bl, retry_interval_s=2.0) \ No newline at end of file diff --git a/daq/src/mxlibs3/workflow_tools.py b/src/aare/devices/workflow_tools.py similarity index 100% rename from daq/src/mxlibs3/workflow_tools.py rename to src/aare/devices/workflow_tools.py diff --git a/gui/src/aaregui/panels/__init__.py b/src/aare/gui/__init__.py similarity index 100% rename from gui/src/aaregui/panels/__init__.py rename to src/aare/gui/__init__.py diff --git a/src/aare/gui/auth.py b/src/aare/gui/auth.py new file mode 100644 index 00000000..00655c81 --- /dev/null +++ b/src/aare/gui/auth.py @@ -0,0 +1,65 @@ +import os +import jwt +import requests + +from aare.common.models import TokenData + +from aare.common.logger_config import setup_logger + +logger = setup_logger('aareGUI') + +def auth(base_url: str | None) -> str: + curr_user = os.getlogin() + if base_url is None: + token_data = TokenData(sub=curr_user, + staff=True, + session=15, + pgroups=["p16371", "p22233"]) + return jwt.encode(token_data.model_dump(), "ABC123") + + url = f"{base_url}/token" + try: + response = requests.post( + url, + data={ + "username": curr_user, + "password": "" + }, + headers={ + "Content-Type": "application/x-www-form-urlencoded" + }, + timeout=(2.0, 5.0), # (connect timeout, read timeout) + ) + except requests.RequestException as e: + logger.error(f"Authentication request failed (network): {e}") + raise RuntimeError( + "Cannot reach AareDAQ server (network error). " + "Please check the server is running and your connection." + ) from e + + if response.status_code != 200: + # Avoid dumping full HTML/tracebacks into the GUI; keep it short and actionable + logger.error(f"Authentication request failed: HTTP {response.status_code}. Body: {response.text[:500]}") + raise RuntimeError( + f"Authentication failed (HTTP {response.status_code}). " + "The server may be starting up or unavailable." + ) + + try: + response_json = response.json() + except ValueError as e: + logger.error(f"Authentication response was not JSON. Body: {response.text[:500]}") + raise RuntimeError( + "Authentication failed (invalid server response). " + "The server may be starting up or misconfigured." + ) from e + + token = response_json.get("access_token") + if not token or not isinstance(token, str): + logger.error(f"Authentication response missing access_token. Keys: {list(response_json.keys())}") + raise RuntimeError( + "Authentication failed (missing token in server response). " + "The server may be starting up." + ) + + return token \ No newline at end of file diff --git a/src/aare/gui/auto_focus_test.py b/src/aare/gui/auto_focus_test.py new file mode 100644 index 00000000..39cd3f98 --- /dev/null +++ b/src/aare/gui/auto_focus_test.py @@ -0,0 +1,670 @@ +import time +from typing import Callable, Iterable + +import cv2 +import numpy as np +from aare.common.autofocus_tools import focus_measure_edges +from aare.common.beamline import mx_beamline +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.models import AutofocusSettings +from aare.daq.config import BeamlineConfig +from aare.daq.daq import AareDAQ +from aare.daq.devices import BeamlineDevices + +def make_circular_mask(shape_hw: tuple[int, int], center_x: float, center_y: float, radius: float) -> np.ndarray: + h, w = int(shape_hw[0]), int(shape_hw[1]) + y, x = np.ogrid[:h, :w] + return (x - float(center_x)) ** 2 + (y - float(center_y)) ** 2 <= float(radius) ** 2 + +def _parabola_vertex(x1, y1, x2, y2, x3, y3) -> float | None: + # Fit parabola through 3 points; return vertex x if it's a maximum. + denom = (x1 - x2) * (x1 - x3) * (x2 - x3) + if abs(denom) < 1e-15: + return None + a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom + b = (x3**2 * (y1 - y2) + x2**2 * (y3 - y1) + x1**2 * (y2 - y3)) / denom + if a >= 0: + return None + return float(-b / (2 * a)) + +class AutofocusController: + """ + Fast autofocus: bracket -> ternary -> optional parabola. + + You inject: + - get_gray_image(): np.ndarray (2D) + - get_frame_id(): int (UniqueId) OR None + - move_to(z): move stage to requested z (units are up to you) + - wait_for_stop(): block until motion ends + + The key speed/robustness trick is waiting for a *new frame id* after motion. + """ + def __init__( + self, + *, + get_gray_image, + focus_measure, + move_to, + wait_for_stop, + get_frame_id=None, + fps: float = 25.0, + ): + self.get_gray_image = get_gray_image + self.focus_measure = focus_measure + self.move_to = move_to + self.wait_for_stop = wait_for_stop + self.get_frame_id = get_frame_id + self.fps = float(fps) + + self._uid_stuck_count = 0 + self._uid_stuck_disable_after = 3 + + def _wait_new_frames(self, frames: int = 1, timeout_s: float = 0.12) -> bool: + """ + Wait for new frames by UniqueId. + If uid appears stuck (common in standalone tests if acquisition isn't running), + quickly fall back to a short sleep so autofocus stays fast. + """ + if self.get_frame_id is None or self._uid_stuck_count >= self._uid_stuck_disable_after: + time.sleep(max(0.0, float(frames)) / max(1e-6, self.fps)) + return True + start = int(self.get_frame_id()) + print(f"Waiting for {frames} frames (uid={start})...") + target = start + int(frames) + deadline = time.perf_counter() + float(timeout_s) + + while time.perf_counter() < deadline: + if int(self.get_frame_id()) >= target: + self._uid_stuck_count = 0 + print(f"Acquired {frames} frames (uid={target}, start={start})") + return True + time.sleep(0.001) + + # uid didn't advance in time -> count as "stuck" and fall back + print(f"UID stuck for {timeout_s} s, falling back to sleep...") + self._uid_stuck_count += 1 + time.sleep(1.0 / max(1e-6, self.fps)) + return False + + def _score_at(self, z, mask: np.ndarray | None, robust_frames: int) -> float: + st = time.perf_counter() + self.move_to(z) + print(f"move_to command to z={z:.2f} (t={time.perf_counter() - st:.5f} s)") + st = time.perf_counter() + self.wait_for_stop() + print(f"wait_for_stop command (t={time.perf_counter() - st:.5f} s)") + + # Ensure next image is not a stale buffer + print("Waiting for new frame...") + st = time.perf_counter() + self._wait_new_frames(frames=1, timeout_s=0.4) + print(f"Acquired new frame (t={time.perf_counter() - st:.5f} s)") + st = time.perf_counter() + if robust_frames <= 1: + gray = self.get_gray_image() + print(f"got grey image (t={time.perf_counter() - st:.5f} s)") + return float(self.focus_measure(gray, mask)) + + vals: list[float] = [] + for _ in range(int(robust_frames)): + gray = self.get_gray_image() + vals.append(float(self.focus_measure(gray, mask))) + self._wait_new_frames(frames=1, timeout_s=0.4) + print(f'Got values after {time.perf_counter() - st:.5f} s: {vals}') + return float(np.median(np.asarray(vals, dtype=np.float64))) + + def run_once( + self, + *, + z0: float, + z_range: float, + mask: np.ndarray | None = None, + robust_frames: int = 1, + ternary_iters: int = 4, + do_parabola: bool = True, + edge_stop: bool = True, + flat_rel_tol: float = 0.03, + ) -> tuple[float, float]: + """ + Returns (best_z, best_focus). + + edge_stop: + If True and the best bracket point is at ±0.5*z_range, stop early. + (Means the peak is likely outside the search window.) + + flat_rel_tol: + If (max-min)/max is below this, treat focus curve as flat and stop early. + """ + R = float(z_range) + + # 1) 5-point bracket + zs = np.array( + [z0 - 0.5 * R, z0 - 0.25 * R, z0, z0 + 0.25 * R, z0 + 0.5 * R], + dtype=np.float64, + ) + fs = np.array([self._score_at(float(z), mask, robust_frames) for z in zs], dtype=np.float64) + f0 = float(fs[2]) # z0 + f_max = float(fs.max()) + if f0 > 0 and (f_max / f0) < 1.05: # <5% improvement available + return float(zs[2]), f0 + + best_i = int(np.argmax(fs)) + z_best = float(zs[best_i]) + f_best = float(fs[best_i]) + + # Early exit if the curve is basically flat (no meaningful improvement) + f_min = float(fs.min()) + if f_max > 0 and (f_max - f_min) / f_max < float(flat_rel_tol): + return z_best, f_best + + # Early exit if best is at range edge: bracket does not contain a maximum + if edge_stop and (best_i == 0 or best_i == len(zs) - 1): + return z_best, f_best + + # Local bracket for ternary search + iL = max(0, best_i - 1) + iR = min(len(zs) - 1, best_i + 1) + zL, zR = float(zs[iL]), float(zs[iR]) + + sampled: dict[float, float] = {float(zs[i]): float(fs[i]) for i in range(len(zs))} + + if zL == zR: + return z_best, f_best + + # 2) ternary search in local bracket (assumes unimodal-ish) + for _ in range(int(ternary_iters)): + a, b = (zL, zR) if zL < zR else (zR, zL) + z1 = a + (b - a) / 3.0 + z2 = b - (b - a) / 3.0 + + if z1 not in sampled: + sampled[z1] = self._score_at(float(z1), mask, robust_frames) + if z2 not in sampled: + sampled[z2] = self._score_at(float(z2), mask, robust_frames) + + if sampled[z1] < sampled[z2]: + zL = z1 + else: + zR = z2 + + # 3) optional 3-point parabola around current best sample + if do_parabola and len(sampled) >= 3: + items = sorted(sampled.items(), key=lambda t: t[0]) + zz = np.array([p[0] for p in items], dtype=np.float64) + ff = np.array([p[1] for p in items], dtype=np.float64) + k = int(np.argmax(ff)) + + if 0 < k < len(zz) - 1: + zv = _parabola_vertex( + float(zz[k - 1]), float(ff[k - 1]), + float(zz[k]), float(ff[k]), + float(zz[k + 1]), float(ff[k + 1]), + ) + if zv is not None and float(zz[k - 1]) <= zv <= float(zz[k + 1]): + if zv not in sampled: + sampled[zv] = self._score_at(float(zv), mask, robust_frames) + + z_best, f_best = max(sampled.items(), key=lambda t: t[1]) + return float(z_best), float(f_best) + +def __auto_focus(settings: AutofocusSettings) -> float: + """ + Fast autofocus on Smargon Z: + - bracket (5 points) + - ternary search (few iters) + - optional parabola refine + + Returns: + Best Z offset in mm (beamline Z delta) relative to the starting position. + """ + geom = daq.sample_geometry + start_smargon = devs.smargon_pos + + # ROI center: use provided, else use beam location (beam mark) + center_x = float(settings.center_x_pxl) if settings.center_x_pxl is not None else float(geom.beam_location_pxl.x) + center_y = float(settings.center_y_pxl) if settings.center_y_pxl is not None else float(geom.beam_location_pxl.y) + radius_pxl = float(settings.radius_pxl) + + z_range_mm = float(settings.z_range_um) / 1000.0 + z_steps = int(settings.z_steps) + + # Build mask once (needs image shape) + first = daq.camera_image_gray + if first is None: + raise RuntimeError("Autofocus: no camera image available.") + if first.ndim != 2: + raise RuntimeError("Autofocus: expected grayscale image (2D).") + + #mask = make_circular_mask(first.shape[:2], center_x=center_x, center_y=center_y, radius=radius_pxl) + + height, width = first.shape + y, x = np.ogrid[:height, :width] + mask = (x - center_x) ** 2 + (y - center_y) ** 2 <= radius_pxl ** 2 + + def move_to_delta_z_mm(dz_mm: float) -> None: + # Apply relative motion in *beamline Z* via the geometry transform + sh_new = start_smargon.sh_mm + geom.smargon_nudge(Coordinate(z=float(dz_mm))) + target = SmargonCoordinate( + sh_mm=sh_new, + phi_deg=start_smargon.phi_deg, + chi_deg=start_smargon.chi_deg, + ) + devs.smargon_pos = target + + def wait_for_stop() -> None: + devs.smargon_wait(timeout=30) + + def get_gray() -> np.ndarray: + img = daq.camera_image_gray + if img is None: + raise RuntimeError("Autofocus: failed to acquire image.") + return img + + ctrl = StepwiseAutofocus( + get_gray_image=get_gray, + focus_measure=focus_measure_edges, + move_to=move_to_delta_z_mm, + wait_for_stop=wait_for_stop, + get_frame_id=devs.samcam_frame_id, + fps=25.0, + ) + + # Robustness vs speed: + # - 1 is fastest + # - 2 is more stable (median of 2 frames) and often still < 1 s total + robust_frames = 1 + + best_dz, best_f, zs, fs = ctrl.run(z0=0.0, z_range=z_range_mm, z_steps=z_steps, mask=mask, + refine=False, include_baseline=False) + + # Move to the best position (controller ends at last probed z; ensure final is best) + move_to_delta_z_mm(best_dz) + wait_for_stop() + + print( + f"Autofocus complete: best_dz={best_dz * 1000.0:.1f} um, focus={best_f:.2f}, " + f"roi_center=({center_x:.1f},{center_y:.1f}), r={radius_pxl:.1f}px" + ) + + return float(best_dz) + + # def auto_focus(self, settings: AutofocusSettings) -> float: + # """ + # Public autofocus method. Only allowed in SampleAlignment state. + # Returns best Z offset in mm (beamline Z delta) relative to start. + # """ + # self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment) + # try: + # best_dz_mm = self.__auto_focus(settings) + # self.__cfg.state_busy = False + # return best_dz_mm + # except Exception as e: + # logger.error(f"Autofocus failed: {e}") + # self.__cfg.state_busy = False + # raise +class StepwiseAutofocus: + def __init__(self, *, get_gray_image, focus_measure, move_to, wait_for_stop, get_frame_id=None, fps=25.0): + self.get_gray_image = get_gray_image + self.focus_measure = focus_measure + self.move_to = move_to + self.wait_for_stop = wait_for_stop + self.get_frame_id = get_frame_id + self.fps = float(fps) + + def _wait_new_frame(self, timeout_s: float = 0.25) -> None: + if self.get_frame_id is None: + time.sleep(1.0 / max(1e-6, self.fps)) + return + start = int(self.get_frame_id()) + deadline = time.perf_counter() + float(timeout_s) + while time.perf_counter() < deadline: + if int(self.get_frame_id()) > start: + return + time.sleep(0.001) + # fallback: don't hang + time.sleep(1.0 / max(1e-6, self.fps)) + + def score_at(self, z: float, mask=None) -> float: + self.move_to(float(z)) + self.wait_for_stop() + self._wait_new_frame(timeout_s=0.25) + gray = self.get_gray_image() + return float(self.focus_measure(gray, mask)) + + def run( + self, + *, + z0: float, + z_range: float, + z_steps: int, + mask=None, + refine: bool = False, + include_baseline: bool = False, + ) -> tuple[float, float, np.ndarray, np.ndarray]: + """ + Returns: + (best_z, best_focus, z_positions, focus_values) + + If include_baseline=False and refine=False, this will evaluate focus exactly `z_steps` times. + """ + z_steps = int(z_steps) + if z_steps < 3: + raise ValueError("z_steps must be >= 3 for a meaningful scan.") + + if include_baseline: + _ = self.score_at(float(z0), mask=mask) + + zs = np.linspace(z0 - 0.5 * float(z_range), z0 + 0.5 * float(z_range), z_steps, dtype=np.float64) + fs = np.empty_like(zs) + + for i, z in enumerate(zs): + fs[i] = self.score_at(float(z), mask=mask) + + best_i = int(np.argmax(fs)) + best_z = float(zs[best_i]) + best_f = float(fs[best_i]) + + if refine and 0 < best_i < (len(zs) - 1): + dz = float(zs[best_i + 1] - zs[best_i]) + z_candidates = np.array([best_z - dz, best_z, best_z + dz], dtype=np.float64) + f_candidates = np.array([self.score_at(float(zc), mask=mask) for zc in z_candidates], dtype=np.float64) + j = int(np.argmax(f_candidates)) + best_z = float(z_candidates[j]) + best_f = float(f_candidates[j]) + + return best_z, best_f, zs, fs + +def __auto_focus_with_aerotech(settings: AutofocusSettings) -> float: + """ + 1) Fast focus scan on Aerotech GMZ (true focus axis) + 2) Return GMZ to home position + 3) Apply one Smargon move to preserve the focus (using a local Jacobian estimate) + + Returns: + Smargon delta (in the same "beamline z command" units you use in geom.smargon_nudge(Coordinate(z=...))). + """ + geom = daq.sample_geometry + start_smargon = devs.smargon_pos + + center_x = float(geom.beam_location_pxl.x) + center_y = float(geom.beam_location_pxl.y) + radius_pxl = float(settings.radius_pxl) + + z_range_mm = float(settings.z_range_um) / 1000.0 + z_steps = int(settings.z_steps) + + def get_gray() -> np.ndarray: + """ + Match GUI pipeline: + - if Bayer: debayer -> RGB + - flip horizontally + - convert to gray (uint8) + """ + img = daq.camera_image # <-- NOTE: use raw, not camera_image_gray + if img is None: + raise RuntimeError("Autofocus: failed to acquire image.") + + # If already grayscale + if img.ndim == 2: + bayer = img.astype(np.uint8, copy=False) + rgb = cv2.cvtColor(bayer, cv2.COLOR_BAYER_GB2RGB) + rgb = rgb[:, ::-1, :].copy() + gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY) + return gray + + # If RGB-like + if img.ndim == 3 and img.shape[2] >= 3: + rgb = img[:, :, :3] + rgb = rgb[:, ::-1, :].copy() + if rgb.dtype != np.uint8: + rgb = np.clip(rgb, 0, 255).astype(np.uint8) + gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY) + return gray + + raise RuntimeError(f"Autofocus: unexpected image shape {img.shape}") + + + first = get_gray() + print(first.shape[:2]) + print(center_x, center_y, radius_pxl) + print((first.shape[1]-1) - center_x) + if first is None or first.ndim != 2: + raise RuntimeError("Autofocus: no grayscale image available.") + mask = make_circular_mask(first.shape[:2], center_x=center_x, center_y=center_y, radius=radius_pxl) + + def score_focus() -> float: + gray = get_gray() + + # Ensure we're comparing apples-to-apples in logs + g = gray + if g.dtype != np.uint8: + g_u8 = np.clip(g, 0, 255).astype(np.uint8) + else: + g_u8 = g + + roi = g_u8[mask] + mean_dn = float(roi.mean()) if roi.size else 0.0 + std_dn = float(roi.std()) if roi.size else 0.0 + + raw = float(focus_measure_edges(g_u8, mask)) + + # Normalize to reduce exposure/gain dependence (gradient energy scales ~ intensity^2) + norm = raw / ((mean_dn + 1e-6) ** 2) + + print(f"AF: mean={mean_dn:.1f} std={std_dn:.1f} raw_focus={raw:.2f} norm_focus={norm:.6f}") + return norm + + # --------- + # A) Aerotech GMZ scan (relative to current GMZ = "home" for this autofocus call) + # --------- + aero0 = devs.aerotech_pos + gmz0 = float(aero0.z) + + gmz_offsets = np.linspace(-0.5 * z_range_mm, 0.5 * z_range_mm, z_steps, dtype=np.float64) + gmz_scores = [] + + for dz in gmz_offsets: + devs.aerotech.move_motor_linear("Z", gmz0 + float(dz), 10) + # wait 1 new frame after motion so we don't score an old buffer + start_uid = devs.samcam_frame_id() + t_deadline = time.perf_counter() + 0.25 + while time.perf_counter() < t_deadline and devs.samcam_frame_id() == start_uid: + time.sleep(0.001) + gmz_scores.append(score_focus()) + + gmz_scores = np.asarray(gmz_scores, dtype=np.float64) + best_i = int(np.argmax(gmz_scores)) + best_gmz_offset = float(gmz_offsets[best_i]) + best_focus = float(gmz_scores[best_i]) + + # Move GMZ back to "home" (gmz0) + devs.aerotech.move_motor_absolute("Z", gmz0, 10000) + + # If best was ~0 anyway, nothing to bake in + if abs(best_gmz_offset) < 1e-6: + print(f"Aerotech prefocus: best_gmz_offset≈0, focus={best_focus:.2f}") + return 0.0 + + # --------- + # B) Estimate local Jacobian: how Aerotech GMZ changes per unit Smargon beamline-z command + # We do two probe moves in the Smargon command space and measure GMZ readback. + # --------- + def move_smargon_beamline_dz(dz_mm: float) -> None: + sh_new = start_smargon.sh_mm + geom.smargon_nudge(Coordinate(z=float(dz_mm))) + target = SmargonCoordinate( + sh_mm=sh_new, + phi_deg=start_smargon.phi_deg, + chi_deg=start_smargon.chi_deg, + ) + devs.smargon_pos = target + devs.smargon_wait(timeout=30) + + move_smargon_beamline_dz(best_gmz_offset) + + print( + f"Aerotech prefocus: best_gmz_offset={best_gmz_offset*1000} um, focus={best_focus:.2f} " + f"Smargon_start: {start_smargon.sh_mm} um, Smargon_end: {devs.smargon_pos.sh_mm} um" + ) + return float(best_gmz_offset) + +def focus_measure_laplacian(gray: np.ndarray, mask: np.ndarray | None = None) -> float: + """ + Fast focus metric: variance of Laplacian. + + Notes: + - Works best on uint8 images. + - Use a mask/ROI to avoid scoring irrelevant background. + """ + if gray is None: + return 0.0 + if gray.ndim != 2: + raise ValueError(f"Expected 2D grayscale image, got shape={gray.shape}") + + g = gray + if g.dtype != np.uint8: + g = np.clip(g, 0, 255).astype(np.uint8) + + if mask is not None: + roi = g[mask] + if roi.size < 64: # too few pixels -> unstable variance + return 0.0 + # Laplacian needs 2D input; reshape ROI to a thin image is awkward. + # Better: compute Laplacian on full image and then mask the result. + lap = cv2.Laplacian(g, cv2.CV_64F, ksize=3) + v = float(lap[mask].var()) + return v + + lap = cv2.Laplacian(g, cv2.CV_64F, ksize=3) + return float(lap.var()) + + +def _wait_for_new_uid( + get_frame_id: Callable[[], int] | None, + last_uid: int | None, + *, + frames: int = 1, + timeout_s: float = 0.30, + poll_s: float = 0.002, + fallback_sleep_s: float = 0.04, +) -> int | None: + """ + Wait until UniqueId advances by `frames`. + Returns the new uid (or last_uid if we couldn't observe advancement). + """ + if get_frame_id is None: + time.sleep(fallback_sleep_s) + return last_uid + + try: + uid0 = int(get_frame_id()) if last_uid is None else int(last_uid) + except Exception: + time.sleep(fallback_sleep_s) + return last_uid + + target = uid0 + int(frames) + deadline = time.perf_counter() + float(timeout_s) + + while time.perf_counter() < deadline: + try: + uid = int(get_frame_id()) + except Exception: + uid = uid0 + + if uid >= target: + return uid + + time.sleep(poll_s) + + # Timeout: don't hang autofocus; just do a small sleep to reduce stale-buffer chance. + time.sleep(fallback_sleep_s) + return uid0 + + +def autofocus_gpt( + z_positions: Iterable[float], + move_stage_fn: Callable[[float], None], + *, + get_frame_id: Callable[[], int] | None = None, + wait_for_stop: Callable[[], None] | None = None, + mask: np.ndarray | None = None, + robust_frames: int = 1, +) -> tuple[float, list[tuple[float, float]]]: + """ + Simple autofocus scan with reliability improvements: + - waits for a new UniqueId after motion (avoids scoring stale frames) + - optional median-of-N scoring per z + """ + measures: list[tuple[float, float]] = [] + last_uid: int | None = None + + # Prime last_uid so the first point also waits for a "fresh" frame + if get_frame_id is not None: + try: + last_uid = int(get_frame_id()) + except Exception: + last_uid = None + + for z in z_positions: + move_stage_fn(float(z)) + if wait_for_stop is not None: + wait_for_stop() + + # Wait for camera to deliver a frame AFTER the move + last_uid = _wait_for_new_uid(get_frame_id, last_uid, frames=1, timeout_s=0.35) + + if robust_frames <= 1: + img = daq.camera_image_gray + score = focus_measure_laplacian(img, mask=mask) + else: + vals: list[float] = [] + for _ in range(int(robust_frames)): + img = daq.camera_image_gray + vals.append(focus_measure_laplacian(img, mask=mask)) + last_uid = _wait_for_new_uid(get_frame_id, last_uid, frames=1, timeout_s=0.35) + score = float(np.median(np.asarray(vals, dtype=np.float64))) + + measures.append((float(z), float(score))) + print(f"Z={z:.6f}, sharpness={score:.3f}") + + best_z = max(measures, key=lambda x: x[1])[0] + return best_z, measures + +# ---- Example z positions ---- +coarse = np.linspace(-0.1, 0.1, 10) # 0 to 200 microns in 10µm steps + +def move_stage(z): + # Insert your hardware code here: + print(z) + devs.aerotech.move_motor_absolute("Z", z, 1000) + #devs.aerotech.controller.read_status() + # e.g. serial.write(f"MOVE Z {z}") + + +def get_frame_id(): + return int(devs.samcam_frame_id()) + +if __name__ == "__main__": + devs = BeamlineDevices(mx_beamline()) + cfg = BeamlineConfig(mx_beamline()) + daq = AareDAQ(cfg, bl=mx_beamline()) + zoom = devs.zoom + beam_center = cfg.get_beam_mark(zoom) + settings = AutofocusSettings(center_x_pxl=beam_center[0], center_y_pxl=beam_center[1], + radius_pxl=30, z_range_um=400, z_steps=40) + st = time.perf_counter() + best_z, curve = autofocus_gpt(coarse, move_stage, get_frame_id=get_frame_id) + move_stage(0) + #move_stage(best_z) + geom = daq.sample_geometry + start_smargon = devs.smargon_pos + + sh_new = start_smargon.sh_mm + geom.smargon_nudge(Coordinate(z=float(best_z))) + target = SmargonCoordinate( + sh_mm=sh_new, + phi_deg=start_smargon.phi_deg, + chi_deg=start_smargon.chi_deg, + ) + devs.smargon_pos = target + devs.smargon_wait(timeout=30) + print("Best focus at:", best_z) + print(f"Total time: {time.perf_counter() - st:.5f} s") \ No newline at end of file diff --git a/gui/src/aaregui/gui.py b/src/aare/gui/gui.py similarity index 70% rename from gui/src/aaregui/gui.py rename to src/aare/gui/gui.py index 16699833..284ec734 100644 --- a/gui/src/aaregui/gui.py +++ b/src/aare/gui/gui.py @@ -5,11 +5,11 @@ from PySide6.QtCore import QCommandLineParser, QCommandLineOption from PySide6.QtWidgets import QApplication, QMessageBox -from aaredaqlib.logger_config import setup_logger -from aaregui.main_window import MainWindow +from aare.common.logger_config import setup_logger +from aare.gui.main_window import MainWindow #from aaregui.widgets.login import LoginDialog -from aaredaqlib.beamline import MXBeamline, mx_beamline -from aaregui.auth import auth +from aare.common.beamline import MXBeamline, mx_beamline +from aare.gui.auth import auth logger = setup_logger("aareGUI") @@ -32,18 +32,30 @@ if __name__ == "__main__": default_url = "http://mx-x06da-queue-01.psi.ch:5210" default_zmq_addr = "tcp://x06da-pserv-01:9089" #129.129.110.12:9089 default_pred_zmq_addr = "tcp://mx-ml:9091" + default_beamline_cam_addr = "x06da-axis-1.psi.ch" + default_gonio_cam_addr = "axis-accc8ed2972e.psi.ch" + default_gonio_camera_id = 3 case MXBeamline.X10SA: - default_url = "http://mx-x10sa-queue-01.psi.ch:5210" - default_zmq_addr = "" - default_pred_zmq_addr = "" + default_url = "http://127.0.0.1:5210" + default_zmq_addr = "tcp://x10sa-spark-01:9091" #"tcp://x10sa-pserv-01:9089" # + default_pred_zmq_addr = "tcp://x10sa-spark-01:9091" #"tcp://sls-gpu-003:9089"#"" + default_beamline_cam_addr = "axis-accc8eb02488.psi.ch" + default_gonio_cam_addr = "axis-accc8ea5e463.psi.ch" + default_gonio_camera_id = 1 case MXBeamline.X06SA: default_url = "http://mx-x06sa-queue-01.psi.ch:5210" default_zmq_addr = "" default_pred_zmq_addr = "" + default_beamline_cam_addr = "" + default_gonio_cam_addr = "" + default_gonio_camera_id = 1 case _: default_url = "" default_zmq_addr = "" default_pred_zmq_addr = "" + default_beamline_cam_addr = "" + default_gonio_cam_addr = "" + default_gonio_camera_id = 1 # Add custom options as needed urlOption = QCommandLineOption(["u", "aaredaq-url"], @@ -91,6 +103,11 @@ if __name__ == "__main__": try: token = auth(base_url) + if not token or token.count(".") != 2: + raise RuntimeError( + "Authentication did not return a valid token. " + "Please check the server is running (it may still be initialising)." + ) logger.info("Authentication successful") except Exception as e: logger.error(f"Cannot connect to AareDAQ server. Exiting. {e}") @@ -107,7 +124,10 @@ if __name__ == "__main__": token=token, default_image=default_image, zmq_addr=zmq_addr, - pred_zmq_addr=pred_zmq_addr) + pred_zmq_addr=pred_zmq_addr, + beamline_cam_addr = default_beamline_cam_addr, + gonio_cam_addr = default_gonio_cam_addr, + gonio_cam_id = default_gonio_camera_id) win.show() sys.exit(app.exec()) except Exception as e: @@ -118,8 +138,9 @@ if __name__ == "__main__": QMessageBox.critical( None, "Fatal Error", - f"An error occurred during startup:\n\n{str(e)}\n\nSee console for details." + f"An error occurred during startup. See console for details." f"\nPlease check the server is running and your network connection." + f"\n\n{str(e)}\n\n" ) except: pass diff --git a/gui/src/aaregui/main_window.py b/src/aare/gui/main_window.py similarity index 58% rename from gui/src/aaregui/main_window.py rename to src/aare/gui/main_window.py index e4d5bd32..dcc40ce0 100644 --- a/gui/src/aaregui/main_window.py +++ b/src/aare/gui/main_window.py @@ -1,42 +1,52 @@ +import time + import jwt -from PySide6.QtCore import Qt, Slot, Signal -from PySide6.QtGui import QAction +from PySide6.QtCore import Qt, Slot, Signal, QTimer, QSettings +from PySide6.QtGui import QAction, QPixmap from PySide6.QtWidgets import ( QMainWindow, QWidget, - QSplitter, QHBoxLayout, QVBoxLayout, QMessageBox, - QApplication, - QDockWidget, QTabWidget) + QDockWidget, + QTabWidget, QFrame, QSizePolicy, QLabel) -from aaredaqlib.coordinate import Coordinate, SmargonCoordinate -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import SampleShortInfoList, TokenData, DAQStatusModel, BeamlineStateEnum -from aaredaqlib.sample_geometry import SampleGeometryModel -from aaregui.panels.LogPanel import LogDock +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.logger_config import setup_logger +from aare.common.models import SampleShortInfoList, TokenData, DAQStatusModel, BeamlineStateEnum +from aare.common.sample_geometry import SampleGeometryModel +from aare.gui.panels.LogPanel import LogDock -from aaregui.panels.beamline_controls import BeamlineControls -from aaregui.panels.data_collection_settings import DataCollectionSettings -from aaregui.panels.manual_sample_panel import ManualSamplePanel -from aaregui.panels.reference_tools_panel import ReferenceToolsPanel -from aaregui.panels.sample_queue_panel import SampleQueuePanel -from aaregui.panels.tell_sample_panel import TellSamplePanel -from aaregui.panels.face_detection_panel import FaceDetectionPanel -from aaregui.scan_logic.raster_grid_manager import RasterGridManager -from aaregui.scan_logic.rotation_scan_manager import RotationScanManager -from aaregui.scan_logic.sample_mount_logic import SampleMountLogic -from aaregui.threads.axis_video_thread import VideoThread -from aaregui.threads.camera_thread import SampleCameraThread, PredictionSubscriber -from aaregui.threads.daq_worker import DAQWorker -from aaregui.threads.jfjoch_viewer import JFJochDBusClient -from aaregui.widgets.camera_image import SampleCameraImageLabel -from aaregui.widgets.no_wheel_scroll_area import NoWheelScrollArea -from aaregui.widgets.status_bar import StatusBar -from aaregui.widgets.video_image import VideoGraphicsView -from aaregui.panels.fluorescence_panel import FluorescencePanel +from aare.gui.panels.beamline_controls import BeamlineControls +from aare.gui.panels.data_collection_settings import DataCollectionSettings +from aare.gui.panels.developer_help_dialog import DeveloperHelpDialog +from aare.gui.panels.beamline_recovery_panel import BeamlineRecoveryDialog +from aare.gui.panels.manual_sample_panel import ManualSamplePanel +from aare.gui.panels.reference_tools_panel import ReferenceToolsPanel +from aare.gui.panels.sample_queue_panel import SampleQueuePanel +from aare.gui.panels.tell_sample_panel import TellSamplePanel +from aare.gui.panels.face_detection_panel import FaceDetectionPanel +from aare.gui.panels.smargon_trace_panel import SmargonTracePanel +from aare.gui.scan_logic.raster_grid_manager import RasterGridManager +from aare.gui.scan_logic.rotation_scan_manager import RotationScanManager +from aare.gui.scan_logic.sample_mount_logic import SampleMountLogic +from aare.gui.threads.axis_video_thread import VideoThread +from aare.gui.tutorials.tutorial_manager import TutorialManager, TutorialStep +from aare.gui.tutorials.controls_help_dialog import ControlsHelpDialog + +from aare.gui.threads.camera_thread import SampleCameraThread +from aare.gui.threads.prediction_subscriber import PredictionSubscriber +from aare.gui.threads.daq_worker import DAQWorker +from aare.gui.threads.jfjoch_viewer import JFJochDBusClient +from aare.gui.tutorials.tutorial_registration import register_tutorials +from aare.gui.widgets.alert_banner import AlertBanner +from aare.gui.widgets.camera_image import SampleCameraImageLabel +from aare.gui.widgets.no_wheel_scroll_area import NoWheelScrollArea +from aare.gui.widgets.status_bar import StatusBar +from aare.gui.widgets.video_image import VideoGraphicsView +from aare.gui.panels.fluorescence_panel import FluorescencePanel logger = setup_logger("aareGUI") @@ -47,29 +57,65 @@ class MainWindow(QMainWindow): token: str, default_image: str | None, zmq_addr: str | None, - pred_zmq_addr: str | None): + pred_zmq_addr: str | None, + beamline_cam_addr: str | None, + gonio_cam_addr: str | None, + gonio_cam_id: int | None + ): super().__init__() self.__base_url = base_url self.__token = token self.__mounting = False + self._dev_help_dialog = None + self._beamline_recovery_dialog = None + self._controls_help_dialog = None + self._cleanup_done = False + + # Tutorial manager (define tutorials after widgets exist) + self.tutorial_manager = TutorialManager(self) self.viewer = JFJochDBusClient() - # Decode the JWT without signature verification - self.__decoded_token = TokenData(**jwt.decode(token, options={"verify_signature": False})) - logger.debug(self.__decoded_token) + try: + token_str = (token or "").strip() + if token_str.count(".") != 2: + raise ValueError( + "Invalid authentication token received (not a JWT). " + "This usually happens when the server is not running or still starting." + ) + + payload = jwt.decode(token_str, options={"verify_signature": False}) + self.__decoded_token = TokenData(**payload) + except Exception as e: + logger.error(f"Failed to decode authentication token: {e}", exc_info=True) + QMessageBox.critical( + None, + "Authentication Error", + "Could not start the GUI because authentication data was invalid.\n\n" + "Most commonly the server is not running yet (or is still initialising).\n" + "Please start/restart the server and try again." + ) + raise self.setStyleSheet("background-color: rgb(216, 228, 253);") - top_widget = QWidget(parent=self) + root_widget = QWidget(parent=self) + root_layout = QVBoxLayout(root_widget) + root_layout.setContentsMargins(0, 0, 0, 0) + root_layout.setSpacing(0) + + self.alert_banner = AlertBanner(parent=root_widget) + root_layout.addWidget(self.alert_banner) + + top_widget = QWidget(parent=root_widget) top_widget_layout = QHBoxLayout(top_widget) top_widget.setLayout(top_widget_layout) diffraction = DiffractionGeometry( energy_keV=12.4, dtz_mm=100, - detector_size_pxl=(1553,1630), - pixel_size_mm=0.150, #PILATUS 4 + detector_size_pxl=(1553, 1630), + pixel_size_mm=0.150, # PILATUS 4 beam_center_pxl=(750, 750), detector_description="PILATUS 4", detector_serial_number="1", @@ -77,7 +123,7 @@ class MainWindow(QMainWindow): poni_rot2_rad=-0.003839724 ) - geom = SampleGeometryModel(beam_location_pxl=Coordinate(x=1000,y=1000), + geom = SampleGeometryModel(beam_location_pxl=Coordinate(x=1000, y=1000), pixel_in_mm=0.001, aerotech=Coordinate(), smargon=SmargonCoordinate(sh_mm=Coordinate(), phi_deg=0, chi_deg=0), @@ -96,7 +142,6 @@ class MainWindow(QMainWindow): raster_mgr=self.raster, diffraction=diffraction) - top_widget_layout.addWidget(collection_controls_scroll) collection_controls_scroll.setWidget(self.data_collection) collection_controls_scroll.setHorizontalScrollBarPolicy( @@ -104,14 +149,14 @@ class MainWindow(QMainWindow): ) collection_controls_scroll.setFixedWidth(self.data_collection.set_width + 10) - self.video_tab = QTabWidget(parent=top_widget) - self.sample_camera = SampleCameraImageLabel(geom=geom, raster=self.raster, parent=top_widget, default_image=default_image) + self.sample_camera = SampleCameraImageLabel(geom=geom, raster=self.raster, parent=top_widget, + default_image=default_image) self.beamline_view_container = QWidget(parent=top_widget) self.beamline_view_layout = QVBoxLayout(self.beamline_view_container) - self.beamline_view_layout.setContentsMargins(0,0,0,0) + self.beamline_view_layout.setContentsMargins(0, 0, 0, 0) self.beamline_view_layout.setSpacing(6) self.beamline_view_1_combined = VideoGraphicsView() @@ -120,18 +165,20 @@ class MainWindow(QMainWindow): self.beamline_view_layout.addWidget(self.beamline_view_2_combined) self.beamline_view = VideoGraphicsView() - self.beamline_camera_thread = VideoThread(ip="x06da-axis-1.psi.ch") - self.beamline_camera_thread.frame_ready.connect(self.beamline_view.update_frame) - self.beamline_camera_thread.frame_ready.connect(self.beamline_view_2_combined.update_frame) - self.beamline_camera_thread.start() + if beamline_cam_addr: + self.beamline_camera_thread = VideoThread(ip=beamline_cam_addr) + self.beamline_camera_thread.frame_ready.connect(self.beamline_view.update_frame) + self.beamline_camera_thread.frame_ready.connect(self.beamline_view_2_combined.update_frame) + self.beamline_camera_thread.start() self.beamline_view_layout.addWidget(self.beamline_view) self.gonio_view = VideoGraphicsView() - #TODO add option to change cameras for gonio_camera_thread - self.gonio_camera_thread = VideoThread(ip="axis-accc8ed2972e.psi.ch", camera=3) - self.gonio_camera_thread.frame_ready.connect(self.gonio_view.update_frame) - self.gonio_camera_thread.frame_ready.connect(self.beamline_view_1_combined.update_frame) - self.gonio_camera_thread.start() + # TODO add option to change cameras for gonio_camera_thread + if gonio_cam_addr and gonio_cam_id: + self.gonio_camera_thread = VideoThread(ip=gonio_cam_addr, camera=gonio_cam_id) + self.gonio_camera_thread.frame_ready.connect(self.gonio_view.update_frame) + self.gonio_camera_thread.frame_ready.connect(self.beamline_view_1_combined.update_frame) + self.gonio_camera_thread.start() self.beamline_view_layout.addWidget(self.gonio_view) self.video_tab.addTab(self.sample_camera, "Sample camera") @@ -151,8 +198,8 @@ class MainWindow(QMainWindow): ) beamline_controls_scroll.setFixedWidth(self.beamline.set_width + 10) - self.tell_samples = TellSamplePanel(samples=SampleShortInfoList(s = [])) - self.ref_tools_panel = ReferenceToolsPanel(samples=SampleShortInfoList(s = [])) + self.tell_samples = TellSamplePanel(samples=SampleShortInfoList(s=[])) + self.ref_tools_panel = ReferenceToolsPanel(samples=SampleShortInfoList(s=[])) self.job_list_panel = SampleQueuePanel() self.tell_samples_dock = QDockWidget("Sample List", self) @@ -162,6 +209,7 @@ class MainWindow(QMainWindow): self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.tell_samples_dock) self.ref_tools_dock = QDockWidget("Reference Tools", self) + self.ref_tools_dock.setObjectName("ref_tools_dock") self.ref_tools_dock.setWidget(self.ref_tools_panel) self.ref_tools_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.ref_tools_dock) @@ -170,6 +218,7 @@ class MainWindow(QMainWindow): self.sample_logic = SampleMountLogic() self.job_list_dock = QDockWidget("Automation list", self) + self.job_list_dock.setObjectName("job_list_dock") self.job_list_dock.setWidget(self.job_list_panel) self.job_list_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.job_list_dock) @@ -177,36 +226,58 @@ class MainWindow(QMainWindow): self.manual_sample_panel = ManualSamplePanel() self.manual_sample_dock = QDockWidget("Manual sample", self) + self.manual_sample_dock.setObjectName("manual_sample_dock") self.manual_sample_dock.setWidget(self.manual_sample_panel) self.manual_sample_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.manual_sample_dock) self.face_panel = FaceDetectionPanel() self.face_panel_dock = QDockWidget("Face detection", self) + self.face_panel_dock.setObjectName("face_panel_dock") self.face_panel_dock.setWidget(self.face_panel) - self.face_panel_dock.setAllowedAreas(Qt.DockWidgetArea.RightDockWidgetArea | Qt.DockWidgetArea.LeftDockWidgetArea) + self.face_panel_dock.setAllowedAreas( + Qt.DockWidgetArea.RightDockWidgetArea | Qt.DockWidgetArea.LeftDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.face_panel_dock) self.face_panel_dock.hide() self.fluor_panel = FluorescencePanel() self.fluor_panel_dock = QDockWidget("Fluorescence", self) + self.fluor_panel_dock.setObjectName("fluor_panel_dock") self.fluor_panel_dock.setWidget(self.fluor_panel) - self.fluor_panel_dock.setAllowedAreas(Qt.DockWidgetArea.TopDockWidgetArea | Qt.DockWidgetArea.BottomDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea) + self.fluor_panel_dock.setAllowedAreas( + Qt.DockWidgetArea.TopDockWidgetArea | Qt.DockWidgetArea.BottomDockWidgetArea | Qt.DockWidgetArea.RightDockWidgetArea) self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.fluor_panel_dock) self.fluor_panel_dock.hide() # Create and add the dock to your main window self.log_dock = LogDock("Console Log", self) + self.log_dock.setObjectName("log_dock") self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock) self.log_dock.attach_logger("") self.log_dock.attach_logger("aareDAQ") self.log_dock.attach_logger("aareGUI") self.log_dock.hide() - self.setCentralWidget(top_widget) + self.smargon_trace_panel = SmargonTracePanel() + self.smargon_trace_dock = QDockWidget("Smargon trace", self) + self.smargon_trace_dock.setObjectName("smargon_trace_dock") + self.smargon_trace_dock.setWidget(self.smargon_trace_panel) + self.smargon_trace_dock.setAllowedAreas( + Qt.DockWidgetArea.RightDockWidgetArea + | Qt.DockWidgetArea.LeftDockWidgetArea + | Qt.DockWidgetArea.BottomDockWidgetArea + ) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.smargon_trace_dock) + self.smargon_trace_dock.hide() + + root_layout.addWidget(top_widget) + self.setCentralWidget(root_widget) self.setWindowTitle("AareGUI") self.create_menu_bar() + self._restore_window_state() + + # Define tutorials now that the UI exists self.status_bar = StatusBar(self.__decoded_token, parent=self) self.setStatusBar(self.status_bar) @@ -217,6 +288,7 @@ class MainWindow(QMainWindow): self.daq.reference_tools.connect(self.ref_tools_panel.new_list) self.beamline.samcam.changed.connect(self.daq.samcam_settings) + self.beamline.samcam.screenshot_requested.connect(self.daq.send_screenshot_db) self.beamline.loopctr.background.clicked.connect(self.daq.alc_background) self.beamline.loopctr.find_tip.clicked.connect(self.daq.center_loop) self.beamline.loopctr.bounding_box.clicked.connect(self.daq.ml_bounding_box) @@ -229,10 +301,13 @@ class MainWindow(QMainWindow): self.raster.omega.connect(self.daq.set_omega) self.raster.smargon.connect(self.daq.move_smargon) + self.beamline.omega_panel.set_omega_rel.connect(self.daq.set_omega_rel) self.beamline.omega_panel.set_omega.connect(self.daq.set_omega) self.sample_camera.set_omega.connect(self.daq.set_omega) self.beamline.zoom_panel.zoom.connect(self.daq.zoom) - self.beamline.illumination_panel.light.connect(self.daq.light) + self.beamline.illumination_panel.front_light.connect(self.daq.front_light) + self.beamline.illumination_panel.back_light.connect(self.daq.back_light) + if self.__decoded_token.staff: self.beamline.abr_tweak.abr_tweak.connect(self.daq.abr_tweak) self.beamline.abr_tweak.abr_save.connect(self.daq.abr_save) @@ -248,25 +323,38 @@ class MainWindow(QMainWindow): if zmq_addr is not None: self.camera_thread = SampleCameraThread(zmq_url=zmq_addr) - self.camera_thread.camera_image.connect(self.sample_camera.update_pixmap) self.camera_thread.start() + self.camera_thread.focus_measure.connect(self.status_bar.update_sharpness) + self.camera_thread.fps_measure.connect(self.status_bar.update_samcam_fps) else: self.camera_thread = None # Prediction subscriber thread if pred_zmq_addr is not None: logger.debug(f"Starting prediction subscriber thread {pred_zmq_addr}") - self.prediction_thread = PredictionSubscriber(pred_zmq_url=pred_zmq_addr) + self.prediction_thread = PredictionSubscriber(pred_zmq_url=pred_zmq_addr, topic="detections") self.prediction_thread.prediction.connect(self.sample_camera.update_detections) self.prediction_thread.start() else: self.prediction_thread = None + self._last_pred_image_ts: float | None = None + self._pred_preferred_timeout_s: float = 0.7 # tune: how long we "trust" prediction images + self._pred_is_preferred: bool = False - QApplication.instance().aboutToQuit.connect(self.cleanup) + if self.camera_thread is not None: + self.camera_thread.camera_image.connect(self._on_samcam_camera_pixmap) + + if self.prediction_thread is not None: + self.prediction_thread.image.connect(self._on_samcam_prediction_pixmap) + + self._samcam_source_timer = QTimer(self) + self._samcam_source_timer.setInterval(200) # ms + self._samcam_source_timer.timeout.connect(self._update_samcam_source_preference) + self._samcam_source_timer.start() # -# self.data_collection.helical.helical_scan.connect(self.worker.helical_scan) + # self.data_collection.helical.helical_scan.connect(self.worker.helical_scan) # self.data_collection.helical.update_bookmarks.connect( # self.camera_image.update_bookmarks # ) @@ -336,6 +424,7 @@ class MainWindow(QMainWindow): self.daq.update.connect(self.sample_camera.update_daq_status) self.daq.update.connect(self.tell_samples.update_daq_status) self.daq.update.connect(self.ref_tools_panel.update_daq_status) + self.daq.update.connect(self.camera_thread.update_daq_status) if self.__decoded_token.staff: self.daq.update.connect(self.beamline.beam_size.update_daq_status) @@ -368,6 +457,42 @@ class MainWindow(QMainWindow): self.daq.fluorimeter_spectrum_update.connect(self.fluor_panel.update_plot) self.daq.fluorimeter_spectrum_update.connect(lambda: self.fluor_panel_dock.setVisible(True)) + self.daq.status_message.connect(self.status_bar.show_connection_message) + self.daq.status_message.connect(self.alert_banner.show_message) + + register_tutorials(self, self.tutorial_manager) + + @Slot(QPixmap) + def _on_samcam_prediction_pixmap(self, pix: QPixmap) -> None: + self._last_pred_image_ts = time.monotonic() + self._pred_is_preferred = True + self.sample_camera.update_pixmap(pix) + + @Slot(QPixmap) + def _on_samcam_camera_pixmap(self, pix: QPixmap) -> None: + # Only show camera frames when prediction is not currently "healthy" + if not self._pred_is_preferred: + self.sample_camera.update_pixmap(pix) + + @Slot() + def _update_samcam_source_preference(self) -> None: + if self.prediction_thread is None: + self._pred_is_preferred = False + return + + if self._last_pred_image_ts is None: + self._pred_is_preferred = False + return + + age_s = time.monotonic() - self._last_pred_image_ts + self._pred_is_preferred = age_s <= self._pred_preferred_timeout_s + + def start_text_tutorial(self) -> None: + self.tutorial_manager.start("intro_text") + + def start_interactive_tutorial(self) -> None: + self.tutorial_manager.start("intro_interactive") + def create_menu_bar(self): """Create a menu bar with File->Quit and Help->About.""" # Main menu bar @@ -420,6 +545,15 @@ class MainWindow(QMainWindow): self.fluor_panel_dock.visibilityChanged.connect(show_fluor_panel_action.setChecked) view_menu.addAction(show_fluor_panel_action) + show_smargon_trace_action = QAction("Show Smargon trace", self) + show_smargon_trace_action.setCheckable(True) + show_smargon_trace_action.setChecked(False) + show_smargon_trace_action.triggered.connect(lambda checked: self.smargon_trace_dock.setVisible(checked)) + self.smargon_trace_dock.visibilityChanged.connect( + lambda visible: self.smargon_trace_panel.refresh_plot(force=True) if visible else None + ) + view_menu.addAction(show_smargon_trace_action) + show_log_action = QAction("Show Log", self) show_log_action.setCheckable(True) show_log_action.setChecked(False) @@ -432,6 +566,29 @@ class MainWindow(QMainWindow): about_action.triggered.connect(self.show_about_dialog) help_menu.addAction(about_action) + controls_help_action = QAction("Mouse / Keyboard Controls", self) + controls_help_action.triggered.connect(self.show_controls_help) + help_menu.addAction(controls_help_action) + + dev_help_action = QAction("Developer / Help", self) + dev_help_action.triggered.connect(self.show_developer_help) + help_menu.addAction(dev_help_action) + + if self.__decoded_token.staff: + beamline_recovery_action = QAction("Beamline Recovery", self) + beamline_recovery_action.triggered.connect(self.show_beamline_recovery) + help_menu.addAction(beamline_recovery_action) + + help_menu.addSeparator() + + start_text_tutorial_action = QAction("Start Tutorial (Text)", self) + start_text_tutorial_action.triggered.connect(self.start_text_tutorial) + help_menu.addAction(start_text_tutorial_action) + + start_interactive_tutorial_action = QAction("Start Tutorial (Interactive)", self) + start_interactive_tutorial_action.triggered.connect(self.start_interactive_tutorial) + help_menu.addAction(start_interactive_tutorial_action) + def show_about_dialog(self): QMessageBox.about( self, @@ -439,6 +596,37 @@ class MainWindow(QMainWindow): "Aare Macromolecular Crystallography GUI\nVersion: 1.0\nCopyright: Paul Scherrer Institute 2024-2025", ) + def show_controls_help(self) -> None: + if self._controls_help_dialog is None: + self._controls_help_dialog = ControlsHelpDialog(parent=self) + self._controls_help_dialog.show() + self._controls_help_dialog.raise_() + self._controls_help_dialog.activateWindow() + + def show_developer_help(self) -> None: + if self._dev_help_dialog is None: + self._dev_help_dialog = DeveloperHelpDialog( + daq=self.daq, + is_staff=bool(getattr(self.__decoded_token, "staff", False)), + parent=self, + ) + self._dev_help_dialog.refresh() + self._dev_help_dialog.show() + self._dev_help_dialog.raise_() + self._dev_help_dialog.activateWindow() + + def show_beamline_recovery(self) -> None: + if not bool(getattr(self.__decoded_token, "staff", False)): + return + if self._beamline_recovery_dialog is None: + self._beamline_recovery_dialog = BeamlineRecoveryDialog( + daq=self.daq, + parent=self, + ) + self._beamline_recovery_dialog.show() + self._beamline_recovery_dialog.raise_() + self._beamline_recovery_dialog.activateWindow() + @Slot(str) def show_sample_missing_dialog(self, msg: str): if self.job_list_panel.is_running(): @@ -456,8 +644,12 @@ class MainWindow(QMainWindow): @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): - self.beamline_camera_thread.set_busy(s.busy) - self.gonio_camera_thread.set_busy(s.busy) + if hasattr(self, "beamline_camera_thread") and self.beamline_camera_thread is not None: + self.beamline_camera_thread.set_busy(s.busy) + + if hasattr(self, "gonio_camera_thread") and self.gonio_camera_thread is not None: + self.gonio_camera_thread.set_busy(s.busy) + if not self.__mounting and s.state == BeamlineStateEnum.RobotSampleExchange: self.__mounting = True self.video_tab.setCurrentIndex(3) @@ -465,17 +657,57 @@ class MainWindow(QMainWindow): self.__mounting = False self.video_tab.setCurrentIndex(0) - @Slot(str) - def display_error(self, msg: str): - self.status_bar.setStyleSheet("color: red;") - self.status_bar.showMessage(f' {msg} ', 10000) + def _restore_window_state(self) -> None: + settings = QSettings() + geometry = settings.value("main_window/geometry") + state = settings.value("main_window/state") + + if geometry is not None: + self.restoreGeometry(geometry) + if state is not None: + self.restoreState(state) + + def closeEvent(self, event) -> None: + try: + settings = QSettings() + settings.setValue("main_window/geometry", self.saveGeometry()) + settings.setValue("main_window/state", self.saveState()) + except Exception as e: + logger.warning(f"Failed to save main window state: {e}") + + try: + self.cleanup() + except Exception as e: + logger.warning(f"Cleanup during closeEvent failed: {e}") + + super().closeEvent(event) def cleanup(self): - if self.camera_thread is not None: - self.camera_thread.stop() - if self.prediction_thread is not None: - self.prediction_thread.stop() - if self.beamline_camera_thread is not None: - self.beamline_camera_thread.stop() - if self.gonio_camera_thread is not None: - self.gonio_camera_thread.stop() + if getattr(self, "_cleanup_done", False): + return + self._cleanup_done = True + + try: + if hasattr(self, "_samcam_source_timer") and self._samcam_source_timer is not None: + self._samcam_source_timer.stop() + except Exception as e: + logger.warning(f"Failed to stop _samcam_source_timer: {e}") + + for attr_name in ( + "camera_thread", + "prediction_thread", + "beamline_camera_thread", + "gonio_camera_thread", + ): + thread = getattr(self, attr_name, None) + if thread is None: + continue + + logger.debug(f"Stopping {attr_name}") + + try: + thread.stop() + except Exception as e: + logger.warning(f"Failed to stop {attr_name}: {e}") + + setattr(self, attr_name, None) \ No newline at end of file diff --git a/gui/src/aaregui/scan_logic/__init__.py b/src/aare/gui/models/__init__.py similarity index 100% rename from gui/src/aaregui/scan_logic/__init__.py rename to src/aare/gui/models/__init__.py diff --git a/gui/src/aaregui/models/bookmark.py b/src/aare/gui/models/bookmark.py similarity index 92% rename from gui/src/aaregui/models/bookmark.py rename to src/aare/gui/models/bookmark.py index eff95c59..39e265aa 100644 --- a/gui/src/aaregui/models/bookmark.py +++ b/src/aare/gui/models/bookmark.py @@ -2,7 +2,7 @@ from typing import Literal from PySide6.QtGui import QColor -from aaredaqlib.coordinate import SmargonCoordinate +from aare.common.coordinate import SmargonCoordinate class SmargonBookmark: diff --git a/gui/src/aaregui/models/sample_queue_model.py b/src/aare/gui/models/sample_queue_model.py similarity index 96% rename from gui/src/aaregui/models/sample_queue_model.py rename to src/aare/gui/models/sample_queue_model.py index 58030236..2721e29f 100644 --- a/gui/src/aaregui/models/sample_queue_model.py +++ b/src/aare/gui/models/sample_queue_model.py @@ -1,7 +1,7 @@ -from PySide6.QtCore import QAbstractTableModel, Qt, Slot +from PySide6.QtCore import QAbstractTableModel, Qt from PySide6.QtGui import QBrush, QColor -from aaredaqlib.models import SampleShortInfo, SampleShortInfoList +from aare.common.models import SampleShortInfo, SampleShortInfoList def get_entry(sample: SampleShortInfo, column: int): diff --git a/gui/src/aaregui/models/user_sample_model.py b/src/aare/gui/models/user_sample_model.py similarity index 99% rename from gui/src/aaregui/models/user_sample_model.py rename to src/aare/gui/models/user_sample_model.py index 71ebd782..7e6cef80 100644 --- a/gui/src/aaregui/models/user_sample_model.py +++ b/src/aare/gui/models/user_sample_model.py @@ -3,7 +3,7 @@ import re from PySide6.QtCore import QAbstractTableModel, Qt, QMimeData from PySide6.QtGui import QBrush, QColor -from aaredaqlib.models import SampleShortInfo, SampleShortInfoList +from aare.common.models import SampleShortInfo, SampleShortInfoList def get_entry(sample: SampleShortInfo, column: int): diff --git a/gui/src/aaregui/panels/LogPanel.py b/src/aare/gui/panels/LogPanel.py similarity index 85% rename from gui/src/aaregui/panels/LogPanel.py rename to src/aare/gui/panels/LogPanel.py index 1a93ae77..9af0e920 100644 --- a/gui/src/aaregui/panels/LogPanel.py +++ b/src/aare/gui/panels/LogPanel.py @@ -1,9 +1,9 @@ # Python -from PySide6.QtCore import Qt, Signal, QObject +from PySide6.QtCore import Qt from PySide6.QtWidgets import QDockWidget, QPlainTextEdit -from aaredaqlib.logger_config import QtLogEmitter, QtLogHandler, find_existing_formatter, attach_to_logger +from aare.common.logger_config import QtLogEmitter, QtLogHandler, find_existing_formatter, attach_to_logger class LogDock(QDockWidget): diff --git a/gui/src/aaregui/threads/__init__.py b/src/aare/gui/panels/__init__.py similarity index 100% rename from gui/src/aaregui/threads/__init__.py rename to src/aare/gui/panels/__init__.py diff --git a/gui/src/aaregui/panels/abr_tweak_panel.py b/src/aare/gui/panels/abr_tweak_panel.py similarity index 94% rename from gui/src/aaregui/panels/abr_tweak_panel.py rename to src/aare/gui/panels/abr_tweak_panel.py index e1434aa2..8741f0dd 100644 --- a/gui/src/aaregui/panels/abr_tweak_panel.py +++ b/src/aare/gui/panels/abr_tweak_panel.py @@ -1,12 +1,12 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtGui import Qt from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.models import DAQStatusModel +from aare.common.coordinate import Coordinate +from aare.common.models import DAQStatusModel -from aaregui.widgets.button_with_payload import ButtonWithPayload -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.button_with_payload import ButtonWithPayload +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel DEFAULT_ABR_STEP_UM = 5 @@ -103,7 +103,7 @@ class AbrTweakWidget(QWidget): goto_button = QPushButton("Go to meas.") grid_layout.addWidget(goto_button, 4, 0, 1, 3) - save_button.pressed.connect(self.goto_button_pressed) + goto_button.pressed.connect(self.goto_button_pressed) @Slot() def goto_button_pressed(self): diff --git a/gui/src/aaregui/panels/beam_center_panel.py b/src/aare/gui/panels/beam_center_panel.py similarity index 88% rename from gui/src/aaregui/panels/beam_center_panel.py rename to src/aare/gui/panels/beam_center_panel.py index 3fd7c385..e59c0c58 100644 --- a/gui/src/aaregui/panels/beam_center_panel.py +++ b/src/aare/gui/panels/beam_center_panel.py @@ -1,9 +1,9 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QLabel -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import DAQStatusModel +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel class BeamCenterWidget(QWidget): diff --git a/gui/src/aaregui/panels/beam_mark_panel.py b/src/aare/gui/panels/beam_mark_panel.py similarity index 91% rename from gui/src/aaregui/panels/beam_mark_panel.py rename to src/aare/gui/panels/beam_mark_panel.py index aeb4ef46..0d064db9 100644 --- a/gui/src/aaregui/panels/beam_mark_panel.py +++ b/src/aare/gui/panels/beam_mark_panel.py @@ -1,8 +1,8 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QPushButton, QLabel -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import DAQStatusModel +from aare.gui.widgets.title_label import TitleLabel class BeamMarkWidget(QWidget): diff --git a/gui/src/aaregui/panels/beam_size_panel.py b/src/aare/gui/panels/beam_size_panel.py similarity index 87% rename from gui/src/aaregui/panels/beam_size_panel.py rename to src/aare/gui/panels/beam_size_panel.py index 59fd54cd..31c3ed88 100644 --- a/gui/src/aaregui/panels/beam_size_panel.py +++ b/src/aare/gui/panels/beam_size_panel.py @@ -1,9 +1,9 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QLabel -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import DAQStatusModel +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel class BeamSizeWidget(QWidget): diff --git a/gui/src/aaregui/panels/beamline_controls.py b/src/aare/gui/panels/beamline_controls.py similarity index 70% rename from gui/src/aaregui/panels/beamline_controls.py rename to src/aare/gui/panels/beamline_controls.py index 187f33f8..4ed7a2ec 100644 --- a/gui/src/aaregui/panels/beamline_controls.py +++ b/src/aare/gui/panels/beamline_controls.py @@ -1,16 +1,15 @@ from PySide6.QtWidgets import QFrame, QVBoxLayout -from aaregui.panels.abr_tweak_panel import AbrTweakWidget -from aaregui.panels.beam_center_panel import BeamCenterWidget -from aaregui.panels.beam_mark_panel import BeamMarkWidget -from aaregui.panels.beam_size_panel import BeamSizeWidget -from aaregui.panels.beamline_state_panel import BeamlineStatePanel -from aaregui.panels.illumination_panel import IlluminationPanel -from aaregui.panels.loop_centering_panel import LoopCenteringPanel -from aaregui.panels.omega_panel import OmegaPanel -from aaregui.panels.samcam_panel import SamcamPanel -from aaregui.panels.smargon_panel import SmargonPanel -from aaregui.panels.zoom_panel import ZoomPanel +from aare.gui.panels.abr_tweak_panel import AbrTweakWidget +from aare.gui.panels.beam_center_panel import BeamCenterWidget +from aare.gui.panels.beam_mark_panel import BeamMarkWidget +from aare.gui.panels.beam_size_panel import BeamSizeWidget +from aare.gui.panels.illumination_panel import IlluminationPanel +from aare.gui.panels.loop_centering_panel import LoopCenteringPanel +from aare.gui.panels.omega_panel import OmegaPanel +from aare.gui.panels.samcam_panel import SamcamPanel +from aare.gui.panels.smargon_panel import SmargonPanel +from aare.gui.panels.zoom_panel import ZoomPanel class BeamlineControls(QFrame): diff --git a/src/aare/gui/panels/beamline_recovery_panel.py b/src/aare/gui/panels/beamline_recovery_panel.py new file mode 100644 index 00000000..4891e9e0 --- /dev/null +++ b/src/aare/gui/panels/beamline_recovery_panel.py @@ -0,0 +1,327 @@ +from __future__ import annotations + +from PySide6.QtCore import Slot +from PySide6.QtWidgets import ( + QDialog, + QVBoxLayout, + QLabel, + QPushButton, + QWidget, + QDialogButtonBox, + QInputDialog, + QLineEdit, + QMessageBox, +) + +from aare.common.models import DAQStatusModel +from aare.gui.threads.daq_worker import DAQWorker + + +class RecoveryPanel(QWidget): + def __init__(self, *, daq: DAQWorker, parent=None): + super().__init__(parent) + self._daq = daq + self._last_status: DAQStatusModel | None = None + + layout = QVBoxLayout(self) + layout.setSpacing(10) + + self._warning_primary = QLabel( + "⚠ Recovery actions are staff-only and intentionally dangerous.", + self, + ) + self._warning_primary.setWordWrap(True) + self._warning_primary.setStyleSheet( + "QLabel {" + " background: #fff3cd;" + " color: #7a4b00;" + " border: 1px solid #f0c36d;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + layout.addWidget(self._warning_primary) + + self._warning_secondary = QLabel( + "Only use these commands when beamline is stuck and certain beamline is unrecoverable through normal operation.", + self, + ) + self._warning_secondary.setWordWrap(True) + self._warning_secondary.setStyleSheet( + "QLabel {" + " background: #fdeaea;" + " color: #8b1e1e;" + " border: 1px solid #e6a8a8;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + layout.addWidget(self._warning_secondary) + + self._status = QLabel("Current status: waiting for DAQ status update…", self) + self._status.setWordWrap(True) + self._status.setStyleSheet( + "QLabel {" + " background: #fafafa;" + " border: 1px solid #d0d0d0;" + " border-radius: 6px;" + " padding: 8px;" + "}" + ) + layout.addWidget(self._status) + + self._last_action = QLabel("Last action: -", self) + self._last_action.setWordWrap(True) + self._last_action.setStyleSheet( + "QLabel {" + " background: #eef6ff;" + " color: #12406a;" + " border: 1px solid #a8c7e6;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + layout.addWidget(self._last_action) + + self._take_over_btn = QPushButton("Take over beamline", self) + self._take_over_btn.setStyleSheet( + "QPushButton {" + " background: #fff3cd;" + " border: 1px solid #f0c36d;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + self._take_over_btn.clicked.connect(self._take_over_beamline) + layout.addWidget(self._take_over_btn) + + self._free_beamline_btn = QPushButton("Free beamline", self) + self._free_beamline_btn.setStyleSheet( + "QPushButton {" + " background: #fff3cd;" + " border: 1px solid #f0c36d;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + self._free_beamline_btn.clicked.connect(self._free_beamline) + layout.addWidget(self._free_beamline_btn) + + self._recover_beamline_btn = QPushButton("Recover beamline", self) + self._recover_beamline_btn.setStyleSheet( + "QPushButton {" + " background: #fdeaea;" + " color: #8b1e1e;" + " border: 1px solid #e6a8a8;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 700;" + "}" + ) + self._recover_beamline_btn.clicked.connect(self._recover_beamline) + layout.addWidget(self._recover_beamline_btn) + + self._recovery_unmount_btn = QPushButton("Unmount sample (recovery)", self) + self._recovery_unmount_btn.setStyleSheet( + "QPushButton {" + " background: #fdeaea;" + " color: #8b1e1e;" + " border: 1px solid #e6a8a8;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 700;" + "}" + ) + self._recovery_unmount_btn.clicked.connect(self._recovery_unmount_sample) + layout.addWidget(self._recovery_unmount_btn) + + self._resync_sample_btn = QPushButton("Resync sample from TELL", self) + self._resync_sample_btn.setStyleSheet( + "QPushButton {" + " background: #eef6ff;" + " color: #12406a;" + " border: 1px solid #a8c7e6;" + " border-radius: 6px;" + " padding: 8px;" + " font-weight: 600;" + "}" + ) + self._resync_sample_btn.clicked.connect(self._resync_sample) + layout.addWidget(self._resync_sample_btn) + + layout.addStretch(1) + + self._daq.update.connect(self._set_daq_status) + self._daq.sample_resync_completed.connect(self._set_last_action) + self._refresh_buttons() + + def _prompt_recovery_code(self, action_name: str) -> str | None: + code, ok = QInputDialog.getText( + self, + action_name, + "Enter recovery confirmation code:", + QLineEdit.EchoMode.Password, + ) + if not ok: + return None + code = code.strip() + return code or None + + def _sample_appears_mounted(self) -> bool: + try: + return self._last_status is not None and self._last_status.sample is not None + except Exception: + return False + + def _beamline_appears_busy(self) -> bool: + try: + return self._last_status is not None and bool(self._last_status.busy) + except Exception: + return False + + def _status_text(self) -> str: + if self._last_status is None: + return "Current status: waiting for DAQ status update…" + + state_name = getattr(self._last_status.state, "name", str(self._last_status.state)) + busy = bool(getattr(self._last_status, "busy", False)) + sample_mounted = self._sample_appears_mounted() + tell_connected = bool(getattr(self._last_status, "tell_connected", False)) + + return ( + f"State: {state_name}\n" + f"Busy: {busy}\n" + f"Sample mounted: {sample_mounted}\n" + f"TELL connected: {tell_connected}" + ) + + def _refresh_buttons(self) -> None: + sample_mounted = self._sample_appears_mounted() + beamline_busy = self._beamline_appears_busy() + + self._recovery_unmount_btn.setEnabled(sample_mounted) + self._recovery_unmount_btn.setToolTip( + "" if sample_mounted else "Disabled because no mounted sample is visible in current status." + ) + + self._free_beamline_btn.setEnabled(beamline_busy) + self._free_beamline_btn.setToolTip( + "" if beamline_busy else "Disabled because beamline does not currently appear busy." + ) + + self._resync_sample_btn.setEnabled(True) + self._resync_sample_btn.setToolTip("Force a one-shot sample reconciliation against TELL.") + + def _confirm(self, title: str, msg: str) -> bool: + reply = QMessageBox.warning( + self, + title, + msg, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) + return reply == QMessageBox.StandardButton.Yes + + @Slot(DAQStatusModel) + def _set_daq_status(self, s: DAQStatusModel) -> None: + self._last_status = s + self._status.setText(self._status_text()) + self._refresh_buttons() + + @Slot() + def _take_over_beamline(self) -> None: + if not self._confirm( + "Take over beamline", + "This will forcefully grab the active beamline session.\n\nDo you want to continue?", + ): + return + code = self._prompt_recovery_code("Take over beamline") + if not code: + return + self._last_action.setText("Last action: Taking over beamline session...") + self._daq.take_over_beamline(code) + + @Slot() + def _free_beamline(self) -> None: + if not self._confirm( + "Free beamline", + "This will clear the beamline busy flag.\n\nDo you want to continue?", + ): + return + code = self._prompt_recovery_code("Free beamline") + if not code: + return + self._last_action.setText("Last action: Clearing beamline busy flag...") + self._daq.free_beamline(code) + + @Slot() + def _recover_beamline(self) -> None: + if self._sample_appears_mounted(): + if not self._confirm( + "Recover beamline", + "A sample appears to be mounted.\n\n" + "Recovering the beamline may damage the sample or leave hardware in an unsafe state.\n\n" + "Only continue if you are sure this is the correct recovery action.", + ): + return + else: + if not self._confirm( + "Recover beamline", + "This will take over the beamline, clear the busy flag, and set the state to Maintenance.\n\n" + "Do you want to continue?", + ): + return + + code = self._prompt_recovery_code("Recover beamline") + if not code: + return + self._last_action.setText("Last action: Recovering beamline to Maintenance...") + self._daq.recover_beamline(code) + + @Slot() + def _recovery_unmount_sample(self) -> None: + if not self._confirm( + "Unmount sample (recovery)", + "This will force-take the session and attempt a controlled recovery unmount.\n\n" + "Use this only if normal unmount is not possible.", + ): + return + + code = self._prompt_recovery_code("Unmount sample (recovery)") + if not code: + return + self._last_action.setText("Last action: Performing recovery sample unmount...") + self._daq.recovery_unmount_sample(code) + + @Slot() + def _resync_sample(self) -> None: + self._last_action.setText("Last action: Resyncing sample cache from TELL...") + self._daq.resync_sample() + + @Slot(str) + def _set_last_action(self, message: str) -> None: + self._last_action.setText(f"Last action: {message}") + + +class BeamlineRecoveryDialog(QDialog): + def __init__(self, *, daq: DAQWorker, parent=None): + super().__init__(parent) + self.setWindowTitle("Beamline Recovery") + self.setMinimumSize(560, 420) + + layout = QVBoxLayout(self) + layout.setContentsMargins(12, 12, 12, 12) + layout.setSpacing(8) + + self._panel = RecoveryPanel(daq=daq, parent=self) + layout.addWidget(self._panel, 1) + + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close, parent=self) + buttons.rejected.connect(self.reject) + buttons.accepted.connect(self.accept) + layout.addWidget(buttons) diff --git a/gui/src/aaregui/panels/beamline_state_panel.py b/src/aare/gui/panels/beamline_state_panel.py similarity index 93% rename from gui/src/aaregui/panels/beamline_state_panel.py rename to src/aare/gui/panels/beamline_state_panel.py index 12064bff..1928f630 100644 --- a/gui/src/aaregui/panels/beamline_state_panel.py +++ b/src/aare/gui/panels/beamline_state_panel.py @@ -1,6 +1,6 @@ from PySide6.QtWidgets import QWidget, QGridLayout, QPushButton -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.title_label import TitleLabel class BeamlineStatePanel(QWidget): diff --git a/gui/src/aaregui/panels/data_collection_settings.py b/src/aare/gui/panels/data_collection_settings.py similarity index 80% rename from gui/src/aaregui/panels/data_collection_settings.py rename to src/aare/gui/panels/data_collection_settings.py index b89d695c..bfba7515 100644 --- a/gui/src/aaregui/panels/data_collection_settings.py +++ b/src/aare/gui/panels/data_collection_settings.py @@ -3,23 +3,19 @@ from PySide6.QtWidgets import ( QFrame, QVBoxLayout, QTabWidget, - QGridLayout, QPushButton, - QWidget, ) -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.models import DAQStatusModel -from aaredaqlib.rotation_scan import RotationScanRequest -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.models import DAQStatusModel +from aare.common.sample_geometry import SampleGeometryModel -from aaregui.panels.file_path_panel import FilePathPanel -from aaregui.panels.fluorescence_data_collection import FluorescenceDataCollectionPanel -from aaregui.panels.raster_data_collection import RasterDataCollectionPanel -from aaregui.panels.rotation_data_collection import RotationDataCollectionPanel -from aaregui.panels.smart_rotation_panel import SimpleRotationSettingsPanel -from aaregui.scan_logic.raster_grid_manager import RasterGridManager -from aaregui.widgets.title_label import TitleLabel +from aare.gui.panels.file_path_panel import FilePathPanel +from aare.gui.panels.fluorescence_data_collection import FluorescenceDataCollectionPanel +from aare.gui.panels.raster_data_collection import RasterDataCollectionPanel +from aare.gui.panels.rotation_data_collection import RotationDataCollectionPanel +from aare.gui.panels.smart_rotation_panel import SimpleRotationSettingsPanel +from aare.gui.scan_logic.raster_grid_manager import RasterGridManager class DataCollectionSettings(QFrame): diff --git a/src/aare/gui/panels/developer_help_dialog.py b/src/aare/gui/panels/developer_help_dialog.py new file mode 100644 index 00000000..5979f2b2 --- /dev/null +++ b/src/aare/gui/panels/developer_help_dialog.py @@ -0,0 +1,494 @@ +from __future__ import annotations + +import json +import logging +from typing import Dict + +from PySide6.QtCore import Qt, Slot, QUrl +from PySide6.QtGui import QGuiApplication, QDesktopServices +from PySide6.QtWidgets import ( + QDialog, + QVBoxLayout, + QHBoxLayout, + QLineEdit, + QPushButton, + QTabWidget, + QTableWidget, + QTableWidgetItem, + QTextEdit, + QLabel, + QWidget, + QCheckBox, + QDialogButtonBox, + QFormLayout, + QFrame, +) + +from aare.common.error_codes import error_code_help +from aare.common.logger_config import QtLogEmitter, QtLogHandler, find_existing_formatter, attach_to_logger +from aare.gui.threads.daq_worker import DAQWorker + + + +class DeveloperHelpDialog(QDialog): + def __init__(self, *, daq: DAQWorker, is_staff: bool, parent=None): + super().__init__(parent) + self._daq = daq + self._is_staff = bool(is_staff) + + self._codes: Dict[str, str] = {} + self._last_payload: dict = {} + self._freeze_payload: bool = False + self._always_highlight_last_error: bool = True + + self.setWindowTitle("Developer / Help") + self.setMinimumSize(860, 560) + + root = QVBoxLayout(self) + root.setContentsMargins(12, 12, 12, 12) + root.setSpacing(8) + + # Compact banner (staff only) + self._banner = QLabel(self) + self._banner.setVisible(self._is_staff) + self._banner.setWordWrap(True) + self._banner.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + self._banner.setStyleSheet( + "QLabel {" + " background: #f6f6f6;" + " border: 1px solid #d0d0d0;" + " border-radius: 6px;" + " padding: 6px 8px;" + "}" + ) + root.addWidget(self._banner) + + # Top controls + top = QHBoxLayout() + top.setSpacing(8) + root.addLayout(top) + + top.addWidget(QLabel("Filter:", self)) + + self._filter = QLineEdit(self) + self._filter.setPlaceholderText("Type to filter (matches name, value, or help)…") + self._filter.setClearButtonEnabled(True) + self._filter.setMinimumHeight(28) + self._filter.setStyleSheet( + "QLineEdit {" + " background: white;" + " border: 1px solid #bdbdbd;" + " border-radius: 6px;" + " padding: 4px 8px;" + "}" + ) + self._filter.textChanged.connect(self._apply_filter) + top.addWidget(self._filter, 1) + + self._refresh_btn = QPushButton("Refresh", self) + self._refresh_btn.clicked.connect(self.refresh) + top.addWidget(self._refresh_btn) + + self._freeze_cb = QCheckBox("Freeze payload", self) + self._freeze_cb.setVisible(self._is_staff) + self._freeze_cb.toggled.connect(self._set_freeze_payload) + top.addWidget(self._freeze_cb) + + self._highlight_cb = QCheckBox("Always highlight last error code", self) + self._highlight_cb.setVisible(self._is_staff) + self._highlight_cb.setChecked(True) + self._highlight_cb.toggled.connect(self._set_always_highlight) + top.addWidget(self._highlight_cb) + + self._copy_selected_btn = QPushButton("Copy code", self) + self._copy_selected_btn.clicked.connect(self._copy_selected_code) + top.addWidget(self._copy_selected_btn) + + self._copy_all_btn = QPushButton("Copy all (filtered)", self) + self._copy_all_btn.clicked.connect(self._copy_all_filtered) + top.addWidget(self._copy_all_btn) + + self._copy_payload_btn = QPushButton("Copy payload", self) + self._copy_payload_btn.setVisible(self._is_staff) + self._copy_payload_btn.clicked.connect(self._copy_payload) + top.addWidget(self._copy_payload_btn) + + # Staff utilities: open log files + self._open_gui_log_btn = QPushButton("Open GUI log", self) + self._open_gui_log_btn.setVisible(self._is_staff) + self._open_gui_log_btn.clicked.connect(lambda: self._open_log_file_for_logger("aareGUI")) + top.addWidget(self._open_gui_log_btn) + + self._open_daq_log_btn = QPushButton("Open DAQ log", self) + self._open_daq_log_btn.setVisible(self._is_staff) + self._open_daq_log_btn.clicked.connect(lambda: self._open_log_file_for_logger("aareDAQ")) + top.addWidget(self._open_daq_log_btn) + + # Tabs + self._tabs = QTabWidget(self) + root.addWidget(self._tabs, 1) + + # Tab: error codes + details pane + self._codes_table = QTableWidget(self) + self._codes_table.setColumnCount(1) + self._codes_table.setHorizontalHeaderLabels(["Name"]) + self._codes_table.setSortingEnabled(True) + self._codes_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) + self._codes_table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) + self._codes_table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection) + self._codes_table.itemSelectionChanged.connect(self._update_code_details) + self._codes_table.horizontalHeader().setStretchLastSection(True) + + self._details_frame = QFrame(self) + self._details_frame.setFrameShape(QFrame.Shape.StyledPanel) + self._details_frame.setStyleSheet( + "QFrame {" + " background: #fafafa;" + " border: 1px solid #d0d0d0;" + " border-radius: 6px;" + "}" + ) + + details_layout = QVBoxLayout(self._details_frame) + details_layout.setContentsMargins(10, 10, 10, 10) + details_layout.setSpacing(8) + + form = QFormLayout() + form.setLabelAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) + details_layout.addLayout(form) + + self._detail_name = QLabel("-", self) + self._detail_name.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + form.addRow("Name:", self._detail_name) + + value_row = QHBoxLayout() + value_row.setSpacing(8) + self._detail_value = QLabel("-", self) + self._detail_value.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + self._copy_value_btn = QPushButton("Copy value", self) + self._copy_value_btn.clicked.connect(self._copy_selected_value) + value_row.addWidget(self._detail_value, 1) + value_row.addWidget(self._copy_value_btn, 0) + value_row_widget = QWidget(self) + value_row_widget.setLayout(value_row) + form.addRow("Value:", value_row_widget) + + self._detail_help = QLabel("-", self) + self._detail_help.setWordWrap(True) + self._detail_help.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + self._detail_help.setStyleSheet( + "QLabel {" + " background: white;" + " border: 1px solid #e0e0e0;" + " border-radius: 6px;" + " padding: 8px;" + "}" + ) + details_layout.addWidget(QLabel("Help:", self)) + details_layout.addWidget(self._detail_help, 1) + + codes_container = QWidget(self) + codes_layout = QVBoxLayout(codes_container) + codes_layout.setContentsMargins(0, 0, 0, 0) + codes_layout.setSpacing(8) + codes_layout.addWidget(self._codes_table, 1) + codes_layout.addWidget(self._details_frame, 0) + + self._tabs.addTab(codes_container, "Error codes") + + # Tab: last error payload (staff only) + summary header + self._payload_summary = QLabel(self) + self._payload_summary.setVisible(self._is_staff) + self._payload_summary.setWordWrap(True) + self._payload_summary.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + + self._payload_text = QTextEdit(self) + self._payload_text.setReadOnly(True) + self._payload_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) + + if self._is_staff: + payload_container = QWidget(self) + payload_layout = QVBoxLayout(payload_container) + payload_layout.setContentsMargins(0, 0, 0, 0) + payload_layout.addWidget(self._payload_summary, 0) + payload_layout.addWidget(self._payload_text, 1) + self._tabs.addTab(payload_container, "Last error payload") + else: + self._payload_text.setPlainText("Hidden (staff only).") + + # Tab: recent payloads (staff only) + self._payloads_text = QTextEdit(self) + self._payloads_text.setReadOnly(True) + self._payloads_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) + if self._is_staff: + payloads_container = QWidget(self) + payloads_layout = QVBoxLayout(payloads_container) + payloads_layout.setContentsMargins(0, 0, 0, 0) + payloads_layout.addWidget(self._payloads_text, 1) + self._tabs.addTab(payloads_container, "Recent payloads") + + # Tab: tracebacks (staff only) + self._tracebacks_text = QTextEdit(self) + self._tracebacks_text.setReadOnly(True) + self._tracebacks_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) + self._tracebacks_text.setPlainText("Tracebacks will appear here (last 10).") + + if self._is_staff: + tb_container = QWidget(self) + tb_layout = QVBoxLayout(tb_container) + tb_layout.setContentsMargins(0, 0, 0, 0) + tb_layout.addWidget(self._tracebacks_text, 1) + self._tabs.addTab(tb_container, "Tracebacks") + + # Tab: error log (staff only) – live view from python logging + self._error_log_text = QTextEdit(self) + self._error_log_text.setReadOnly(True) + self._error_log_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) + if self._is_staff: + log_container = QWidget(self) + log_layout = QVBoxLayout(log_container) + log_layout.setContentsMargins(0, 0, 0, 0) + log_layout.addWidget(self._error_log_text, 1) + self._tabs.addTab(log_container, "Error log") + + + # Bottom button box + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close, parent=self) + buttons.rejected.connect(self.reject) + buttons.accepted.connect(self.accept) + root.addWidget(buttons) + + # Wire signals + self._daq.error_codes_loaded.connect(self.set_error_codes) + self._daq.last_error_payload_changed.connect(self.set_last_error_payload) + self._daq.last_error_payloads_changed.connect(self.set_last_error_payloads) + + # Hook a Qt logging handler to show ERROR+ messages in the dialog + if self._is_staff: + self._qt_log_emitter = QtLogEmitter() + self._qt_log_emitter.message.connect(self._append_error_log_line) + + self._qt_log_handler = QtLogHandler(self._qt_log_emitter) + self._qt_log_handler.setLevel(logging.ERROR) + self._qt_log_handler.setFormatter(find_existing_formatter()) + + attach_to_logger("aareGUI", self._qt_log_handler) + attach_to_logger("aareDAQ", self._qt_log_handler) + + self._update_banner() + self._update_code_details() + + def _open_log_file_for_logger(self, logger_name: str) -> None: + """ + Opens the first FileHandler path attached to the given logger name. + """ + log = logging.getLogger(logger_name) + paths: list[str] = [] + for h in getattr(log, "handlers", []) or []: + p = getattr(h, "baseFilename", None) + if p and isinstance(p, str): + paths.append(p) + + if not paths: + self._banner.setText(f"No file handler found for logger '{logger_name}'.") + return + + QDesktopServices.openUrl(QUrl.fromLocalFile(paths[0])) + + @Slot(bool) + def _set_freeze_payload(self, enabled: bool) -> None: + self._freeze_payload = bool(enabled) + + @Slot(bool) + def _set_always_highlight(self, enabled: bool) -> None: + self._always_highlight_last_error = bool(enabled) + + @Slot() + def refresh(self) -> None: + self._daq.get_error_codes() + self.set_last_error_payload(self._daq.get_last_error_payload()) + if self._is_staff: + self.set_last_error_payloads(self._daq.get_last_error_payloads()) + + @Slot(dict) + def set_error_codes(self, codes: dict) -> None: + self._codes = {str(k): str(v) for k, v in (codes or {}).items()} + self._apply_filter() + + @Slot(dict) + def set_last_error_payload(self, payload: dict) -> None: + if not self._is_staff: + return + if self._freeze_payload: + return + + self._last_payload = payload or {} + pretty = json.dumps(self._last_payload, indent=2, sort_keys=True, default=str) + self._payload_text.setPlainText(pretty) + + code, msg = self._extract_code_message() + url = str((self._last_payload or {}).get("url") or "") + status = (self._last_payload or {}).get("http_status") + self._payload_summary.setText( + f"URL: {url}\nHTTP: {status}\nCode: {code or '-'}\nMessage: {msg or '-'}" + ) + + self._update_banner() + self._select_code_from_last_error() + + @Slot(list) + def set_last_error_payloads(self, payloads: list) -> None: + if not self._is_staff: + return + blocks: list[str] = [] + for i, p in enumerate(payloads[-10:], start=max(1, len(payloads) - 9)): + try: + pretty = json.dumps(p or {}, indent=2, sort_keys=True, default=str) + except Exception: + pretty = str(p) + blocks.append(f"#{i}\n{pretty}") + self._payloads_text.setPlainText("\n\n".join(blocks) if blocks else "(none captured yet)") + + @Slot(str) + def _append_error_log_line(self, line: str) -> None: + if not self._is_staff: + return + self._error_log_text.append(line) + + def _code_name_for_value(self, value: str) -> str | None: + for k, v in self._codes.items(): + if v == value: + return k + return None + + def _extract_code_message(self) -> tuple[str | None, str | None]: + body = (self._last_payload or {}).get("body_json") + if isinstance(body, dict): + code = body.get("code") + msg = body.get("message") + return (str(code) if code is not None else None, str(msg) if msg is not None else None) + return (None, None) + + def _update_banner(self) -> None: + if not self._is_staff: + return + + code, msg = self._extract_code_message() + if code or msg: + parts = [] + if code: + parts.append(f"Last error: {code}") + if msg: + parts.append(msg) + self._banner.setText(" — ".join(parts)) + else: + self._banner.setText("Last error: (none captured yet)") + + def _code_name_for_value(self, value: str) -> str | None: + for name, v in (self._codes or {}).items(): + if str(v) == str(value): + return str(name) + return None + + def _select_code_by_name(self, name: str) -> None: + if not name: + return + for row in range(self._codes_table.rowCount()): + item = self._codes_table.item(row, 0) + if item and item.text() == name: + self._codes_table.setCurrentCell(row, 0) + self._codes_table.scrollToItem(item) + return + + def _select_code_from_last_error(self) -> None: + if not self._codes: + return + code_value, _ = self._extract_code_message() + if not code_value: + return + name = self._code_name_for_value(code_value) + if name: + self._select_code_by_name(name) + + @Slot() + def _apply_filter(self) -> None: + term = (self._filter.text() or "").strip().lower() + + items = sorted(self._codes.items(), key=lambda kv: kv[0]) + + if term: + def _match(name: str, value: str) -> bool: + h = error_code_help(value) or "" + return term in f"{name}\n{value}\n{h}".lower() + items = [(k, v) for (k, v) in items if _match(k, v)] + + self._codes_table.setRowCount(len(items)) + for row, (k, v) in enumerate(items): + item = QTableWidgetItem(k) + item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable) + self._codes_table.setItem(row, 0, item) + + self._codes_table.resizeColumnsToContents() + # Keep selection sensible (don’t resize columns here; avoids jitter) + if self._codes_table.rowCount() > 0 and self._codes_table.currentRow() < 0: + self._codes_table.setCurrentCell(0, 0) + + self._update_code_details() + + # If enabled, re-try selection after the table content changes + if self._is_staff and self._always_highlight_last_error and not self._freeze_payload: + self._select_code_from_last_error() + + def _selected_code(self) -> tuple[str | None, str | None]: + row = self._codes_table.currentRow() + if row < 0: + return (None, None) + name_item = self._codes_table.item(row, 0) + if not name_item: + return (None, None) + name = name_item.text() + value = self._codes.get(name) + return (name, value) + + @Slot() + def _update_code_details(self) -> None: + name, value = self._selected_code() + if not name or not value: + self._detail_name.setText("-") + self._detail_value.setText("-") + self._detail_help.setText("Select an error code to see details.") + self._copy_value_btn.setEnabled(False) + return + + self._detail_name.setText(name) + self._detail_value.setText(value) + self._detail_help.setText(error_code_help(value) or "(no help text defined yet)") + self._copy_value_btn.setEnabled(True) + + @Slot() + def _copy_selected_code(self) -> None: + name, value = self._selected_code() + if not name or not value: + QGuiApplication.clipboard().setText("") + return + QGuiApplication.clipboard().setText(f"{name}={value}") + + @Slot() + def _copy_selected_value(self) -> None: + _, value = self._selected_code() + QGuiApplication.clipboard().setText(value or "") + + @Slot() + def _copy_all_filtered(self) -> None: + rows = self._codes_table.rowCount() + out = {} + for r in range(rows): + name = self._codes_table.item(r, 0).text() + out[name] = self._codes.get(name, "") + QGuiApplication.clipboard().setText(json.dumps(out, indent=2, sort_keys=True)) + + @Slot() + def _copy_payload(self) -> None: + if not self._is_staff: + return + QGuiApplication.clipboard().setText(self._payload_text.toPlainText()) diff --git a/gui/src/aaregui/panels/face_detection_panel.py b/src/aare/gui/panels/face_detection_panel.py similarity index 62% rename from gui/src/aaregui/panels/face_detection_panel.py rename to src/aare/gui/panels/face_detection_panel.py index 9721e83c..9551551d 100644 --- a/gui/src/aaregui/panels/face_detection_panel.py +++ b/src/aare/gui/panels/face_detection_panel.py @@ -1,18 +1,17 @@ -# Python -from PySide6.QtCore import Slot, Qt, Signal -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QSpacerItem, QSizePolicy, QVBoxLayout, \ - QHBoxLayout +from PySide6.QtCore import Signal +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton, QVBoxLayout from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import numpy as np -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") + class FaceDetectionPanel(QWidget): face_detection = Signal(int, int) @@ -21,6 +20,7 @@ class FaceDetectionPanel(QWidget): super().__init__(parent) self.steps = 14 self.step_size = 15 + self._manual_run_requested = False def _set_steps(val: float): self.steps = int(val) @@ -28,29 +28,31 @@ class FaceDetectionPanel(QWidget): def _set_step_size(val: float): self.step_size = int(val) - self.fig = Figure(figsize=(5, 4), tight_layout=True) + self.fig = Figure(figsize=(5, 4)) + self.fig.subplots_adjust( + left=0.12, + right=0.97, + bottom=0.10, + top=0.95, + hspace=0.45, + ) self.canvas = FigureCanvas(self.fig) - self.ax1 = self.fig.add_subplot(2, 1, 1) # Height vs angle - self.ax2 = self.fig.add_subplot(2, 1, 2) # Area vs angle + self.ax1 = self.fig.add_subplot(2, 1, 1) + self.ax2 = self.fig.add_subplot(2, 1, 2) self._top_layout = QGridLayout() self._top_layout.addWidget(TitleLabel("TELL sample changer", self), 0, 0, 1, 3) - self.status_lbl = QLabel("") + self.status_lbl = QLabel("Idle") self._top_layout.addWidget(self.status_lbl, 0, 2) self._top_layout.addWidget(QLabel("step size", parent=self), 1, 0) - self.step_size_enter = NumberLineEdit( - 0, 50, 15, decimals=4, parent=self - ) - + self.step_size_enter = NumberLineEdit(0, 50, 15, decimals=4, parent=self) self._top_layout.addWidget(self.step_size_enter, 1, 1, 1, 3) self.step_size_enter.newValue.connect(_set_step_size) self._top_layout.addWidget(QLabel("°", parent=self), 1, 4) self._top_layout.addWidget(QLabel("number of steps", parent=self), 2, 0) - self.steps_enter = NumberLineEdit( - 0, 50, 14, decimals=4, parent=self - ) + self.steps_enter = NumberLineEdit(0, 50, 14, decimals=4, parent=self) self._top_layout.addWidget(self.steps_enter, 2, 1, 1, 3) self._top_layout.addWidget(QLabel("", parent=self), 2, 4) self.steps_enter.newValue.connect(_set_steps) @@ -70,49 +72,68 @@ class FaceDetectionPanel(QWidget): def run_and_refresh(self): try: + self._manual_run_requested = True + self.status_lbl.setText("Starting...") + self.face_detection_button.setEnabled(False) self.face_detection.emit(int(self.steps), int(self.step_size)) except Exception as e: + self._manual_run_requested = False self.status_lbl.setText(f"Error: {e}") + self.face_detection_button.setEnabled(True) def update_plot(self, data): - samples = data.get("samples", []) - print(samples) + samples = data.get("samples", []) or [] + running = bool(data.get("running", False)) + angle = data.get("current_angle_deg") + status = data.get("status", "") + + if running: + if self._manual_run_requested: + self.status_lbl.setText(f"Running... angle {angle}" if angle is not None else "Running...") + else: + self.status_lbl.setText(f"Automation running... angle {angle}" if angle is not None else "Automation running...") + else: + if self._manual_run_requested: + self.status_lbl.setText("Done") + self.face_detection_button.setEnabled(True) + self._manual_run_requested = False + elif samples: + self.status_lbl.setText("Showing latest result") + else: + self.status_lbl.setText("Idle") + + self.ax1.clear() + self.ax2.clear() + if not samples: - self.ax1.clear() - self.ax2.clear() self.ax1.text(0.5, 0.5, "No data", ha="center", va="center") self.ax2.text(0.5, 0.5, "No data", ha="center", va="center") self.canvas.draw_idle() - logger.info("No data") return angles = np.array([s["angle_deg"] for s in samples], dtype=float) heights = np.array([s["height"] for s in samples], dtype=float) areas = np.array([s["area"] for s in samples], dtype=float) - self.ax1.clear() - self.ax2.clear() self.ax1.scatter(angles, heights, s=16, c="tab:blue", label="Height") self.ax2.scatter(angles, areas, s=16, c="tab:green", label="Area") - ang_grid = np.linspace(angles.min(),angles.max(), 400) - #ang_grid_wrapped = ((ang_grid + 180) % 360) - 180 - hf = data.get("height_fit", {}) + ang_grid = np.linspace(angles.min(), angles.max(), 400) + + hf = data.get("height_fit", {}) or {} if {"A", "B", "phi_rad", "C"} <= hf.keys(): A, B, phi, C = hf["A"], hf["B"], hf["phi_rad"], hf["C"] - height_fit = A + B * np.cos(C*np.deg2rad(ang_grid) - phi) + height_fit = A + B * np.cos(C * np.deg2rad(ang_grid) - phi) self.ax1.plot(ang_grid, height_fit, color="tab:orange", label="Height fit") if "best_angle_deg" in hf: - logger.info(f"best angle: {hf['best_angle_deg']}") self.ax1.axvline(hf["best_angle_deg"], color="tab:orange", ls="--", alpha=0.6) - af = data.get("area_fit", {}) - if {"A", "B", "phi_rad", "C"} <= hf.keys(): + af = data.get("area_fit", {}) or {} + if {"A", "B", "phi_rad", "C"} <= af.keys(): A2, B2, phi2, C2 = af["A"], af["B"], af["phi_rad"], af["C"] area_fit = A2 + B2 * np.cos(C2 * np.deg2rad(ang_grid) - phi2) self.ax2.plot(ang_grid, area_fit, color="tab:red", label="Area fit") if "best_angle_deg" in af: - logger.info(f"best angle: {af['best_angle_deg']}") self.ax2.axvline(af["best_angle_deg"], color="tab:red", ls="--", alpha=0.6) self.ax1.set_xlabel("Angle (deg)") diff --git a/gui/src/aaregui/panels/file_path_panel.py b/src/aare/gui/panels/file_path_panel.py similarity index 98% rename from gui/src/aaregui/panels/file_path_panel.py rename to src/aare/gui/panels/file_path_panel.py index 89c69eae..db141a7f 100644 --- a/gui/src/aaregui/panels/file_path_panel.py +++ b/src/aare/gui/panels/file_path_panel.py @@ -1,13 +1,12 @@ -import copy import os from datetime import datetime from pathlib import Path from PySide6.QtCore import Signal, Slot, Qt -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QLineEdit, QSpinBox, QCheckBox, QMessageBox +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QLineEdit, QSpinBox, QMessageBox -from aaredaqlib.models import SampleShortInfo, DAQStatusModel -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import SampleShortInfo, DAQStatusModel +from aare.gui.widgets.title_label import TitleLabel ## Logic for filenames: ## 1. For rasters 'raster/' subfolder is added at the top level of the path (managed by DAQ) - e.g. raster/20250101/PX-456/01/dataset @@ -183,6 +182,7 @@ class FilePathPanel(QWidget): self.__puck_pos = 99 self.directory_edit.setText(f"{self.__formatted_date}/test") else: + self.__sample_id = sample.db_id self.__sample_name = sample.sample_name self.__dewar_pos = sample.loc_str() self.__puck_name = sample.puck_name diff --git a/gui/src/aaregui/panels/fluorescence_data_collection.py b/src/aare/gui/panels/fluorescence_data_collection.py similarity index 93% rename from gui/src/aaregui/panels/fluorescence_data_collection.py rename to src/aare/gui/panels/fluorescence_data_collection.py index bf112e50..df68c90c 100644 --- a/gui/src/aaregui/panels/fluorescence_data_collection.py +++ b/src/aare/gui/panels/fluorescence_data_collection.py @@ -1,8 +1,8 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton, QCheckBox -from aaredaqlib.models import FluorescenceSpectrumParameterModel -from aaregui.widgets.number_line_edit import NumberLineEdit +from aare.common.models import FluorescenceSpectrumParameterModel +from aare.gui.widgets.number_line_edit import NumberLineEdit class FluorescenceDataCollectionPanel(QWidget): diff --git a/gui/src/aaregui/panels/fluorescence_panel.py b/src/aare/gui/panels/fluorescence_panel.py similarity index 98% rename from gui/src/aaregui/panels/fluorescence_panel.py rename to src/aare/gui/panels/fluorescence_panel.py index d977543a..a5849ee5 100644 --- a/gui/src/aaregui/panels/fluorescence_panel.py +++ b/src/aare/gui/panels/fluorescence_panel.py @@ -1,11 +1,11 @@ import numpy as np from PySide6.QtCharts import QChart, QChartView, QLineSeries, QValueAxis -from PySide6.QtCore import QPointF, Qt, Slot, Signal, QEvent +from PySide6.QtCore import QPointF, Qt, Slot, QEvent from PySide6.QtGui import QPainter, QColor, QPen from PySide6.QtWidgets import QWidget, QGridLayout, QGraphicsSimpleTextItem, QLabel -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import FluorescenceSpectrumOutputModel, DAQStatusModel +from aare.common.logger_config import setup_logger +from aare.common.models import FluorescenceSpectrumOutputModel, DAQStatusModel logger = setup_logger("aareGUI") diff --git a/src/aare/gui/panels/illumination_panel.py b/src/aare/gui/panels/illumination_panel.py new file mode 100644 index 00000000..376b2c94 --- /dev/null +++ b/src/aare/gui/panels/illumination_panel.py @@ -0,0 +1,57 @@ +from PySide6.QtCore import Qt, Signal, Slot +from PySide6.QtWidgets import QWidget, QGridLayout, QSlider, QLabel +from aare.common.models import DAQStatusModel + +from aare.gui.widgets.title_label import TitleLabel + + +class IlluminationPanel(QWidget): + front_light = Signal(int) + back_light = Signal(int) + + def __init__(self, parent=None): + super().__init__(parent) + grid_layout = QGridLayout(self) + + grid_layout.addWidget(TitleLabel("Light", self), 0, 0, 1, 2) + + front_label = QLabel("Front light", parent=self) + front_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + grid_layout.addWidget(front_label, 1, 0, 1, 2) + self.is_sliding = False + + self.front_light_slider = QSlider(orientation=Qt.Orientation.Horizontal, parent=self) + self.front_light_slider.setRange(0, 100) + self.front_light_slider.sliderPressed.connect(self.on_slider_pressed) + self.front_light_slider.sliderReleased.connect(self.on_front_slider_released) + grid_layout.addWidget(self.front_light_slider, 2, 0, 1, 2) + + back_label = QLabel("Back light", parent=self) + back_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + grid_layout.addWidget(back_label, 3, 0, 1, 2) + + self.back_light_slider = QSlider(orientation=Qt.Orientation.Horizontal, parent=self) + self.back_light_slider.setRange(0, 100) + self.back_light_slider.sliderPressed.connect(self.on_slider_pressed) + self.back_light_slider.sliderReleased.connect(self.on_back_slider_released) + grid_layout.addWidget(self.back_light_slider, 4, 0, 1, 2) + + @Slot() + def on_slider_pressed(self): + self.is_sliding = True + + @Slot() + def on_front_slider_released(self): + self.is_sliding = False + self.front_light.emit(self.front_light_slider.value()) + + @Slot() + def on_back_slider_released(self): + self.is_sliding = False + self.back_light.emit(self.back_light_slider.value()) + + @Slot(DAQStatusModel) + def update_daq_status(self, s: DAQStatusModel): + if not self.is_sliding: # Update only if not sliding + self.front_light_slider.setValue(round(s.bl.front_light)) + self.back_light_slider.setValue(round(s.bl.back_light)) diff --git a/gui/src/aaregui/panels/loop_centering_panel.py b/src/aare/gui/panels/loop_centering_panel.py similarity index 93% rename from gui/src/aaregui/panels/loop_centering_panel.py rename to src/aare/gui/panels/loop_centering_panel.py index 18199693..41de4548 100644 --- a/gui/src/aaregui/panels/loop_centering_panel.py +++ b/src/aare/gui/panels/loop_centering_panel.py @@ -1,6 +1,6 @@ from PySide6.QtWidgets import QWidget, QGridLayout, QPushButton -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.title_label import TitleLabel class LoopCenteringPanel(QWidget): diff --git a/gui/src/aaregui/panels/manual_sample_panel.py b/src/aare/gui/panels/manual_sample_panel.py similarity index 93% rename from gui/src/aaregui/panels/manual_sample_panel.py rename to src/aare/gui/panels/manual_sample_panel.py index 5dce6884..bb0bf81a 100644 --- a/gui/src/aaregui/panels/manual_sample_panel.py +++ b/src/aare/gui/panels/manual_sample_panel.py @@ -1,10 +1,10 @@ from PySide6.QtCore import Signal, Slot -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QTextEdit, QPushButton, QCheckBox, QLineEdit -from aareDBclient import DataCollectionParameters +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton, QCheckBox, QLineEdit +from aareDB import DataCollectionParameters -from aaredaqlib.models import SampleShortInfo, DAQStatusModel -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import SampleShortInfo, DAQStatusModel +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel class ManualSamplePanel(QWidget): diff --git a/gui/src/aaregui/panels/omega_panel.py b/src/aare/gui/panels/omega_panel.py similarity index 87% rename from gui/src/aaregui/panels/omega_panel.py rename to src/aare/gui/panels/omega_panel.py index 338167d3..e578f82c 100644 --- a/gui/src/aaregui/panels/omega_panel.py +++ b/src/aare/gui/panels/omega_panel.py @@ -1,10 +1,10 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QHBoxLayout -from aaredaqlib.models import DAQStatusModel +from aare.common.models import DAQStatusModel -from aaregui.widgets.button_with_payload import ButtonWithPayload -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.button_with_payload import ButtonWithPayload +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel class OmegaEntryWidget(QWidget): @@ -21,6 +21,7 @@ class OmegaEntryWidget(QWidget): class OmegaPanel(QWidget): set_omega = Signal(float) + set_omega_rel = Signal(float) def __init__(self, parent=None): super().__init__(parent) @@ -57,7 +58,7 @@ class OmegaPanel(QWidget): @Slot(dict) def omega_button_pressed(self, payload: dict): if "rel" in payload: - self.set_omega.emit(self.__omega + payload["rel"]) + self.set_omega_rel.emit(payload["rel"]) elif "abs" in payload: self.set_omega.emit(payload["abs"]) diff --git a/gui/src/aaregui/panels/raster_data_collection.py b/src/aare/gui/panels/raster_data_collection.py similarity index 94% rename from gui/src/aaregui/panels/raster_data_collection.py rename to src/aare/gui/panels/raster_data_collection.py index 0e083f62..b882e0ef 100644 --- a/gui/src/aaregui/panels/raster_data_collection.py +++ b/src/aare/gui/panels/raster_data_collection.py @@ -1,14 +1,13 @@ from PySide6.QtCore import Signal, Slot, Qt -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QSizePolicy, QSpacerItem, QPushButton, QHBoxLayout, \ - QComboBox, QSlider, QMessageBox +from PySide6.QtWidgets import QLabel, QSizePolicy, QSpacerItem, QPushButton, QComboBox, QSlider, QMessageBox -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.models import DAQStatusModel, BeamlineStateEnum -from aaregui.panels.scan_settings_panel import ScanSettingsPanel -from aaregui.scan_logic.raster_grid_manager import RasterGridManager, RasterGridMetric -from aaregui.widgets.number_line_edit import NumberLineEdit, CheckedLineEdit -from aaregui.widgets.raster_grid_table import RasterGridTable -from aaredaqlib.logger_config import setup_logger +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.models import DAQStatusModel, BeamlineStateEnum +from aare.gui.panels.scan_settings_panel import ScanSettingsPanel +from aare.gui.scan_logic.raster_grid_manager import RasterGridManager, RasterGridMetric +from aare.gui.widgets.number_line_edit import CheckedLineEdit +from aare.gui.widgets.raster_grid_table import RasterGridTable +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/reference_tools_panel.py b/src/aare/gui/panels/reference_tools_panel.py similarity index 97% rename from gui/src/aaregui/panels/reference_tools_panel.py rename to src/aare/gui/panels/reference_tools_panel.py index 59fd5c80..b21807b4 100644 --- a/gui/src/aaregui/panels/reference_tools_panel.py +++ b/src/aare/gui/panels/reference_tools_panel.py @@ -1,7 +1,7 @@ # reference_tools_panel.py -from typing import Callable, List, Dict, Optional +from typing import Optional -from PySide6.QtCore import Qt, QAbstractTableModel, QModelIndex, QTimer, Slot, Signal +from PySide6.QtCore import Qt, QAbstractTableModel, QModelIndex, Slot, Signal from PySide6.QtGui import QBrush, QColor from PySide6.QtWidgets import ( QFrame, @@ -14,9 +14,9 @@ from PySide6.QtWidgets import ( QAbstractItemView, ) -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import SampleShortInfoList, SampleShortInfo, BeamlineStateEnum, DAQStatusModel -from aaregui.widgets.title_label import TitleLabel +from aare.common.logger_config import setup_logger +from aare.common.models import SampleShortInfoList, SampleShortInfo, DAQStatusModel +from aare.gui.widgets.title_label import TitleLabel logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/rotation_data_collection.py b/src/aare/gui/panels/rotation_data_collection.py similarity index 96% rename from gui/src/aaregui/panels/rotation_data_collection.py rename to src/aare/gui/panels/rotation_data_collection.py index 5e951ad9..ba03aa49 100644 --- a/gui/src/aaregui/panels/rotation_data_collection.py +++ b/src/aare/gui/panels/rotation_data_collection.py @@ -3,12 +3,12 @@ from pathlib import Path from PySide6.QtCore import Slot, Signal, Qt from PySide6.QtWidgets import QLabel, QComboBox, QPushButton, QMessageBox -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import DAQStatusModel, BeamlineStateEnum -from aaredaqlib.rotation_scan import RotationScanRequest -from aaregui.panels.scan_settings_panel import ScanSettingsPanel -from aaregui.widgets.number_line_edit import NumberLineEdit, CheckedLineEdit +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.logger_config import setup_logger +from aare.common.models import DAQStatusModel, BeamlineStateEnum +from aare.common.rotation_scan import RotationScanRequest +from aare.gui.panels.scan_settings_panel import ScanSettingsPanel +from aare.gui.widgets.number_line_edit import NumberLineEdit, CheckedLineEdit logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/samcam_panel.py b/src/aare/gui/panels/samcam_panel.py similarity index 62% rename from gui/src/aaregui/panels/samcam_panel.py rename to src/aare/gui/panels/samcam_panel.py index abeebc78..d08a1df1 100644 --- a/gui/src/aaregui/panels/samcam_panel.py +++ b/src/aare/gui/panels/samcam_panel.py @@ -1,14 +1,16 @@ -from PySide6.QtWidgets import QWidget, QSpinBox, QVBoxLayout, QHBoxLayout, QLabel, QDoubleSpinBox, QCheckBox +from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QDoubleSpinBox, QCheckBox, QLineEdit, \ + QPushButton from PySide6.QtCore import Signal, Slot -from aaredaqlib.models import SampleCameraSettings, DAQStatusModel -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import SampleCameraSettings, DAQStatusModel +from aare.gui.widgets.title_label import TitleLabel class SamcamPanel(QWidget): # Signals for when exposure or gain values change changed = Signal(SampleCameraSettings) show_detections_changed = Signal(bool) + screenshot_requested = Signal(str, str) old_settings = SampleCameraSettings(gain=100, exposure=0.001) def __init__(self, parent=None): @@ -44,6 +46,25 @@ class SamcamPanel(QWidget): gain_layout.addWidget(gain_label) gain_layout.addWidget(self.gain_spinbox) + screenshot_filename_layout = QHBoxLayout() + screenshot_filename_label = QLabel("Filename:") + self.screenshot_filename_edit = QLineEdit() + self.screenshot_filename_edit.setPlaceholderText("optional") + self.screenshot_filename_edit.setStyleSheet("QLineEdit { background-color: white; }") + screenshot_filename_layout.addWidget(screenshot_filename_label) + screenshot_filename_layout.addWidget(self.screenshot_filename_edit) + + screenshot_message_layout = QHBoxLayout() + screenshot_message_label = QLabel("Message:") + self.screenshot_message_edit = QLineEdit() + self.screenshot_message_edit.setPlaceholderText("optional") + self.screenshot_message_edit.setStyleSheet("QLineEdit { background-color: white; }") + screenshot_message_layout.addWidget(screenshot_message_label) + screenshot_message_layout.addWidget(self.screenshot_message_edit) + + self.screenshot_button = QPushButton("Take screenshot") + self.screenshot_button.clicked.connect(self.__request_screenshot) + # Show detections checkbox detections_layout = QHBoxLayout() self.show_detections_checkbox = QCheckBox("Show ML detections") @@ -54,6 +75,9 @@ class SamcamPanel(QWidget): # Add controls to main layout layout.addLayout(exposure_layout) layout.addLayout(gain_layout) + layout.addLayout(screenshot_filename_layout) + layout.addLayout(screenshot_message_layout) + layout.addWidget(self.screenshot_button) layout.addLayout(detections_layout) self.setLayout(layout) @@ -61,6 +85,12 @@ class SamcamPanel(QWidget): self.changed.emit(SampleCameraSettings(gain=self.gain_spinbox.value(), exposure=self.exposure_spinbox.value())) + def __request_screenshot(self): + self.screenshot_requested.emit( + self.screenshot_filename_edit.text(), + self.screenshot_message_edit.text(), + ) + @Slot(DAQStatusModel) def update_daq_status(self, s: DAQStatusModel): if self.old_settings != s.bl.sample_camera: diff --git a/gui/src/aaregui/panels/sample_queue_panel.py b/src/aare/gui/panels/sample_queue_panel.py similarity index 86% rename from gui/src/aaregui/panels/sample_queue_panel.py rename to src/aare/gui/panels/sample_queue_panel.py index b52b4157..09ac5f5c 100644 --- a/gui/src/aaregui/panels/sample_queue_panel.py +++ b/src/aare/gui/panels/sample_queue_panel.py @@ -2,18 +2,20 @@ from PySide6.QtCore import Signal, Slot, Qt, QTimer from PySide6.QtWidgets import QFrame, QVBoxLayout, QHBoxLayout, QPushButton, QHeaderView, QSizePolicy, \ QTableView, QMessageBox from PySide6.QtGui import QKeySequence, QShortcut -from aaredaqlib.models import SampleShortInfoList, SampleShortInfo, BeamlineStateEnum +from aare.common.models import SampleShortInfoList, SampleShortInfo, BeamlineStateEnum -from aaregui.models.sample_queue_model import SampleQueueSpreadsheet -from aaregui.widgets.message_box import ring_current_low_check, experiment_hutch_shutter_check, LOW_CURRENT_THRESHOLD, \ +from aare.gui.models.sample_queue_model import SampleQueueSpreadsheet +from aare.gui.widgets.message_box import ring_current_low_check, experiment_hutch_shutter_check, LOW_CURRENT_THRESHOLD, \ ring_current_auto_check -from aaregui.widgets.title_label import TitleLabel -from aaredaqlib.models import DAQStatusModel +from aare.gui.widgets.title_label import TitleLabel +from aare.common.models import DAQStatusModel -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") +CHECK_ENABLED = False + class SampleQueuePanel(QFrame): auto_scan = Signal(SampleShortInfo) unmount = Signal() @@ -152,25 +154,26 @@ class SampleQueuePanel(QFrame): def run(self): self.__recovery_timer.stop() - if hasattr(self, '__warning_msg_box') and self.__warning_msg_box: - self.__warning_msg_box.done(0) - self.__warning_msg_box = None + if CHECK_ENABLED: + if hasattr(self, '__warning_msg_box') and self.__warning_msg_box: + self.__warning_msg_box.done(0) + self.__warning_msg_box = None - if self.__beamline_state != BeamlineStateEnum.SampleAlignment: - self.show_error_dialog(title="wrong beamline state", - msg="Cannot run automation while beamline is not in sample alignment state", - info="Please change the state at the bottom of the menu") - return + if self.__beamline_state != BeamlineStateEnum.SampleAlignment: + self.show_error_dialog(title="wrong beamline state", + msg="Cannot run automation while beamline is not in sample alignment state", + info="Please change the state at the bottom of the menu") + return if self.__pause: if len(self.table_model.samples) > 0: + if CHECK_ENABLED: + if not self.ring_current_check(): + logger.debug("low ring current, skipping") + return - if not self.ring_current_check(): - logger.debug("low ring current, skipping") - return - - elif not experiment_hutch_shutter_check(parent=self, shutter_state=self._experiment_shutter_state): - logger.debug("experiment shutter closed, user chose to skip") + elif not experiment_hutch_shutter_check(parent=self, shutter_state=self._experiment_shutter_state): + logger.debug("experiment shutter closed, user chose to skip") self.table_model.set_running(True) self.__set_to_pause = False @@ -206,15 +209,15 @@ class SampleQueuePanel(QFrame): if self._current_db_id is not None and db_id != self._current_db_id: return - def current_ok() -> bool: - return (self.ring_current is not None) and (self.ring_current >= LOW_CURRENT_THRESHOLD) - - if self.ring_current is None or (self.ring_current < LOW_CURRENT_THRESHOLD): + if CHECK_ENABLED and (self.ring_current is None or (self.ring_current < LOW_CURRENT_THRESHOLD)): # Pause UI state self.pause_automation(set_id_to_None=False) # This dialog should auto-accept when current_ok() returns True. # No user button press is required to continue. + def current_ok() -> bool: + return (self.ring_current is not None) and (self.ring_current >= LOW_CURRENT_THRESHOLD) + if ring_current_auto_check(self, self.ring_current, current_ok): logger.debug("Ring current recovered or user chose to continue," "resuming automation") diff --git a/gui/src/aaregui/panels/scan_settings_panel.py b/src/aare/gui/panels/scan_settings_panel.py similarity index 95% rename from gui/src/aaregui/panels/scan_settings_panel.py rename to src/aare/gui/panels/scan_settings_panel.py index 4816ee5a..fa779029 100644 --- a/gui/src/aaregui/panels/scan_settings_panel.py +++ b/src/aare/gui/panels/scan_settings_panel.py @@ -1,11 +1,11 @@ from PySide6.QtCore import Slot, Signal -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QMessageBox +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton -from aaredaqlib.diffraction_geometry import DiffractionGeometry -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.message_box import ring_current_low_check, experiment_hutch_shutter_check -from aaregui.widgets.number_line_edit import NumberLineEdit, CheckedLineEdit +from aare.common.diffraction_geometry import DiffractionGeometry +from aare.common.logger_config import setup_logger +from aare.common.models import DAQStatusModel +from aare.gui.widgets.message_box import ring_current_low_check, experiment_hutch_shutter_check +from aare.gui.widgets.number_line_edit import CheckedLineEdit logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/smargon_panel.py b/src/aare/gui/panels/smargon_panel.py similarity index 87% rename from gui/src/aaregui/panels/smargon_panel.py rename to src/aare/gui/panels/smargon_panel.py index 571a9cef..c9b1f5f6 100644 --- a/gui/src/aaregui/panels/smargon_panel.py +++ b/src/aare/gui/panels/smargon_panel.py @@ -1,12 +1,12 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.button_with_payload import ButtonWithPayload -from aaregui.widgets.number_line_edit import NumberLineEdit -from aaregui.widgets.title_label import TitleLabel -from aaredaqlib.coordinate import SmargonCoordinate, Coordinate -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.models import DAQStatusModel +from aare.gui.widgets.button_with_payload import ButtonWithPayload +from aare.gui.widgets.number_line_edit import NumberLineEdit +from aare.gui.widgets.title_label import TitleLabel +from aare.common.coordinate import SmargonCoordinate, Coordinate +from aare.common.sample_geometry import SampleGeometryModel class SmargonMoveWidget(QWidget): @@ -85,7 +85,8 @@ class SmargonPanel(QWidget): @Slot() def home(self): - self.smargon.emit(Smargon.SMARGON_HOME) + #TODO move SMARGON_HOME to REDIS, allow GUI to read this value + self.smargon.emit(SmargonCoordinate(sh_mm=Coordinate(x=0, y=0, z=18), phi_deg=0, chi_deg=0)) @Slot(float) def phi(self, f: float): diff --git a/src/aare/gui/panels/smargon_trace_panel.py b/src/aare/gui/panels/smargon_trace_panel.py new file mode 100644 index 00000000..fe958702 --- /dev/null +++ b/src/aare/gui/panels/smargon_trace_panel.py @@ -0,0 +1,639 @@ +from __future__ import annotations + +import csv +from math import sqrt +from pathlib import Path + +import numpy as np +from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.figure import Figure +from PySide6.QtCore import QSettings, QTimer, Qt +from PySide6.QtWidgets import ( + QCheckBox, + QComboBox, + QFileDialog, + QFormLayout, + QGroupBox, + QHBoxLayout, + QLabel, + QPushButton, + QTableWidget, + QTableWidgetItem, + QVBoxLayout, + QWidget, +) + + +class SmargonTracePanel(QWidget): + HOME_X_MM = 0.0 + HOME_Y_MM = 0.0 + HOME_Z_MM = 18.0 + TABLE_MAX_ROWS = 20 + + COLOR_X = "tab:red" + COLOR_Y = "tab:green" + COLOR_Z = "tab:blue" + COLOR_DISTANCE = "tab:purple" + + SETTINGS_GROUP = "smargon_trace_panel" + + def __init__(self, csv_path: str | Path = "logs/smargon_trace.csv", parent=None): + super().__init__(parent) + + self._csv_path = Path(csv_path) + self._active_csv_path: Path | None = None + self._last_mtime_ns: int | None = None + self._last_rows: list[dict[str, object]] = [] + self._last_distances: list[float] = [] + self._last_lengths: list[float] = [] + + self._status = QLabel("Waiting for smargon trace data...") + self._status.setWordWrap(True) + + self._summary = QLabel( + f"Home position: " + f"X={self.HOME_X_MM:.3f} mm, " + f"Y={self.HOME_Y_MM:.3f} mm, " + f"Z={self.HOME_Z_MM:.3f} mm" + ) + self._summary.setWordWrap(True) + + self._metrics = QLabel("Latest metrics: distance=n/a | length=n/a") + self._metrics.setWordWrap(True) + + self._show_summary_cb = QCheckBox("Summary") + self._show_delta_cb = QCheckBox("Delta") + self._show_absolute_cb = QCheckBox("Absolute") + self._show_distance_cb = QCheckBox("Total distance") + self._show_table_cb = QCheckBox("Table") + + self._show_summary_cb.setChecked(True) + self._show_delta_cb.setChecked(True) + self._show_absolute_cb.setChecked(False) + self._show_distance_cb.setChecked(False) + self._show_table_cb.setChecked(False) + + self._units_combo = QComboBox() + self._units_combo.addItems(["mm", "µm"]) + self._units_combo.setCurrentText("mm") + self._units_combo.setMaximumWidth(90) + + self._export_btn = QPushButton("Export table CSV") + self._export_btn.clicked.connect(self._export_table_csv) + + display_group = QGroupBox("Display") + display_layout = QHBoxLayout(display_group) + display_layout.setContentsMargins(8, 6, 8, 6) + display_layout.setSpacing(10) + display_layout.addWidget(self._show_summary_cb) + display_layout.addWidget(self._show_delta_cb) + display_layout.addWidget(self._show_absolute_cb) + display_layout.addWidget(self._show_distance_cb) + display_layout.addWidget(self._show_table_cb) + display_layout.addStretch() + display_layout.addWidget(QLabel("Units:")) + display_layout.addWidget(self._units_combo) + display_layout.addWidget(self._export_btn) + + self._summary_group = QGroupBox("Summary") + summary_layout = QFormLayout(self._summary_group) + summary_layout.setContentsMargins(8, 6, 8, 6) + summary_layout.setSpacing(6) + summary_layout.addRow("Status:", self._status) + summary_layout.addRow("Position:", self._summary) + summary_layout.addRow("Metrics:", self._metrics) + + self._figure = Figure(figsize=(7, 7)) + self._canvas = FigureCanvas(self._figure) + + self._table = QTableWidget(self) + self._table.setColumnCount(8) + self._table.setHorizontalHeaderLabels( + ["Point", "Event", "Sample", "X", "Y", "Z", "Distance", "Length"] + ) + self._table.verticalHeader().setVisible(False) + self._table.setAlternatingRowColors(True) + self._table.setVisible(False) + + layout = QVBoxLayout(self) + layout.setContentsMargins(6, 6, 6, 6) + layout.setSpacing(8) + layout.addWidget(display_group) + layout.addWidget(self._summary_group) + layout.addWidget(self._canvas) + layout.addWidget(self._table) + + self._show_summary_cb.toggled.connect(self._on_controls_changed) + self._show_delta_cb.toggled.connect(self._on_controls_changed) + self._show_absolute_cb.toggled.connect(self._on_controls_changed) + self._show_distance_cb.toggled.connect(self._on_controls_changed) + self._show_table_cb.toggled.connect(self._on_controls_changed) + self._units_combo.currentTextChanged.connect(lambda _text: self._on_controls_changed()) + + self._load_settings() + + self._timer = QTimer(self) + self._timer.setInterval(1000) + self._timer.timeout.connect(self.refresh_plot) + self._timer.start() + + self._apply_visibility_settings() + self.refresh_plot(force=True) + + def refresh_plot(self, force: bool = False) -> None: + csv_path = self._resolve_csv_path() + + if csv_path is None or not csv_path.exists(): + self._active_csv_path = None + self._last_mtime_ns = None + self._last_rows = [] + self._last_distances = [] + self._last_lengths = [] + self._status.setText( + "No trace file found. Tried: " + + ", ".join(str(p) for p in self._candidate_paths()) + ) + self._summary.setText( + f"Home position: " + f"X={self.HOME_X_MM:.3f} mm, " + f"Y={self.HOME_Y_MM:.3f} mm, " + f"Z={self.HOME_Z_MM:.3f} mm" + ) + self._metrics.setText("Latest metrics: distance=n/a | length=n/a") + self._draw_empty("No smargon trace file found yet") + self._clear_table() + return + + try: + stat = csv_path.stat() + if ( + not force + and self._active_csv_path == csv_path + and self._last_mtime_ns == stat.st_mtime_ns + ): + return + + self._active_csv_path = csv_path + self._last_mtime_ns = stat.st_mtime_ns + + rows = self._read_rows(csv_path) + if not rows: + self._last_rows = [] + self._last_distances = [] + self._last_lengths = [] + self._status.setText(f"Trace file is empty: {csv_path}") + self._summary.setText( + f"Home position: " + f"X={self.HOME_X_MM:.3f} mm, " + f"Y={self.HOME_Y_MM:.3f} mm, " + f"Z={self.HOME_Z_MM:.3f} mm" + ) + self._metrics.setText("Latest metrics: distance=n/a | length=n/a") + self._draw_empty("Smargon trace file is empty") + self._clear_table() + return + + unit_name, unit_scale = self._unit_settings() + + x = list(range(1, len(rows) + 1)) + + shx_mm = [row["shx_mm"] for row in rows] + shy_mm = [row["shy_mm"] for row in rows] + shz_mm = [row["shz_mm"] for row in rows] + + dx_mm = [value - self.HOME_X_MM for value in shx_mm] + dy_mm = [value - self.HOME_Y_MM for value in shy_mm] + dz_mm = [value - self.HOME_Z_MM for value in shz_mm] + + shx = [value * unit_scale for value in shx_mm] + shy = [value * unit_scale for value in shy_mm] + shz = [value * unit_scale for value in shz_mm] + + dx = [value * unit_scale for value in dx_mm] + dy = [value * unit_scale for value in dy_mm] + dz = [value * unit_scale for value in dz_mm] + + distances_mm = [ + sqrt(dx0**2 + dy0**2 + dz0**2) + for dx0, dy0, dz0 in zip(dx_mm, dy_mm, dz_mm) + ] + distances = [value * unit_scale for value in distances_mm] + + lengths_mm = [self._projected_length_mm(row) for row in rows] + lengths = [value * unit_scale for value in lengths_mm] + + self._last_rows = rows + self._last_distances = distances + self._last_lengths = lengths + + self._redraw_plots( + x=x, + shx=shx, + shy=shy, + shz=shz, + dx=dx, + dy=dy, + dz=dz, + distances=distances, + unit_name=unit_name, + ) + + last = rows[-1] + last_dx_mm = dx_mm[-1] + last_dy_mm = dy_mm[-1] + last_dz_mm = dz_mm[-1] + + distance_value = distances[-1] + length_value = lengths[-1] + + self._status.setText( + f"Loaded {len(rows)} points from {csv_path} | " + f"last event={last['event']} | " + f"sample_id={last['sample_id']}" + ) + self._summary.setText( + f"Home: X={self.HOME_X_MM * unit_scale:.3f}, " + f"Y={self.HOME_Y_MM * unit_scale:.3f}, " + f"Z={self.HOME_Z_MM * unit_scale:.3f} {unit_name} | " + f"Latest: X={last['shx_mm'] * unit_scale:.5f}, " + f"Y={last['shy_mm'] * unit_scale:.5f}, " + f"Z={last['shz_mm'] * unit_scale:.5f} {unit_name} | " + f"Δ: X={last_dx_mm * unit_scale:+.5f}, " + f"Y={last_dy_mm * unit_scale:+.5f}, " + f"Z={last_dz_mm * unit_scale:+.5f} {unit_name}" + ) + self._metrics.setText( + f"distance={distance_value:.5f} {unit_name} | " + f"length={length_value:.5f} {unit_name} (beamline-plane projected)" + ) + + self._populate_table( + rows=rows, + distances=distances, + lengths=lengths, + unit_name=unit_name, + unit_scale=unit_scale, + ) + + except Exception as e: + self._last_rows = [] + self._last_distances = [] + self._last_lengths = [] + self._status.setText(f"Failed to load trace from {csv_path}: {e}") + self._summary.setText( + f"Home position: " + f"X={self.HOME_X_MM:.3f} mm, " + f"Y={self.HOME_Y_MM:.3f} mm, " + f"Z={self.HOME_Z_MM:.3f} mm" + ) + self._metrics.setText("Latest metrics: distance=n/a | length=n/a") + self._draw_empty("Failed to parse smargon trace") + self._clear_table() + + def showEvent(self, event) -> None: + super().showEvent(event) + self.refresh_plot(force=True) + + def _on_controls_changed(self) -> None: + self._save_settings() + self._apply_visibility_settings() + + def _load_settings(self) -> None: + settings = QSettings() + settings.beginGroup(self.SETTINGS_GROUP) + self._show_summary_cb.setChecked(settings.value("show_summary", True, type=bool)) + self._show_delta_cb.setChecked(settings.value("show_delta", True, type=bool)) + self._show_absolute_cb.setChecked(settings.value("show_absolute", False, type=bool)) + self._show_distance_cb.setChecked(settings.value("show_distance", False, type=bool)) + self._show_table_cb.setChecked(settings.value("show_table", False, type=bool)) + self._units_combo.setCurrentText(settings.value("units", "mm", type=str)) + settings.endGroup() + + def _save_settings(self) -> None: + settings = QSettings() + settings.beginGroup(self.SETTINGS_GROUP) + settings.setValue("show_summary", self._show_summary_cb.isChecked()) + settings.setValue("show_delta", self._show_delta_cb.isChecked()) + settings.setValue("show_absolute", self._show_absolute_cb.isChecked()) + settings.setValue("show_distance", self._show_distance_cb.isChecked()) + settings.setValue("show_table", self._show_table_cb.isChecked()) + settings.setValue("units", self._units_combo.currentText()) + settings.endGroup() + + def _apply_visibility_settings(self) -> None: + if not ( + self._show_delta_cb.isChecked() + or self._show_absolute_cb.isChecked() + or self._show_distance_cb.isChecked() + ): + self._show_delta_cb.blockSignals(True) + self._show_delta_cb.setChecked(True) + self._show_delta_cb.blockSignals(False) + + self._summary_group.setVisible(self._show_summary_cb.isChecked()) + self._table.setVisible(self._show_table_cb.isChecked()) + self.refresh_plot(force=True) + + def _export_table_csv(self) -> None: + if not self._last_rows: + return + + unit_name, unit_scale = self._unit_settings() + file_path, _ = QFileDialog.getSaveFileName( + self, + "Export Smargon Trace Table", + "smargon_trace_export.csv", + "CSV Files (*.csv)", + ) + if not file_path: + return + + with open(file_path, "w", encoding="utf-8", newline="") as f: + writer = csv.writer(f) + writer.writerow([ + "point", + "timestamp", + "event", + "sample_id", + f"shx_{unit_name}", + f"shy_{unit_name}", + f"shz_{unit_name}", + f"distance_{unit_name}", + f"length_{unit_name}", + "omega_deg", + "phi_deg", + "chi_deg", + ]) + + for idx, (row, distance_value, length_value) in enumerate( + zip(self._last_rows, self._last_distances, self._last_lengths), + start=1, + ): + writer.writerow([ + idx, + row["timestamp"], + row["event"], + row["sample_id"], + float(row["shx_mm"]) * unit_scale, + float(row["shy_mm"]) * unit_scale, + float(row["shz_mm"]) * unit_scale, + distance_value, + length_value, + row["omega_deg"], + row["phi_deg"], + row["chi_deg"], + ]) + + def _redraw_plots( + self, + *, + x: list[int], + shx: list[float], + shy: list[float], + shz: list[float], + dx: list[float], + dy: list[float], + dz: list[float], + distances: list[float], + unit_name: str, + ) -> None: + self._figure.clear() + + enabled = [] + if self._show_delta_cb.isChecked(): + enabled.append("delta") + if self._show_absolute_cb.isChecked(): + enabled.append("absolute") + if self._show_distance_cb.isChecked(): + enabled.append("distance") + + axes = self._figure.subplots(len(enabled), 1, squeeze=False) + axes_list = [row[0] for row in axes] + + for ax, plot_name in zip(axes_list, enabled): + if plot_name == "delta": + ax.plot(x, dx, marker="o", color=self.COLOR_X, label=f"ΔSHX [{unit_name}]") + ax.plot(x, dy, marker="o", color=self.COLOR_Y, label=f"ΔSHY [{unit_name}]") + ax.plot(x, dz, marker="o", color=self.COLOR_Z, label=f"ΔSHZ [{unit_name}]") + ax.axhline(0.0, color="black", linewidth=1.0, alpha=0.5) + ax.set_title("Smargon displacement from home") + ax.set_ylabel(f"Δ position [{unit_name}]") + ax.grid(True, alpha=0.3) + ax.legend(loc="best") + + elif plot_name == "absolute": + ax.plot(x, shx, marker="o", color=self.COLOR_X, label=f"SHX [{unit_name}]") + ax.plot(x, shy, marker="o", color=self.COLOR_Y, label=f"SHY [{unit_name}]") + ax.plot(x, shz, marker="o", color=self.COLOR_Z, label=f"SHZ [{unit_name}]") + ax.set_title("Smargon absolute position") + ax.set_ylabel(f"Position [{unit_name}]") + ax.grid(True, alpha=0.3) + ax.legend(loc="best") + + elif plot_name == "distance": + ax.plot(x, distances, marker="o", color=self.COLOR_DISTANCE, label=f"Total distance [{unit_name}]") + ax.set_title("Total distance from home") + ax.set_ylabel(f"Distance [{unit_name}]") + ax.grid(True, alpha=0.3) + ax.legend(loc="best") + + ax.set_xlabel("Trace point") + + self._figure.tight_layout() + self._canvas.draw_idle() + + def _populate_table( + self, + *, + rows: list[dict[str, object]], + distances: list[float], + lengths: list[float], + unit_name: str, + unit_scale: float, + ) -> None: + recent_rows = rows[-self.TABLE_MAX_ROWS:] + recent_distances = distances[-self.TABLE_MAX_ROWS:] + recent_lengths = lengths[-self.TABLE_MAX_ROWS:] + + self._table.setRowCount(len(recent_rows)) + self._table.setHorizontalHeaderLabels( + [ + "Point", + "Event", + "Sample", + f"X [{unit_name}]", + f"Y [{unit_name}]", + f"Z [{unit_name}]", + f"Distance [{unit_name}]", + f"Length [{unit_name}]", + ] + ) + + start_idx = len(rows) - len(recent_rows) + 1 + for row_idx, (row, distance_value, length_value) in enumerate( + zip(recent_rows, recent_distances, recent_lengths) + ): + values = [ + str(start_idx + row_idx), + str(row["event"]), + str(row["sample_id"]), + f"{float(row['shx_mm']) * unit_scale:.5f}", + f"{float(row['shy_mm']) * unit_scale:.5f}", + f"{float(row['shz_mm']) * unit_scale:.5f}", + f"{distance_value:.5f}", + f"{length_value:.5f}", + ] + for col_idx, value in enumerate(values): + item = QTableWidgetItem(value) + item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self._table.setItem(row_idx, col_idx, item) + + self._table.resizeColumnsToContents() + + def _clear_table(self) -> None: + self._table.setRowCount(0) + + def _unit_settings(self) -> tuple[str, float]: + if self._units_combo.currentText() == "µm": + return "µm", 1000.0 + return "mm", 1.0 + + def _candidate_paths(self) -> list[Path]: + here = Path(__file__).resolve() + project_root = here.parents[4] + + candidates = [ + Path.cwd() / self._csv_path, + project_root / self._csv_path, + project_root / "src" / "aare" / "daq" / "logs" / "smargon_trace.csv", + project_root / "src" / "aare" / "gui" / "logs" / "smargon_trace.csv", + ] + + out: list[Path] = [] + seen: set[str] = set() + for path in candidates: + key = str(path.resolve()) if path.exists() else str(path) + if key not in seen: + out.append(path) + seen.add(key) + return out + + def _resolve_csv_path(self) -> Path | None: + existing = [p for p in self._candidate_paths() if p.exists()] + if not existing: + return None + return max(existing, key=lambda p: p.stat().st_mtime_ns) + + def _read_rows(self, csv_path: Path) -> list[dict[str, object]]: + rows: list[dict[str, object]] = [] + + with csv_path.open("r", encoding="utf-8", newline="") as f: + reader = csv.DictReader(f) + for row in reader: + try: + rows.append( + { + "timestamp": row.get("timestamp", row.get("ts", "")), + "event": row.get("event", ""), + "sample_id": row.get("sample_id", ""), + "omega_deg": float(row.get("omega_deg", "nan")), + "zoom": float(row.get("zoom", "nan")), + "shx_mm": float(row.get("shx_mm", "nan")), + "shy_mm": float(row.get("shy_mm", "nan")), + "shz_mm": float(row.get("shz_mm", "nan")), + "phi_deg": float(row.get("phi_deg", "nan")), + "chi_deg": float(row.get("chi_deg", "nan")), + } + ) + except (TypeError, ValueError): + continue + + return rows + + def _projected_length_mm(self, row: dict[str, object]) -> float: + rel = np.array( + [ + float(row["shx_mm"]) - self.HOME_X_MM, + float(row["shy_mm"]) - self.HOME_Y_MM, + float(row["shz_mm"]) - self.HOME_Z_MM, + ], + dtype=float, + ) + + vec_x = self._smargon_nudge_basis( + axis="x", + omega_deg=float(row["omega_deg"]), + phi_deg=float(row["phi_deg"]), + chi_deg=float(row["chi_deg"]), + ) + vec_y = self._smargon_nudge_basis( + axis="y", + omega_deg=float(row["omega_deg"]), + phi_deg=float(row["phi_deg"]), + chi_deg=float(row["chi_deg"]), + ) + + beam_x = float(np.dot(rel, vec_x)) + beam_y = float(np.dot(rel, vec_y)) + + return sqrt(beam_x**2 + beam_y**2) + + def _smargon_nudge_basis( + self, + *, + axis: str, + omega_deg: float, + phi_deg: float, + chi_deg: float, + ) -> np.ndarray: + phi = np.radians(np.around(phi_deg, decimals=1)) + chi = np.radians(np.around(chi_deg, decimals=1)) + omega = np.radians(np.around(omega_deg, decimals=1)) + + if axis == "x": + coord_x, coord_y, coord_z = 1.0, 0.0, 0.0 + elif axis == "y": + coord_x, coord_y, coord_z = 0.0, 1.0, 0.0 + else: + raise ValueError(f"Unsupported axis: {axis}") + + co = np.cos(omega) + so = np.sin(omega) + cp = np.cos(phi) + sp = np.sin(phi) + cc = np.cos(chi) + sc = np.sin(chi) + + offset_x = ( + -coord_z * co * sp + - coord_y * so * sp + + coord_x * cp * sc + - coord_y * co * cc * cp + + coord_z * so * cc * cp + ) + offset_y = ( + -coord_z * co * cp + - coord_y * so * cp + - coord_x * sc * sp + + coord_y * co * cc * sp + - coord_z * so * cc * sp + ) + offset_z = -coord_x * cc - coord_y * co * sc + coord_z * so * sc + + vec = np.array([offset_x, offset_y, offset_z], dtype=float) + norm = np.linalg.norm(vec) + + if norm == 0.0: + return np.array([0.0, 0.0, 0.0], dtype=float) + + return vec / norm + + def _draw_empty(self, message: str) -> None: + self._figure.clear() + ax = self._figure.add_subplot(111) + ax.set_title("Smargon trace") + ax.text(0.5, 0.5, message, ha="center", va="center", transform=ax.transAxes) + ax.set_xticks([]) + ax.set_yticks([]) + self._figure.tight_layout() + self._canvas.draw_idle() \ No newline at end of file diff --git a/gui/src/aaregui/panels/smart_rotation_panel.py b/src/aare/gui/panels/smart_rotation_panel.py similarity index 97% rename from gui/src/aaregui/panels/smart_rotation_panel.py rename to src/aare/gui/panels/smart_rotation_panel.py index 08c0c90d..bf88477e 100644 --- a/gui/src/aaregui/panels/smart_rotation_panel.py +++ b/src/aare/gui/panels/smart_rotation_panel.py @@ -1,13 +1,13 @@ import math from PySide6.QtCore import Slot, Qt, Signal -from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QFrame, QPushButton, QSpacerItem, QSizePolicy +from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QPushButton, QSpacerItem, QSizePolicy -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import DAQStatusModel, SimpleScanParameters, CrystalSize -from aaredaqlib.rotation_scan import RotationScanRequest -from aaregui.panels.rotation_data_collection import add_data_to_path -from aaregui.widgets.number_line_edit import NumberLineEdit +from aare.common.logger_config import setup_logger +from aare.common.models import DAQStatusModel, SimpleScanParameters, CrystalSize +from aare.common.rotation_scan import RotationScanRequest +from aare.gui.panels.rotation_data_collection import add_data_to_path +from aare.gui.widgets.number_line_edit import NumberLineEdit logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/status_panel.py b/src/aare/gui/panels/status_panel.py similarity index 93% rename from gui/src/aaregui/panels/status_panel.py rename to src/aare/gui/panels/status_panel.py index f37c3906..67051080 100644 --- a/gui/src/aaregui/panels/status_panel.py +++ b/src/aare/gui/panels/status_panel.py @@ -1,11 +1,11 @@ from PySide6.QtCore import Qt, Slot from PySide6.QtGui import QPixmap from PySide6.QtWidgets import QFrame, QGridLayout, QLabel, QSpacerItem, QSizePolicy -from aaredaqlib.models import DAQStatusModel -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.models import DAQStatusModel +from aare.common.sample_geometry import SampleGeometryModel -from aaregui.widgets.status_label import StatusLabel -from aaregui.widgets.title_label import TitleLabel +from aare.gui.widgets.status_label import StatusLabel +from aare.gui.widgets.title_label import TitleLabel class StatusPanel(QFrame): diff --git a/gui/src/aaregui/panels/tell_sample_panel.py b/src/aare/gui/panels/tell_sample_panel.py similarity index 96% rename from gui/src/aaregui/panels/tell_sample_panel.py rename to src/aare/gui/panels/tell_sample_panel.py index 9984bcf7..fce011fd 100644 --- a/gui/src/aaregui/panels/tell_sample_panel.py +++ b/src/aare/gui/panels/tell_sample_panel.py @@ -10,11 +10,11 @@ from PySide6.QtWidgets import ( QAbstractItemView, ) -from aaredaqlib.logger_config import setup_logger -from aaredaqlib.models import BeamlineStateEnum, SampleShortInfo, SampleShortInfoList, DAQStatusModel +from aare.common.logger_config import setup_logger +from aare.common.models import BeamlineStateEnum, SampleShortInfo, SampleShortInfoList, DAQStatusModel -from aaregui.models.user_sample_model import UserSampleSpreadsheet -from aaregui.widgets.title_label import TitleLabel +from aare.gui.models.user_sample_model import UserSampleSpreadsheet +from aare.gui.widgets.title_label import TitleLabel logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/panels/zoom_panel.py b/src/aare/gui/panels/zoom_panel.py similarity index 90% rename from gui/src/aaregui/panels/zoom_panel.py rename to src/aare/gui/panels/zoom_panel.py index f5009049..3911a901 100644 --- a/gui/src/aaregui/panels/zoom_panel.py +++ b/src/aare/gui/panels/zoom_panel.py @@ -1,9 +1,9 @@ from PySide6.QtCore import Slot, Signal from PySide6.QtWidgets import QWidget, QGridLayout -from aaredaqlib.models import DAQStatusModel -from aaregui.widgets.button_with_payload import ButtonWithPayload -from aaregui.widgets.title_label import TitleLabel +from aare.common.models import DAQStatusModel +from aare.gui.widgets.button_with_payload import ButtonWithPayload +from aare.gui.widgets.title_label import TitleLabel class ZoomPanel(QWidget): diff --git a/src/aare/gui/sam_cam_test.py b/src/aare/gui/sam_cam_test.py new file mode 100644 index 00000000..abe00a96 --- /dev/null +++ b/src/aare/gui/sam_cam_test.py @@ -0,0 +1,739 @@ +from __future__ import annotations + +import time +from dataclasses import dataclass +from time import sleep, perf_counter +from typing import Callable, Optional + +import numpy as np + +from aare.common.beamline import mx_beamline +from aare.devices.area_detector import epicsAD +from aare.daq.devices import BeamlineDevices + +# Python +@dataclass(frozen=True) +class MeteringConfig: + """ + Metering and robustness parameters for dark-background + bright sample scenes. + """ + # Use central ROI to reduce chance of metering random bright junk near edges. + # 1.0 = full frame, 0.7 = central 70% in width/height. + center_roi: float = 0.7 + + # Dynamic threshold: thr = percentile(gray, bg_percentile) + delta_dn + bg_percentile: float = 10.0 + delta_dn: int = 15 + + # If mask is too small, fall back to a larger ROI or whole frame. + min_mask_fraction: float = 0.002 # 0.2% of ROI pixels + + # Winsorization for brightness metric (NOT for clipping metric): + # clamp values above winsor_high before computing percentiles. + winsor_high: int = 245 + subsample: int = 2 + + +@dataclass(frozen=True) +class TargetConfig: + """ + Control objectives. + """ + # Hard constraint: keep saturated fraction small. + clip_limit: float = 0.003 # 0.3% of metered pixels >= clip_level + + # Clip threshold (8-bit): treat >=254 as "near-saturated". + clip_level: int = 254 + + # Percentile target of metered (masked) pixels. For metallic base variability, + # p80 is usually more stable than p90. + percentile: float = 80.0 + percentile_target: float = 160.0 + + # Optional: if the metered pixels are too sparse, you can skip updates. + min_metered_pixels: int = 5000 + + +@dataclass(frozen=True) +class LimitsConfig: + """ + Exposure/gain bounds and stepping. + """ + exposure_min_s: float = 0.0001 + exposure_max_s: float = 1.0 + + exposure_effective_min_s: float = 0.002 + exposure_quantum_s: float = 1e-6 + + gain_min: float = 36.0 + gain_max: float = 512.0 + + # Update aggressiveness + exposure_k: float = 0.35 # proportional factor for percentile error + exposure_clip_drop: float = 0.7 # multiply exposure by this when clipping too high + + gain_step: float = 1.0 # gain adjustment step when exposure hits bounds + + # Safety: limit how fast exposure can change to avoid oscillations + max_exposure_scale_up: float = 1.25 + max_exposure_scale_down: float = 0.75 + + +@dataclass +class Metrics: + bg: float + thr: int + n_total: int + n_metered: int + mask_fraction: float + clip_frac: float + p50: float + p70: float + p80: float + p90: float + mean: float + + +def _center_crop(gray: np.ndarray, frac: float) -> np.ndarray: + if frac >= 1.0: + return gray + if frac <= 0.0: + raise ValueError("center_roi must be in (0, 1].") + h, w = gray.shape[:2] + rh = max(1, int(h * frac)) + rw = max(1, int(w * frac)) + y0 = (h - rh) // 2 + x0 = (w - rw) // 2 + return gray[y0:y0 + rh, x0:x0 + rw] + +def _percentile_from_hist(hist: np.ndarray, percentile: float) -> int: + """ + hist: counts per DN bin [0..255] + percentile: 0..100 + returns: DN value (0..255) + """ + total = int(hist.sum()) + if total <= 0: + return 0 + k = int(np.ceil((percentile / 100.0) * total)) + c = np.cumsum(hist) + return int(np.searchsorted(c, k, side="left")) + +def _hist_u8(a: np.ndarray) -> np.ndarray: + """ + Fast histogram for uint8 array -> length 256. + """ + return np.bincount(a.ravel(), minlength=256) + +def compute_metrics(gray: np.ndarray, met: MeteringConfig, tgt: TargetConfig) -> Metrics: + """ + Compute robust metering metrics for 8-bit dark-background scenes. + + Optimized: + - avoids np.percentile on million-pixel arrays (uses 256-bin histograms) + - optional subsampling + """ + if gray.ndim != 2: + raise ValueError("compute_metrics expects a 2D grayscale image.") + + g = gray + if g.dtype != np.uint8: + g = np.clip(g, 0, 255).astype(np.uint8) + + roi_full = _center_crop(g, met.center_roi) + + # Optional subsampling for speed + s = int(getattr(met, "subsample", 1)) + if s > 1: + roi = roi_full[::s, ::s] + else: + roi = roi_full + + n_total = int(roi.size) + + # Background percentile from histogram + hist_roi = _hist_u8(roi) + bg_dn = _percentile_from_hist(hist_roi, met.bg_percentile) + thr = int(min(255, max(0, bg_dn + int(met.delta_dn)))) + + mask = roi > thr + n_metered = int(mask.sum()) + mask_fraction = float(n_metered / max(1, n_total)) + + # If mask too small, fall back to full frame (still subsampled) + if mask_fraction < met.min_mask_fraction: + roi_full = g + if s > 1: + roi = roi_full[::s, ::s] + else: + roi = roi_full + n_total = int(roi.size) + + hist_roi = _hist_u8(roi) + bg_dn = _percentile_from_hist(hist_roi, met.bg_percentile) + thr = int(min(255, max(0, bg_dn + int(met.delta_dn)))) + + mask = roi > thr + n_metered = int(mask.sum()) + mask_fraction = float(n_metered / max(1, n_total)) + + # Clip fraction on ROI (not just masked) + # Uses histogram so it is cheap. + hist_roi = _hist_u8(roi) + clip_bins = hist_roi[int(tgt.clip_level):].sum() + clip_frac = float(clip_bins / max(1, n_total)) + + if n_metered == 0: + # Approx mean from hist (avoids np.mean) + mean_roi = float(np.dot(np.arange(256, dtype=np.float64), hist_roi) / max(1, n_total)) + return Metrics( + bg=float(bg_dn), + thr=thr, + n_total=n_total, + n_metered=0, + mask_fraction=0.0, + clip_frac=clip_frac, + p50=0.0, + p70=0.0, + p80=0.0, + p90=0.0, + mean=mean_roi, + ) + + # Histogram of masked pixels with winsorization applied: + # - compute histogram of masked values + # - fold bins above winsor_high into winsor_high + vals = roi[mask] + hist_vals = _hist_u8(vals) + + wh = int(met.winsor_high) + if wh < 255: + hist_vals[wh] += hist_vals[wh + 1:].sum() + hist_vals[wh + 1:] = 0 + + p50 = float(_percentile_from_hist(hist_vals, 50.0)) + p70 = float(_percentile_from_hist(hist_vals, 70.0)) + p80 = float(_percentile_from_hist(hist_vals, 80.0)) + p90 = float(_percentile_from_hist(hist_vals, 90.0)) + + mean_vals = float(np.dot(np.arange(256, dtype=np.float64), hist_vals) / max(1, hist_vals.sum())) + + return Metrics( + bg=float(bg_dn), + thr=thr, + n_total=n_total, + n_metered=n_metered, + mask_fraction=mask_fraction, + clip_frac=clip_frac, + p50=p50, + p70=p70, + p80=p80, + p90=p90, + mean=mean_vals, + ) + +def _get_percentile_value(m: Metrics, percentile: float) -> float: + if abs(percentile - 50.0) < 1e-6: + return m.p50 + if abs(percentile - 70.0) < 1e-6: + return m.p70 + if abs(percentile - 80.0) < 1e-6: + return m.p80 + if abs(percentile - 90.0) < 1e-6: + return m.p90 + # If you want arbitrary percentiles, compute them directly in compute_metrics. + raise ValueError("This implementation supports percentile ∈ {50, 80, 90} for speed/stability.") + + +class AutoExposureController: + """ + Camera-agnostic controller: you inject how to read image and how to set/get exposure/gain. + + This keeps the logic testable and usable both in DAQ and GUI contexts. + """ + def __init__( + self, + get_gray_image: Callable[[], np.ndarray], + get_exposure_s: Callable[[], float], + set_exposure_s: Callable[[float], None], + get_gain: Callable[[], float], + set_gain: Callable[[float], None], + metering: MeteringConfig | None = None, + target: TargetConfig | None = None, + limits: LimitsConfig | None = None, + get_frame_id: Callable[[], int] | None = None, + ): + self.get_gray_image = get_gray_image + self.get_exposure_s = get_exposure_s + self.set_exposure_s = set_exposure_s + self.get_gain = get_gain + self.set_gain = set_gain + self.get_frame_id = get_frame_id + + self.metering = metering or MeteringConfig() + self.target = target or TargetConfig() + self.limits = limits or LimitsConfig() + + # simple exponential smoothing for metrics + self._ema_clip: Optional[float] = None + self._ema_p: Optional[float] = None + + def _clamp(self, x: float, lo: float, hi: float) -> float: + # Enforce "effective" minimum to avoid PV rounding to 0. + lo_eff = max(lo, self.limits.exposure_effective_min_s) + + x = max(lo_eff, min(hi, x)) + + q = float(self.limits.exposure_quantum_s) + if q > 0: + x = round(x / q) * q + + # Re-enforce bounds after rounding + x = max(lo_eff, min(hi, x)) + return x + + def _wait_frames(self, frames: int, timeout_s: float = 0.5) -> bool: + """ + Wait for `frames` new frames (by frame counter), if get_frame_id is available. + + Returns: + True if the requested number of frames were observed, False on timeout. + """ + if self.get_frame_id is None: + sleep(0.04 * frames) + return True + + start_id = int(self.get_frame_id()) + deadline = perf_counter() + float(timeout_s) + target_id = start_id + int(frames) + + while perf_counter() < deadline: + if int(self.get_frame_id()) >= target_id: + return True + sleep(0.002) + + return False + + def _settle_after_change(self, new_exp_s: float, base_settle_s: float, fps:float = 25.0) -> None: + """ + Wait long enough that the next acquired frame reflects the new exposure. + """ + ok = self._wait_frames(frames=1, timeout_s=0.25) + if not ok: + # If frame IDs aren't advancing reliably, avoid reusing the same buffer. + # Keep it small to preserve speed. + sleep(min(0.02, max(0.0, float(new_exp_s)))) + + t_extra = max(0.0, float(new_exp_s) - (1.0 / float(fps))) + if t_extra > 0: + sleep(min(t_extra, 0.35)) + + if base_settle_s > 0: + sleep(float(base_settle_s)) + + def _set_exposure_if_changed(self, new_exp: float, current_exp: float) -> bool: + q = float(self.limits.exposure_quantum_s) if self.limits.exposure_quantum_s > 0 else 0.0 + eps = max(1e-9, 0.5 * q) + if abs(new_exp - current_exp) <= eps: + return False + self.set_exposure_s(new_exp) + return True + + def _set_gain_if_changed(self, new_gain: float, current_gain: float) -> bool: + if abs(new_gain - current_gain) < 1e-6: + return False + self.set_gain(new_gain) + return True + + def time_test(self): + t0 = perf_counter() + gray = self.get_gray_image() + t1 = perf_counter() + m = compute_metrics(gray, self.metering, self.target) + t2 = perf_counter() + exp = float(self.get_exposure_s()) + gain = float(self.get_gain()) + t3 = perf_counter() + print("gray:", t1 - t0, "metrics:", t2 - t1, "pvs:", t3 - t2) + + def run_once( + self, + settle_s: float = 0.15, + max_iters: int = 12, + verbose: bool = True, + deadband_dn: float = 12.0, + metering_unreliable_boost: float = 1.4, + ) -> tuple[float, float, Metrics]: + + base_settle_s = float(settle_s) + last_m = None + + # Make EMA more responsive so it doesn't lag by ~10 iterations + ema_alpha_p = 0.60 + ema_pv: float | None = None + + # 1 stable frame is typically enough once the loop is well behaved + stable_needed = 1 + stable_count = 0 + + # Use raw pv for the first few iterations to avoid EMA-lag overshoot + raw_control_iters = 3 + + for i in range(max_iters): + t0 = perf_counter() + gray = self.get_gray_image() + t1 = perf_counter() + m = compute_metrics(gray, self.metering, self.target) + t2 = perf_counter() + + exp = float(self.get_exposure_s()) + gain = float(self.get_gain()) + pv_raw = float(_get_percentile_value(m, self.target.percentile)) + t3 = perf_counter() + + last_m = m + + if ema_pv is None: + ema_pv = pv_raw + else: + ema_pv = ema_alpha_p * pv_raw + (1.0 - ema_alpha_p) * ema_pv + + if verbose: + print( + f"[AE once {i + 1:02d}/{max_iters}] exp={exp:.6f}s gain={gain:.2f} " + f"clip={m.clip_frac:.4f} p{int(self.target.percentile)}={pv_raw:.1f} (ema_p={ema_pv:.1f}) " + f"mask={m.mask_fraction * 100:.2f}% thr={m.thr} n={m.n_metered} " + f"timing(gray={t1 - t0:.3f}s metrics={t2 - t1:.3f}s pvs={t3 - t2:.3f}s)" + ) + + # Stop condition: use raw pv (not EMA) so we don't "wait out" lag + in_clip = (m.clip_frac <= self.target.clip_limit) + in_p = (abs(self.target.percentile_target - pv_raw) <= deadband_dn) + if in_clip and in_p: + stable_count += 1 + if stable_count >= stable_needed: + break + else: + stable_count = 0 + + # 1) clipping protection (unchanged) + if m.clip_frac > self.target.clip_limit: + r = min(8.0, m.clip_frac / max(1e-12, self.target.clip_limit)) + adaptive_drop = 0.85 - (r - 1.0) * (0.85 - 0.35) / (8.0 - 1.0) + adaptive_drop = self._clamp(adaptive_drop, 0.35, 0.90) + + new_exp = self._clamp(exp * adaptive_drop, self.limits.exposure_min_s, self.limits.exposure_max_s) + if self._set_exposure_if_changed(new_exp, exp): + self._settle_after_change(new_exp, base_settle_s) + continue + + # 2) unreliable metering (unchanged) + if m.n_metered < self.target.min_metered_pixels: + boost = float(max(1.05, min(metering_unreliable_boost, self.limits.max_exposure_scale_up))) + new_exp = self._clamp(exp * boost, self.limits.exposure_min_s, self.limits.exposure_max_s) + if self._set_exposure_if_changed(new_exp, exp): + self._settle_after_change(new_exp, base_settle_s) + continue + + # 3) main control: use pv_raw for the first few steps, then EMA + pv_for_control = pv_raw if i < raw_control_iters else float(ema_pv) + + err = float(self.target.percentile_target - pv_for_control) + if abs(err) <= float(deadband_dn): + continue + + pv = max(1.0, float(pv_for_control)) + ratio = float(self.target.percentile_target) / pv + + k = float(self.limits.exposure_k) + scale = ratio ** k + scale = max(self.limits.max_exposure_scale_down, min(self.limits.max_exposure_scale_up, scale)) + + new_exp = self._clamp(exp * scale, self.limits.exposure_min_s, self.limits.exposure_max_s) + if self._set_exposure_if_changed(new_exp, exp): + self._settle_after_change(new_exp, base_settle_s) + + exp = float(self.get_exposure_s()) + gain = float(self.get_gain()) + return exp, gain, last_m if last_m is not None else compute_metrics(self.get_gray_image(), self.metering, self.target) +# Python +def build_controller(sample_cam, lim: LimitsConfig, tgt: TargetConfig, met:MeteringConfig) -> AutoExposureController: + # sample_cam should be whatever your EPICS/AD wrapper object is. + # Important: ensure camera is in manual exposure/gain mode before control. + + def get_gray() -> np.ndarray: + img = sample_cam.get_image(gray=True) + return img # may be float; controller converts/clamps to uint8 + + def get_exp() -> float: + return float(sample_cam.expo_rbv.get()) + + def set_exp(v: float) -> None: + sample_cam.expo.put(float(v), wait=False) + + def get_gain() -> float: + return float(sample_cam.gain_rbv.get()) + + def set_gain(v: float) -> None: + sample_cam.gain.put(float(v), wait=False) + + def get_frame_id() -> int: + return int(sample_cam.uid.get()) + + return AutoExposureController(get_gray, get_exp, set_exp, get_gain, set_gain, + metering=met, target=tgt, limits=lim, get_frame_id=get_frame_id) + +def _now_s() -> float: + return perf_counter() + +def _fmt_ms(s: float) -> str: + return f"{s * 1000.0:.1f} ms" + +def _condition_name(reflector_up: bool, back_light: float) -> str: + if reflector_up and back_light > 0.91: + return "reflector_up + backlight_max" + if reflector_up and back_light <= 0.91: + return "reflector_up + backlight_off" + return "reflector_down" + +def _select_profiles(devs) -> tuple[MeteringConfig, TargetConfig, LimitsConfig]: + """ + Choose metering/targets/limits based on current lighting/reflector state. + + IMPORTANT: + - Use a fine exposure_quantum_s for backlight if you want sub-ms exposures. + - exposure_effective_min_s can be as low as 50 us in backlight mode (per your tests). + """ + # You can keep your existing metering/targets here, or define distinct profiles. + # These are conservative defaults; tweak as needed. + metering_front = MeteringConfig(center_roi=0.7, bg_percentile=10.0, delta_dn=15, winsor_high=230) + targets_front = TargetConfig(clip_limit=0.01, percentile=70.0, percentile_target=160.0, min_metered_pixels=5000) + + metering_back = MeteringConfig(center_roi=0.6, bg_percentile=10.0, delta_dn=8, winsor_high=245) + targets_back = TargetConfig(clip_limit=0.02, percentile=70.0, percentile_target=170.0, min_metered_pixels=2000) + + if devs.reflector_up and devs.back_light > 0.91: + limits = LimitsConfig( + exposure_min_s=0.00005, + exposure_max_s=0.1, + exposure_effective_min_s=0.00005, + exposure_quantum_s=1e-6, # NOT 0.001: you want sub-ms capability here + gain_min=0.0, + gain_max=36.0, + exposure_k=0.70, + max_exposure_scale_up=2.2, + max_exposure_scale_down=0.45, + ) + return metering_back, targets_back, limits + + if devs.reflector_up: + limits = LimitsConfig( + exposure_min_s=0.0005, + exposure_max_s=0.2, + exposure_effective_min_s=0.001, # you said 1 ms is safe in backlight mode + exposure_quantum_s=1e-4, + gain_min=0.0, + gain_max=36.0, + exposure_k=0.80, + max_exposure_scale_up=2.2, + max_exposure_scale_down=0.45, + ) + return metering_back, targets_back, limits + + limits = LimitsConfig( + exposure_min_s=0.002, + exposure_max_s=0.5, + exposure_effective_min_s=0.002, + exposure_quantum_s=1e-4, + gain_min=0.0, + gain_max=36.0, + exposure_k=0.80, + max_exposure_scale_up=2.2, + max_exposure_scale_down=0.45, + ) + return metering_front, targets_front, limits + +def _bench_run_one(ctrl: AutoExposureController, + start_exp_s: float, + start_gain: float, + settle_s: float, + max_iters: int, + label: str, + tol_dn: float) -> dict: + """ + Sets starting exposure/gain, then times run_once convergence. + """ + # Prime starting point + ctrl.set_gain(float(start_gain)) + ctrl.set_exposure_s(float(start_exp_s)) + ctrl._settle_after_change(float(start_exp_s), settle_s) + + t0 = _now_s() + end_exp, end_gain, m = ctrl.run_once(settle_s=settle_s, max_iters=max_iters, verbose=False) + dt = _now_s() - t0 + + pv = _get_percentile_value(m, ctrl.target.percentile) + ok = (m.clip_frac <= ctrl.target.clip_limit) and (abs(ctrl.target.percentile_target - pv) <= float(tol_dn)) + + return { + "label": label, + "t_s": dt, + "start_exp_s": start_exp_s, + "start_gain": start_gain, + "end_exp_s": float(end_exp), + "end_gain": float(end_gain), + "clip": float(m.clip_frac), + "p": float(pv), + "mask_frac": float(m.mask_fraction), + "ok": bool(ok), + "n_metered": int(m.n_metered), + "tol_dn": float(tol_dn), + } + +def benchmark_controller(devs, + sample_cam, + expected_exp_s: dict[str, float], + tolerance_dn: dict[str, float] | None = None, + trials: int = 5, + settle_s: float = 0.01, + max_iters: int = 20, + start_gain: float = 0.0) -> None: + """ + Benchmarks controller convergence speed for three lighting conditions. + + tolerance_dn: optional per-condition tolerance on the chosen percentile metric. + """ + cond = _condition_name(devs.reflector_up, float(devs.back_light)) + met, tgt, lim = _select_profiles(devs) + ctrl = build_controller(sample_cam, lim=lim, tgt=tgt, met=met) + + exp_expected = float(expected_exp_s.get(cond, 0.01)) + exp_min = float(lim.exposure_min_s) + exp_max = float(lim.exposure_max_s) + + tol_dn = 5.0 if tolerance_dn is None else float(tolerance_dn.get(cond, 5.0)) + + starts = [ + ("start=min", exp_min), + ("start=expected", exp_expected), + ("start=max", exp_max), + ] + + print(f"\n=== Benchmark: {cond} ===") + print(f"limits: exp[{lim.exposure_min_s} .. {lim.exposure_max_s}] effective_min={lim.exposure_effective_min_s} quantum={lim.exposure_quantum_s}") + print(f"target: p{int(tgt.percentile)}={tgt.percentile_target} clip_limit={tgt.clip_limit} tol=±{tol_dn:.1f}DN settle_s(base)={settle_s} max_iters={max_iters} trials={trials}") + + results: list[dict] = [] + for label, start_exp in starts: + for k in range(trials): + r = _bench_run_one( + ctrl=ctrl, + start_exp_s=start_exp, + start_gain=start_gain, + settle_s=settle_s, + max_iters=max_iters, + label=label, + tol_dn=tol_dn, + ) + r["trial"] = k + 1 + results.append(r) + + # Print summary + for label, _ in starts: + rr = [r for r in results if r["label"] == label] + times = np.array([r["t_s"] for r in rr], dtype=float) + ok_rate = sum(1 for r in rr if r["ok"]) / max(1, len(rr)) + print( + f"{label:14s} mean={_fmt_ms(times.mean())} p95={_fmt_ms(np.percentile(times, 95))} " + f"min={_fmt_ms(times.min())} max={_fmt_ms(times.max())} ok={ok_rate*100:.0f}%" + ) + + print("\nlabel,trial,t_ms,start_exp_ms,end_exp_ms,start_gain,end_gain,clip,p,mask_frac,tol_dn,ok,n_metered") + for r in results: + print( + f"{r['label']},{r['trial']},{r['t_s']*1000.0:.3f}," + f"{r['start_exp_s']*1000.0:.6f},{r['end_exp_s']*1000.0:.6f}," + f"{r['start_gain']:.2f},{r['end_gain']:.2f}," + f"{r['clip']:.6f},{r['p']:.3f},{r['mask_frac']:.6f},{r['tol_dn']:.1f},{int(r['ok'])},{r['n_metered']}" + ) + + +sample_cam = epicsAD(f"{mx_beamline().name.upper()}-ES-MS:") +devs = BeamlineDevices(mx_beamline()) +metering = MeteringConfig(center_roi=0.7, bg_percentile=10.0, delta_dn=15, winsor_high=230) +targets = TargetConfig(clip_limit=0.01, percentile=70.0, percentile_target=160.0) + + +# +if devs.reflector_up and devs.back_light > 0.91: + limits = LimitsConfig(exposure_min_s=0.00005, exposure_max_s=0.1, exposure_effective_min_s=0.00005, + exposure_quantum_s=1e-6, + gain_min=0.0, gain_max=36.0, exposure_k=0.70, max_exposure_scale_up=1.6, + max_exposure_scale_down=0.6) + metering = MeteringConfig( + center_roi=0.6, + bg_percentile=10.0, + delta_dn=8, + winsor_high=245, + ) + targets = TargetConfig( + clip_limit=0.02, # allow more clipping (bright field can clip) + percentile=70.0, + percentile_target=170.0, + min_metered_pixels=2000, # can be lower because backlight mask is usually strong + ) + +elif devs.reflector_up: + limits = LimitsConfig(exposure_min_s=0.0005, exposure_max_s=0.2, exposure_effective_min_s=0.001, + exposure_quantum_s=1e-4, + gain_min=0.0, gain_max=36.0, exposure_k=0.80, max_exposure_scale_up=2.2, + max_exposure_scale_down=0.6) + + metering = MeteringConfig( + center_roi=0.7, + bg_percentile=10.0, + delta_dn=10, + winsor_high=230, + ) + targets = TargetConfig( + clip_limit=0.02, # allow more clipping (bright field can clip) + percentile=70.0, + percentile_target=170.0, + min_metered_pixels=5000, # can be lower because backlight mask is usually strong + ) + +else: + limits = LimitsConfig(exposure_min_s=0.002, exposure_max_s=0.5, exposure_effective_min_s=0.002, + exposure_quantum_s=0.001, + gain_min=0.0, gain_max=36.0, exposure_k=0.60, max_exposure_scale_up=1.6, + max_exposure_scale_down=0.6) + targets = TargetConfig( + clip_limit=0.02, + percentile=70.0, + percentile_target=160.0, + min_metered_pixels=5000, + ) + metering = MeteringConfig( + center_roi=0.7, + bg_percentile=10.0, + delta_dn=15, + winsor_high=230, + ) +ctrl = build_controller(sample_cam, lim=limits, tgt=targets, met=metering) + +# After centering and stationary: +st = time.perf_counter() +exp, gain, m = ctrl.run_once(settle_s=0.0, max_iters=20, verbose=True, deadband_dn=10.0, metering_unreliable_boost=1.3) +print(f"run_once took {time.perf_counter() - st} s") + +# expected = { +# "reflector_up + backlight_max": 0.001, # ~1 ms typical +# "reflector_up + backlight_off": 0.025, # adjust based on your observed behaviour +# "reflector_down": 0.052, # 52 ms you reported +# } +# tolerance = { +# "reflector_up + backlight_max": 5.0, +# "reflector_up + backlight_off": 5.0, +# "reflector_down": 5.0, +# } +# benchmark_controller(devs=devs, sample_cam=sample_cam, expected_exp_s=expected, trials=5, settle_s=0.01, max_iters=20, start_gain=0.0) \ No newline at end of file diff --git a/gui/src/aaregui/widgets/__init__.py b/src/aare/gui/scan_logic/__init__.py similarity index 100% rename from gui/src/aaregui/widgets/__init__.py rename to src/aare/gui/scan_logic/__init__.py diff --git a/gui/src/aaregui/scan_logic/raster_grid_manager.py b/src/aare/gui/scan_logic/raster_grid_manager.py similarity index 98% rename from gui/src/aaregui/scan_logic/raster_grid_manager.py rename to src/aare/gui/scan_logic/raster_grid_manager.py index 73271c63..3ce894a9 100644 --- a/gui/src/aaregui/scan_logic/raster_grid_manager.py +++ b/src/aare/gui/scan_logic/raster_grid_manager.py @@ -1,4 +1,3 @@ -import copy import math from enum import Enum @@ -7,12 +6,12 @@ from PySide6.QtGui import QPainter, QPen, QColor, QBrush from PySide6.QtCore import Qt, QRect from typing import List, Tuple -from aaredaqlib.coordinate import Coordinate, SmargonCoordinate -from aaredaqlib.models import DAQStatusModel -from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem -from aaredaqlib.sample_geometry import SampleGeometryModel +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.models import DAQStatusModel +from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem +from aare.common.sample_geometry import SampleGeometryModel -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") diff --git a/gui/src/aaregui/scan_logic/rotation_scan_manager.py b/src/aare/gui/scan_logic/rotation_scan_manager.py similarity index 86% rename from gui/src/aaregui/scan_logic/rotation_scan_manager.py rename to src/aare/gui/scan_logic/rotation_scan_manager.py index 29907bab..16922e51 100644 --- a/gui/src/aaregui/scan_logic/rotation_scan_manager.py +++ b/src/aare/gui/scan_logic/rotation_scan_manager.py @@ -1,6 +1,6 @@ from PySide6.QtCore import QObject, Signal, Slot -from aaredaqlib.rotation_scan import CompletedRotationScan +from aare.common.rotation_scan import CompletedRotationScan class RotationScanManager(QObject): diff --git a/gui/src/aaregui/scan_logic/sample_mount_logic.py b/src/aare/gui/scan_logic/sample_mount_logic.py similarity index 87% rename from gui/src/aaregui/scan_logic/sample_mount_logic.py rename to src/aare/gui/scan_logic/sample_mount_logic.py index 03ecaa88..60bdccb3 100644 --- a/gui/src/aaregui/scan_logic/sample_mount_logic.py +++ b/src/aare/gui/scan_logic/sample_mount_logic.py @@ -1,6 +1,6 @@ from PySide6.QtCore import QObject, Slot, Signal -from aaredaqlib.models import DAQStatusModel, SampleShortInfo +from aare.common.models import DAQStatusModel, SampleShortInfo class SampleMountLogic(QObject): diff --git a/src/aare/gui/threads/__init__.py b/src/aare/gui/threads/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gui/src/aaregui/threads/axis_video_thread.py b/src/aare/gui/threads/axis_video_thread.py similarity index 100% rename from gui/src/aaregui/threads/axis_video_thread.py rename to src/aare/gui/threads/axis_video_thread.py diff --git a/src/aare/gui/threads/camera_thread.py b/src/aare/gui/threads/camera_thread.py new file mode 100644 index 00000000..aba490d3 --- /dev/null +++ b/src/aare/gui/threads/camera_thread.py @@ -0,0 +1,127 @@ +import json +import time + +import cv2 +import numpy as np +import zmq +from PySide6.QtCore import QThread, Signal, Slot +from PySide6.QtGui import QImage, QPixmap + +from aare.common.autofocus_tools import focus_measure_edges +from aare.common.models import DAQStatusModel + +class SampleCameraThread(QThread): + # Define a signal to communicate messages from the thread to the main GUI + camera_image = Signal(QPixmap) + focus_measure = Signal(float) # Emits Laplacian variance (higher = sharper) + fps_measure = Signal(float) + + def __init__(self, zmq_url: str, parent=None): + super().__init__(parent) + context = zmq.Context() + self.__socket = context.socket(zmq.SUB) + self.__socket.setsockopt(zmq.SUBSCRIBE, b"") + self.__socket.setsockopt(zmq.RCVTIMEO, 500) + self.__socket.connect(zmq_url) + + self.running = True + self.__measure_focus = False + self.__focus_mask = None + self.__beam_x = 0 + self.__beam_y = 0 + self.__last_beam_pos = None + self.__radius = 40 + + self.__fps_window_start = time.perf_counter() + self.__fps_frame_count = 0 + self.__fps_emit_period_s = 0.5 + self.__last_frame_time = None + self.__no_frame_timeout_s = 5.0 + + @Slot(DAQStatusModel) + def update_daq_status(self, s: DAQStatusModel): + self.__beam_x = s.geom.beam_location_pxl.x + self.__beam_y = s.geom.beam_location_pxl.y + if (self.__beam_x, self.__beam_y) != self.__last_beam_pos: + self.__focus_mask = None # Invalidate cache + self.__last_beam_pos = (self.__beam_x, self.__beam_y) + + @Slot(bool) + def enable_focus_measurement(self, enabled: bool = True): + """Enable or disable focus measurement.""" + self.__measure_focus = enabled + + def run(self): + while self.running: + try: + r = self.__socket.recv_multipart() + + now = time.perf_counter() + self.__last_frame_time = now + self.__fps_frame_count += 1 + + elapsed = now - self.__fps_window_start + if elapsed >= self.__fps_emit_period_s: + fps = self.__fps_frame_count / elapsed if elapsed > 0 else 0.0 + self.fps_measure.emit(float(fps)) + self.__fps_window_start = now + self.__fps_frame_count = 0 + + if len(r) < 2: + continue + + data = r[-1] + header = None + + for part in r[:-1]: + try: + decoded = json.loads(part.decode("utf-8")) + if isinstance(decoded, dict) and "shape" in decoded: + header = decoded + break + except: + continue + + if header and header.get("type") == "uint8": + h, w = header["shape"][:2] + raw = np.frombuffer(data, np.uint8).reshape((h, w)) + + rgb = cv2.cvtColor(raw, cv2.COLOR_BAYER_GB2RGB) # choose correct Bayer order + #rgb = cv2.flip(rgb, 0) + + if self.__measure_focus: + gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY) + if self.__focus_mask is None or self.__focus_mask.shape != gray.shape: + height, width = gray.shape + y, x = np.ogrid[:height, :width] + self.__focus_mask = (x - self.__beam_x) ** 2 + ( + y - self.__beam_y) ** 2 <= self.__radius ** 2 + + sharpness = focus_measure_edges(gray, self.__focus_mask) + self.focus_measure.emit(sharpness) + + qimage = QImage(rgb.data, rgb.shape[1], rgb.shape[0], QImage.Format.Format_RGB888).copy() + self.camera_image.emit(QPixmap.fromImage(qimage)) + else: + print("Sample camera image has wrong dimensions") + except zmq.Again: # Timeout occurred + now = time.perf_counter() + elapsed = now - self.__fps_window_start + if elapsed >= self.__fps_emit_period_s: + last = self.__fps_frame_count + no_frames_long = (last is None) or ((now - last) >= self.__no_frame_timeout_s) + self.fps_measure.emit(float("nan") if no_frames_long else 0.0) + self.__fps_window_start = now + self.__fps_frame_count = 0 + continue # Check self.running again + except Exception as e: + print(f"Error in sample camera thread {e}") + + def stop(self): + # Signal the thread to stop + self.running = False + + if self.__socket: + self.__socket.close() + self.quit() + self.wait() diff --git a/gui/src/aaregui/threads/daq_worker.py b/src/aare/gui/threads/daq_worker.py similarity index 57% rename from gui/src/aaregui/threads/daq_worker.py rename to src/aare/gui/threads/daq_worker.py index 934b816e..16f77b8d 100644 --- a/gui/src/aaregui/threads/daq_worker.py +++ b/src/aare/gui/threads/daq_worker.py @@ -2,18 +2,20 @@ import copy import random import time import json +from collections import deque from PySide6.QtCore import Signal, QUrl, Slot, QTimer, QObject, QByteArray from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from jfjoch_client import ScanResult, ScanResultImagesInner -from aaredaqlib.coordinate import SmargonCoordinate, Coordinate -from aaredaqlib.models import DAQStatusModel, SampleShortInfoList, SampleShortInfo, SampleCameraSettings, \ +from aare.common.coordinate import SmargonCoordinate, Coordinate +from aare.common.error_codes import export_error_codes +from aare.common.models import DAQStatusModel, SampleShortInfoList, SampleShortInfo, SampleCameraSettings, \ AutofocusSettings, SimpleScanParameters, FluorescenceSpectrumParameterModel, FluorescenceSpectrumOutputModel -from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid -from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan +from aare.common.raster_grid import RasterGridRequest, CompletedRasterGrid +from aare.common.rotation_scan import RotationScanRequest, CompletedRotationScan -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") @@ -25,6 +27,7 @@ class DAQWorker(QObject): spreadsheet = Signal(SampleShortInfoList) reference_tools = Signal(SampleShortInfoList) http_error = Signal(str) + status_message = Signal(str, bool) auth_error = Signal() sample_missing = Signal(str) automated_scan_done = Signal(int, bool, str) # sample ID, success @@ -36,6 +39,11 @@ class DAQWorker(QObject): staff_pgroups_loaded = Signal(list) fluorimeter_update = Signal(list, list, int) fluorimeter_spectrum_update = Signal(FluorescenceSpectrumOutputModel) + sample_resync_completed = Signal(str) + + error_codes_loaded = Signal(dict) + last_error_payload_changed = Signal(dict) + last_error_payloads_changed = Signal(list) def __init__(self, base_url: str | None, token: str, parent=None): super().__init__(parent) @@ -52,8 +60,87 @@ class DAQWorker(QObject): self._auth_error_min_interval = 10.0 self._last_status_request_ts = 0.0 - self._status_request_min_interval = 10.0 + self._status_request_min_interval = 0.5 + self._smargon_retry_interval_s = 2.0 + self._smargon_log_min_interval_s = 10.0 + + self._device_error_log_min_interval_s = 10.0 + self._last_device_error_log_ts: dict[str, float] = {"tell": 0.0, "smargon": 0.0} + self._last_device_error_log_key: dict[str, str | None] = {"tell": None, "smargon": None} + self._last_status_error = None + self._smargon_error_active = False + self._last_smargon_log_ts = 0.0 + self._last_smargon_log_key: str | None = None + + self._last_error_payload: dict = {} + self._last_error_payloads = deque(maxlen=10) + + self._last_tell_connected: bool | None = None + self._last_smargon_connected: bool | None = None + self._server_connected: bool | None = None + self._last_server_error: str | None = None + + self._face_detection_stream_reply: QNetworkReply | None = None + + if self.__base_url is not None: + self.start_face_detection_stream() + + def get_last_error_payload(self) -> dict: + return dict(self._last_error_payload or {}) + + def get_last_error_payloads(self) -> list[dict]: + return [dict(p or {}) for p in list(self._last_error_payloads)] + + def _set_last_error_payload(self, payload: dict) -> None: + payload = payload or {} + self._last_error_payload = payload + self._last_error_payloads.append(payload) + + self.last_error_payload_changed.emit(self.get_last_error_payload()) + self.last_error_payloads_changed.emit(self.get_last_error_payloads()) + + def _log_smargon_throttled(self, *, endpoint: str | None, message: str) -> None: + """ + Log immediately if endpoint/message changed; otherwise at most every N seconds. + """ + key = f"{endpoint or ''}|{message or ''}" + now = time.monotonic() + + if self._last_smargon_log_key != key: + self._last_smargon_log_key = key + self._last_smargon_log_ts = now + logger.error(f"Smargon connection error (endpoint={endpoint}): {message}") + return + + if now - self._last_smargon_log_ts >= self._smargon_log_min_interval_s: + self._last_smargon_log_ts = now + logger.error(f"Smargon connection error (endpoint={endpoint}): {message}") + + def _log_device_error_throttled(self, *, device: str, message: str | None) -> None: + """ + Log device error string immediately if it changes; otherwise at most every N seconds. + Intended for status-poll derived errors like tell_error / smargon_error. + """ + if not message: + return + + device = (device or "unknown").lower() + now = time.monotonic() + key = str(message) + + last_key = self._last_device_error_log_key.get(device) + last_ts = self._last_device_error_log_ts.get(device, 0.0) + + if last_key != key: + self._last_device_error_log_key[device] = key + self._last_device_error_log_ts[device] = now + logger.error(f"{device.upper()} error: {message}") + return + + if now - last_ts >= self._device_error_log_min_interval_s: + self._last_device_error_log_ts[device] = now + logger.error(f"{device.upper()} error: {message}") @Slot() def regular_update(self): @@ -67,6 +154,11 @@ class DAQWorker(QObject): if self.__base_url is None: return + now = time.monotonic() + if now - self._last_status_request_ts < self._status_request_min_interval: + return + self._last_status_request_ts = now + request = QNetworkRequest(QUrl(f"{self.__base_url}/status")) request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) reply = self.__net_manager.get(request) @@ -83,23 +175,117 @@ class DAQWorker(QObject): logger.error(f"Error in response: {reply.errorString()}") raise RuntimeError(reply.errorString()) + def _emit_status_if_changed(self, key: str | None, message: str | None, is_error: bool) -> None: + if not message: + self._active_status_error_key = None + return + + if is_error: + if self._active_status_error_key != key: + self._active_status_error_key = key + self.status_message.emit(message, True) + return + + self._active_status_error_key = None + self.status_message.emit(message, False) + + def _compose_device_status_message( + self, + *, + tell_conn: bool, + smargon_conn: bool, + tell_changed: bool, + smargon_changed: bool, + ) -> tuple[str | None, str | None, bool]: + disconnected: list[str] = [] + restored: list[str] = [] + + if not tell_conn: + disconnected.append("TELL") + elif tell_changed: + restored.append("TELL") + + if not smargon_conn: + disconnected.append("Smargon") + elif smargon_changed: + restored.append("Smargon") + + if disconnected: + if len(disconnected) == 2: + return ( + "tell+smargon-down", + "TELL and Smargon connection errors, please inform your local contact.", + True, + ) + device = disconnected[0] + return ( + f"{device.lower()}-down", + f"{device} connection error, please inform your local contact.", + True, + ) + + if restored: + if len(restored) == 2: + return (None, "TELL and Smargon connections restored.", False,) + device = restored[0] + return (None, f"{device} connection restored.",False) + + return (None, None, False) + @Slot(QNetworkReply) def handle_status_response(self, reply: QNetworkReply): try: response_data = self.handle_response(reply) parsed_response = DAQStatusModel.model_validate_json(response_data) self.update.emit(parsed_response) + + if self._server_connected is False: + self._emit_status_if_changed(None, "Server connection restored.", False) + self._server_connected = True + self._last_server_error = None + + tell_conn = bool(getattr(parsed_response, "tell_connected", True)) + smargon_conn = bool(getattr(parsed_response, "smargon_connected", True)) + tell_err = getattr(parsed_response, "tell_error", None) + smargon_err = getattr(parsed_response, "smargon_error", None) + + tell_changed = self._last_tell_connected is not None and self._last_tell_connected != tell_conn + smargon_changed = ( + self._last_smargon_connected is not None and self._last_smargon_connected != smargon_conn + ) + + self._last_tell_connected = tell_conn + self._last_smargon_connected = smargon_conn + + status_key, status_msg, is_error = self._compose_device_status_message( + tell_conn=tell_conn, + smargon_conn=smargon_conn, + tell_changed=tell_changed, + smargon_changed=smargon_changed, + ) + self._emit_status_if_changed(status_key, status_msg, is_error) + + if not tell_conn: + self._log_device_error_throttled(device="tell", message=tell_err) + if not smargon_conn: + self._log_device_error_throttled(device="smargon", message=smargon_err) + except Exception as e: - now = time.monotonic() - if str(e) == str(self._last_status_error): - if now - self._last_auth_error_log_ts > self._auth_error_min_interval: - self._last_auth_error_log_ts = now - logger.error(f"Exception from status response: {e}") - else: - self._last_status_error = e - self._last_auth_error_log_ts = now - logger.error(f"Exception from status response: {e}") - self.http_error.emit(str(e)) + err_msg = str(e) + + if self._server_connected is not False: + self._emit_status_if_changed( + "server-down", + "Server connection lost. Trying to reconnect...", + True, + ) + + self._server_connected = False + self._last_server_error = err_msg + self._last_tell_connected = None + self._last_smargon_connected = None + + logger.error(f"Exception from status response: {e}") @Slot(QNetworkReply) def handle_spreadsheet_response(self, reply: QNetworkReply): @@ -125,18 +311,44 @@ class DAQWorker(QObject): if reply.error() != QNetworkReply.NetworkError.NoError: status = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) err_details = reply.errorString() + raw_body = "" + body_json = None try: - response_body = reply.readAll().data().decode("utf-8") - if response_body: - body_json = json.loads(response_body) - if "detail" in body_json: - err_details = body_json["detail"] + raw_body = reply.readAll().data().decode("utf-8") + if raw_body: + body_json = json.loads(raw_body) + if isinstance(body_json, dict): + if "detail" in body_json: + err_details = body_json["detail"] + elif "message" in body_json: + err_details = body_json["message"] + else: + err_details = raw_body else: - err_details = response_body + err_details = raw_body except Exception: pass - if status== 401: + try: + url = reply.request().url().toString() + except Exception: + url = "" + + net_err = reply.error() + net_err_name = getattr(net_err, "name", None) + net_err_value = getattr(net_err, "value", None) + + self._set_last_error_payload({ + "url": url, + "http_status": int(status) if status is not None else None, + "network_error": net_err_name or str(net_err), + "network_error_value": int(net_err_value) if isinstance(net_err_value, int) else None, + "error_string": str(reply.errorString()), + "body_raw": raw_body, + "body_json": body_json, + }) + + if status == 401: now = time.monotonic() if now - self._last_auth_error_log_ts > self._auth_error_min_interval: logger.error(f"{err_details}: baton taken by another user") @@ -147,8 +359,35 @@ class DAQWorker(QObject): else: logger.error(f"{err_details}") self.http_error.emit(err_details) + reply.deleteLater() + def _handle_sample_resync_response(self, reply: QNetworkReply): + try: + response_data = self.handle_response(reply) + payload = json.loads(response_data) if response_data else {} + message = str(payload.get("message") or "TELL sample cache resynced.") + logger.info(message) + self.status_message.emit(message, False) + self.sample_resync_completed.emit(message) + self.send_status_request() + except Exception as e: + logger.error(f"Sample resync failed: {e}") + self.http_error.emit(str(e)) + + def _handle_recovery_action_response(self, reply: QNetworkReply, default_message: str): + try: + response_data = self.handle_response(reply) + payload = json.loads(response_data) if response_data else {} + message = str(payload.get("message") or default_message) + logger.info(message) + self.status_message.emit(message, False) + self.recovery_action_completed.emit(message) + self.send_status_request() + except Exception as e: + logger.error(f"Recovery action failed: {e}") + self.http_error.emit(str(e)) + def generic_post(self, url: str, body: str = ""): if self.__base_url is None: logger.info(f"POST /{url}: {body}") @@ -186,13 +425,21 @@ class DAQWorker(QObject): def set_omega(self, f: float): self.generic_put(f"beamline/omega?val={f:.3f}") + @Slot(float) + def set_omega_rel(self, f: float): + self.generic_put(f"beamline/omega_rel?val={f:.3f}") + @Slot(float) def zoom(self, f: float): self.generic_put(f"beamline/zoom?val={f:.3f}") @Slot(int) - def light(self, v: int): - self.generic_put(f"beamline/light?val={v:d}") + def front_light(self, v: int): + self.generic_put(f"beamline/front_light?val={v:d}") + + @Slot(int) + def back_light(self, v: int): + self.generic_put(f"beamline/back_light?val={v:d}") @Slot() def close_shutter(self): @@ -234,6 +481,66 @@ class DAQWorker(QObject): def beam_location(self): self.generic_post("state/beam_location") + @Slot(str) + def free_beamline(self, confirmation_code: str): + if self.__base_url is None: + logger.info("POST /state/free_beamline") + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/state/free_beamline")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + request.setRawHeader(b"Content-Type", b"application/json") + body = json.dumps({"confirmation_code": confirmation_code}) + reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8"))) + reply.finished.connect( + lambda: self._handle_recovery_action_response(reply, "Beamline busy flag cleared.") + ) + + @Slot(str) + def take_over_beamline(self, confirmation_code: str): + if self.__base_url is None: + logger.info("POST /access/take_over_beamline") + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/access/take_over_beamline")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + request.setRawHeader(b"Content-Type", b"application/json") + body = json.dumps({"confirmation_code": confirmation_code}) + reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8"))) + reply.finished.connect( + lambda: self._handle_recovery_action_response(reply, "Beamline session taken over.") + ) + + @Slot(str) + def recover_beamline(self, confirmation_code: str): + if self.__base_url is None: + logger.info("POST /recovery/recover_beamline") + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/recovery/recover_beamline")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + request.setRawHeader(b"Content-Type", b"application/json") + body = json.dumps({"confirmation_code": confirmation_code}) + reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8"))) + reply.finished.connect( + lambda: self._handle_recovery_action_response(reply, "Beamline recovered to Maintenance.") + ) + + @Slot(str) + def recovery_unmount_sample(self, confirmation_code: str): + if self.__base_url is None: + logger.info("POST /recovery/unmount_sample") + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/recovery/unmount_sample")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + request.setRawHeader(b"Content-Type", b"application/json") + body = json.dumps({"confirmation_code": confirmation_code}) + reply = self.__net_manager.post(request, QByteArray(body.encode("utf-8"))) + reply.finished.connect( + lambda: self._handle_recovery_action_response(reply, "Recovery unmount completed.") + ) + @Slot(str) def set_pgroup(self, val: str): if val == "": @@ -484,6 +791,18 @@ class DAQWorker(QObject): def beam_size_mm(self, x: float, y: float): self.generic_post(f"beamline/beam_size_mm?x={x}&y={y}") + @Slot() + def resync_sample(self): + if self.__base_url is None: + logger.info("POST /sample/resync") + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/sample/resync")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + request.setRawHeader(b"Content-Type", b"application/json") + reply = self.__net_manager.post(request, QByteArray(b"")) + reply.finished.connect(lambda: self._handle_sample_resync_response(reply)) + @Slot() def unmount(self): self.generic_post("sample/unmount") @@ -536,11 +855,43 @@ class DAQWorker(QObject): finally: reply.deleteLater() + def _read_face_detection_stream(self, reply: QNetworkReply): + try: + chunk = reply.readAll().data().decode("utf-8") + for line in chunk.splitlines(): + if line.startswith("data:"): + payload = line[5:].strip() + if payload: + data = json.loads(payload) + self.face_detection_result.emit(data) + except Exception as e: + logger.error(f"Face detection stream parse error: {e}") + + def _restart_face_detection_stream(self): + self._face_detection_stream_reply = None + if self.__base_url is not None: + QTimer.singleShot(1000, self.start_face_detection_stream) + + def start_face_detection_stream(self): + if self.__base_url is None: + return + + if self._face_detection_stream_reply is not None: + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/sse/face_detection")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + reply = self.__net_manager.get(request) + reply.readyRead.connect(lambda: self._read_face_detection_stream(reply)) + reply.finished.connect(self._restart_face_detection_stream) + self._face_detection_stream_reply = reply + @Slot() - def face_detection(self, steps:int, step_size:int): + def face_detection(self, steps: int, step_size: int): if self.__base_url is None: logger.info(f"POST /face_detection/run?steps={steps}&step_size={step_size}") return + request = QNetworkRequest(QUrl(f"{self.__base_url}/face_detection/run?steps={steps}&step_size={step_size}")) request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) request.setRawHeader(b"Content-Type", b"application/json") @@ -650,4 +1001,92 @@ class DAQWorker(QObject): status = obj.get("status", -1) self.fluorimeter_update.emit(data, bkg, status) except Exception as e: - logger.error(f"SSE parse error: {e}") \ No newline at end of file + logger.error(f"SSE parse error: {e}") + + @staticmethod + def _flatten_error_codes_payload(obj: dict) -> dict[str, str]: + """ + Accept either: + - flat: {"INVALID_TOKEN": "INVALID_TOKEN"} + - grouped: {"AuthErrorCode": {"INVALID_TOKEN": "INVALID_TOKEN"}, "DAQErrorCode": {...}} + + Output is always flat strings, using 'Group.KEY' for grouped input. + """ + out: dict[str, str] = {} + for k, v in (obj or {}).items(): + if isinstance(v, dict): + group = str(k) + for kk, vv in v.items(): + out[f"{group}.{str(kk)}"] = str(vv) + else: + out[str(k)] = str(v) + return out + + @Slot() + @Slot() + def get_error_codes(self) -> None: + """ + Fetch server error codes registry for developer/help UI. + Emits error_codes_loaded(dict). + + Server default is grouped. We flatten grouped payloads for existing UI. + """ + if self.__base_url is None: + self.error_codes_loaded.emit(export_error_codes()) + return + + request = QNetworkRequest(QUrl(f"{self.__base_url}/meta/error-codes")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + reply = self.__net_manager.get(request) + reply.finished.connect(lambda: self._handle_error_codes_response(reply)) + + def _retry_error_codes_legacy(self) -> None: + request = QNetworkRequest(QUrl(f"{self.__base_url}/meta/error-codes/flat")) + request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8")) + reply = self.__net_manager.get(request) + reply.finished.connect(lambda: self._handle_error_codes_response(reply)) + + @Slot(QNetworkReply) + def _handle_error_codes_response(self, reply: QNetworkReply) -> None: + try: + status = reply.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + + try: + url = reply.request().url().toString() + except Exception: + url = "" + + if int(status) == 404 and url.endswith("/meta/error-codes"): + reply.deleteLater() + logger.error(f"Error codes not found on server.") + return + + payload = self.handle_response(reply) + obj = json.loads(payload) if payload else {} + if not isinstance(obj, dict): + raise RuntimeError("Invalid error-codes payload (expected JSON object)") + out = self._flatten_error_codes_payload(obj) + self.error_codes_loaded.emit(out) + except Exception as e: + logger.error(f"Failed to load error codes: {e}") + self.http_error.emit(str(e)) + + @Slot(str, str) + def send_screenshot_db(self, filename: str = "", message: str = ""): + if self.__base_url is None: + logger.info(f"POST /samcam/send_screenshot_db?filename={filename}&message={message}") + return + + from urllib.parse import quote + + query = [] + filename = filename.strip() + message = message.strip() + + if filename: + query.append(f"filename={quote(filename)}") + if message: + query.append(f"message={quote(message)}") + + suffix = f"?{'&'.join(query)}" if query else "" + self.generic_post(f"samcam/send_screenshot_db{suffix}") \ No newline at end of file diff --git a/gui/src/aaregui/threads/jfjoch_viewer.py b/src/aare/gui/threads/jfjoch_viewer.py similarity index 100% rename from gui/src/aaregui/threads/jfjoch_viewer.py rename to src/aare/gui/threads/jfjoch_viewer.py diff --git a/src/aare/gui/threads/prediction_subscriber.py b/src/aare/gui/threads/prediction_subscriber.py new file mode 100644 index 00000000..2c1de0a7 --- /dev/null +++ b/src/aare/gui/threads/prediction_subscriber.py @@ -0,0 +1,146 @@ +import json +import numpy as np +import zmq + +from PySide6.QtCore import QThread, Signal +from PySide6.QtGui import QImage, QPixmap + +# If you need Bayer conversion like your SampleCameraThread did: +import cv2 + +from aare.common.logger_config import setup_logger + +logger = setup_logger("aareGUI") + +class PredictionSubscriber(QThread): + # emits parsed JSON payload (dict with keys: time, frame_id, shape, boxes) + prediction = Signal(dict) + + # NEW: emit the image that came with the prediction stream + image = Signal(QPixmap) + + def __init__(self, pred_zmq_url: str, topic: bytes | str = b"", parent=None): + super().__init__(parent) + self._ctx = zmq.Context() + self._sock = self._ctx.socket(zmq.SUB) + self._sock.setsockopt(zmq.RCVTIMEO, 500) + self._sock.setsockopt(zmq.LINGER, 0) + + if isinstance(topic, str): + self._sock.setsockopt_string(zmq.SUBSCRIBE, topic) + elif isinstance(topic, bytes): + self._sock.setsockopt(zmq.SUBSCRIBE, topic) + else: + self._sock.setsockopt(zmq.SUBSCRIBE, b"") + + self._sock.connect(pred_zmq_url) + self.running = True + + def _try_parse_json(self, part: bytes) -> dict | None: + try: + decoded = json.loads(part.decode("utf-8")) + return decoded if isinstance(decoded, dict) else None + except Exception: + return None + + def _decode_image(self, header: dict, data: bytes) -> QPixmap | None: + """ + Supports: + - header["type"] == "uint8" + - header["shape"] == [H, W] (Bayer) -> converted to RGB + - header["shape"] == [H, W, 3] (RGB) -> used directly + """ + if not header or header.get("type") != "uint8": + return None + shape = header.get("shape") + if not shape or not isinstance(shape, (list, tuple)): + return None + + arr = np.frombuffer(data, dtype=np.uint8) + + if len(shape) == 2: + h, w = int(shape[0]), int(shape[1]) + if arr.size != h * w: + return None + bayer = arr.reshape((h, w)) + rgb = cv2.cvtColor(bayer, cv2.COLOR_BAYER_GB2RGB) + elif len(shape) == 3 and int(shape[2]) == 3: + h, w, c = int(shape[0]), int(shape[1]), int(shape[2]) + if arr.size != h * w * c: + return None + rgb = arr.reshape((h, w, 3)) + else: + return None + + qimage = QImage(rgb.data, rgb.shape[1], rgb.shape[0], QImage.Format.Format_RGB888).copy() + return QPixmap.fromImage(qimage) + + def run(self): + try: + while self.running: + try: + parts = self._sock.recv_multipart() + except zmq.Again: + continue + + if not parts: + continue + + json_dicts: list[dict] = [] + non_json_parts: list[bytes] = [] + + for p in parts: + d = self._try_parse_json(p) + if d is not None: + json_dicts.append(d) + else: + non_json_parts.append(p) + + header = next( + (d for d in json_dicts if "shape" in d and d.get("type") == "uint8"), + None, + ) + detections = next((d for d in json_dicts if "boxes" in d), None) + + image_bytes = max(non_json_parts, key=len) if non_json_parts else None + + if header and image_bytes: + pix = self._decode_image(header, image_bytes) + if pix is not None and self.running: + self.image.emit(pix) + + if detections and self.running: + self.prediction.emit(detections) + + except Exception as e: + if self.running: + logger.exception(f"PredictionSubscriber error: {e}") + finally: + try: + if self._sock is not None: + self._sock.close(0) + except Exception: + pass + finally: + self._sock = None + + try: + if self._ctx is not None: + self._ctx.term() + except Exception: + pass + finally: + self._ctx = None + + def stop(self): + self.running = False + self.requestInterruption() + + try: + if self._sock is not None: + self._sock.close(0) + except Exception: + pass + + if not self.wait(1500): + logger.warning("PredictionSubscriber did not stop within timeout") \ No newline at end of file diff --git a/gui/src/aaregui/threads/sse_client.py b/src/aare/gui/threads/sse_client.py similarity index 99% rename from gui/src/aaregui/threads/sse_client.py rename to src/aare/gui/threads/sse_client.py index 50d9124f..86906fae 100644 --- a/gui/src/aaregui/threads/sse_client.py +++ b/src/aare/gui/threads/sse_client.py @@ -1,7 +1,5 @@ from PySide6.QtCore import QObject, Signal, Slot -from aaredaqlib.models import SampleShortInfoList - class SSEClient(QObject): # Signals diff --git a/src/aare/gui/tutorials/__init__.py b/src/aare/gui/tutorials/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/aare/gui/tutorials/controls_help_dialog.py b/src/aare/gui/tutorials/controls_help_dialog.py new file mode 100644 index 00000000..88e8c731 --- /dev/null +++ b/src/aare/gui/tutorials/controls_help_dialog.py @@ -0,0 +1,156 @@ +from PySide6.QtCore import Qt +from PySide6.QtWidgets import ( + QDialog, + QVBoxLayout, + QTextEdit, + QDialogButtonBox, + QTabWidget, + QWidget, +) + + +class ControlsHelpDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + + self.setWindowTitle("Mouse / Keyboard Controls") + self.setMinimumSize(760, 560) + + layout = QVBoxLayout(self) + + self._tabs = QTabWidget(self) + self._tabs.addTab( + self._create_tab( + """ +

Sample Camera

+ +

Mouse Wheel

+
    +
  • Mouse wheel: rotate omega by 90°
  • +
  • Shift + Mouse wheel: rotate omega by 10°
  • +
  • Ctrl + Mouse wheel: change sample camera exposure by a large step
  • +
  • Alt + Mouse wheel: change sample camera exposure by a small step
  • +
+ +

Mouse Click / Drag

+
    +
  • Left click: move sample to clicked position
  • +
  • Shift + Left click: move using the special Z-alignment click behaviour
  • +
  • Left drag on active raster grid: move active raster grid
  • +
  • Right click: open sample camera context menu
  • +
  • Right drag on empty area: draw raster grid
  • +
  • Right drag on active raster grid: resize raster grid
  • +
+ +

Mouse Move

+
    +
  • Shift + Mouse move: inspect/load raster image under cursor
  • +
  • Mouse move: show completed-grid tooltip or coordinates, depending on mode
  • +
+ +

Beam Mark Mode

+
    +
  • Shift + Left click: set beam mark at clicked position
  • +
  • Mouse wheel: change exposure by a large step
  • +
  • Alt + Mouse wheel: change exposure by a small step
  • +
+ """ + ), + "Sample Camera", + ) + self._tabs.addTab( + self._create_tab( + """ +

Sample Camera Context Menu

+
    +
  • Scale to fit
  • +
  • Show coordinates
  • +
  • Grab
  • +
  • Grab with overlay
  • +
  • Auto-focus
  • +
  • Mark beam center
  • +
  • Delete grid (when on active grid)
  • +
  • Evaluate grid (when on active grid)
  • +
  • Delete completed grids
  • +
+ +

Notes

+
    +
  • Some actions appear only when the cursor is over the active raster grid.
  • +
  • Grid actions depend on the current sample camera state and current raster visibility.
  • +
+ """ + ), + "Context Menu", + ) + self._tabs.addTab( + self._create_tab( + """ +

Video Views

+

Applies to gonio camera, beamline view, and combined beamline views.

+ +

Mouse

+
    +
  • Ctrl + Mouse wheel: zoom in/out
  • +
  • Mouse wheel: normal scrolling when Ctrl is not pressed
  • +
  • Mouse drag: rubber-band drag/selection behaviour is enabled
  • +
+ +

Keyboard

+
    +
  • F: fit to view
  • +
  • R: reset zoom
  • +
  • + or =: zoom in
  • +
  • -: zoom out
  • +
+ """ + ), + "Video Views", + ) + self._tabs.addTab( + self._create_tab( + """ +

Other Interactive Areas

+ +

Sample Queue

+
    +
  • Delete: remove selected samples from the queue
  • +
+ +

Fluorescence Plot

+
    +
  • Mouse move: show energy/count tooltip and vertical marker line
  • +
  • Right click: save spectrum as CSV
  • +
+ +

General Widgets

+
    +
  • Left click on clickable labels/value labels: trigger the widget's click action
  • +
+ +

Notes

+
    +
  • Some wheel interactions are intentionally disabled in certain scroll areas to prevent accidental scrolling.
  • +
  • Available actions can depend on beamline state, current mode, and widget focus.
  • +
+ """ + ), + "Other Panels", + ) + layout.addWidget(self._tabs) + + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close, parent=self) + buttons.rejected.connect(self.reject) + buttons.accepted.connect(self.accept) + layout.addWidget(buttons) + + def _create_tab(self, html: str) -> QWidget: + text = QTextEdit(self) + text.setReadOnly(True) + text.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth) + text.setTextInteractionFlags( + Qt.TextInteractionFlag.TextSelectableByMouse + | Qt.TextInteractionFlag.TextSelectableByKeyboard + ) + text.setHtml(html) + return text diff --git a/src/aare/gui/tutorials/tutorial_manager.py b/src/aare/gui/tutorials/tutorial_manager.py new file mode 100644 index 00000000..ea9bb43f --- /dev/null +++ b/src/aare/gui/tutorials/tutorial_manager.py @@ -0,0 +1,404 @@ +from __future__ import annotations +from dataclasses import dataclass +from typing import List, Dict, Callable, Optional + +from PySide6.QtCore import ( + Qt, + QRect, + QPoint, + QPropertyAnimation, + QObject, + Signal, + QEasingCurve, + Property, + QTimer, +) +from PySide6.QtGui import ( + QColor, QPainter, QPen +) +from PySide6.QtWidgets import ( + QWidget, QLabel, QPushButton +) + + +@dataclass +class TutorialStep: + widget: QWidget + text: str + wait_for_click: bool = False # If true, wait for user clicking the highlight area + + # New: auto-advance when condition becomes True + wait_for_condition: Optional[Callable[[], bool]] = None + condition_poll_ms: int = 200 + condition_timeout_ms: Optional[int] = None # None = no timeout + + on_step_start: Optional[Callable] = None + on_step_end: Optional[Callable] = None + + +class TutorialOverlay(QWidget): + """Visual layer: draws highlight, handles animations, shows callouts.""" + + animation_finished = Signal() # Visual-only + proceed_requested = Signal() # Next / Finish / click highlight + cancelled = Signal() # End tutorial + + def __init__(self, parent=None): + super().__init__(parent) + self.setAttribute(Qt.WA_TransparentForMouseEvents, False) + + # IMPORTANT: keep this as a CHILD widget of the main window. + # Using Qt.Tool turns it into a top-level tool window and breaks geometry alignment. + self.setWindowFlags(Qt.FramelessWindowHint) + + self.setAttribute(Qt.WA_TranslucentBackground, True) + self.setFocusPolicy(Qt.StrongFocus) + + self.current_rect = QRect() + self.target_rect = QRect() + self.opacity = 1.0 + self._waiting_for_click = False + + self._highlight_padding_px = 6 # makes highlight cover frames/margins better + + self._dummy = 0.0 # Qt-animatable backing field + + self.anim = QPropertyAnimation(self, b"dummy") + self.anim.valueChanged.connect(self.update) + self.anim.finished.connect(self.animation_finished.emit) + + # Callout bubble + self.callout = QLabel(self) + self.callout.setStyleSheet(""" + background: white; + color: black; + padding: 10px; + border: 2px solid #555; + border-radius: 8px; + font-size: 13px; + """) + self.callout.setWordWrap(True) + self.callout.hide() + + button_style = """ + QPushButton { + font-size: 14px; + font-weight: 600; + padding: 10px 16px; + } + """ + + # Next/Finish button + self.next_button = QPushButton("Next", self) + self.next_button.setStyleSheet(button_style) + self.next_button.setMinimumHeight(44) + self.next_button.clicked.connect(self.proceed_requested.emit) + self.next_button.hide() + + # Always-available "End tutorial" button (top-right) + self.end_button = QPushButton("End tutorial", self) + self.end_button.setStyleSheet(button_style) + self.end_button.setMinimumHeight(44) + self.end_button.clicked.connect(self.cancelled.emit) + self.end_button.hide() + + self.hide() + + def get_dummy(self) -> float: + return float(self._dummy) + + def set_dummy(self, value: float) -> None: + self._dummy = float(value) + t = self._dummy + + self.current_rect = self._interpolate_rect(self.current_rect, self.target_rect, t) + self.opacity = t + self.update() + + dummy = Property(float, get_dummy, set_dummy) + + def showEvent(self, event): + super().showEvent(event) + if self.parentWidget() is not None: + self.setGeometry(self.parentWidget().rect()) + self._position_end_button() + + def resizeEvent(self, event): + super().resizeEvent(event) + if self.parentWidget() is not None: + self.setGeometry(self.parentWidget().rect()) + self._position_end_button() + + def _position_end_button(self) -> None: + self.end_button.adjustSize() + margin = 10 + x = max(margin, self.width() - self.end_button.width() - margin) + y = margin + self.end_button.move(x, y) + self.end_button.setVisible(True) + + def keyPressEvent(self, event): + if event.key() == Qt.Key_Escape: + self.cancelled.emit() + event.accept() + return + super().keyPressEvent(event) + + def mousePressEvent(self, event): + if self._waiting_for_click and self.current_rect.isValid(): + if self.current_rect.contains(event.pos()): + self.proceed_requested.emit() + event.accept() + return + super().mousePressEvent(event) + + def animate_to(self, rect: QRect, duration=400): + """Fade old highlight out, fade new one in.""" + # Clamp target rect inside overlay so it stays visible + self.target_rect = rect.intersected(self.rect()) + + self.anim.stop() + self.anim.setStartValue(0.0) + self.anim.setEndValue(1.0) + self.anim.setDuration(duration) + self.anim.setEasingCurve(QEasingCurve.InOutQuad) + self.anim.start() + + def paintEvent(self, event): + painter = QPainter(self) + painter.fillRect(self.rect(), QColor(0, 0, 0, int(150 * self.opacity))) + + if self.current_rect.isValid(): + pen = QPen(Qt.yellow, 4) + painter.setPen(pen) + painter.setBrush(Qt.NoBrush) + painter.drawRoundedRect(self.current_rect, 8, 8) + + def _interpolate_rect(self, r1: QRect, r2: QRect, t: float) -> QRect: + x = r1.x() + (r2.x() - r1.x()) * t + y = r1.y() + (r2.y() - r1.y()) * t + w = r1.width() + (r2.width() - r1.width()) * t + h = r1.height() + (r2.height() - r1.height()) * t + return QRect(int(x), int(y), int(w), int(h)) + + def show_step(self, step: TutorialStep): + widget = step.widget + + # Map the widget's *rect* (not just size) to global -> overlay coords + top_left_global = widget.mapToGlobal(widget.rect().topLeft()) + bottom_right_global = widget.mapToGlobal(widget.rect().bottomRight()) + + top_left = self.mapFromGlobal(top_left_global) + bottom_right = self.mapFromGlobal(bottom_right_global) + + rect = QRect(top_left, bottom_right).normalized() + + # Pad highlight so it better covers frames/margins + pad = int(self._highlight_padding_px) + rect.adjust(-pad, -pad, pad, pad) + + rect = rect.intersected(self.rect()) + + self.current_rect = rect + self.target_rect = rect + + self.callout.setText(step.text) + self.callout.adjustSize() + + margin = 10 + + bubble_x = rect.x() + bubble_y_above = rect.y() - self.callout.height() - 12 + bubble_y_below = rect.y() + rect.height() + 12 + bubble_y = bubble_y_above if bubble_y_above >= margin else bubble_y_below + + bubble_x = min(max(margin, bubble_x), max(margin, self.width() - self.callout.width() - margin)) + bubble_y = min(max(margin, bubble_y), max(margin, self.height() - self.callout.height() - margin)) + + self.callout.move(bubble_x, bubble_y) + self.callout.show() + + self._reposition_next_button() + self.update() + + def _reposition_next_button(self) -> None: + if not self.next_button.isVisible(): + return + + self.next_button.adjustSize() + margin = 10 + + x = self.callout.x() + self.callout.width() - self.next_button.width() + y = self.callout.y() + self.callout.height() + 10 + + x = min(max(margin, x), max(margin, self.width() - self.next_button.width() - margin)) + y = min(max(margin, y), max(margin, self.height() - self.next_button.height() - margin)) + + self.next_button.move(x, y) + + def set_waiting_for_click(self, waiting: bool): + self._waiting_for_click = waiting + + def set_next_enabled(self, enabled: bool, label: str = "Next"): + self.next_button.setText(label) + self.next_button.setVisible(enabled) + self.next_button.setEnabled(enabled) + self._reposition_next_button() + + def set_next_visible_but_disabled(self, label: str) -> None: + """Show Next/Finish button but disabled (useful while waiting for a condition).""" + self.next_button.setText(label) + self.next_button.setVisible(True) + self.next_button.setEnabled(False) + self._reposition_next_button() + + +class TutorialManager(QObject): + """Handles multiple tutorials, step sequencing, waiting for clicks/conditions.""" + + def __init__(self, parent_window): + super().__init__() + self.window = parent_window + self.overlay = TutorialOverlay(parent_window) + + self.tutorials: Dict[str, List[TutorialStep]] = {} + self.current_tutorial: Optional[List[TutorialStep]] = None + self.index = -1 + + self._timeout_timer = QTimer(self) + self._timeout_timer.setSingleShot(True) + self._timeout_timer.timeout.connect(self.stop) + + self._condition_poll_timer = QTimer(self) + self._condition_poll_timer.setSingleShot(False) + self._condition_poll_timer.timeout.connect(self._check_condition_and_advance) + + self._condition_timeout_timer = QTimer(self) + self._condition_timeout_timer.setSingleShot(True) + self._condition_timeout_timer.timeout.connect(self._condition_timed_out) + + self.overlay.proceed_requested.connect(self._next_step_logic) + self.overlay.cancelled.connect(self.stop) + + def add_tutorial(self, name: str, steps: List[TutorialStep]): + self.tutorials[name] = steps + + def start(self, name: str, timeout_ms: int | None = None): + if name not in self.tutorials: + print("Tutorial not found:", name) + return + + self.current_tutorial = self.tutorials[name] + self.index = -1 + + self.overlay.setGeometry(self.window.rect()) + self.overlay.show() + self.overlay.raise_() + self.overlay.activateWindow() + self.overlay.setFocus() + + self._timeout_timer.stop() + if timeout_ms is not None and timeout_ms > 0: + self._timeout_timer.start(int(timeout_ms)) + + self._stop_condition_wait() + self._next_step_logic() + + def stop(self): + self._timeout_timer.stop() + self._stop_condition_wait() + self.overlay.hide() + self.current_tutorial = None + self.index = -1 + + def _stop_condition_wait(self) -> None: + self._condition_poll_timer.stop() + self._condition_timeout_timer.stop() + + def _check_condition_and_advance(self) -> None: + """Poll the current step condition; advance when satisfied.""" + if not self.current_tutorial: + self._stop_condition_wait() + return + if not (0 <= self.index < len(self.current_tutorial)): + self._stop_condition_wait() + return + + step = self.current_tutorial[self.index] + cond = step.wait_for_condition + if cond is None: + self._stop_condition_wait() + return + + try: + ok = bool(cond()) + except Exception as exc: + # Don't crash the GUI; just stop waiting and let user end tutorial. + print(f"Tutorial condition raised exception: {exc}") + self._stop_condition_wait() + self.overlay.set_next_enabled(True, label="Next") + return + + if ok: + self._stop_condition_wait() + self._next_step_logic() + + def _condition_timed_out(self) -> None: + """If a condition times out, re-enable Next so user can proceed manually.""" + self._condition_poll_timer.stop() + self.overlay.set_next_enabled(True, label="Next") + + def _next_step_logic(self): + if not self.current_tutorial: + return + + # End previous step hook + if 0 <= self.index < len(self.current_tutorial): + prev = self.current_tutorial[self.index] + if prev.on_step_end: + prev.on_step_end() + + # Next step + self.index += 1 + if self.index >= len(self.current_tutorial): + self.stop() + return + + step = self.current_tutorial[self.index] + + if step.on_step_start: + step.on_step_start() + + widget = step.widget + global_pos = widget.mapToGlobal(QPoint(0, 0)) + pos = self.overlay.mapFromGlobal(global_pos) + rect = QRect(pos, widget.size()).intersected(self.overlay.rect()) + + self.overlay.animate_to(rect) + self.overlay.show_step(step) + + is_last = (self.index == len(self.current_tutorial) - 1) + + # Interaction gating priority: + # 1) wait_for_condition (auto-advance) + # 2) wait_for_click (click highlight) + # 3) manual Next/Finish + self._stop_condition_wait() + + if step.wait_for_condition is not None: + # show disabled button to communicate "waiting..." + self.overlay.set_waiting_for_click(False) + self.overlay.set_next_visible_but_disabled("Waiting…") + + poll_ms = max(50, int(step.condition_poll_ms)) + self._condition_poll_timer.start(poll_ms) + + if step.condition_timeout_ms is not None and step.condition_timeout_ms > 0: + self._condition_timeout_timer.start(int(step.condition_timeout_ms)) + return + + self.overlay.set_waiting_for_click(bool(step.wait_for_click)) + if step.wait_for_click: + self.overlay.set_next_enabled(False) + else: + self.overlay.set_next_enabled(True, label=("Finish" if is_last else "Next")) \ No newline at end of file diff --git a/src/aare/gui/tutorials/tutorial_registration.py b/src/aare/gui/tutorials/tutorial_registration.py new file mode 100644 index 00000000..b296c53f --- /dev/null +++ b/src/aare/gui/tutorials/tutorial_registration.py @@ -0,0 +1,53 @@ +# src/aare/gui/tutorials/tutorial_definitions.py +from __future__ import annotations + +from aare.common.models import BeamlineStateEnum +from aare.gui.tutorials.tutorial_manager import TutorialManager, TutorialStep + + +def register_tutorials(window, tutorial_manager: TutorialManager) -> None: + """ + Register all GUI tutorials. + + IMPORTANT: + - Do NOT import MainWindow here (avoids import loops). + - Use widgets that already exist on `window`. + """ + + steps_text = [ + TutorialStep( + widget=window.data_collection, + text="This panel contains controls for configuring data collection.\n\nClick Next to continue." + ), + TutorialStep( + widget=window.video_tab, + text="This area shows camera and beamline views.\n\nClick Next to continue." + ), + TutorialStep( + widget=window.beamline, + text="These panels contain beamline controls.\n\nClick Next to finish." + ), + ] + + steps_interactive = [ + TutorialStep( + widget=window.data_collection, + text="Interactive tutorial: click inside the highlighted area to continue.", + wait_for_click=True + ), + TutorialStep( + widget=window.video_tab, + text="Now click inside the highlighted video tab area to continue.", + wait_for_click=True + ), + TutorialStep( + widget=window.status_bar, + text="Waiting for the beamline to return to SampleAlignment...", + wait_for_condition=lambda: window.status_bar.last_status.state == BeamlineStateEnum.SampleAlignment, + condition_poll_ms=200, + condition_timeout_ms=30_000, + ) + ] + + tutorial_manager.add_tutorial("intro_text", steps_text) + tutorial_manager.add_tutorial("intro_interactive", steps_interactive) diff --git a/src/aare/gui/widgets/__init__.py b/src/aare/gui/widgets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/aare/gui/widgets/alert_banner.py b/src/aare/gui/widgets/alert_banner.py new file mode 100644 index 00000000..fe10f4c7 --- /dev/null +++ b/src/aare/gui/widgets/alert_banner.py @@ -0,0 +1,84 @@ +from PySide6.QtCore import QTimer, Slot, Qt +from PySide6.QtGui import QColor +from PySide6.QtWidgets import QFrame, QHBoxLayout, QLabel, QSizePolicy, QGraphicsDropShadowEffect + +from aare.common.logger_config import setup_logger + +logger = setup_logger("aareGUI") + + +class AlertBanner(QFrame): + def __init__(self, parent=None): + super().__init__(parent) + + self._clear_timer = QTimer(self) + self._clear_timer.setSingleShot(True) + self._clear_timer.timeout.connect(self.clear_message) + + self._label = QLabel("", self) + self._label.setWordWrap(True) + self._label.setAlignment(Qt.AlignmentFlag.AlignCenter) + + layout = QHBoxLayout(self) + layout.setContentsMargins(24, 12, 24, 12) + layout.addWidget(self._label) + + shadow = QGraphicsDropShadowEffect(self) + shadow.setBlurRadius(18) + shadow.setOffset(0, 3) + shadow.setColor(QColor(0, 0, 0, 55)) + self.setGraphicsEffect(shadow) + + self.setVisible(False) + self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) + + @Slot(str, bool) + def show_message(self, msg: str, is_error: bool = True): + self._clear_timer.stop() + + if not msg: + self.clear_message() + return + + if is_error: + decorated = f"🛑 {msg} 🛑" + self.setStyleSheet( + "QFrame {" + " background-color: #fbe4e6;" + " border: 2px solid #d97a84;" + " border-radius: 12px;" + " margin: 8px 12px 8px 12px;" + "}" + "QLabel {" + " color: #8f1d2c;" + " font-weight: 700;" + " font-size: 20px;" + " padding: 2px 6px 2px 6px;" + "}" + ) + else: + decorated = f"✅ {msg} ✅" + self.setStyleSheet( + "QFrame {" + " background-color: #e7f6ea;" + " border: 2px solid #7bbf8e;" + " border-radius: 12px;" + " margin: 8px 12px 8px 12px;" + "}" + "QLabel {" + " color: #1f6a3a;" + " font-weight: 700;" + " font-size: 20px;" + " padding: 2px 6px 2px 6px;" + "}" + ) + self._clear_timer.start(5000) + + self._label.setText(decorated) + self.setVisible(True) + + @Slot() + def clear_message(self): + self._clear_timer.stop() + self._label.clear() + self.setVisible(False) diff --git a/gui/src/aaregui/widgets/button_with_payload.py b/src/aare/gui/widgets/button_with_payload.py similarity index 100% rename from gui/src/aaregui/widgets/button_with_payload.py rename to src/aare/gui/widgets/button_with_payload.py diff --git a/gui/src/aaregui/widgets/camera_image.py b/src/aare/gui/widgets/camera_image.py similarity index 96% rename from gui/src/aaregui/widgets/camera_image.py rename to src/aare/gui/widgets/camera_image.py index 54342405..900681e3 100644 --- a/gui/src/aaregui/widgets/camera_image.py +++ b/src/aare/gui/widgets/camera_image.py @@ -10,7 +10,7 @@ from PySide6.QtGui import ( QWheelEvent, QTransform, QCursor, - QLinearGradient, QFont, QFontMetrics, + QLinearGradient, QFont, QFontMetrics, QPolygonF, ) from PySide6.QtWidgets import ( QMenu, @@ -22,13 +22,13 @@ from PySide6.QtWidgets import ( QFrame, ) -from aaredaqlib.models import DAQStatusModel, AutofocusSettings, SampleCameraSettings, BeamlineStateEnum, \ +from aare.common.models import DAQStatusModel, AutofocusSettings, SampleCameraSettings, BeamlineStateEnum, \ SessionsStateEnum -from aaregui.models.bookmark import SmargonBookmarkList -from aaredaqlib.coordinate import Coordinate, SmargonCoordinate -from aaredaqlib.sample_geometry import SampleGeometryModel -from aaregui.scan_logic.raster_grid_manager import RasterGridManager -from aaredaqlib.logger_config import setup_logger +from aare.gui.models.bookmark import SmargonBookmarkList +from aare.common.coordinate import Coordinate, SmargonCoordinate +from aare.common.sample_geometry import SampleGeometryModel +from aare.gui.scan_logic.raster_grid_manager import RasterGridManager +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") @@ -371,9 +371,10 @@ class SampleCameraImageLabel(QGraphicsView): self.__screenshot_with_dialog(overlay=True) elif action == autofocus_action: c = self.mapToScene(event.pos()) - self.autofocus.emit(AutofocusSettings(center_x_pxl=c.x(), center_y_pxl=c.y(), - radius_pxl=100, z_range_um=0.5, - z_steps=25)) + self.autofocus.emit(AutofocusSettings(center_x_pxl=None, center_y_pxl=None, + radius_pxl=30, + z_range_um=2000, + z_steps=10)) elif action == beam_mark_action: c = self.mapToScene(event.pos()) self.update_beam_mark.emit(c.x(), c.y()) @@ -525,6 +526,7 @@ class SampleCameraImageLabel(QGraphicsView): y1 = det['y1'] * sy x2 = det['x2'] * sx y2 = det['y2'] * sy + poly = det.get('poly', None) label = str(det.get('label', '')).lower() conf = det.get('conf', 0.0) except Exception as e: @@ -539,6 +541,12 @@ class SampleCameraImageLabel(QGraphicsView): painter.setBrush(Qt.BrushStyle.NoBrush) detection_rect = QRect(int(x1), int(y1), int(max(1, x2 - x1)), int(max(1, y2 - y1))) painter.drawRect(detection_rect) + if poly and len(poly) >= 3: + polygon = QPolygonF([ + QPointF(x1 + float(p[0]) * sx, y1 + float(p[1]) * sy) + for p in poly + ]) + painter.drawPolygon(polygon) # Draw label text with white text on colored background painter.setPen(QPen(QColor(255, 255, 255), 1)) diff --git a/gui/src/aaregui/widgets/clickable_label.py b/src/aare/gui/widgets/clickable_label.py similarity index 100% rename from gui/src/aaregui/widgets/clickable_label.py rename to src/aare/gui/widgets/clickable_label.py diff --git a/gui/src/aaregui/widgets/login.py b/src/aare/gui/widgets/login.py similarity index 98% rename from gui/src/aaregui/widgets/login.py rename to src/aare/gui/widgets/login.py index 4712f5a2..d75d983a 100644 --- a/gui/src/aaregui/widgets/login.py +++ b/src/aare/gui/widgets/login.py @@ -8,7 +8,7 @@ from PySide6.QtWidgets import ( QDialog, QVBoxLayout, QLineEdit, QPushButton, QLabel, QHBoxLayout ) -from aaredaqlib.models import TokenData +from aare.common.models import TokenData class LoginDialog(QDialog): diff --git a/gui/src/aaregui/widgets/message_box.py b/src/aare/gui/widgets/message_box.py similarity index 96% rename from gui/src/aaregui/widgets/message_box.py rename to src/aare/gui/widgets/message_box.py index a8134a20..34ef3db6 100644 --- a/gui/src/aaregui/widgets/message_box.py +++ b/src/aare/gui/widgets/message_box.py @@ -1,6 +1,6 @@ from PySide6.QtCore import QTimer, QEventLoop from PySide6.QtWidgets import QMessageBox -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") @@ -58,7 +58,7 @@ def ring_current_low_check(parent, ring_current) -> bool: too_low = ring_current < LOW_CURRENT_THRESHOLD if too_low: rc = round(ring_current, 2) - logger.debug(f"Ring current low {rc}") + logger.debug(f"Ring current low {rc} mA") msg = f"Ring current is low: {rc} mA." else: logger.debug(f"Ring current: {round(ring_current, 2)} mA") diff --git a/gui/src/aaregui/widgets/no_wheel_scroll_area.py b/src/aare/gui/widgets/no_wheel_scroll_area.py similarity index 100% rename from gui/src/aaregui/widgets/no_wheel_scroll_area.py rename to src/aare/gui/widgets/no_wheel_scroll_area.py diff --git a/gui/src/aaregui/widgets/number_line_edit.py b/src/aare/gui/widgets/number_line_edit.py similarity index 100% rename from gui/src/aaregui/widgets/number_line_edit.py rename to src/aare/gui/widgets/number_line_edit.py diff --git a/gui/src/aaregui/widgets/pgroup_dialog.py b/src/aare/gui/widgets/pgroup_dialog.py similarity index 100% rename from gui/src/aaregui/widgets/pgroup_dialog.py rename to src/aare/gui/widgets/pgroup_dialog.py diff --git a/gui/src/aaregui/widgets/raster_grid_table.py b/src/aare/gui/widgets/raster_grid_table.py similarity index 97% rename from gui/src/aaregui/widgets/raster_grid_table.py rename to src/aare/gui/widgets/raster_grid_table.py index 3f12ce66..3a3d91a5 100644 --- a/gui/src/aaregui/widgets/raster_grid_table.py +++ b/src/aare/gui/widgets/raster_grid_table.py @@ -1,8 +1,7 @@ from PySide6.QtCore import Signal, Slot from PySide6.QtWidgets import QTableWidget, QHeaderView, QTableWidgetItem, QWidget, QHBoxLayout, QPushButton -from aaredaqlib.raster_grid import RasterGridRequest -from aaregui.scan_logic.raster_grid_manager import RasterGridManager +from aare.gui.scan_logic.raster_grid_manager import RasterGridManager class RasterGridTable(QTableWidget): diff --git a/gui/src/aaregui/widgets/status_bar.py b/src/aare/gui/widgets/status_bar.py similarity index 86% rename from gui/src/aaregui/widgets/status_bar.py rename to src/aare/gui/widgets/status_bar.py index 4fc1ca07..b59ae947 100644 --- a/gui/src/aaregui/widgets/status_bar.py +++ b/src/aare/gui/widgets/status_bar.py @@ -1,13 +1,15 @@ +import math + from PySide6.QtCore import Signal, Slot, QPoint, QTimer from PySide6.QtGui import QFont -from PySide6.QtWidgets import QStatusBar, QDialog, QMenu, QLabel, QMessageBox +from PySide6.QtWidgets import QStatusBar, QDialog, QMenu, QMessageBox, QLabel, QSizePolicy -from aaredaqlib.models import TokenData, BeamlineStateEnum, DAQStatusModel, SessionsStateEnum -from aaregui.widgets.clickable_label import ClickableLabel -from aaregui.widgets.pgroup_dialog import PGroupDialog -from aaregui.widgets.value_label import ValueLabel +from aare.common.models import TokenData, BeamlineStateEnum, DAQStatusModel, SessionsStateEnum +from aare.gui.widgets.clickable_label import ClickableLabel +from aare.gui.widgets.pgroup_dialog import PGroupDialog +from aare.gui.widgets.value_label import ValueLabel -from aaredaqlib.logger_config import setup_logger +from aare.common.logger_config import setup_logger logger = setup_logger("aareGUI") @@ -32,6 +34,16 @@ class StatusBar(QStatusBar): self.__is_staff = self.__decoded_token.staff self.__allowed_pgroups = self.__decoded_token.pgroups + self._message_clear_timer = QTimer(self) + self._message_clear_timer.setSingleShot(True) + self._message_clear_timer.timeout.connect(self.clear_connection_message) + + self.message_label = QLabel("", self) + self.message_label.setVisible(False) + self.message_label.setSizePolicy(QSizePolicy.Policy.Maximum, QSizePolicy.Policy.Preferred) + + self.sharpness = ValueLabel("Samcam image sharpness", "", self) + self.samcam_fps = ValueLabel("Samcam FPS", "fps", self) self.flux = ValueLabel("Flux", "x 109 ph/s", self) self.transmission = ValueLabel("Transmission", "", self) self.ring_current = ValueLabel("Ring current", "mA", self) @@ -53,6 +65,9 @@ class StatusBar(QStatusBar): self.shutter_label.clicked.connect(self.show_shutter_menu) self.exp_shutter_label = ValueLabel("ExpHutch Shutter", "", self) + self.addWidget(self.message_label) + self.addPermanentWidget(self.sharpness) + self.addPermanentWidget(self.samcam_fps) self.addPermanentWidget(self.flux) self.addPermanentWidget(self.transmission) self.addPermanentWidget(self.ring_current) @@ -66,6 +81,37 @@ class StatusBar(QStatusBar): self.addPermanentWidget(self.busy_label) self.addPermanentWidget(self.session_label) + @Slot(str, bool) + def show_connection_message(self, msg: str, is_error: bool = True): + color = "red" if is_error else "green" + self._message_clear_timer.stop() + self.message_label.setText(msg) + self.message_label.setStyleSheet(f"color: {color}; font-weight: bold;") + self.message_label.setVisible(bool(msg)) + + if not is_error: + self._message_clear_timer.start(5000) + + @Slot() + def clear_connection_message(self): + self._message_clear_timer.stop() + self.message_label.clear() + self.message_label.setVisible(False) + + @Slot(float) + def update_sharpness(self, val: float): + self.sharpness.set_value(f"{val:.3f}") + + @Slot(float) + def update_samcam_fps(self, fps: float): + if fps is None or (isinstance(fps, float) and math.isnan(fps)): + self.samcam_fps.set_value("off") + return + if not math.isfinite(fps) or fps < 0: + self.samcam_fps.set_value("error") + return + self.samcam_fps.set_value(f"{fps:.1f}") + @Slot(DAQStatusModel) def update_daq_status(self, status: DAQStatusModel): self.__status = status diff --git a/gui/src/aaregui/widgets/status_label.py b/src/aare/gui/widgets/status_label.py similarity index 100% rename from gui/src/aaregui/widgets/status_label.py rename to src/aare/gui/widgets/status_label.py diff --git a/gui/src/aaregui/widgets/title_label.py b/src/aare/gui/widgets/title_label.py similarity index 100% rename from gui/src/aaregui/widgets/title_label.py rename to src/aare/gui/widgets/title_label.py diff --git a/gui/src/aaregui/widgets/value_label.py b/src/aare/gui/widgets/value_label.py similarity index 100% rename from gui/src/aaregui/widgets/value_label.py rename to src/aare/gui/widgets/value_label.py diff --git a/gui/src/aaregui/widgets/video_image.py b/src/aare/gui/widgets/video_image.py similarity index 100% rename from gui/src/aaregui/widgets/video_image.py rename to src/aare/gui/widgets/video_image.py diff --git a/update_version.sh b/update_version.sh deleted file mode 100644 index ebff14ba..00000000 --- a/update_version.sh +++ /dev/null @@ -1,9 +0,0 @@ -#/bin/bash - -VERSION=$(