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
8 changes: 6 additions & 2 deletions pyaml/common/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,9 @@ class ElementConfigModel(BaseModel):
- [name]@idx[,idx] : Element indices in the subset formed by name.
- [name]#start_idx..end_idx : Element range in the subset formed by name.
In the above syntax, if the name is not specficied, the whole set
of lattice element is used for indexing.
of lattice element is used for indexing. ``name`` refers to the
``FamName`` of the lattice elements, or to the attribute configured
in the simulator linker when one is used.
"""

model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
Expand Down Expand Up @@ -260,7 +262,9 @@ class Element:
| ``[name]#start_idx..end_idx`` : Lattice element range in the subset formed by name.

In the above syntax, if the name is not specficied, the whole set
of lattice element is used for indexing.
of lattice element is used for indexing. ``name`` refers to the
``FamName`` of the lattice elements, or to the attribute configured
in the simulator linker when one is used.

description : str or None, optional
Human-readable element description.
Expand Down
18 changes: 17 additions & 1 deletion pyaml/lattice/attribute_linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,23 @@ def get_element_identifier(self, element: Element) -> LinkerIdentifier:
LinkerIdentifier
The identifier for linking the element
"""
return PyAtAttributeIdentifier(self.linker_config_model.attribute_name, element.get_name())
return self.get_identifier_for_name(element.get_name())

def get_identifier_for_name(self, name: str) -> LinkerIdentifier:
"""
Get the identifier for a name used in an element ``lattice_names`` selector.

Parameters
----------
name : str
Expected value of the configured attribute.

Returns
-------
LinkerIdentifier
The identifier matching the lattice elements whose attribute equals ``name``
"""
return PyAtAttributeIdentifier(self.linker_config_model.attribute_name, name)

def _test_at_element(self, identifier: PyAtAttributeIdentifier, element: at.Element) -> bool:
"""
Expand Down
27 changes: 27 additions & 0 deletions pyaml/lattice/lattice_elements_linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class LatticeElementsLinker(ABC):
Set the lattice for element linking.
get_element_identifier(element)
Get the identifier for linking an element.
get_identifier_for_name(name)
Get the identifier for a name given in an element ``lattice_names`` selector.
get_at_elements(element_id)
Return a list of PyAT elements matching the given identifiers.
get_at_element(element_id)
Expand Down Expand Up @@ -130,6 +132,31 @@ def get_element_identifier(self, element: Element) -> LinkerIdentifier:
"""
pass

def get_identifier_for_name(self, name: str) -> LinkerIdentifier:
"""
Get the identifier for a name used in an element ``lattice_names`` selector.

Called when a PyAML element selects its lattice elements explicitly
(``lattice_names: list(a,b)``, ``a@0,1`` or ``a#0..2``): each ``name`` of the
selector is resolved through the linker instead of the element name.

Parameters
----------
name : str
Name given in the ``lattice_names`` selector.

Returns
-------
LinkerIdentifier
The identifier matching the lattice element(s) designated by ``name``.

Raises
------
NotImplementedError
If the linker does not support ``lattice_names`` selectors.
"""
raise NotImplementedError(f"{self.__class__.__name__} does not support 'lattice_names' selectors")

def _iter_matches(self, identifier: LinkerIdentifier) -> Iterable[at.Element]:
"""
Yield all lattice elements matching ``identifier``.
Expand Down
33 changes: 28 additions & 5 deletions pyaml/lattice/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ def get_at_elems(self, element: Element) -> list[at.Element]:
"""
Resolve a PyAML element to matching PyAT lattice elements.

The ``lattice_names`` selector of the element is honoured with or without a
linker. With a linker, the names of the selector are resolved through
``linker.get_identifier_for_name`` (e.g. the configured attribute for
``pyaml.lattice.attribute_linker``) instead of ``FamName``; without a
selector the linker uses the element name.

Parameters
----------
element : Element
Expand All @@ -398,11 +404,28 @@ def get_at_elems(self, element: Element) -> list[at.Element]:
Matching Accelerator Toolbox lattice elements.
"""
if self._linker:
identifier = self._linker.get_element_identifier(element)
element_list = self._linker.get_at_elements(identifier)
if not element_list:
raise PyAMLException(f"{identifier} not found in lattice:{self._lattice}")
return element_list
if element.get_lattice_names() is None:
# By name
return self._linker.get_at_elements(self._linker.get_element_identifier(element))
# By list
nameList = self.get_names(element)
if nameList is not None:
identifiers = [self._linker.get_identifier_for_name(name) for name in nameList]
return self._linker.get_at_elements(identifiers)
# By name or indices
name, indices = self.get_indices(element)
if name is None:
# Direct indexing in the ring
return [self.ring[idx] for idx in indices]
elts = self._linker.get_at_elements(self._linker.get_identifier_for_name(name))
if indices is None:
return elts
try:
return [elts[idx] for idx in indices]
except IndexError as err:
strErr = f"{element.get_name()}: Invalid lattice_names index "
strErr += f"for {element.get_lattice_names()}, {len(elts)} element(s) found for {name}"
raise PyAMLException(strErr) from err
else:
# By list
nameList = self.get_names(element)
Expand Down
95 changes: 95 additions & 0 deletions tests/config/EBSNames-linker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
type: pyaml.accelerator
facility: ESRF
machine: sr
energy: 6e9
simulators:
- type: pyaml.lattice.simulator
lattice: sr/lattices/ebs-original-names.mat
name: design
linker:
type: pyaml.lattice.attribute_linker
attribute_name: FamName # equivalent to the default linker
controls:
- type: tango.pyaml.controlsystem
tango_host: ebs-simu-3:10000
name: live
catalog: catalogs/ebs_catalogs.yaml
data_folder: /data/store
devices:
- type: pyaml.magnet.quadrupole
name: QF1E
model:
type: pyaml.magnet.linear_model
calibration_factor: 1.00054
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c04-e/current
- type: pyaml.magnet.quadrupole
name: QF1E-ALL
lattice_names: list(QF1E,QF1I)
model:
type: pyaml.magnet.linear_model
calibration_factor: 1.00054
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c04-e/current
- type: pyaml.magnet.quadrupole
name: QF1E-C05
lattice_names: QF1E@1
model:
type: pyaml.magnet.linear_model
calibration_factor: 0.996841
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c05-a/current
- type: pyaml.magnet.quadrupole
name: QF1E-C04-C05-C06
lattice_names: QF1E@0,1,2
model:
type: pyaml.magnet.linear_model
calibration_factor: 1.00191
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c05-e/current
- type: pyaml.magnet.quadrupole
name: QF1E-C04-C05-C06-2
lattice_names: "@140,290,424"
model:
type: pyaml.magnet.linear_model
calibration_factor: 1.00191
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c05-e/current
- type: pyaml.magnet.quadrupole
name: QF1E-C04-C05-C06-3
lattice_names: QF1E#0..3
model:
type: pyaml.magnet.linear_model
calibration_factor: 1.00191
crosstalk: 1.0
curve:
type: pyaml.magnet.csvcurve
file: sr/magnet_models/QF1_strength.csv
unit: 1/m
hardware_unit: A
powerconverter: srmag/vps-qf1/c05-e/current
Loading
Loading