diff --git a/examples/BESSY2_example/BESSY2Chroma.yaml b/examples/BESSY2_example/BESSY2Chroma.yaml index 61f0993a..3060ff55 100644 --- a/examples/BESSY2_example/BESSY2Chroma.yaml +++ b/examples/BESSY2_example/BESSY2Chroma.yaml @@ -8,7 +8,7 @@ simulators: name: design controls: - type: pyaml_cs_oa.controlsystem - prefix: 'a3744:' + prefix: 'pons:' name: live data_folder: /data/store devices: @@ -24,15 +24,15 @@ devices: unit: '' - type: pyaml.diagnostics.chromaticity_monitor name: KSI - betatron_tune: BETATRON_TUNE - RFfreq: RF + betatron_tune_name: BETATRON_TUNE + rf_plant_name: RF fit_order: 2 - N_tune_meas: 1 - N_step: 5 - Sleep_between_meas: 2 - Sleep_between_RFvar: 2 - E_delta: 1e-3 - Max_E_delta: 1e-3 + n_avg_meas: 1 + n_step: 5 + sleep_between_meas: 2 + sleep_between_step: 2 + e_delta: 1e-3 + max_e_delta: 1e-3 - type: pyaml.rf.rf_plant name: RF masterclock: diff --git a/examples/BESSY2_example/BESSY2Orbit.yaml b/examples/BESSY2_example/BESSY2Orbit.yaml index c6e00aa3..2d1abe96 100644 --- a/examples/BESSY2_example/BESSY2Orbit.yaml +++ b/examples/BESSY2_example/BESSY2Orbit.yaml @@ -8,7 +8,7 @@ simulators: name: design controls: - type: pyaml_cs_oa.controlsystem - prefix: "a3744:" + prefix: "pons:" name: live data_folder: /data/store arrays: diff --git a/examples/BESSY2_example/BESSY2Tune.yaml b/examples/BESSY2_example/BESSY2Tune.yaml index 6cf5c9ed..3dc795d8 100644 --- a/examples/BESSY2_example/BESSY2Tune.yaml +++ b/examples/BESSY2_example/BESSY2Tune.yaml @@ -8,7 +8,7 @@ simulators: name: design controls: - type: pyaml_cs_oa.controlsystem - prefix: 'a3744:' + prefix: 'pons:' name: live data_folder: /data/store arrays: @@ -892,6 +892,11 @@ devices: unit: '' - type: pyaml.tuning_tools.tune name: DEFAULT_TUNE_CORRECTION - quad_array: QForTune - betatron_tune: BETATRON_TUNE - delta: 1e-4 + quad_array_name: QForTune + betatron_tune_name: BETATRON_TUNE + response_matrix: file:trm.json +- type: pyaml.tuning_tools.tune_response_matrix + name: DEFAULT_TUNE_RESPONSE_MATRIX + quad_array_name: QForTune + betatron_tune_name: BETATRON_TUNE + quad_delta: 1e-4 diff --git a/examples/BESSY2_example/bessy2-chroma.py b/examples/BESSY2_example/bessy2-chroma.py index 2eda70ed..21872e4c 100644 --- a/examples/BESSY2_example/bessy2-chroma.py +++ b/examples/BESSY2_example/bessy2-chroma.py @@ -10,7 +10,7 @@ import numpy as np from pyaml.accelerator import Accelerator -from pyaml.common.constants import ACTION_MEASURE +from pyaml.common.constants import Action # ----- Load the configuration ----- # Remember to change the prefix for the live mode to the one matching @@ -22,9 +22,9 @@ # This callback is used to print output during the chromaticity measurement. -def chroma_callback(step: int, action: int, rf: float, tune: np.array): - if action == ACTION_MEASURE: - print(f"Chromaticy measurement: #{step} RF={rf} Tune={tune}") +def chroma_callback(action: int, cb_data: dict): + if action == Action.MEASURE: + print(f"Chromaticy measurement: #{cb_data['step']} RF={cb_data['rf']} Tune={cb_data['tune']}") return True diff --git a/examples/BESSY2_example/bessy2-orbit.py b/examples/BESSY2_example/bessy2-orbit.py index a2e0540a..5b900f12 100644 --- a/examples/BESSY2_example/bessy2-orbit.py +++ b/examples/BESSY2_example/bessy2-orbit.py @@ -13,8 +13,7 @@ import numpy as np from pyaml.accelerator import Accelerator -from pyaml.tuning_tools.orbit_response_matrix import ConfigModel as ORM_ConfigModel -from pyaml.tuning_tools.orbit_response_matrix import OrbitResponseMatrix +from pyaml.tuning_tools.orbit_response_matrix_data import OrbitResponseMatrixData # ----- Load the configuration ----- # Remember to change the prefix for the live mode to the one matching your virtual @@ -34,26 +33,10 @@ # if the ORM is not present measure it if sr.design.orbit.response_matrix is None: - SR.orm.measure(set_wait_time=0.0 if SR == sr.design else 2.0) - orm_data = SR.orm.get() - - # Save the data to json - ORM_data = { - "type": "pyaml.tuning_tools.response_matrix", - "matrix": orm_data["matrix"], - "input_names": orm_data["input_names"], - "output_names": orm_data["output_names"], - "input_planes": orm_data["input_planes"], - "output_planes": orm_data["output_planes"], - } - json.dump(ORM_data, open("orm.json", "w")) - -# ----- Load the response matrix ----- -# The example does the correction for the live mode but it can also be done on the -# design mode. - -# Load the ORM for the live mode -sr.live.orbit.load_response_matrix("orm.json") + SR.orm.measure(sleep_between_step=0.0 if SR == sr.design else 2.0) + SR.orm.save("orm.json") + # Load it on live + sr.live.orbit.load("orm.json") # ----- Correct the orbit ----- diff --git a/examples/BESSY2_example/bessy2-tune.py b/examples/BESSY2_example/bessy2-tune.py index b673a3ef..f293078f 100644 --- a/examples/BESSY2_example/bessy2-tune.py +++ b/examples/BESSY2_example/bessy2-tune.py @@ -12,7 +12,7 @@ import numpy as np from pyaml.accelerator import Accelerator -from pyaml.common.constants import ACTION_MEASURE +from pyaml.common.constants import Action from pyaml.magnet.magnet import Magnet # ----- Load the configuration ----- @@ -25,10 +25,10 @@ # This callback is used to print output during the tune response measurement. -def tune_callback(step: int, action: int, m: Magnet, dtune: np.array): - if action == ACTION_MEASURE: +def tune_callback(action: int, cb_data: dict): + if action == Action.MEASURE: # On action measure, the measured dq / dk is passed as argument - print(f"Tune response: #{step} {m.get_name()} {dtune}") + print(f"Tune response: #{cb_data['step']} {cb_data['magnet']} {cb_data['tune']}") return True @@ -40,17 +40,12 @@ def tune_callback(step: int, action: int, m: Magnet, dtune: np.array): # Choose which backend to use. SR = sr.design -tune_adjust = sr.design.tune -tune_adjust.response.measure( - callback=tune_callback, set_wait_time=0.0 if SR == sr.design else 2.0 -) -tune_adjust.response.save_json("tune-response.json") - -# ----- Load the response matrix ----- -# The example does the correction for the live mode but it can also be done -# on the design mode. - -sr.live.tune.response.load_json("tune-response.json") +# if the TRM is not present measure it +if sr.design.tune.response_matrix is None: + SR.trm.measure(sleep_between_step=0.0 if SR == sr.design else 2.0, callback=tune_callback) + SR.trm.save("trm.json") + # Load it on live + sr.live.tune.load("trm.json") # ----- Correct the tune ----- diff --git a/pyaml/tuning_tools/chromaticity.py b/pyaml/tuning_tools/chromaticity.py index a06ab569..27a4d892 100644 --- a/pyaml/tuning_tools/chromaticity.py +++ b/pyaml/tuning_tools/chromaticity.py @@ -79,6 +79,13 @@ def __init__(self, cfg: ConfigModel): # TODO: Initialise first setpoint self._setpoint = np.array([np.nan, np.nan]) + @property + def response_matrix(self) -> ResponseMatrixData | None: + """ + Return the response matrix if it has been loaded None otherwise + """ + return self._cfg.response_matrix + def load(self, load_path: Path): """ Dyanmically loads a response matrix. diff --git a/pyaml/tuning_tools/chromaticity_response_matrix.py b/pyaml/tuning_tools/chromaticity_response_matrix.py index 1f00f611..8b995fbf 100644 --- a/pyaml/tuning_tools/chromaticity_response_matrix.py +++ b/pyaml/tuning_tools/chromaticity_response_matrix.py @@ -212,5 +212,6 @@ def callback(action: Action, data:dict): observable_names=[cm.get_name() + ".x", cm.get_name() + ".y"], ) self.latest_measurement.update(mat.model_dump()) + self.latest_measurement["type"] = "pyaml.tuning_tools.response_matrix_data" return True diff --git a/pyaml/tuning_tools/orbit.py b/pyaml/tuning_tools/orbit.py index 06475125..2dff6a18 100644 --- a/pyaml/tuning_tools/orbit.py +++ b/pyaml/tuning_tools/orbit.py @@ -75,25 +75,44 @@ def __init__(self, cfg: ConfigModel): try: cfg.response_matrix = OrbitResponseMatrixData.load(cfg.response_matrix) except Exception as e: - logger.warning(f"{str(e)}") + logger.warning(f"Loading {cfg.response_matrix} failed {str(e)}") cfg.response_matrix = None # Converts to self._pySC_response_matrix if cfg.response_matrix: - m = cfg.response_matrix._cfg.model_dump() - m["input_names"] = m.pop("variable_names") - m["output_names"] = m.pop("observable_names") - m["input_planes"] = m.pop("variable_planes") - m["output_planes"] = m.pop("observable_planes") - self._pySC_response_matrix = pySC_ResponseMatrix.model_validate(m) + self._set_response_matrix(cfg.response_matrix) self._hcorr: MagnetArray = None self._vcorr: MagnetArray = None self._hvcorr: MagnetArray = None self._rf_plant: RFPlant = None + def load(self, load_path: Path): + """ + Dynamically loads a response matrix. + + Parameters + ---------- + load_path : Path + Filename of the :class:`~.OrbitResponseMatrixData` to load + """ + self._cfg.response_matrix = OrbitResponseMatrixData.load(load_path) + self._set_response_matrix(self._cfg.response_matrix) + + def _set_response_matrix(self, mat): + m = mat._cfg.model_dump() + m["input_names"] = m.pop("variable_names") + m["output_names"] = m.pop("observable_names") + m["input_planes"] = m.pop("variable_planes") + m["output_planes"] = m.pop("observable_planes") + self._cfg.response_matrix = mat + self._pySC_response_matrix = pySC_ResponseMatrix.model_validate(m) + @property - def reponse_matrix(self) -> OrbitResponseMatrixData | None: + def response_matrix(self) -> OrbitResponseMatrixData | None: + """ + Return the response matrix if it has been loaded None otherwise + """ return self._cfg.response_matrix def correct( diff --git a/pyaml/tuning_tools/orbit_response_matrix.py b/pyaml/tuning_tools/orbit_response_matrix.py index 18511f34..99c8d2fd 100644 --- a/pyaml/tuning_tools/orbit_response_matrix.py +++ b/pyaml/tuning_tools/orbit_response_matrix.py @@ -159,6 +159,7 @@ def measure( orm_data = self._pySC_response_data_to_ORMData(measurement.response_data.model_dump()) self.latest_measurement.update(orm_data.model_dump()) + self.latest_measurement["type"] = "pyaml.tuning_tools.orbit_response_matrix_data" def _pySC_response_data_to_ORMData(self, data: dict) -> OrbitResponseMatrixDataConfigModel: # all metadata is discarded here. Should we keep something? diff --git a/pyaml/tuning_tools/response_matrix_data.py b/pyaml/tuning_tools/response_matrix_data.py index 44abd184..4cfd4800 100644 --- a/pyaml/tuning_tools/response_matrix_data.py +++ b/pyaml/tuning_tools/response_matrix_data.py @@ -40,7 +40,7 @@ def __init__(self, cfg: ConfigModel): self._cfg = cfg @staticmethod - def load(filename: str) -> None: + def load(filename: str) -> "ResponseMatrixData": """ Load a reponse matrix from a configuration file """ diff --git a/pyaml/tuning_tools/tune.py b/pyaml/tuning_tools/tune.py index a4d53b45..382092bf 100644 --- a/pyaml/tuning_tools/tune.py +++ b/pyaml/tuning_tools/tune.py @@ -82,7 +82,7 @@ def __init__(self, cfg: ConfigModel): def load(self, load_path: Path): """ - Dyanmically loads a response matrix. + Dynamically loads a response matrix. Parameters ---------- @@ -94,6 +94,13 @@ def load(self, load_path: 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() diff --git a/pyaml/tuning_tools/tune_response_matrix.py b/pyaml/tuning_tools/tune_response_matrix.py index c2c74681..15f432dc 100644 --- a/pyaml/tuning_tools/tune_response_matrix.py +++ b/pyaml/tuning_tools/tune_response_matrix.py @@ -199,5 +199,6 @@ def callback(action: Action, data:dict): observable_names=[tm.get_name() + ".x", tm.get_name() + ".y"], ) self.latest_measurement.update(mat.model_dump()) + self.latest_measurement["type"] = "pyaml.tuning_tools.response_matrix_data" return True