Operational interface
Operational measurements use a small interface object to connect pySC to a machine or control system. The interface owns all hardware-specific details: reading orbits, reading setpoints, writing setpoints, waiting for devices to settle, and triggering turn-by-turn acquisition when needed.
The base methods required by pySC operational tools are:
get_orbit()Return the current horizontal and vertical orbit arrays.
get(name)Return one magnet strength in physics units.
set(name, value)Set one magnet strength in physics units and wait until it is settled.
get_many(names)Return a dictionary mapping magnet names to strengths.
set_many(data)Set many magnet strengths from a dictionary and wait until they are settled.
Some workflows need extra methods. Orbit correction against an operational
reference uses get_ref_orbit(). RF correction uses
get_rf_main_frequency() and set_rf_main_frequency().
For first-turn correction, InterfaceInjection.get_orbit() should return the
turn-by-turn trajectory flattened with order="F". Its get_ref_orbit()
method should return a reference trajectory with the same shape and flattening.
Download the skeleton: interface.py
"""Control-system interface skeleton for operational pySC examples."""
from pathlib import Path
import numpy as np
from pySC.apps.interface import AbstractInterface
DATA_FOLDER = Path("data")
class Interface(AbstractInterface):
"""Implement these methods for the target control system."""
def get_orbit(self) -> tuple[np.ndarray, np.ndarray]:
"""Return the current horizontal and vertical orbit arrays."""
raise NotImplementedError("Implement get_orbit() for your control system.")
def get_ref_orbit(self) -> tuple[np.ndarray, np.ndarray]:
"""Return the horizontal and vertical reference orbit arrays."""
raise NotImplementedError("Implement get_ref_orbit() for your control system.")
def get(self, name: str) -> float:
"""Return one magnet strength in physics units."""
raise NotImplementedError("Implement get() for your control system.")
def set(self, name: str, value: float) -> None:
"""Set one magnet strength in physics units and wait until it is settled."""
raise NotImplementedError("Implement set() for your control system.")
def get_many(self, names: list[str]) -> dict[str, float]:
"""Return magnet strengths as a mapping from control name to value."""
raise NotImplementedError("Implement get_many() for your control system.")
def set_many(self, data: dict[str, float]) -> None:
"""Set multiple magnet strengths and wait until they are settled."""
raise NotImplementedError("Implement set_many() for your control system.")
def get_rf_main_frequency(self) -> float:
"""Return the main RF frequency in Hz if RF correction is used."""
raise NotImplementedError("Implement get_rf_main_frequency() if RF correction is used.")
def set_rf_main_frequency(self, frequency: float) -> None:
"""Set the main RF frequency in Hz if RF correction is used."""
raise NotImplementedError("Implement set_rf_main_frequency() if RF correction is used.")
class InterfaceInjection(Interface):
"""Interface variant for first-turn or multi-turn trajectory measurements."""
n_turns: int = 1
trigger_injection: bool = False
def get_orbit(self) -> tuple[np.ndarray, np.ndarray]:
"""Return turn-by-turn trajectory arrays flattened with order='F'."""
raise NotImplementedError("Implement get_orbit() for turn-by-turn data.")
def get_ref_orbit(self) -> tuple[np.ndarray, np.ndarray]:
"""Return the matching reference trajectory flattened with order='F'."""
raise NotImplementedError("Implement get_ref_orbit() for turn-by-turn data.")