Skip to content
Merged
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
43 changes: 14 additions & 29 deletions pyaml/arrays/serialized_magnet_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from ..magnet.serialized_magnet import SerializedMagnets
from .element_array import ElementArray

# TODO handle aggregator for CFM
# TODO handle aggregator for serialized magnets


class RWMagnetStrengths(ReadWriteFloatArray):
Expand All @@ -16,19 +16,13 @@ def __init__(self, name: str, magnets: list[SerializedMagnets]):

# Gets the values
def get(self) -> np.array:
r = np.zeros(self.__nb)
idx = 0
for m in self.__magnets:
r[idx : idx + m.get_nb_magnets()] = m.strengths.get()
idx += m.get_nb_magnets()
return r
return np.array([m.strength.get() for m in self.__magnets])

# Sets the values
def set(self, value: np.array):
nvalue = np.ones(self.__nb) * value if isinstance(value, float) else value
for idx, m in enumerate(self.__magnets):
m.strengths.set(nvalue[idx])
idx += m.get_nb_magnets()
nvalue = np.ones(len(self.__magnets)) * value if isinstance(value, float) else value
for value, m in zip(nvalue, self.__magnets, strict=True):
m.strength.set(value)

# Sets the values and waits that the read values reach their setpoint
def set_and_wait(self, value: np.array):
Expand All @@ -38,7 +32,7 @@ def set_and_wait(self, value: np.array):
def unit(self) -> list[str]:
r = []
for m in self.__magnets:
r.extend(m.strengths.unit())
r.extend(m.strength.unit())
return r


Expand All @@ -50,18 +44,13 @@ def __init__(self, name: str, magnets: list[SerializedMagnets]):

# Gets the values
def get(self) -> np.array:
r = np.zeros(self.__nb)
idx = 0
for m in self.__magnets:
r[idx : idx + m.get_nb_magnets()] = m.hardwares.get()
idx += m.get_nb_magnets()
return r
return np.array([m.hardware.get() for m in self.__magnets])

# Sets the values
def set(self, value: np.array):
nvalue = np.ones(self.__nb) * value if isinstance(value, float) else value
for idx, m in enumerate(self.__magnets):
m.hardwares.set(nvalue[idx])
nvalue = np.ones(len(self.__magnets)) * value if isinstance(value, float) else value
for value, m in zip(nvalue, self.__magnets, strict=True):
m.hardware.set(value)

# Sets the values and waits that the read values reach their setpoint
def set_and_wait(self, value: np.array):
Expand All @@ -71,13 +60,13 @@ def set_and_wait(self, value: np.array):
def unit(self) -> list[str]:
r = []
for m in self.__magnets:
r.extend(m.hardwares.unit())
r.extend(m.hardware.unit())
return r


class SerializedMagnetsArray(ElementArray):
"""
Class that implements access to a combined function magnet array
Class that implements access to a serialized magnets array

Parameters
----------
Expand All @@ -87,7 +76,7 @@ class SerializedMagnetsArray(ElementArray):
Magnet list, all elements must be attached to the same instance of
either a Simulator or a ControlSystem.
use_aggregator : bool
Use aggregator to increase performance by using paralell
Use aggregator to increase performance by using parallel
access to underlying devices.
"""

