diff --git a/pyaml/apidoc/gen_api.py b/pyaml/apidoc/gen_api.py index a0be9b7a5..138e8d350 100644 --- a/pyaml/apidoc/gen_api.py +++ b/pyaml/apidoc/gen_api.py @@ -29,6 +29,7 @@ "pyaml.common.exception", "pyaml.common.holders.element_holder", "pyaml.common.holders.sub_holders", + "pyaml.common.holders.rf_holder", "pyaml.configuration.factory", "pyaml.configuration.fileloader", "pyaml.configuration.manager", diff --git a/pyaml/common/holders/element_holder.py b/pyaml/common/holders/element_holder.py index 0ea08a11b..3b5128d5e 100644 --- a/pyaml/common/holders/element_holder.py +++ b/pyaml/common/holders/element_holder.py @@ -23,6 +23,7 @@ from ..abstract_aggregator import ScalarAggregator from ..element import Element from ..exception import PyAMLException +from .rf_holder import RFHolder from .sub_holders import ( BPMHolder, BPMsHolder, @@ -89,6 +90,7 @@ def __init__(self): self._combined_function_magnets_holder = CombinedFunctionMagnetsHolder(self) self._bpm_holder = BPMHolder(self) self._bpms_holder = BPMsHolder(self) + self._rf_holder = RFHolder(self) @property def peer(self) -> "Accelerator": @@ -131,6 +133,10 @@ def bpm(self) -> BPMHolder: def bpms(self) -> BPMsHolder: return self._bpms_holder + @property + def rf(self) -> RFHolder: + return self._rf_holder + def post_init(self): """ Method triggered after all initialisations are done @@ -233,20 +239,6 @@ def get_elements(self, name: str) -> ElementArray: def get_all_elements(self) -> list[Element]: return [value for key, value in self._ALL.items()] - # RF - - def get_rf_plant(self, name: str) -> RFPlant: - return self._get("RFPlant", name, self._RFPLANT) - - def add_rf_plant(self, rf: RFPlant): - self._add(self._RFPLANT, rf) - - def add_rf_transmitter(self, rf: RFTransmitter): - self._add(self._RFTRANSMITTER, rf) - - def get_rf_trasnmitter(self, name: str) -> RFTransmitter: - return self._get("RFTransmitter", name, self._RFTRANSMITTER) - # Tune monitor def get_betatron_tune_monitor(self, name: str) -> BetatronTuneMonitor: diff --git a/pyaml/common/holders/rf_holder.py b/pyaml/common/holders/rf_holder.py new file mode 100644 index 000000000..31644a8fd --- /dev/null +++ b/pyaml/common/holders/rf_holder.py @@ -0,0 +1,77 @@ +from typing import TYPE_CHECKING + +from ...rf.rf_plant import RFPlant +from ...rf.rf_transmitter import RFTransmitter +from ..abstract import ReadWriteFloatScalar + +if TYPE_CHECKING: + from .element_holder import ElementHolder + + +class RFTransmitterHolder: + def __init__(self, peer: "ElementHolder"): + self._peer = peer + + def get(self, name: str) -> RFTransmitter: + return self._peer._get("RFTransmitter", name, self._peer._RFTRANSMITTER) + + def add(self, rf: RFTransmitter): + self._peer._add(self._peer._RFTRANSMITTER, rf) + + +class RFHolder: + """ + RF holder + """ + + def __init__(self, peer: "ElementHolder"): + self._peer = peer + self._rftransmitter_holder = RFTransmitterHolder(peer) + + @property + def transmitter(self) -> RFTransmitterHolder: + """ + Returns RF transmitter holder + + Parameters + ---------- + name : str + Name of the element + """ + return self._rftransmitter_holder + + @property + def frequency(self) -> ReadWriteFloatScalar: + """ + Return a handle to RF frequency of the DEFAULT_RF_PLANT + """ + return self.get("DEFAULT_RF_PLANT").frequency + + @property + def voltage(self) -> ReadWriteFloatScalar: + """ + Return a handle to RF voltage of the DEFAULT_RF_PLANT + """ + return self.get("DEFAULT_RF_PLANT").voltage + + def get(self, name: str) -> RFPlant: + """ + Returns the specified RF plant + + Parameters + ---------- + name : str + Name of the RF plant + """ + return self._peer._get("RFPlant", name, self._peer._RFPLANT) + + def add(self, rf: RFPlant): + """ + Adds the specified RF plant to the holder + + Parameters + ---------- + rf : RFPlant + RF Plant to be added + """ + self._peer._add(self._peer._RFPLANT, rf) diff --git a/pyaml/control/controlsystem.py b/pyaml/control/controlsystem.py index e6dd7f561..82ecba541 100644 --- a/pyaml/control/controlsystem.py +++ b/pyaml/control/controlsystem.py @@ -186,14 +186,14 @@ def fill_device(self, elements: list[Element]): voltage = RWRFVoltageScalar(t, vDev) phase = RWRFPhaseScalar(t, pDev) nt = t.attach(self, voltage, phase) - self.add_rf_transmitter(nt) + self.rf.transmitter.add(nt) attachedTrans.append(nt) fDev = self.get_device_access(e.masterclock) frequency = RWRFFrequencyScalar(e, fDev) voltage = RWTotalVoltage(attachedTrans) if e.transmitters else None ne = e.attach(self, frequency, voltage) - self.add_rf_plant(ne) + self.rf.add(ne) elif isinstance(e, BetatronTuneMonitor): # Built in tune monitor diff --git a/pyaml/diagnostics/tune_monitor.py b/pyaml/diagnostics/tune_monitor.py index 55db430b2..b3f6b5ec9 100644 --- a/pyaml/diagnostics/tune_monitor.py +++ b/pyaml/diagnostics/tune_monitor.py @@ -94,7 +94,7 @@ def get(self) -> NDArray: rf_name = self.parent._rf_plant_name if h is not None and rf_name is not None: tune = self.parent.tune.get() - rf = self.parent.peer.get_rf_plant(rf_name) + rf = self.parent.peer.rf.get(rf_name) freq = rf.frequency.get() return tune * freq / h diff --git a/pyaml/external/pySC_interface.py b/pyaml/external/pySC_interface.py index 15294f88f..7a50bf518 100644 --- a/pyaml/external/pySC_interface.py +++ b/pyaml/external/pySC_interface.py @@ -24,7 +24,7 @@ def __init__( self.rf_plant_name = rf_plant_name if rf_plant_name is not None: - self.rf_plant = element_holder.get_rf_plant(self.rf_plant_name) + self.rf_plant = element_holder.rf.get(self.rf_plant_name) else: self.rf_plant = None diff --git a/pyaml/lattice/simulator.py b/pyaml/lattice/simulator.py index 26774fd84..aa1769f60 100644 --- a/pyaml/lattice/simulator.py +++ b/pyaml/lattice/simulator.py @@ -230,20 +230,20 @@ def fill_device(self, elements: list[Element]): voltage = RWRFVoltageScalar(cavsPerTrans) phase = RWRFPhaseScalar(cavsPerTrans) nt = t.attach(self, voltage, phase) - self.add_rf_transmitter(nt) + self.rf.transmitter.add(nt) cavs.extend(cavsPerTrans) attachedTrans.append(nt) frequency = RWRFFrequencyScalar(cavs, harmonics) voltage = RWTotalVoltage(attachedTrans) ne = e.attach(self, frequency, voltage) - self.add_rf_plant(ne) + self.rf.add(ne) else: # No transmitter defined switch to AT methods frequency = RWRFATFrequencyScalar(self.ring) voltage = RWRFATotalVoltageScalar(self.ring) ne = e.attach(self, frequency, voltage) - self.add_rf_plant(ne) + self.rf.add(ne) elif isinstance(e, BetatronTuneMonitor): betatron_tune = RBetatronTuneArray(self.ring) diff --git a/pyaml/tuning_tools/chromaticity_monitor.py b/pyaml/tuning_tools/chromaticity_monitor.py index 439e6aa98..57b792238 100644 --- a/pyaml/tuning_tools/chromaticity_monitor.py +++ b/pyaml/tuning_tools/chromaticity_monitor.py @@ -245,7 +245,7 @@ def measure( # Get devices self.check_peer() tm = self.peer.get_betatron_tune_monitor(self.betatron_tune_name) - rf = self.peer.get_rf_plant(self.rf_plant_name) + rf = self.peer.rf.get(self.rf_plant_name) bpms = None n_bpm = 0 orbit = None diff --git a/pyaml/tuning_tools/orbit.py b/pyaml/tuning_tools/orbit.py index 243e10692..4b9ac17c7 100644 --- a/pyaml/tuning_tools/orbit.py +++ b/pyaml/tuning_tools/orbit.py @@ -319,4 +319,4 @@ def post_init(self): hvElts.extend(self._vcorr) self._hvcorr = MagnetArray("", hvElts) if self._cfg.rf_plant_name is not None: - self._rf_plant = self.peer.get_rf_plant(self._cfg.rf_plant_name) + self._rf_plant = self.peer.rf.get(self._cfg.rf_plant_name) diff --git a/tests/config/EBSOrbit.yaml b/tests/config/EBSOrbit.yaml index 351f3e40d..5d6ea2570 100644 --- a/tests/config/EBSOrbit.yaml +++ b/tests/config/EBSOrbit.yaml @@ -71,7 +71,7 @@ devices: - type: pyaml.tuning_tools.chromaticity_monitor name: CHROMATICITY_MONITOR betatron_tune_name: BETATRON_TUNE - rf_plant_name: RF + rf_plant_name: DEFAULT_RF_PLANT bpm_array_name: BPM n_step: 5 - type: pyaml.tuning_tools.tune @@ -98,7 +98,7 @@ devices: bpm_array_name: BPM hcorr_array_name: HCorr vcorr_array_name: VCorr - rf_plant_name: RF + rf_plant_name: DEFAULT_RF_PLANT name: DEFAULT_ORBIT_CORRECTION singular_values: 162 response_matrix: ${path:ideal_orm_disp.json} @@ -110,11 +110,11 @@ devices: name: DEFAULT_ORBIT_RESPONSE_MATRIX - type: pyaml.tuning_tools.dispersion bpm_array_name: BPM - rf_plant_name: RF + rf_plant_name: DEFAULT_RF_PLANT frequency_delta: 10 name: DEFAULT_DISPERSION - type: pyaml.rf.rf_plant - name: RF + name: DEFAULT_RF_PLANT masterclock: sy/ms/1/Frequency transmitters: - type: pyaml.rf.rf_transmitter diff --git a/tests/config/EBS_rf.yaml b/tests/config/EBS_rf.yaml index 96bd100a8..52b40210f 100644 --- a/tests/config/EBS_rf.yaml +++ b/tests/config/EBS_rf.yaml @@ -13,7 +13,7 @@ controls: data_folder: /data/store devices: - type: pyaml.rf.rf_plant - name: RF + name: DEFAULT_RF_PLANT masterclock: sy/ms/1/Frequency transmitters: - type: pyaml.rf.rf_transmitter diff --git a/tests/config/EBS_rf_multi.yaml b/tests/config/EBS_rf_multi.yaml index dd550a919..d3c7133be 100644 --- a/tests/config/EBS_rf_multi.yaml +++ b/tests/config/EBS_rf_multi.yaml @@ -14,7 +14,7 @@ controls: data_folder: /data/store devices: - type: pyaml.rf.rf_plant - name: RF + name: DEFAULT_RF_PLANT masterclock: sy/ms/1/Frequency transmitters: - type: pyaml.rf.rf_transmitter diff --git a/tests/config/EBS_rf_notrans.yaml b/tests/config/EBS_rf_notrans.yaml index 080715af7..1306d8c28 100644 --- a/tests/config/EBS_rf_notrans.yaml +++ b/tests/config/EBS_rf_notrans.yaml @@ -14,5 +14,5 @@ controls: data_folder: /data/store devices: - type: pyaml.rf.rf_plant - name: RF + name: DEFAULT_RF_PLANT masterclock: sy/ms/1/Frequency diff --git a/tests/integration/test_dt4acc_twin_smoke.py b/tests/integration/test_dt4acc_twin_smoke.py index c216dbb5b..9734debcd 100644 --- a/tests/integration/test_dt4acc_twin_smoke.py +++ b/tests/integration/test_dt4acc_twin_smoke.py @@ -79,7 +79,7 @@ def test_dt4acc_twin_accelerator_instantiates_and_reads_live_values(root_folder: assert accelerator.live is not None assert "live" in accelerator.controls() - accelerator.live.get_rf_plant("RF") + accelerator.live.rf.get("RF") reference_frequency = _readback_value(accelerator.live.get_device_access(RF_REFERENCE_FREQUENCY)) diff --git a/tests/rf/test_rf.py b/tests/rf/test_rf.py index 964e25e7b..1d8b5a570 100644 --- a/tests/rf/test_rf.py +++ b/tests/rf/test_rf.py @@ -7,9 +7,8 @@ def test_rf(): sr: Accelerator = Accelerator.load("tests/config/EBS_rf.yaml", ignore_external=True) - RF = sr.design.get_rf_plant("RF") - RF.frequency.set(3.523e8) + sr.design.rf.frequency.set(3.523e8) # Check that frequency has been applied on all cavities ring = sr.design.get_lattice() @@ -17,7 +16,7 @@ def test_rf(): if e.FamName.startswith("CAV"): assert e.Frequency == 3.523e8 - RF.voltage.set(10.0e6) + sr.design.rf.voltage.set(10.0e6) # Check that voltage has been applied on all cavities ring = sr.design.get_lattice() @@ -26,11 +25,10 @@ def test_rf(): assert np.isclose(e.Voltage, 10.0e6 / 13.0) if False: - RF = sr.live.get_rf_plant("RF") - RF.frequency.set(3.523721693993786e8) - RF.voltage.set(6.5e6) - assert np.isclose(RF.frequency.get(), 3.523721693993786e8) - assert np.isclose(RF.voltage.get(), 6.5e6) + sr.live.rf.frequency.set(3.523721693993786e8) + sr.live.rf.voltage.set(6.5e6) + assert np.isclose(sr.live.rf.frequency.get(), 3.523721693993786e8) + assert np.isclose(sr.live.rf.voltage.get(), 6.5e6) @pytest.mark.parametrize( @@ -42,9 +40,8 @@ def test_rf_multi(install_test_package): sr: Accelerator = Accelerator.load("tests/config/EBS_rf_multi.yaml") # Simulator - RF = sr.design.get_rf_plant("RF") - RF.frequency.set(3.523e8) + sr.design.rf.frequency.set(3.523e8) # Check that frequency has been applied on all cavities ring = sr.design.get_lattice() @@ -56,9 +53,9 @@ def test_rf_multi(install_test_package): else: assert e.Frequency == 3.523e8 - RFTRA_HARMONIC = sr.design.get_rf_trasnmitter("RFTRA_HARMONIC") + RFTRA_HARMONIC = sr.design.rf.transmitter.get("RFTRA_HARMONIC") RFTRA_HARMONIC.voltage.set(300e3) - RF.voltage.set(12e6) + sr.design.rf.voltage.set(12e6) for e in ring: if e.FamName.startswith("CAV"): @@ -69,14 +66,13 @@ def test_rf_multi(install_test_package): assert np.isclose(e.Voltage, 1e6) # Control system - RF = sr.live.get_rf_plant("RF") - RF1 = sr.live.get_rf_trasnmitter("RFTRA1") - RF2 = sr.live.get_rf_trasnmitter("RFTRA2") - RFTRA_HARMONIC = sr.live.get_rf_trasnmitter("RFTRA_HARMONIC") + RF1 = sr.live.rf.transmitter.get("RFTRA1") + RF2 = sr.live.rf.transmitter.get("RFTRA2") + RFTRA_HARMONIC = sr.live.rf.transmitter.get("RFTRA_HARMONIC") - RF.frequency.set(3.523e8) + sr.live.rf.frequency.set(3.523e8) RFTRA_HARMONIC.voltage.set(300e3) - RF.voltage.set(12e6) + sr.live.rf.voltage.set(12e6) assert np.isclose(RF1.voltage.get(), 10e6) assert np.isclose(RF2.voltage.get(), 2e6) @@ -92,9 +88,8 @@ def test_rf_multi_notrans(install_test_package): sr: Accelerator = Accelerator.load("tests/config/EBS_rf_notrans.yaml") # Simulator - RF = sr.design.get_rf_plant("RF") - RF.frequency.set(3.523e8) - RF.voltage.set(10e6) + sr.design.rf.frequency.set(3.523e8) + sr.design.rf.voltage.set(10e6) # Check that frequency and voltage has been applied on all cavities ring = sr.design.get_lattice() for e in ring: @@ -103,11 +98,10 @@ def test_rf_multi_notrans(install_test_package): assert np.isclose(e.Voltage, 10e6 / 13.0) # Control system - RF = sr.live.get_rf_plant("RF") - RF.frequency.set(3.523e8) + sr.live.rf.frequency.set(3.523e8) with pytest.raises(PyAMLException) as exc: - RF.voltage.set(10e6) + sr.live.rf.voltage.set(10e6) assert "has no transmitter device defined" in str(exc) # Check that frequency and voltage has been applied on the masterclock device - assert np.isclose(RF.frequency.get(), 3.523e8) + assert np.isclose(sr.live.rf.frequency.get(), 3.523e8) diff --git a/tests/tuning_tools/test_tuning_orbit_correction.py b/tests/tuning_tools/test_tuning_orbit_correction.py index 0e0f83696..d2648c7a4 100644 --- a/tests/tuning_tools/test_tuning_orbit_correction.py +++ b/tests/tuning_tools/test_tuning_orbit_correction.py @@ -183,9 +183,8 @@ def test_tuning_orbit_correction(): x, y = bpms.positions.get().T # get reference orbit reference_before_rf = np.concat((x, y)) - plant = element_holder.get_rf_plant("RF") - frf = plant.frequency.get() - plant.frequency.set(frf + 100) + frf = element_holder.rf.frequency.get() + element_holder.rf.frequency.set(frf + 100) for _ in range(3): element_holder.orbit.correct( reference=reference_before_rf, @@ -195,7 +194,7 @@ def test_tuning_orbit_correction(): gain_H=0, ) - frf_after = plant.frequency.get() + frf_after = element_holder.rf.frequency.get() assert np.isclose(frf, frf_after, rtol=0, atol=1e-16) # no need to mangle orbit again, test rf @@ -204,9 +203,8 @@ def test_tuning_orbit_correction(): rf_weight = element_holder.orbit.get_rf_weight() element_holder.orbit.set_rf_weight(1.1 * rf_weight) - plant = element_holder.get_rf_plant("RF") - frf = plant.frequency.get() - plant.frequency.set(frf + 100) + frf = element_holder.rf.frequency.get() + element_holder.rf.frequency.set(frf + 100) for _ in range(8): element_holder.orbit.correct( reference=reference_before_rf, @@ -216,7 +214,7 @@ def test_tuning_orbit_correction(): gain_H=0, ) - frf_after = plant.frequency.get() + frf_after = element_holder.rf.frequency.get() assert np.isclose(frf, frf_after, rtol=0, atol=1e-16) element_holder.orbit.set_rf_weight(rf_weight)