Skip to content

Commit 4765bec

Browse files
authored
Merge pull request #223 from python-accelerator-middle-layer/217-strange-behavior-of-serialized-magnets
217 strange behavior of serialized magnets
2 parents d1d409e + f94ee7a commit 4765bec

9 files changed

Lines changed: 539 additions & 85 deletions

File tree

pyaml/arrays/serialized_magnet_array.py

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ..magnet.serialized_magnet import SerializedMagnets
66
from .element_array import ElementArray
77

8-
# TODO handle aggregator for CFM
8+
# TODO handle aggregator for serialized magnets
99

1010

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

1717
# Gets the values
1818
def get(self) -> np.array:
19-
r = np.zeros(self.__nb)
20-
idx = 0
21-
for m in self.__magnets:
22-
r[idx : idx + m.get_nb_magnets()] = m.strengths.get()
23-
idx += m.get_nb_magnets()
24-
return r
19+
return np.array([m.strength.get() for m in self.__magnets])
2520

2621
# Sets the values
2722
def set(self, value: np.array):
28-
nvalue = np.ones(self.__nb) * value if isinstance(value, float) else value
29-
for idx, m in enumerate(self.__magnets):
30-
m.strengths.set(nvalue[idx])
31-
idx += m.get_nb_magnets()
23+
nvalue = np.ones(len(self.__magnets)) * value if isinstance(value, float) else value
24+
for value, m in zip(nvalue, self.__magnets, strict=True):
25+
m.strength.set(value)
3226

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

4438

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

5145
# Gets the values
5246
def get(self) -> np.array:
53-
r = np.zeros(self.__nb)
54-
idx = 0
55-
for m in self.__magnets:
56-
r[idx : idx + m.get_nb_magnets()] = m.hardwares.get()
57-
idx += m.get_nb_magnets()
58-
return r
47+
return np.array([m.hardware.get() for m in self.__magnets])
5948

6049
# Sets the values
6150
def set(self, value: np.array):
62-
nvalue = np.ones(self.__nb) * value if isinstance(value, float) else value
63-
for idx, m in enumerate(self.__magnets):
64-
m.hardwares.set(nvalue[idx])
51+
nvalue = np.ones(len(self.__magnets)) * value if isinstance(value, float) else value
52+
for value, m in zip(nvalue, self.__magnets, strict=True):
53+
m.hardware.set(value)
6554

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

7766

7867
class SerializedMagnetsArray(ElementArray):
7968
"""
80-
Class that implements access to a combined function magnet array
69+
Class that implements access to a serialized magnets array
8170
8271
Parameters
8372
----------
@@ -87,7 +76,7 @@ class SerializedMagnetsArray(ElementArray):
8776
Magnet list, all elements must be attached to the same instance of
8877
either a Simulator or a ControlSystem.
8978
use_aggregator : bool
90-
Use aggregator to increase performance by using paralell
79+
Use aggregator to increase performance by using parallel
9180
access to underlying devices.
9281
"""
9382

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

10594
if use_aggregator:
106-
raise (
107-
PyAMLException(
108-
"Aggregator not implemented for CombinedFunctionMagnetArray"
109-
)
110-
)
95+
raise (PyAMLException("Aggregator not implemented for SerializedMagnetsArray"))
11196

11297
@property
11398
def strengths(self) -> RWMagnetStrengths:

pyaml/lattice/abstract_impl.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM
2828
self.__poly = [e.__getattribute__(poly.attName) for e in elements]
2929
self.__sign = poly.sign
3030
self.__polyIdx = poly.index
31-
self.__length = 0
31+
self.__length: float = 0.0
3232
for e in elements:
3333
self.__length += e.Length
3434

35+
def get_length(self) -> float:
36+
return self.__length
37+
3538
def get(self) -> float:
3639
s = 0
3740
for idx, e in enumerate(self.__elements):
@@ -71,6 +74,9 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM
7174
for e in elements:
7275
self.__length += e.Length
7376

77+
def get_element_length(self) -> float:
78+
return self.__length
79+
7480
# Gets the value
7581
def get(self) -> float:
7682
s = 0
@@ -103,6 +109,15 @@ class RWSerializedHardware(abstract.ReadWriteFloatScalar):
103109
def __init__(self, elements: list[RWHardwareScalar], element_index: int):
104110
self.__elements = elements
105111
self.__element_index = element_index
112+
self.__total_length = 0
113+
for e in elements:
114+
self.__total_length += e.get_length()
115+
116+
def get_element_length(self) -> float:
117+
return self.__elements[self.__element_index].get_length()
118+
119+
def get_total_length(self) -> float:
120+
return self.__total_length
106121

