Description, motivation and use case
So far, CFM mapping keys such as B0, A0, B1, etc. are hardcoded to specific magnet classes. Each class defines its own PolynomInfo, which links the virtual magnet to a fixed AT polynomial attribute and coefficient index.
This makes the AT polynomial linking rigid. For example, pyAML cannot directly target KickAngle, and the current mapping does not support polynomial coefficient indexes above 3.
This limitation mainly affects simulator/design usage, where pyAML must read from and write to AT lattice attributes. Live control-system access remains driven by the configured model/backend/catalogue devices.
Proposed solution
Parse the CFM mapping key to retrieve the target AT attribute and index to write to. The mapping should support at least PolynomA, PolynomB, and KickAngle targets.
The existing H and V correctors should be updated by implementing a RWCorrectorStrength mirroring the RWCorrectorAngle so they can target either the current polynomial coefficient representation or the AT KickAngle attribute while preserving the same public behavior.
To manage indexes > 3, a new generic magnet type should be created and all other magnet classes should inherit from it to avoid code duplication. They would become empty classes, just for typing.
class GenericMagnetConfigModel(MagnetConfigModel):
polynom_name: str
polynom_index: int | str # For KickAngle, H/V aliases could map to 0/1.
class GenericMagnet(Magnet):
def __init__(self, cfg: GenericMagnetConfigModel):
super().__init__(cfg.name, cfg.model if hasattr(cfg, "model") else None)
if isinstance(cfg.polynom_index, str):
if cfg.polynom_index in ["H", "V"]:
index = 0 if cfg.polynom_index == "H" else 1
else:
raise PyAMLException(f"Unsupported polynomial index alias: {cfg.polynom_index}")
else:
index = cfg.polynom_index
self.polynom = PolynomInfo(cfg.polynom_name, index)
self._cfg = cfg
class SextupoleConfigModel(MagnetConfigModel):
"""Configuration model for Sextupole magnet."""
...
class Sextupole(GenericMagnet):
def __init__(self, cfg: SextupoleConfigModel):
super().__init__(
GenericMagnetConfigModel(
name=cfg.name,
model=cfg.model,
polynom_name="PolynomB",
polynom_index=2,
)
)
Also, the duplication of the multipole list in cfm_magnet and its model should be removed. The units can be moved to the CFM and it will initialize the model with its data (multipole list)
The existing configuration files will have to be updated for the CFM part only.
The final mapping syntax is intentionally left open and should be defined with the people involved in this topic. The examples below are proposals meant to support the discussion, not final API decisions.
Note: the usage of indexes above 3 may only be used for development purposes on the design part. Nevertheless, it should be possible.
Describe alternatives you've considered
Keep the current implementation and just add KickAngleH and KickAngleV in the mapping as aliases to HCorrector and VCorrector with the new RWCorrectorStrength.
It does not cover the case of indexes > 3 and it is not as flexible.
Another way to achieve it would be to create a small grammar similar to the one used to point indexes for backends devices: PolynomA@0, KickAngle@1, ...
So the PyAt attribute is also retrieved from user input. It adds some complexity though, and it is less readable.
Example
- type: pyaml.magnet.cfm_magnet
name: SJ2A-C04
mapping:
- [KickAngleH, SJ2A-C04-H]
- [KickAngleV, SJ2A-C04-V]
units: [rad, rad]
model:
type: pyaml.magnet.identity_cfm_model
physics:
- srmag/m-sf2/c04-a/Strength_H
- srmag/m-sf2/c04-a/Strength_V
- type: pyaml.magnet.cfm_magnet
name: SH1_COR_001
mapping:
- [B2, SH1_COR_001.sextupole]
- [B0, SH1_COR_001.hcorrector]
- [A0, SH1_COR_001.vcorrector]
- [A4, SH1_COR_001.4]
- [A5, SH1_COR_001.5]
units: [1/m**2, '1', '1', '1', '1']
model:
type: pyaml.magnet.identity_cfm_model
physics:
- AN01-AR/EM-SX/SHF.01/strength
- AN01-AR/EM-COR/SHF.01-CDLH.01/strength
- AN01-AR/EM-COR/SHF.01-CDLV.01/strength
- AN01-AR/EM-COR/SHF.01-CDL4.01/strength
- AN01-AR/EM-COR/SHF.01-CDL5.01/strength
- type: pyaml.magnet.generic_magnet
name: B_011
polynom_name: PolynomB
polynom_index: 0
model:
type: pyaml.magnet.identity_model
unit: 1
physics: AN06-AR/EM-DIP/B.01
Additional context
The CFM refurbishment and the polynomial mapping can be treated into two sub-issues. Since the two subjects are strongly linked together, it can be done in one. This still needs to be defined.
Checklist
Description, motivation and use case
So far, CFM mapping keys such as
B0,A0,B1, etc. are hardcoded to specific magnet classes. Each class defines its ownPolynomInfo, which links the virtual magnet to a fixed AT polynomial attribute and coefficient index.This makes the AT polynomial linking rigid. For example, pyAML cannot directly target
KickAngle, and the current mapping does not support polynomial coefficient indexes above 3.This limitation mainly affects simulator/design usage, where pyAML must read from and write to AT lattice attributes. Live control-system access remains driven by the configured model/backend/catalogue devices.
Proposed solution
Parse the CFM mapping key to retrieve the target AT attribute and index to write to. The mapping should support at least
PolynomA,PolynomB, andKickAngletargets.The existing H and V correctors should be updated by implementing a
RWCorrectorStrengthmirroring theRWCorrectorAngleso they can target either the current polynomial coefficient representation or the ATKickAngleattribute while preserving the same public behavior.To manage indexes > 3, a new generic magnet type should be created and all other magnet classes should inherit from it to avoid code duplication. They would become empty classes, just for typing.
Also, the duplication of the multipole list in cfm_magnet and its model should be removed. The units can be moved to the CFM and it will initialize the model with its data (multipole list)
The existing configuration files will have to be updated for the CFM part only.
The final mapping syntax is intentionally left open and should be defined with the people involved in this topic. The examples below are proposals meant to support the discussion, not final API decisions.
Note: the usage of indexes above 3 may only be used for development purposes on the design part. Nevertheless, it should be possible.
Describe alternatives you've considered
Keep the current implementation and just add KickAngleH and KickAngleV in the mapping as aliases to HCorrector and VCorrector with the new
RWCorrectorStrength.It does not cover the case of indexes > 3 and it is not as flexible.
Another way to achieve it would be to create a small grammar similar to the one used to point indexes for backends devices: PolynomA@0, KickAngle@1, ...
So the PyAt attribute is also retrieved from user input. It adds some complexity though, and it is less readable.
Example
Additional context
The CFM refurbishment and the polynomial mapping can be treated into two sub-issues. Since the two subjects are strongly linked together, it can be done in one. This still needs to be defined.
Checklist