Skip to content

Commit 526615d

Browse files
authored
Merge pull request #57 from python-accelerator-middle-layer/add-element-array
Add element array
2 parents cc9a30d + 1011bd9 commit 526615d

22 files changed

Lines changed: 731 additions & 187 deletions

pyaml/arrays/bpm_array.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from ..common.abstract import ReadFloatArray
22
from ..bpm.bpm import BPM
33
from ..control.deviceaccesslist import DeviceAccessList
4-
from ..common.exception import PyAMLException
4+
from .element_array import get_peer_from_array
55

66
import numpy as np
77

@@ -72,13 +72,10 @@ def __init__(self,arrayName:str,bpms:list[BPM],use_aggregator = True):
7272
use_aggregator : bool
7373
Use aggregator to increase performance by using paralell access to underlying devices.
7474
"""
75-
super().__init__(i for i in bpms)
76-
holder = bpms[0]._peer if len(bpms)>0 else None
77-
if holder is None or any([m._peer!=holder for m in bpms]):
78-
raise PyAMLException(f"BPMArray {arrayName} : All elements must be attached to the same instance of either a Simulator or a ControlSystem")
79-
8075
super().__init__(i for i in bpms)
8176
self.__name = arrayName
77+
holder = get_peer_from_array(self)
78+
8279
self.__hvpos = RWBPMPosition(arrayName,bpms)
8380
self.__hpos = RWBPMSinglePosition(arrayName,bpms,0)
8481
self.__vpos = RWBPMSinglePosition(arrayName,bpms,1)
@@ -89,6 +86,9 @@ def __init__(self,arrayName:str,bpms:list[BPM],use_aggregator = True):
8986
self.__hpos.set_aggregator(aggs[1])
9087
self.__vpos.set_aggregator(aggs[2])
9188

89+
def get_name(self) -> str:
90+
return self.__name
91+
9292
@property
9393
def positions(self) -> RWBPMPosition:
9494
"""

pyaml/arrays/cfm_magnet.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from .array import ArrayConfigModel,ArrayConfig
2+
from ..common.element_holder import ElementHolder
3+
4+
# Define the main class name for this module
5+
PYAMLCLASS = "CombinedFunctionMagnet"
6+
7+
class ConfigModel(ArrayConfigModel):...
8+
9+
class CombinedFunctionMagnet(ArrayConfig):
10+
11+
def __init__(self, cfg: ArrayConfigModel):
12+
super().__init__(cfg)
13+
14+
def fill_array(self,holder:ElementHolder):
15+
holder.fill_cfm_magnet_array(self._cfg.name,self._cfg.elements)

pyaml/arrays/cfm_magnet_array.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from ..common.abstract import ReadWriteFloatArray
2+
from ..magnet.cfm_magnet import CombinedFunctionMagnet
3+
from .element_array import get_peer_from_array
4+
import numpy as np
5+
6+
#TODO handle aggregator for CFM
7+
8+
class RWMagnetStrengths(ReadWriteFloatArray):
9+
10+
def __init__(self, name:str, magnets:list[CombinedFunctionMagnet]):
11+
self.__name = name
12+
self.__magnets = magnets
13+
self.__nb = sum(m.nb_multipole() for m in magnets)
14+
15+
# Gets the values
16+
def get(self) -> np.array:
17+
r = np.zeros(self.__nb)
18+
idx = 0
19+
for m in self.__magnets:
20+
r[idx:idx+m.nb_multipole()] = m.strengths.get()
21+
idx+=m.nb_multipole()
22+
return r
23+
24+
# Sets the values
25+
def set(self, value:np.array):
26+
nvalue = np.ones(self.__nb) * value if isinstance(value,float) else value
27+
idx = 0
28+
for m in self.__magnets:
29+
m.strengths.set(nvalue[idx:idx+m.nb_multipole()])
30+
idx+=m.nb_multipole()
31+
32+
# Sets the values and waits that the read values reach their setpoint
33+
def set_and_wait(self, value:np.array):
34+
raise NotImplementedError("Not implemented yet.")
35+
36+
# Gets the unit of the values
37+
def unit(self) -> list[str]:
38+
r = []
39+
for m in self.__magnets:
40+
r.extend(m.strengths.unit())
41+
return r
42+
43+
class RWMagnetHardwares(ReadWriteFloatArray):
44+
45+
def __init__(self, name:str, magnets:list[CombinedFunctionMagnet]):
46+
self.__name = name
47+
self.__magnets = magnets
48+
self.__nb = sum(m.nb_multipole() for m in magnets)
49+
50+
# Gets the values
51+
def get(self) -> np.array:
52+
r = np.zeros(self.__nb)
53+
idx = 0
54+
for m in self.__magnets:
55+
r[idx:idx+m.nb_multipole()] = m.hardwares.get()
56+
idx+=m.nb_multipole()
57+
return r
58+
59+
# Sets the values
60+
def set(self, value:np.array):
61+
nvalue = np.ones(self.__nb) * value if isinstance(value,float) else value
62+
idx = 0
63+
for m in self.__magnets:
64+
m.hardwares.set(nvalue[idx:idx+m.nb_multipole()])
65+
idx+=m.nb_multipole()
66+
67+
# Sets the values and waits that the read values reach their setpoint
68+
def set_and_wait(self, value:np.array):
69+
raise NotImplementedError("Not implemented yet.")
70+
71+
# Gets the unit of the values
72+
def unit(self) -> list[str]:
73+
r = []
74+
for m in self.__magnets:
75+
r.extend(m.hardwares.unit())
76+
return r
77+
78+
79+
class CombinedFunctionMagnetArray(list[CombinedFunctionMagnet]):
80+
"""
81+
Class that implements access to a magnet array
82+
"""
83+
84+
def __init__(self,arrayName:str,magnets:list[CombinedFunctionMagnet],use_aggregator = False):
85+
"""
86+
Construct a magnet array
87+
88+
Parameters
89+
----------
90+
arrayName : str
91+
Array name
92+
magnets: list[Magnet]
93+
Magnet list, all elements must be attached to the same instance of
94+
either a Simulator or a ControlSystem.
95+
use_aggregator : bool
96+
Use aggregator to increase performance by using paralell access to underlying devices.
97+
"""
98+
super().__init__(i for i in magnets)
99+
self.__name = arrayName
100+
holder = get_peer_from_array(self)
101+
102+
self.__rwstrengths = RWMagnetStrengths(arrayName,magnets)
103+
self.__rwhardwares = RWMagnetHardwares(arrayName,magnets)
104+
105+
if use_aggregator:
106+
raise("Aggregator not implemented for CombinedFunctionMagnetArray")
107+
108+
def get_name(self) -> str:
109+
return self.__name
110+
111+
@property
112+
def strengths(self) -> RWMagnetStrengths:
113+
"""
114+
Give access to strength of each magnet of this array
115+
"""
116+
return self.__rwstrengths
117+
118+
@property
119+
def hardwares(self) -> RWMagnetHardwares:
120+
"""
121+
Give access to hardware value of each magnet of this array
122+
"""
123+
return self.__rwhardwares
124+
125+
126+
127+
128+
129+

