Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions pyaml/common/holders/rf_holder.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,35 @@ class RFHolder:
----------
transmitter
Return the holder for RF transmitter elements.
masterclock
Return the RF plant configured as ``DEFAULT_RF_PLANT``.
frequency
Return the default RF plant's frequency interface.
Return the masterclock's frequency interface.
voltage
Return the default RF plant's total-voltage interface.
Return the masterclock's total-voltage interface.

Methods
-------
get(name)
Return an RF plant by name.
add(rf)
Add an RF plant to the holder.

Notes
-----
``frequency`` and ``voltage`` are backward-compatible aliases for
``masterclock.frequency`` and ``masterclock.voltage``. Do not confuse
this ``masterclock`` (the default :class:`~pyaml.rf.rf_plant.RFPlant`
object) with :attr:`~pyaml.rf.rf_plant.RFPlant.masterclock` (the
master-clock device name configured on an ``RFPlant``).

Examples
--------
>>> masterclock = sr.live.rf.masterclock
>>> masterclock.frequency.set(499.654e6)
>>> masterclock.voltage.set(2.5e6)
>>> same_frequency = sr.live.rf.frequency
>>> spare_rf_plant = sr.live.rf.get("SPARE_RF_PLANT")
"""

def __init__(self, peer: "ElementHolder"):
Expand All @@ -108,15 +126,37 @@ def transmitter(self) -> RFTransmitterHolder:
"""Return the holder for RF transmitter elements."""
return self._rftransmitter_holder

@property
def masterclock(self) -> RFPlant:
"""
Return the RF plant configured as ``DEFAULT_RF_PLANT``.

Returns
-------
RFPlant
RF plant registered under ``DEFAULT_RF_PLANT``.

Raises
------
PyAMLException
If no RF plant is registered under ``DEFAULT_RF_PLANT``.

Examples
--------
>>> masterclock = sr.live.rf.masterclock
>>> masterclock.frequency.set(499.654e6)
"""
return self.get("DEFAULT_RF_PLANT")

@property
def frequency(self) -> ReadWriteFloatScalar:
"""Return the default RF plant's frequency interface."""
return self.get("DEFAULT_RF_PLANT").frequency
"""Return the masterclock's frequency interface (alias for ``masterclock.frequency``)."""
return self.masterclock.frequency

@property
def voltage(self) -> ReadWriteFloatScalar:
"""Return the default RF plant's total-voltage interface."""
return self.get("DEFAULT_RF_PLANT").voltage
"""Return the masterclock's total-voltage interface (alias for ``masterclock.voltage``)."""
return self.masterclock.voltage

def get(self, name: str) -> RFPlant:
"""
Expand Down
44 changes: 44 additions & 0 deletions tests/rf/test_rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from pyaml.accelerator import Accelerator
from pyaml.common.exception import PyAMLException
from pyaml.lattice.simulator import Simulator


def test_rf():
Expand Down Expand Up @@ -105,3 +106,46 @@ def test_rf_multi_notrans(install_test_package):

# Check that frequency and voltage has been applied on the masterclock device
assert np.isclose(sr.live.rf.frequency.get(), 3.523e8)


def test_masterclock_returns_the_default_rf_plant():
sr: Accelerator = Accelerator.load("tests/config/EBS_rf.yaml", ignore_external=True)

assert sr.design.rf.masterclock is sr.design.rf.get("DEFAULT_RF_PLANT")


def test_frequency_and_voltage_are_masterclock_aliases():
sr: Accelerator = Accelerator.load("tests/config/EBS_rf.yaml", ignore_external=True)

assert sr.design.rf.frequency is sr.design.rf.masterclock.frequency
assert sr.design.rf.voltage is sr.design.rf.masterclock.voltage

sr.design.rf.masterclock.frequency.set(3.6e8)
assert sr.design.rf.frequency.get() == pytest.approx(3.6e8)

sr.design.rf.frequency.set(3.523e8)
assert sr.design.rf.masterclock.frequency.get() == pytest.approx(3.523e8)


def test_masterclock_raises_when_default_rf_plant_missing(ebs_lattice_file):
holder = Simulator(name="empty", lattice=str(ebs_lattice_file))

with pytest.raises(PyAMLException) as exc:
_ = holder.rf.masterclock
assert "DEFAULT_RF_PLANT" in str(exc.value)


def test_simple_rf_access():
sr: Accelerator = Accelerator.load("tests/config/EBS_rf.yaml", ignore_external=True)

masterclock = sr.design.rf.masterclock
masterclock.frequency.set(499.654e6)
masterclock.voltage.set(2.5e6)

same_frequency = sr.design.rf.frequency
assert same_frequency.get() == pytest.approx(499.654e6)

# No second RF plant is configured in this fixture: reuse the existing
# one to check that named lookup keeps working alongside the masterclock.
default_rf_plant = sr.design.rf.get("DEFAULT_RF_PLANT")
assert default_rf_plant is masterclock
Loading