From b0011e041df863f97f1c9e0523d9918e90dda2d6 Mon Sep 17 00:00:00 2001 From: guillaumepichon Date: Fri, 24 Apr 2026 11:45:21 +0200 Subject: [PATCH] Fix four AttributeError bugs in LinearSerializedMagnetModel (wrong field names, misplaced attribute access). Rework compute methods to reflect physical reality: one power converter per series, compute_strengths accepts one current and returns N strengths, compute_hardware_values accepts N strengths and returns one current. --- pyaml/magnet/linear_serialized_model.py | 16 +++++++--------- pyaml/magnet/serialized_magnet.py | 5 +---- tests/test_serialized_magnets.py | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/pyaml/magnet/linear_serialized_model.py b/pyaml/magnet/linear_serialized_model.py index 77eef97b..6e6be33e 100644 --- a/pyaml/magnet/linear_serialized_model.py +++ b/pyaml/magnet/linear_serialized_model.py @@ -147,23 +147,21 @@ def get_sub_model(self, index: int) -> LinearMagnetModel: return self.__sub_models[index] def compute_hardware_values(self, strengths: np.array) -> np.array: - return np.array( - [model.compute_hardware_values([strength]) for strength, model in zip(strengths, self.__sub_models, strict=True)] - ) + currents = [model.compute_hardware_values([s])[0] for s, model in zip(strengths, self.__sub_models, strict=True)] + return np.array([np.mean(currents)]) def compute_strengths(self, currents: np.array) -> np.array: - return np.array( - [model.compute_strengths([current]) for current, model in zip(currents, self.__sub_models, strict=True)] - ) + current = currents[0] + return np.array([model.compute_strengths([current])[0] for model in self.__sub_models]) def get_strength_units(self) -> list[str]: - return self._cfg.units + return [self._cfg.unit] * self.__nbMagnets def get_hardware_units(self) -> list[str]: - return [p.unit() for p in self._cfg.__sub_models] + return [self.__sub_models[0].get_hardware_units()[0]] def get_devices(self) -> list[DeviceAccess]: - return self._cfg.powerconverters + return [self._cfg.powerconverter] def set_magnet_rigidity(self, brho: np.double): self.__brho = brho diff --git a/pyaml/magnet/serialized_magnet.py b/pyaml/magnet/serialized_magnet.py index 10613c04..a5d1fdf7 100644 --- a/pyaml/magnet/serialized_magnet.py +++ b/pyaml/magnet/serialized_magnet.py @@ -171,7 +171,4 @@ def __repr__(self): return __pyaml_repr__(self) def get_devices(self) -> list[DeviceAccess]: - if isinstance(self.model.powerconverter, list): - return self.model.powerconverter - else: - return [self._cfg.powerconverter] + return self.model.get_devices() diff --git a/tests/test_serialized_magnets.py b/tests/test_serialized_magnets.py index d1d2bc1e..20506f79 100644 --- a/tests/test_serialized_magnets.py +++ b/tests/test_serialized_magnets.py @@ -154,6 +154,27 @@ def test_tune(sr_file): assert np.abs(diffTune[1] - 0.05) < 1e-3 +@pytest.mark.parametrize( + "sr_file", + [ + "tests/config/sr_serialized_magnets.yaml", + ], +) +def test_get_devices(sr_file): + sr: Accelerator = Accelerator.load(sr_file, use_fast_loader=True, ignore_external=True) + sm: SerializedMagnets = sr.design.get_serialized_magnet("QF1A") + + devices = sm.get_devices() + + # Serialized magnets share a single power converter: exactly 1 device + assert len(devices) == 1 + # Strength and hardware computation must remain consistent after the fix + initial_strength = sm.strength.get() + sm.strength.set(initial_strength * 1.01) + assert abs(sm.strength.get() - initial_strength * 1.01) < 1e-3 + sm.strength.set(initial_strength) + + def get_strengths_from_lattice(sr: Accelerator, sm: SerializedMagnets) -> list: ring = sr.design.get_lattice() strs = []