107122
# Gets the value
108123
def get(self) -> float:
@@ -127,27 +142,43 @@ def set_magnet_rigidity(self, brho: np.double):
127142
class RWSerializedStrength(abstract.ReadWriteFloatScalar):
128143
def __init__(
129144
self,
130-
element: RWStrengthScalar,
145+
elements_strength: list[RWStrengthScalar],
131146
elements_hardware: list[RWHardwareScalar],
132147
element_index: int,
133148
):
134-
self.__element = element
149+
self.__element = elements_strength[element_index]
150+
self.__elements_strength = elements_strength
135151
self.__elements_hardware = elements_hardware
136152
self.__element_index = element_index
153+
self.__total_length = 0
154+
for e in self.__elements_hardware:
155+
self.__total_length += e.get_length()
156+
157+
def get_element_length(self) -> float:
158+
return self.__element.get_element_length()
159+
160+
def get_total_length(self) -> float:
161+
return self.__total_length
137162

138163
# Gets the value
139164
def get(self) -> float:
140-
return self.__element.get()
165+
return self.__elements_strength[self.__element_index].get()
141166

142167
# Sets the value
143168
def set(self, value: float):
144-
self.__element.set(value)
169+
elements_values = [value * e.get_length() / self.get_total_length() for e in self.__elements_hardware]
170+
self.__element.set(elements_values[self.__element_index])
171+
172+
# compute the local hardware value
145173
hardware_value = self.__elements_hardware[self.__element_index].get()
146-
[
147-
element.set(hardware_value)
148-
for index, element in enumerate(self.__elements_hardware)
149-
if index != self.__element_index
150-
]
174+
175+
# compute the total hardware value
176+
total_hardware = hardware_value * self.get_total_length() / self.get_element_length()
177+
178+
# dispatch this value
179+
for index, element in enumerate(self.__elements_hardware):
180+
if index != self.__element_index:
181+
element.set(total_hardware * element.get_length() / self.get_total_length())
151182

152183
# Sets the value and wait that the read value reach the setpoint
153184
def set_and_wait(self, value: float):

pyaml/lattice/simulator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def fill_device(self, elements: list[Element]):
185185
linked_strengths = []
186186
for i in range(e.get_nb_magnets()):
187187
current = RWSerializedHardware(currents, i) if e.model.has_hardware() else None
188-
strength = RWSerializedStrength(strengths[i], currents, i) if e.model.has_physics() else None
188+
strength = RWSerializedStrength(strengths, currents, i) if e.model.has_physics() else None
189189
linked_currents.append(current)
190190
linked_strengths.append(strength)
191191
ms = e.attach(self, linked_strengths, linked_currents)

