diff --git a/pyaml/arrays/magnet_array.py b/pyaml/arrays/magnet_array.py index d8e36d18..fe2905b9 100644 --- a/pyaml/arrays/magnet_array.py +++ b/pyaml/arrays/magnet_array.py @@ -2,8 +2,6 @@ from ..magnet.magnet import Magnet import numpy as np -#TODO: Implement magnet_array.RWMagnetCurrent - class RWMagnetStrength(ReadWriteFloatArray): def __init__(self, magnets:list[Magnet]): @@ -24,8 +22,29 @@ def set_and_wait(self, value:np.array): # Gets the unit of the values def unit(self) -> list[str]: - [m.strength.unit() for m in self.__magnets] + return [m.strength.unit() for m in self.__magnets] + +class RWMagnetHardware(ReadWriteFloatArray): + + def __init__(self, magnets:list[Magnet]): + self.__magnets = magnets + # Gets the values + def get(self) -> np.array: + return np.array([m.hardware.get() for m in self.__magnets]) + + # Sets the values + def set(self, value:np.array): + for idx,m in enumerate(self.__magnets): + m.hardware.set(value[idx]) + + # Sets the values and waits that the read values reach their setpoint + def set_and_wait(self, value:np.array): + raise NotImplementedError("Not implemented yet.") + + # Gets the unit of the values + def unit(self) -> list[str]: + return [m.hardware.unit() for m in self.__magnets] class MagnetArray(list[Magnet]): """ @@ -34,11 +53,15 @@ class MagnetArray(list[Magnet]): def __init__(self,iterable): super().__init__(i for i in iterable) self.__rwstrengths = RWMagnetStrength(iterable) + self.__rwhardwares = RWMagnetHardware(iterable) @property def strengths(self) -> RWMagnetStrength: return self.__rwstrengths + @property + def hardwares(self) -> RWMagnetHardware: + return self.__rwhardwares diff --git a/tests/test_tune_hardware.py b/tests/test_tune_hardware.py new file mode 100644 index 00000000..d8f401ba --- /dev/null +++ b/tests/test_tune_hardware.py @@ -0,0 +1,51 @@ +from pyaml.pyaml import pyaml,PyAML +from pyaml.instrument import Instrument +from pyaml.lattice.element_holder import MagnetType +from pyaml.arrays.magnet_array import MagnetArray +from pyaml.configuration.factory import Factory +import numpy as np +import at +import pytest + +@pytest.mark.parametrize("install_test_package", [{ + "name": "tango", + "path": "tests/dummy_cs/tango" +}], indirect=True) +def test_tune(install_test_package): + + ml:PyAML = pyaml("tests/config/EBSTune.yaml") + sr:Instrument = ml.get('sr') + sr.design.get_lattice().disable_6d() + + quadForTuneDesign = sr.design.get_magnets("QForTune") + + # Build tune response matrix (hardware units) + tune = sr.design.get_lattice().get_tune() + print(tune) + tunemat = np.zeros((len(quadForTuneDesign),2)) + + idx = 0 + for m in quadForTuneDesign: + current = m.hardware.get() + m.hardware.set(current+1e-6) + dq = sr.design.get_lattice().get_tune() - tune + tunemat[idx] = dq*1e6 + m.hardware.set(current) + idx += 1 + + # Compute correction matrix + correctionmat = np.linalg.pinv(tunemat.T) + + # Correct tune + currents = quadForTuneDesign.hardwares.get() + currents += np.matmul(correctionmat,[0.1,0.05]) # Ask for correction [dqx,dqy] + quadForTuneDesign.hardwares.set(currents) + newTune = sr.design.get_lattice().get_tune() + units = quadForTuneDesign.hardwares.unit() + diffTune = newTune - tune + assert( np.abs(diffTune[0]-0.1) < 1e-3 ) + assert( np.abs(diffTune[1]-0.05) < 1.1e-3 ) + assert( np.abs(currents[0]-88.04522942) < 1e-8 ) + assert( np.abs(currents[1]-88.26677735) < 1e-8 ) + assert( units[0] == 'A' and units[1] == 'A' ) + Factory.clear()