Expand All @@ -103,11 +92,7 @@ def __init__(
self.__rwhardwares = RWMagnetHardwares(arrayName, magnets)

if use_aggregator:
raise (
PyAMLException(
"Aggregator not implemented for CombinedFunctionMagnetArray"
)
)
raise (PyAMLException("Aggregator not implemented for SerializedMagnetsArray"))

@property
def strengths(self) -> RWMagnetStrengths:
Expand Down
51 changes: 41 additions & 10 deletions pyaml/lattice/abstract_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM
self.__poly = [e.__getattribute__(poly.attName) for e in elements]
self.__sign = poly.sign
self.__polyIdx = poly.index
self.__length = 0
self.__length: float = 0.0
for e in elements:
self.__length += e.Length

def get_length(self) -> float:
return self.__length

def get(self) -> float:
s = 0
for idx, e in enumerate(self.__elements):
Expand Down Expand Up @@ -71,6 +74,9 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM
for e in elements:
self.__length += e.Length

def get_element_length(self) -> float:
return self.__length

# Gets the value
def get(self) -> float:
s = 0
Expand Down Expand Up @@ -103,6 +109,15 @@ class RWSerializedHardware(abstract.ReadWriteFloatScalar):
def __init__(self, elements: list[RWHardwareScalar], element_index: int):
self.__elements = elements
self.__element_index = element_index
self.__total_length = 0
for e in elements:
self.__total_length += e.get_length()

def get_element_length(self) -> float:
return self.__elements[self.__element_index].get_length()

def get_total_length(self) -> float:
return self.__total_length

# Gets the value
def get(self) -> float:
Expand All @@ -127,27 +142,43 @@ def set_magnet_rigidity(self, brho: np.double):
class RWSerializedStrength(abstract.ReadWriteFloatScalar):
def __init__(
self,
element: RWStrengthScalar,
elements_strength: list[RWStrengthScalar],
elements_hardware: list[RWHardwareScalar],
element_index: int,
):
self.__element = element
self.__element = elements_strength[element_index]
self.__elements_strength = elements_strength
self.__elements_hardware = elements_hardware
self.__element_index = element_index
self.__total_length = 0
for e in self.__elements_hardware:
self.__total_length += e.get_length()

def get_element_length(self) -> float:
return self.__element.get_element_length()

def get_total_length(self) -> float:
return self.__total_length

# Gets the value
def get(self) -> float:
return self.__element.get()
return self.__elements_strength[self.__element_index].get()

# Sets the value
def set(self, value: float):
self.__element.set(value)
elements_values = [value * e.get_length() / self.get_total_length() for e in self.__elements_hardware]
self.__element.set(elements_values[self.__element_index])

# compute the local hardware value
hardware_value = self.__elements_hardware[self.__element_index].get()
[
element.set(hardware_value)
for index, element in enumerate(self.__elements_hardware)
if index != self.__element_index
]

# compute the total hardware value
total_hardware = hardware_value * self.get_total_length() / self.get_element_length()

# dispatch this value
for index, element in enumerate(self.__elements_hardware):
if index != self.__element_index:
element.set(total_hardware * element.get_length() / self.get_total_length())

# Sets the value and wait that the read value reach the setpoint
def set_and_wait(self, value: float):
Expand Down
2 changes: 1 addition & 1 deletion pyaml/lattice/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def fill_device(self, elements: list[Element]):
linked_strengths = []
for i in range(e.get_nb_magnets()):
current = RWSerializedHardware(currents, i) if e.model.has_hardware() else None
strength = RWSerializedStrength(strengths[i], currents, i) if e.model.has_physics() else None
strength = RWSerializedStrength(strengths, currents, i) if e.model.has_physics() else None
linked_currents.append(current)
linked_strengths.append(strength)
ms = e.attach(self, linked_strengths, linked_currents)
Expand Down
35 changes: 15 additions & 20 deletions pyaml/magnet/serialized_magnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, cfg: ConfigModel, elements: list[abstract.ReadWriteFloatScala
self._cfg = cfg

def get(self) -> float:
return self.elements[0].get()
return sum([elem.get() for elem in self.elements])

def set(self, value: float):
self.elements[0].set(value)
Expand Down Expand Up @@ -87,17 +87,13 @@ def __init__(self, cfg: ConfigModel, peer=None):
self.__strengths = None
self.__hardwares = None
self.__virtuals: list[Magnet] = []
self.__elements = (
cfg.elements if isinstance(cfg.elements, list) else [cfg.elements]
)
self.__elements = cfg.elements if isinstance(cfg.elements, list) else [cfg.elements]
self.model.set_number_of_magnets(len(self.__elements))
if peer is None:
# Configuration part
self.polynom = function_map[self._cfg.function].polynom
if self._cfg.function not in function_map:
raise PyAMLException(
self._cfg.function + " not implemented for serialized magnet"
)
raise PyAMLException(self._cfg.function + " not implemented for serialized magnet")
for element in self.__elements:
# Check mapping validity
# Create the virtual magnet for the corresponding magnet
Expand Down Expand Up @@ -132,35 +128,34 @@ def attach(
n_ser_mag.__strengths = ReadWriteSerializedStrengths(self._cfg, strengths)
n_ser_mag.__hardwares = ReadWriteSerializedHardwares(self._cfg, hardwares)
l.append(n_ser_mag)
# Construct a single function magnet for each multipole of this combined function magnet
for idx, magnet in enumerate(self.__elements):
# Construct a single magnet for each magnet.
sub_magnets: list[Magnet] = []
for idx, _ in enumerate(self.__elements):
strength = strengths[idx]
hardware = hardwares[idx] if self.model.has_hardware() else None
l.append(self.__virtuals[idx].attach(peer, strength, hardware))
sub_magnets.append(self.__virtuals[idx].attach(peer, strength, hardware))
n_ser_mag.__virtuals.extend(sub_magnets)
l.extend(sub_magnets)
return l

@property
def strengths(self) -> abstract.ReadWriteFloatScalar:
def strength(self) -> abstract.ReadWriteFloatScalar:
"""
Gives access to the strengths of this combined function magnet in physics unit
Gives access to the strengths of those magnets in physics unit
"""
self.check_peer()
if self.__strengths is None:
raise PyAMLException(
f"{str(self)} has no model that supports physics units"
)
raise PyAMLException(f"{str(self)} has no model that supports physics units")
return self.__strengths

@property
def hardwares(self) -> abstract.ReadWriteFloatScalar:
def hardware(self) -> abstract.ReadWriteFloatScalar:
"""
Gives access to the strengths of this combined function magnet in hardware unit when possible
Gives access to the strengths of this those magnets in hardware unit when possible
"""
self.check_peer()
if self.__hardwares is None:
raise PyAMLException(
f"{str(self)} has no model that supports hardware units"
)
raise PyAMLException(f"{str(self)} has no model that supports hardware units")
return self.__hardwares

def set_energy(self, energy: float):
Expand Down
101 changes: 101 additions & 0 deletions tests/config/sr/magnet_models/serialized_strength.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
0, 0
10, 41.96942873
11.01010101, 45.98112179
12.02020202, 49.99289574
13.03030303, 54.00483142
14.04040404, 58.01700977
15.05050505, 62.02951165
16.06060606, 66.04236719
17.07070707, 70.05543185
18.08080808, 74.0685235
19.09090909, 78.08145999
20.1010101, 82.09405922
21.11111111, 86.10617535
22.12121212, 90.11777041
23.13131313, 94.12882635
24.14141414, 98.13932508
25.15151515, 102.1492488
26.16161616, 106.1586527
27.17171717, 110.1677803
28.18181818, 114.1769052
29.19191919, 118.1863006
30.2020202, 122.1962385
31.21212121, 126.2067161
32.22222222, 130.2171169
33.23232323, 134.2267414
34.24242424, 138.2348902
35.25252525, 142.2408679
36.26262626, 146.2444837
37.27272727, 150.2465267
38.28282828, 154.2478985
39.29292929, 158.2495008
40.3030303, 162.2522266
41.31313131, 166.25631
42.32323232, 170.2608679
43.33333333, 174.2649089
44.34343434, 178.2674417
45.35353535, 182.2674849
46.36363636, 186.2645976
47.37373737, 190.2591392
48.38383838, 194.2515343
49.39393939, 198.2422074
50.4040404, 202.231575
51.41414141, 206.2197412
52.42424242, 210.2064054
53.43434343, 214.1912395
54.44444444, 218.1739158
55.45454545, 222.1540985
56.46464646, 226.1312411
57.47474747, 230.1045547
58.48484848, 234.0732372
59.49494949, 238.0364874
60.50505051, 241.9935203
61.51515152, 245.9439515
62.52525253, 249.8877958
63.53535354, 253.8250857
64.54545455, 257.7558532
65.55555556, 261.6800774
66.56565657, 265.5967522
67.57575758, 269.5040071
68.58585859, 273.3999423
69.5959596, 277.2826582
70.60606061, 281.1502132
71.61616162, 285.0000407
72.62626263, 288.8290937
73.63636364, 292.6343122
74.64646465, 296.4126366
75.65656566, 300.1609618
76.66666667, 303.8756178
77.67676768, 307.5525555
78.68686869, 311.1877177
79.6969697, 314.7770479
80.70707071, 318.3162245
81.71717172, 321.7981951
82.72727273, 325.2142962
83.73737374, 328.5558431
84.74747475, 331.8141516
85.75757576, 334.9809615
86.76767677, 338.0517056
87.77777778, 341.0237187
88.78787879, 343.894351
89.7979798, 346.6609528
90.80808081, 349.3212988
91.81818182, 351.8763
92.82828283, 354.3282731
93.83838384, 356.6795415
94.84848485, 358.9324286
95.85858586, 361.0891913
96.86868687, 363.1516677
97.87878788, 365.1215333
98.88888889, 367.0004624
99.8989899, 368.7901301
100.9090909, 370.4922638
101.9191919, 372.1088764
102.9292929, 373.6420763
103.9393939, 375.0939727
104.9494949, 376.4666742
105.959596, 377.7642106
106.969697, 378.9995406
107.979798, 380.1882157
108.989899, 381.3457874
110, 382.4878076
Loading
Loading