Repository navigation
Conversation
CorrectorPass integrates KickAngle and ignores PolynomA/PolynomB, so a strength set on an at.Corrector element round-tripped through the accessor but never moved the orbit. The simulator accessors now address the dipole component of such an element through KickAngle, keeping a polynom the element carries in step with it. Correctors defined without polynoms are supported, and a kick already present in the lattice is read back. Tests compare the closed orbit against a KickAngle reference.
The multipole pass methods add KickAngle to the polynom. An element that carries one read back only its polynom part, and a write added to the kick instead of replacing it. The accessors now read the sum and, on a write, store the value in the polynom and reset the KickAngle component. A KickAngle on a pass method that ignores it is not read.
|
@thellert Thanks for the contribution. Normally, we've discussed limiting pyAML elements to PolynomA/PolynomB, no kick angle, as the maintaining lab of AT is not using KickAngles much. But I think now there's enough demand to also have KickAngle in pyAML. So, this is a good addition. |
|
I think here you need to test also if it works with a combined function magnet, having a sextupole with dipolar correctors as KickAngles. I think @gupichon did something similar a while ago, but maybe it was never merged. |
|
Thank for the contribution. |
Description
AT keeps the dipole kick of an element in the polynom and in
KickAngle; the simulator's magnet accessors read and write the polynom only. As a result a strength set on aCorrectorPasselement never reaches the beam, and aKickAnglecarried by a multipole element is not read and is doubled by a write. Details, measurements and a script are in the issue.Related Issue
Features/issues described there are:
pyaml/lattice/abstract_impl.py(_KickAngleCoefficients) presents the dipole strength of an element that carries aKickAngleas a single polynom coefficient. The scalar and array accessors use it wherever they looked up the polynom, so their arithmetic is unchanged. This keeps the fix in one place instead of branching in each accessor.Changes to existing functionality
CorrectorPasselements: the strength is written to and read fromKickAngle(PolynomB[0] * L = -KickAngle[0],PolynomA[0] * L = KickAngle[1]), because that pass method ignores the polynoms. A polynom the element carries is kept in step, so the existing accessor tests hold unchanged.at.Correctorelements defined withoutPolynomA/Bnow work; building the accessor raisedAttributeError.KickAngle(ThinMPolePass,StrMPole*,BndMPole*,ExactMultipole*): the strength reads polynom +KickAngle; a write stores the value in the polynom and resets that plane'sKickAngle, so it is not applied twice. This changes an attribute of the user's lattice on write — the alternative is to keepKickAngleand store the difference in the polynom; say which you prefer.KickAngle, or whose pass method ignores it (QuadLinearPass,DriftPass), are untouched.Testing
The following tests (compatible with pytest) were added to
tests/lattice/test_magnet_accessors.py; each compares the closed orbit of a small ring against aKickAnglereference:test_corrector_pass_strength_moves_the_orbit— thin and thickCorrectorPass, both planestest_corrector_pass_without_polynoms_is_supportedtest_corrector_pass_reads_the_kick_of_the_latticetest_corrector_pass_combined_function_strengths_move_the_orbit— strength and hardware arraystest_split_corrector_pass_shares_the_kick_by_lengthtest_multipole_corrector_agrees_with_corrector_passtest_multipole_kick_angle_is_part_of_the_strength— thin multipole, multipole, dipoletest_kick_angle_ignored_by_the_pass_method_is_not_readThe orbit tests fail on
mainand pass here.Verify that your checklist complies with the project
tests/tuning_tools/test_tune_hardware.py::test_tune(4.1e-8 against a 1e-8 tolerance), which fails with the same value on unmodifiedmainon my machine (macOS, Python 3.12, AT 0.8.0)