pyaml/arrays/element.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from .array import ArrayConfigModel,ArrayConfig
2+
from ..common.element_holder import ElementHolder
3+
4+
# Define the main class name for this module
5+
PYAMLCLASS = "Element"
6+
7+
class ConfigModel(ArrayConfigModel):...
8+
9+
class Element(ArrayConfig):
10+
11+
def __init__(self, cfg: ArrayConfigModel):
12+
super().__init__(cfg)
13+
14+
def fill_array(self,holder:ElementHolder):
15+
holder.fill_element_array(self._cfg.name,self._cfg.elements)

pyaml/arrays/element_array.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from ..common.element import Element
2+
from ..common.exception import PyAMLException
3+
4+
def get_peer_from_array(array):
5+
"""
6+
Returns the peer (Simulator or ControlSystem) of an element list
7+
"""
8+
peer = array[0]._peer if len(array)>0 else None
9+
if peer is None or any([m._peer!=peer for m in array]):
10+
raise PyAMLException(f"{array.__class__.__name__} {array.get_name()}: All elements must be attached to the same instance of either a Simulator or a ControlSystem")
11+
return peer
12+
13+
class ElementArray(list[Element]):
14+
"""
15+
Class that implements access to a magnet array
16+
"""
17+
18+
def __init__(self,arrayName:str,elements:list[Element]):
19+
"""
20+
Construct an element array
21+
22+
Parameters
23+
----------
24+
arrayName : str
25+
Array name
26+
elements: list[Element]
27+
Element list, all elements must be attached to the same instance of
28+
either a Simulator or a ControlSystem.
29+
"""
30+
super().__init__(i for i in elements)
31+
self.__name = arrayName
32+
holder = get_peer_from_array(self)
33+
self.__name = arrayName
34+
35+
def get_name(self) -> str:
36+
return self.__name
37+
38+
def names(self) -> list[str]:
39+
return [e.get_name() for e in self]
40+
41+
42+
43+
44+
45+

pyaml/arrays/magnet_array.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
from ..common.abstract import ReadWriteFloatArray
22
from ..magnet.magnet import Magnet
33
from ..common.abstract_aggregator import ScalarAggregator
4-
from ..common.exception import PyAMLException
5-
4+
from .element_array import get_peer_from_array
65
import numpy as np
76

87
class RWMagnetStrength(ReadWriteFloatArray):
@@ -97,11 +96,9 @@ def __init__(self,arrayName:str,magnets:list[Magnet],use_aggregator = True):
9796
Use aggregator to increase performance by using paralell access to underlying devices.
9897
"""
9998
super().__init__(i for i in magnets)
100-
holder = magnets[0]._peer if len(magnets)>0 else None
101-
if holder is None or any([m._peer!=holder for m in magnets]):
102-
raise PyAMLException(f"MagnetArray {arrayName} : All elements must be attached to the same instance of either a Simulator or a ControlSystem")
103-
10499
self.__name = arrayName
100+
holder = get_peer_from_array(self)
101+
105102
self.__rwstrengths = RWMagnetStrength(arrayName,magnets)
106103
self.__rwhardwares = RWMagnetHardware(arrayName,magnets)
107104

@@ -111,6 +108,9 @@ def __init__(self,arrayName:str,magnets:list[Magnet],use_aggregator = True):
111108
self.__rwstrengths.set_aggregator(aggs)
112109
self.__rwhardwares.set_aggregator(aggh)
113110

111+
def get_name(self) -> str:
112+
return self.__name
113+
114114
@property
115115
def strengths(self) -> RWMagnetStrength:
116116
"""

0 commit comments

Comments
 (0)