pyaml/magnet/serialized_magnet.py

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self, cfg: ConfigModel, elements: list[abstract.ReadWriteFloatScala
2929
self._cfg = cfg
3030

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

3434
def set(self, value: float):
3535
self.elements[0].set(value)
@@ -87,17 +87,13 @@ def __init__(self, cfg: ConfigModel, peer=None):
8787
self.__strengths = None
8888
self.__hardwares = None
8989
self.__virtuals: list[Magnet] = []
90-
self.__elements = (
91-
cfg.elements if isinstance(cfg.elements, list) else [cfg.elements]
92-
)
90+
self.__elements = cfg.elements if isinstance(cfg.elements, list) else [cfg.elements]
9391
self.model.set_number_of_magnets(len(self.__elements))
9492
if peer is None:
9593
# Configuration part
9694
self.polynom = function_map[self._cfg.function].polynom
9795
if self._cfg.function not in function_map:
98-
raise PyAMLException(
99-
self._cfg.function + " not implemented for serialized magnet"
100-
)
96+
raise PyAMLException(self._cfg.function + " not implemented for serialized magnet")
10197
for element in self.__elements:
10298
# Check mapping validity
10399
# Create the virtual magnet for the corresponding magnet
@@ -132,35 +128,34 @@ def attach(
132128
n_ser_mag.__strengths = ReadWriteSerializedStrengths(self._cfg, strengths)
133129
n_ser_mag.__hardwares = ReadWriteSerializedHardwares(self._cfg, hardwares)
134130
l.append(n_ser_mag)
135-
# Construct a single function magnet for each multipole of this combined function magnet
136-
for idx, magnet in enumerate(self.__elements):
131+
# Construct a single magnet for each magnet.
132+
sub_magnets: list[Magnet] = []
133+
for idx, _ in enumerate(self.__elements):
137134
strength = strengths[idx]
138135
hardware = hardwares[idx] if self.model.has_hardware() else None
139-
l.append(self.__virtuals[idx].attach(peer, strength, hardware))
136+
sub_magnets.append(self.__virtuals[idx].attach(peer, strength, hardware))
137+
n_ser_mag.__virtuals.extend(sub_magnets)
138+
l.extend(sub_magnets)
140139
return l
141140

142141
@property
143-
def strengths(self) -> abstract.ReadWriteFloatScalar:
142+
def strength(self) -> abstract.ReadWriteFloatScalar:
144143
"""
145-
Gives access to the strengths of this combined function magnet in physics unit
144+
Gives access to the strengths of those magnets in physics unit
146145
"""
147146
self.check_peer()
148147
if self.__strengths is None:
149-
raise PyAMLException(
150-
f"{str(self)} has no model that supports physics units"
151-
)
148+
raise PyAMLException(f"{str(self)} has no model that supports physics units")
152149
return self.__strengths
153150

154151
@property
155-
def hardwares(self) -> abstract.ReadWriteFloatScalar:
152+
def hardware(self) -> abstract.ReadWriteFloatScalar:
156153
"""
157-
Gives access to the strengths of this combined function magnet in hardware unit when possible
154+
Gives access to the strengths of this those magnets in hardware unit when possible
158155
"""
159156
self.check_peer()
160157
if self.__hardwares is None:
161-
raise PyAMLException(
162-
f"{str(self)} has no model that supports hardware units"
163-
)
158+
raise PyAMLException(f"{str(self)} has no model that supports hardware units")
164159
return self.__hardwares
165160

166161
def set_energy(self, energy: float):
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
0, 0
2+
10, 41.96942873
3+
11.01010101, 45.98112179
4+
12.02020202, 49.99289574
5+
13.03030303, 54.00483142
6+
14.04040404, 58.01700977
7+
15.05050505, 62.02951165
8+
16.06060606, 66.04236719
9+
17.07070707, 70.05543185
10+
18.08080808, 74.0685235
11+
19.09090909, 78.08145999
12+
20.1010101, 82.09405922
13+
21.11111111, 86.10617535
14+
22.12121212, 90.11777041
15+
23.13131313, 94.12882635
16+
24.14141414, 98.13932508
17+
25.15151515, 102.1492488
18+
26.16161616, 106.1586527
19+
27.17171717, 110.1677803
20+
28.18181818, 114.1769052
21+
29.19191919, 118.1863006
22+
30.2020202, 122.1962385
23+
31.21212121, 126.2067161
24+
32.22222222, 130.2171169
25+
33.23232323, 134.2267414
26+
34.24242424, 138.2348902
27+
35.25252525, 142.2408679
28+
36.26262626, 146.2444837
29+
37.27272727, 150.2465267
30+
38.28282828, 154.2478985
31+
39.29292929, 158.2495008
32+
40.3030303, 162.2522266
33+
41.31313131, 166.25631
34+
42.32323232, 170.2608679
35+
43.33333333, 174.2649089
36+
44.34343434, 178.2674417
37+
45.35353535, 182.2674849
38+
46.36363636, 186.2645976
39+
47.37373737, 190.2591392
40+
48.38383838, 194.2515343
41+
49.39393939, 198.2422074
42+
50.4040404, 202.231575
43+
51.41414141, 206.2197412
44+
52.42424242, 210.2064054
45+
53.43434343, 214.1912395
46+
54.44444444, 218.1739158
47+
55.45454545, 222.1540985
48+
56.46464646, 226.1312411
49+
57.47474747, 230.1045547
50+
58.48484848, 234.0732372
51+
59.49494949, 238.0364874
52+
60.50505051, 241.9935203
53+
61.51515152, 245.9439515
54+
62.52525253, 249.8877958
55+
63.53535354, 253.8250857
56+
64.54545455, 257.7558532
57+
65.55555556, 261.6800774
58+
66.56565657, 265.5967522
59+
67.57575758, 269.5040071
60+
68.58585859, 273.3999423
61+
69.5959596, 277.2826582
62+
70.60606061, 281.1502132
63+
71.61616162, 285.0000407
64+
72.62626263, 288.8290937
65+
73.63636364, 292.6343122
66+
74.64646465, 296.4126366
67+
75.65656566, 300.1609618
68+
76.66666667, 303.8756178
69+
77.67676768, 307.5525555
70+
78.68686869, 311.1877177
71+
79.6969697, 314.7770479
72+
80.70707071, 318.3162245
73+
81.71717172, 321.7981951
74+
82.72727273, 325.2142962
75+
83.73737374, 328.5558431
76+
84.74747475, 331.8141516
77+
85.75757576, 334.9809615
78+
86.76767677, 338.0517056
79+
87.77777778, 341.0237187
80+
88.78787879, 343.894351
81+
89.7979798, 346.6609528
82+
90.80808081, 349.3212988
83+
91.81818182, 351.8763
84+
92.82828283, 354.3282731
85+
93.83838384, 356.6795415
86+
94.84848485, 358.9324286
87+
95.85858586, 361.0891913
88+
96.86868687, 363.1516677
89+
97.87878788, 365.1215333
90+
98.88888889, 367.0004624
91+
99.8989899, 368.7901301
92+
100.9090909, 370.4922638
93+
101.9191919, 372.1088764
94+
102.9292929, 373.6420763
95+
103.9393939, 375.0939727
96+
104.9494949, 376.4666742
97+
105.959596, 377.7642106
98+
106.969697, 378.9995406
99+
107.979798, 380.1882157
100+
108.989899, 381.3457874
101+
110, 382.4878076

0 commit comments

Comments
 (0)