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
17 changes: 12 additions & 5 deletions pyaml/arrays/bpm_array.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ..common.abstract import ReadFloatArray
from ..bpm.bpm import BPM
from ..control.deviceaccesslist import DeviceAccessList
from ..common.exception import PyAMLException

import numpy as np

Expand Down Expand Up @@ -57,7 +58,7 @@ class BPMArray(list[BPM]):
Class that implements access to a BPM array
"""

def __init__(self,arrayName:str,bpms:list[BPM],holder = None):
def __init__(self,arrayName:str,bpms:list[BPM],use_aggregator = True):
"""
Construct a BPM array

Expand All @@ -66,17 +67,23 @@ def __init__(self,arrayName:str,bpms:list[BPM],holder = None):
arrayName : str
Array name
bpms: list[BPM]
BPM iterator
holder : Element holder
Holder (Simulator or Control System) that contains element of this array used for aggregator
BPM 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 access to underlying devices.
"""
super().__init__(i for i in bpms)
holder = bpms[0]._peer if len(bpms)>0 else None
if holder is None or any([m._peer!=holder for m in bpms]):
raise PyAMLException(f"BPMArray {arrayName} : All elements must be attached to the same instance of either a Simulator or a ControlSystem")

super().__init__(i for i in bpms)
self.__name = arrayName
self.__hvpos = RWBPMPosition(arrayName,bpms)
self.__hpos = RWBPMSinglePosition(arrayName,bpms,0)
self.__vpos = RWBPMSinglePosition(arrayName,bpms,1)

if holder is not None:
if use_aggregator:
aggs = holder.create_bpm_aggregators(bpms)
self.__hvpos.set_aggregator(aggs[0])
self.__hpos.set_aggregator(aggs[1])
Expand Down
16 changes: 11 additions & 5 deletions pyaml/arrays/magnet_array.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ..common.abstract import ReadWriteFloatArray
from ..magnet.magnet import Magnet
from ..common.abstract_aggregator import ScalarAggregator
from ..common.exception import PyAMLException

import numpy as np

Expand Down Expand Up @@ -81,7 +82,7 @@ class MagnetArray(list[Magnet]):
Class that implements access to a magnet array
"""

def __init__(self,arrayName:str,magnets:list[Magnet],holder = None):
def __init__(self,arrayName:str,magnets:list[Magnet],use_aggregator = True):
"""
Construct a magnet array

Expand All @@ -90,16 +91,21 @@ def __init__(self,arrayName:str,magnets:list[Magnet],holder = None):
arrayName : str
Array name
magnets: list[Magnet]
Magnet iterator
holder : Element holder
Holder (Simulator or Control System) that contains element of this array used for aggregator
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 access to underlying devices.
"""
super().__init__(i for i in magnets)
holder = magnets[0]._peer if len(magnets)>0 else None
if holder is None or any([m._peer!=holder for m in magnets]):
raise PyAMLException(f"MagnetArray {arrayName} : All elements must be attached to the same instance of either a Simulator or a ControlSystem")

self.__name = arrayName
self.__rwstrengths = RWMagnetStrength(arrayName,magnets)
self.__rwhardwares = RWMagnetHardware(arrayName,magnets)

if holder is not None:
if use_aggregator:
aggs = holder.create_magnet_strength_aggregator(magnets)
aggh = holder.create_magnet_harddware_aggregator(magnets)
self.__rwstrengths.set_aggregator(aggs)
Expand Down
7 changes: 4 additions & 3 deletions pyaml/bpm/bpm.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..lattice.element import Element, ElementConfigModel
from ..common.element import Element, ElementConfigModel
from ..lattice.abstract_impl import RBpmArray, RWBpmOffsetArray, RWBpmTiltScalar
from ..bpm.bpm_model import BPMModel
from ..common.exception import PyAMLException
Expand Down Expand Up @@ -63,7 +63,7 @@ def tilt(self) -> RWBpmTiltScalar:
raise PyAMLException(f"{str(self)} has no attached tilt")
return self.__tilt

