Source code for pyaml.tuning_tools.tune

import logging
from pathlib import Path
from time import sleep
from typing import TYPE_CHECKING

import numpy as np

try:
    from typing import Self  # Python 3.11+
except ImportError:
    from typing_extensions import Self  # Python 3.10 and earlier

from .. import PyAMLException
from ..common.element import ElementConfigModel
from .response_matrix_data import ResponseMatrixData
from .tuning_tool import TuningTool

if TYPE_CHECKING:
    from ..arrays.magnet_array import MagnetArray
    from ..diagnostics.tune_monitor import BetatronTuneMonitor

logger = logging.getLogger(__name__)

# Define the main class name for this module
PYAMLCLASS = "Tune"


[docs] class ConfigModel(ElementConfigModel): """ Configuration model for Tune Parameters ---------- quad_array_name : str Array name of quad used to adjust the tune betatron_tune_name : str Name of the diagnostic pyaml device for measuring the tune quad_delta : float Delta strength used to get the response matrix """ quad_array_name: str betatron_tune_name: str response_matrix: str | ResponseMatrixData
[docs] class Tune(TuningTool): """ Class providing tune adjustment tool """ def __init__(self, cfg: ConfigModel): """ Construct a Tune adjustment object. Parameters ---------- cfg : ConfigModel Configuration for the tune adjustment. """ super().__init__(cfg.name) self._cfg = cfg self._response_matrix = None self._correctionmat = None # If the configuration response matrix is a filename, load it if type(cfg.response_matrix) is str: try: cfg.response_matrix = ResponseMatrixData.load(cfg.response_matrix) except Exception as e: logger.warning(f"{str(e)}") cfg.response_matrix = None # Invert matrix if cfg.response_matrix: self._response_matrix = np.array(cfg.response_matrix._cfg.matrix) self._correctionmat = np.linalg.pinv(self._response_matrix) # TODO: Initialise first setpoint self._setpoint = np.array([np.nan, np.nan])
[docs] def load(self, load_path: Path): """ Dynamically loads a response matrix. Parameters ---------- load_path : Path Filename of the :class:`~.ResponseMatrixData` to load """ self._cfg.response_matrix = ResponseMatrixData.load(load_path) self._response_matrix = np.array(self._cfg.response_matrix._cfg.matrix) self._correctionmat = np.linalg.pinv(self._response_matrix)
@property def response_matrix(self) -> ResponseMatrixData | None: """ Return the response matrix if it has been loaded None otherwise """ return self._cfg.response_matrix @property def _tm(self) -> "BetatronTuneMonitor": self.check_peer() return self.peer.get_betatron_tune_monitor(self._cfg.betatron_tune_name) @property def _quads(self) -> "MagnetArray": self.check_peer() return self.peer.get_magnets(self._cfg.quad_array_name)
[docs] def get(self): """ Return the betatron tune setpoint """ return self._setpoint
[docs] def readback(self): """ Return the betatron tune measurement """ self.check_peer() return self._tm.tune.get()
[docs] def set(self, tune: np.array, iter: int = 1, wait_time: float = 0.0): """ Sets the tune Parameters ---------- tune : np.array Tune setpoint iter_nb : int Number of iteration wait_time : float Time to wait in second between 2 iterations """ for i in range(iter): diff_tune = tune - self.readback() if i == iter: wait_time = 0 # do not wait on last iteration self.add(diff_tune, wait_time) self._setpoint = np.array(tune)
[docs] def correct(self, dtune: np.array) -> np.array: """ Return delta strengths for tune correction Parameters ---------- dtune : np.array Delta tune """ if self._correctionmat is None: raise PyAMLException("Tune.correct(): no matrix loaded or measured") return np.matmul(self._correctionmat, dtune)
[docs] def add(self, dtune: np.array, wait_time: float = 0.0): """ Add delta tune to the tune Parameters ---------- dtune : np.array Delta tune iter_nb: int wait_time: float """ strengths = self._quads.strengths.get() strengths += self.correct(dtune) self._quads.strengths.set(strengths) sleep(wait_time) self._setpoint += dtune