def attach(self, positions: RBpmArray , offset: RWBpmOffsetArray,
def attach(self, peer, positions: RBpmArray , offset: RWBpmOffsetArray,
tilt: RWBpmTiltScalar) -> Self:
# Attach positions, offset and tilt attributes and returns a new
# reference
Expand All @@ -72,5 +72,6 @@ def attach(self, positions: RBpmArray , offset: RWBpmOffsetArray,
obj.__positions = positions
obj.__offset = offset
obj.__tilt = tilt
obj._peer = peer
return obj


6 changes: 6 additions & 0 deletions pyaml/bpm/bpm_simple_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from pydantic import BaseModel,ConfigDict
import numpy as np
from ..control.deviceaccess import DeviceAccess
from ..common.element import __pyaml_repr__

from numpy.typing import NDArray
# Define the main class name for this module
PYAMLCLASS = "BPMSimpleModel"
Expand Down Expand Up @@ -113,3 +115,7 @@ def get_offset_devices(self) -> list[DeviceAccess]:
Array of DeviceAcess
"""
return []

def __repr__(self):
return __pyaml_repr__(self)

5 changes: 5 additions & 0 deletions pyaml/bpm/bpm_tiltoffset_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from pydantic import BaseModel,ConfigDict
import numpy as np
from ..control.deviceaccess import DeviceAccess
from ..common.element import __pyaml_repr__

from numpy.typing import NDArray
# Define the main class name for this module
PYAMLCLASS = "BPMTiltOffsetModel"
Expand Down Expand Up @@ -113,3 +115,6 @@ def get_offset_devices(self) -> list[DeviceAccess]:
Array of DeviceAcess
"""
return [self.__x_offset,self.__y_offset]

def __repr__(self):
return __pyaml_repr__(self)
69 changes: 69 additions & 0 deletions pyaml/common/element.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from .exception import PyAMLException

from pydantic import BaseModel,ConfigDict


def __pyaml_repr__(obj):
"""
Returns a string representation of a pyaml object
"""
if hasattr(obj,"_cfg"):
if isinstance(obj,Element):
return repr(obj._cfg).replace("ConfigModel(",obj.__class__.__name__ + "(peer='" + obj.get_peer() + "', ")
else:
# no peer
return repr(obj._cfg).replace("ConfigModel",obj.__class__.__name__ )
else:
# Default to repr
return repr(obj)

class ElementConfigModel(BaseModel):

model_config = ConfigDict(arbitrary_types_allowed=True,extra="forbid")

name : str
"""Element name"""

class Element(object):
"""
Class providing access to one element of a physical or simulated lattice

Attributes:
name: str
The unique name identifying the element in the configuration file
"""
def __init__(self,name:str):
self.__name: str = name
self._peer = None # Peer: ControlSystem, Simulator

def get_name(self):
"""
Returns the name of the element
"""
return self.__name

def set_energy(self,E:float):
"""
Set the instrument energy on this element
"""
pass

def check_peer(self):
"""
Throws an exception if the element is not attacched to a simulator or to a control system
"""
if self._peer is None:
raise PyAMLException(f"{str(self)} is not attached to a control system or the a simulator")

def get_peer(self) -> str:
"""
Returns a string representation of peer simulator or control system
"""
return "None" if self._peer is None else f"{self._peer.__class__.__name__}:{self._peer.name()}"

def __repr__(self):
return __pyaml_repr__(self)




19 changes: 8 additions & 11 deletions pyaml/common/element_holder.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""
Module handling element references for simulators and control system
"""
from ..lattice.element import Element
from .element import Element
from ..magnet.magnet import Magnet
from ..rf.rf_plant import RFPlant
from ..rf.rf_transmitter import RFTransmitter
from ..arrays.magnet_array import MagnetArray
from ..arrays.bpm_array import BPMArray
from ..common.exception import PyAMLException
from ..diagnostics.tune_monitor import BetatronTuneMonitor

class ElementHolder(object):
"""
Expand Down Expand Up @@ -53,6 +54,9 @@ def get_magnet(self,name:str) -> Magnet:
return self.__MAGNETS[name]

def add_magnet(self,name:str,m:Magnet):
if name in self.__MAGNETS:
print(self.__MAGNETS)
raise PyAMLException(f"Duplicate magnet name {name}") from None
self.__MAGNETS[name] = m

def get_magnets(self,name:str) -> MagnetArray:
Expand Down Expand Up @@ -104,17 +108,10 @@ def get_rf_trasnmitter(self,name:str) -> RFTransmitter:
raise PyAMLException(f"RFTransmitter {name} not defined")
return self.__RFTRANSMITTER[name]



def get_bpm(self,name:str) -> Element:
if name not in self.__BPMS:
raise Exception(f"BPM {name} not defined")
return self.__BPMS[name]

def add_bpm(self,name:str,bpm:Element):
self.__BPMS[name] = bpm

def get_betatron_tune_monitor(self, name:str) -> Element:
# Tune monitor

def get_betatron_tune_monitor(self, name:str) -> BetatronTuneMonitor:
if name not in self.__DIAG:
raise Exception(f"Diagnostic devices array does not contain {name}")
return self.__DIAG[name]
Expand Down
3 changes: 3 additions & 0 deletions pyaml/configuration/csvcurve.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ def __init__(self, cfg: ConfigModel):

def get_curve(self) -> np.array:
return self._curve

def __repr__(self):
return repr(self._cfg).replace("ConfigModel",self.__class__.__name__)
3 changes: 3 additions & 0 deletions pyaml/configuration/csvmatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ def __init__(self, cfg: ConfigModel):

def get_matrix(self) -> np.array:
return self._mat

def __repr__(self):
return repr(self._cfg).replace("ConfigModel",self.__class__.__name__)
3 changes: 2 additions & 1 deletion pyaml/configuration/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from threading import Lock

from ..common.exception import PyAMLConfigException
from ..lattice.element import Element
from ..common.element import Element
from pydantic import ValidationError

class BuildStrategy:
Expand Down Expand Up @@ -154,6 +154,7 @@ def register_element(self, elt):
if isinstance(elt,Element):
name = elt.get_name()
if name in self._elements:
print(self._elements)
raise PyAMLConfigException(f"element {name} already defined")
self._elements[name] = elt

Expand Down
2 changes: 1 addition & 1 deletion pyaml/control/abstract_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def unit(self) -> str:

#------------------------------------------------------------------------------

class RBetatronTuneArray(abstract.ReadFloatScalar):
class RBetatronTuneArray(abstract.ReadFloatArray):
"""
Class providing read write access to betatron tune of a control system.
"""
Expand Down
16 changes: 9 additions & 7 deletions pyaml/control/controlsystem.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABCMeta, abstractmethod
from ..common.element_holder import ElementHolder
from ..common.abstract import RWMapper
from ..lattice.element import Element
from ..common.element import Element
from ..control.abstract_impl import RWHardwareScalar,RWHardwareArray,RWStrengthScalar,RWStrengthArray
from ..bpm.bpm import BPM
from ..diagnostics.tune_monitor import BetatronTuneMonitor
Expand Down Expand Up @@ -103,22 +103,23 @@ def fill_device(self,elements:list[Element]):
current = RWHardwareScalar(e.model) if e.model.has_hardware() else None
strength = RWStrengthScalar(e.model) if e.model.has_physics() else None
# Create a unique ref for this control system
m = e.attach(strength, current)
m = e.attach(self,strength, current)
self.add_magnet(m.get_name(),m)

elif isinstance(e,CombinedFunctionMagnet):
self.add_magnet(e.get_name(),e)
currents = RWHardwareArray(e.model) if e.model.has_hardware() else None
strengths = RWStrengthArray(e.model) if e.model.has_physics() else None
# Create unique refs of each function for this control system
ms = e.attach(strengths,currents)
ms = e.attach(self,strengths,currents)
for m in ms:
self.add_magnet(m.get_name(),m)

elif isinstance(e,BPM):
tilt = RWBpmTiltScalar(e.model)
offsets = RWBpmOffsetArray(e.model)
positions = RBpmArray(e.model)
e = e.attach(positions, offsets, tilt)
e = e.attach(self,positions, offsets, tilt)
self.add_bpm(e.get_name(),e)


Expand All @@ -128,15 +129,16 @@ def fill_device(self,elements:list[Element]):
for t in e._cfg.transmitters:
voltage = RWRFVoltageScalar(t)
phase = RWRFPhaseScalar(t)
nt = t.attach(voltage,phase)
nt = t.attach(self,voltage,phase)
self.add_rf_transnmitter(nt.get_name(),nt)
attachedTrans.append(nt)

frequency = RWRFFrequencyScalar(e)
voltage = RWTotalVoltage(attachedTrans)
ne = e.attach(frequency,voltage)
ne = e.attach(self,frequency,voltage)
self.add_rf_plant(ne.get_name(),ne)

elif isinstance(e,BetatronTuneMonitor):
betatron_tune = RBetatronTuneArray(e)
e = e.attach(betatron_tune)
e = e.attach(self,betatron_tune)
self.add_betatron_tune_monitor(e.get_name(), e)
15 changes: 8 additions & 7 deletions pyaml/diagnostics/tune_monitor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

from ..lattice.element import Element, ElementConfigModel
from ..lattice.abstract_impl import RBetatronTuneArray
from ..common.element import Element, ElementConfigModel
from ..common.abstract import ReadFloatArray
from ..control.deviceaccess import DeviceAccess

from typing import Self
from pydantic import ConfigDict

Expand Down Expand Up @@ -37,12 +37,13 @@ def __init__(self, cfg: ConfigModel):
self.__tune = None

@property
def tune(self) -> RBetatronTuneArray:
def tune(self) -> ReadFloatArray:
self.check_peer()
return self.__tune

def attach(self, betatron_tune: RBetatronTuneArray) -> Self:

def attach(self, peer, betatron_tune: ReadFloatArray) -> Self:
obj = self.__class__(self._cfg)
obj.__tune = betatron_tune
obj._peer = peer
return obj

2 changes: 1 addition & 1 deletion pyaml/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""

from .control.controlsystem import ControlSystem
from .lattice.element import Element
from .common.element import Element
from .lattice.simulator import Simulator
from .arrays.array import ArrayConfig
from pydantic import BaseModel,ConfigDict
Expand Down
Loading
Loading