You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SerializedMagnets: get/set are not consitent and design/live disagree #461
Serialized magnets (N magnets on one power supply: pyaml.magnet.serialized_magnet + LinearSerializedMagnetModel) do not follow one consistent convention. Depending on the accessor and the mode, a value means one magnet, the sum over the family, or the family total split by magnet length. As a result:
x.set(x.get()) changes the machine for several accessors, including writing N × the current to the power supply in live
the same call gives different results in design and live, often by a factor N.
This was found during a control-room test at SOLEIL. The S9 family (16 sextupoles, one PS) read family.hardware.get() == -3512 A while the PS showed −219 A.
This issue assume that the #458 issue is fixed by #460
Proposed behavior
We need to agree on what the different accessors should do for serialized magnets.
Serialized magnets have a single degree of freedom, the PS current I. Magnet i has strength k_i = f_i(I), where f_i is sub-model i.
Accessor
get()
set(x)
family.hardware
I
write I = x
family.strength
total integrated strength S = Σ f_i(I)
solve Σ f_i(I) = x for one I, write it
magnet[i].hardware
I
write I = x (all magnets follow)
magnet[i].strength
k_i = f_i(I)
write I = f_i⁻¹(x); the others follow as f_j(I). No length weighting.
I agree except on the family.strength. I don't see any use-case for the total integrated strength.
Typically, all magnets that are serialized are the same type of magnets so they share the I = f(x) relation. There it would make sense for family.strength to return the strength that is equal to all magnets.
For the funky case where the magnets don't have the same length, controlling by strength sounds awkward to me.
Perhaps a compromise could be to have family.strength equal to average strength S = Σ f_i(I) / N ?
Then at least in the typical case, family.strength falls back to the strength that is equal to all magnets.
The same follows for its set logic, solve Σ f_i(I) / N = x for one I, write it
I don't think it is guaranteed that I = f(x) is the same for shared magnets? I think there are labs which measure all magnets and have a separate excitation curve per magnet despite that they are powered in series.
I like the idea to have family.strength return the average strength. Then if you want to know the strength of the individual magnet you need to do magnet.strength instead.
I don't think it is guaranteed that I = f(x) is the same for shared magnets? I think there are labs which measure all magnets and have a separate excitation curve per magnet despite that they are powered in series.
You are right, then I = f(x) is still approximately correct. I would still think that S = Σ f_i(I) / N is sensible in that case.
I don't think it is guaranteed that I = f(x) is the same for shared magnets? I think there are labs which measure all magnets and have a separate excitation curve per magnet despite that they are powered in series.
You are right, then I = f(x) is still approximately correct. I would still think that S = Σ f_i(I) / N is sensible in that case.
I agree. Then you can use get and set on the family level to set the average and if you care about the individual strengths you can still read them on the magnet level. And if you at some point in the future buy more power supplies and start to split up families the values will not change much. You just gain the freedom to being able to control the individual strengths and not just read them.
Returning the total integrated strength I don't really understand. That doesn't sound to me like a useful parameter?
I agree with you both, it make sense to go this way. The table is now:
Accessor
get()
set(x)
family.hardware
I
write I = x
family.strength
average strength S = Σ f_i(I) / N
solve Σ f_i(I) / N = x for one I, write it
magnet[i].hardware
I
write I = x (all magnets follow)
magnet[i].strength
k_i = f_i(I)
write I = f_i⁻¹(x); the others follow as f_j(I). No length weighting.
From this definition, do we agree that tuning tools should use the family, not the individual magnets?
Should we provide an accessor to the total integrated strength? It would avoid having to do family.strength * len(magnets_inside_fam) and would make clear that family.strength is actually the average strength.
From this definition, do we agree that tuning tools should use the family, not the individual magnets?
I think this is important and I agree but it is not a simple matter.
From the point of view of configuration, the most straightforward way would be to use arrays. I am not fully up to date with how arrays work. Maybe it is already possible, but I believe it may be ok if an array can contain both individually-powered devices and a serialized family. (Here I mean that set/get of strength/hardware can be done on the array.)
For example, imagine that to control the tune, you are using 8 different power converters attached to 8 quadrupole families. It should be possible to have a configuration that is not more complex than this one:
From this definition, do we agree that tuning tools should use the family, not the individual magnets?
I think this is important and I agree but it is not a simple matter.
From the point of view of configuration, the most straightforward way would be to use arrays. I am not fully up to date with how arrays work. Maybe it is already possible, but I believe it may be ok if an array can contain both individually-powered devices and a serialized family. (Here I mean that set/get of strength/hardware can be done on the array.)
For example, imagine that to control the tune, you are using 8 different power converters attached to 8 quadrupole families. It should be possible to have a configuration that is not more complex than this one:
I thought the specification was that arrays and elements should provide the same interface? So if the tuning tool makes get and set it doesn't matter if it's on an array or an element? It doesn't really make sense to me that you need to make arrays that just contain a single element if all your magnets are individually powered.
From this definition, do we agree that tuning tools should use the family, not the individual magnets?
I think this is important and I agree but it is not a simple matter.
From the point of view of configuration, the most straightforward way would be to use arrays. I am not fully up to date with how arrays work. Maybe it is already possible, but I believe it may be ok if an array can contain both individually-powered devices and a serialized family. (Here I mean that set/get of strength/hardware can be done on the array.)
For example, imagine that to control the tune, you are using 8 different power converters attached to 8 quadrupole families. It should be possible to have a configuration that is not more complex than this one:
I thought the specification was that arrays and elements should provide the same interface? So if the tuning tool makes get and set it doesn't matter if it's on an array or an element? It doesn't really make sense to me that you need to make arrays that just contain a single element if all your magnets are individually powered.
If arrays and elements can provide the same interface, then great.
Sorry my question was too imprecise. I'll try to make it better and form a proposal.
Arrays mixing individual magnets and a serialized family
pyaml.arrays.magnet can mix individually powered magnets with the individual magnets of a series (N entries for one PS) which are treated as the virtual magnets of CFM magnets.
As of today, a pyaml.arrays.magnet cannot hold the serialized magnet family itself.
pyaml.arrays.serialized_magnet can hold serialized_magnet families only.
The tune tools only accept a magnet array. A serialized-magnet array fails.
So today the only way to put a serialized family in a tuning tool is through its virtual magnets (i.e. individual component).
Proposal:
allow to have a serialized magnet family in a pyaml.arrays.magnet
forbid to have a pyaml.arrays.magnet with both a serialized magnet family and its own individual magnets in the same array.
allow the tunning tools to take a pyaml.arrays.serialized_magnet as input
Tune correction example
Imagine the following measurement, using the same lattice but ran with different configuration of the quadrupoles:
Measure the response matrix with tune_response_matrix, then call tune.add([0.01, 0.005]).
Setup
Achieved ΔQ (target [0.01, 0.005])
8 individually powered quads (reference)
✔
Series as 4 virtual magnets + 4 individually powered quads
✘
A single virtual magnet + 4 individually powered quads
✔
The second case will not work with what we proposed so far:
Stepping one virtual magnet moves the whole series, so each of the N columns is the full family response.
The pseudo-inverse treats the N columns as independent knobs and gives each 1/N of the family correction.
Since there is only one PS, the series moves by only that 1/N.
Averaging the requested strengths gives the same result, because the N requests are identical.
Proposal: Tuning tools need one knob per power supply, as in MML, where chromaticity and response matrices work on families:
Input arrays to tuning tool can be a mix of individual magnets and serialized family.
If the an array that holds both individual magnets and member of serialized families is given to a tuning tool, that array is translated to a new array which contain the individual magnets and the serialized families.
Hmm... I think none of those options are really good but rather a review is needed of how the serialized magnets have been implemented and see if it can be simplified or done in some other way. Maybe by looking at how magnets are linked together in the twin. Last time I tested them it was not possible to configure and use them in the way we need for BESSY II (or at least I couldn't understand how). But after we decided to use our own ophyd-async devices instead of the common pyAML devices I have not looked at it further.
I have still not understood why it is needed to have separate classes instead of just defining an individual magnet and if it's serialized link it to a power supply object which is the same for several magnets. For me the serialized magnet at the moment is a bit of a weird hybrid of an individual magnet and an array and if feels like it should be possible to make a simplified implementation.
I would like to move on with this as at SOLEIL this is preventing us from testing further pyAML on the machine.
Here is the proposal I would like to implement.
A serialized family has one degree of freedom, the current I of its power supply. Everything in pyAML (accessors,
arrays, tuning tools) treats it that way, in design and in live.
1. Accessors (as agreed)
Magnet i of the series has strength k_i = f_i(I).
Accessor
get()
set(x)
family.hardware
I
write I = x
family.strength
average strength Σ f_i(I) / N
solve Σ f_i(I) / N = x for I, write it
magnet[i].hardware
I
write I = x (all magnets follow)
magnet[i].strength
k_i = f_i(I)
write I = f_i⁻¹(x), the others follow as f_j(I). No length weighting.
Two guarantees follow:
x.set(x.get()) never changes the machine, for any of these accessors.
design and live return the same values for the same I.
2. A serialized family behaves like a special magnet array
A family is a group of magnets, so it behaves like a magnet array. It also has a family-level value:
fam=sr.live.serialized_magnet.get("S9")
fam.strength.get() # scalar: average strength of the familyfam.hardware.get() # scalar: Ifam.strengths.get() # vector: [k_1, ..., k_N]forminfam: # the N individual magnetsprint(m.get_name(), m.strength.get())
A family name can also be used inside a pyaml.arrays.magnet and stands for its magnets.
3. Magnet arrays can mix everything
As today, a pyaml.arrays.magnet can hold any mix of:
individually powered magnets,
individual magnets of a series (N entries for one PS),
virtual magnets of combined-function magnets (CFM).
Writing through an array follows the table above. Changing one magnet of a series moves its power supply, and so the whole
series. If several magnets of the same series are in the array, the power supply gets the average of the currents they
request. Today, writing to one magnet moves the PS by only 1/N of the request. That is removed.
4. Tuning tools: one knob per power supply
Tuning tools (tune, chromaticity, orbit and their response matrices) only care about what can be moved independently.
Before measuring or correcting, a tool turns its input array into a list of knobs:
an individually powered magnet is one knob,
a series is one knob, the family, driven through family.strength. It does not matter how it was listed: one of its
magnets, all of them, or the family name all give the same knob,
each virtual magnet of a CFM is its own knob (see 5).
This happens inside the tools. Users keep configuring and using normal magnet arrays. The only visible effect is that a series
appears under its family name in the response matrix (variable_names). When a loaded response matrix does not match the knobs
(for example an old matrix with one column per magnet of a series), the tool raises an error and asks for a new measurement,
instead of silently correcting wrong.
Back to the tune correction example (measure the TRM, then tune.add([0.01, 0.005])):
Setup
Today
With this proposal
8 individually powered quads
✔
✔
Series listed as 4 magnets + 4 individual quads
✘ (moves 1/N)
✔ (same as the next two rows)
1 magnet of the series + 4 individual quads
✔
✔
Family name + 4 individual quads
not possible
✔
The tune config stays as simple as @kparasch asked:
- type: pyaml.tuning_tools.tunename: DEFAULT_TUNE_CORRECTIONquad_array_name: QForTune # any mix of individual magnets, series members or family namesbetatron_tune_name: BETATRON_TUNEresponse_matrix: ${path:trm.json}
5. Serialized magnets vs combined-function magnets
Both create "virtual magnets", but in opposite ways:
CFM
Series
Physical object
1 magnet, M multipoles
N magnets, 1 multipole each
Power supplies
K PS mixed by a matrix
1 shared PS
Degrees of freedom
M (when the matrix allows it)
1
Setting one virtual magnet
changes that multipole only, the others stay
moves the whole series
Knob for tuning tools
each virtual magnet
the family
Mixing both in one array is fine. Each CFM multipole stays a knob, and each series collapses into one knob.
Known limitations
Series of CFMs is not covered: one power supply shared between several combined-function magnets (e.g. the main coils of a
sextupole family in series, with individual corrector coils). That needs a model where the power supply is a separate object
shared between magnets (closer to @TeresiaOlsson's suggestion). I suggest a separate design issue if a lab needs it.
A CFM with more multipoles than power supplies stays as today (least-squares compromise).
Implementation
Three sub-issues / PRs, each to be merge into a complete feature branch:
Accessors: implement the table in design and live, fix the array write so it no longer moves 1/N. This alone fixes the main bug.
Family as a special magnet array: iteration and per-magnet vectors on a family, and serialized family names allowed in pyaml.arrays.magnet.
One knob per power supply in tuning tools: internal knob grouping and tests reproducing the table in §4.
Do you agree with this direction?
I'll strat with 1. as this was already agreed.
* **Series of CFMs is not covered:** one power supply shared between several combined-function magnets (e.g. the main coils of a
sextupole family in series, with individual corrector coils). That needs a model where the power supply is a separate object
shared between magnets (closer to [@TeresiaOlsson](https://github.com/TeresiaOlsson)'s suggestion). I suggest a separate design issue if a lab needs it.
* A CFM with more multipoles than power supplies stays as today (least-squares compromise).
@GamelinAl I don't fully understand if this covers the cases I have been struggling with or not:
MAX IV: they have combined function magnets connected in series. It's one power supply controlling for example both quadrupole and sextupole component of several magnets. They currently have no idea how to configure it. I guess that is included in the limitation?
BESSY II and MLS: We have dipoles and sextupoles powered in series with correctors and skew quadrupoles with individual power supplies on top. I don't think of this as combined-function magnets but I have understood that you do. Are these also included in the limitations? I have so far not understood the correct way to configure these in pyAML so I have gone for the approach we currently use in MML and configure them as completely separate magnets.
Interesting cases ... I'll try to answer the best I can. Please correct me if my understanding of these particular cases are wrong.
In pyAML as it is now, a CombinedFunctionMagnet (with linear_cfm_model) is one magnet whose K coils are mixed into M multipoles by a matrix. This is the ESRF type, where each coil current contributes to several multipoles (crosstalk). Extra windings that each produce only their own multipole are not neccesarily a CFM in that sense. They can also be configured as independent magnets that happen to sit on the same lattice element.
BESSY II / MLS: covered by the proposal, not a limitation
Main coils (sextupoles, quadrupoles): one pyaml.magnet.serialized_magnet per power supply, with one member per magnet.
Extra windings (H/V correctors, skew quads): keep them as individual magnets (HCorrector, VCorrector, SkewQuad) on
the same lattice element, using lattice_names.
This becomes a limitation only if the windings have crosstalk with the main coil, e.g. the main current changes the skew
or corrector field, or the reverse. That needs a CFM matrix containing a PS shared with other magnets ("series of CFMs"), which
the proposal does not cover.
MAX IV: a limitation today, but it fits the same concept
I understand that here each magnet has several components (e.g. quadrupole and sextupole) and the N magnets are on one PS. There is still one degree of freedom, I, for N × M strengths k_{i,m} = f_{i,m}(I). So this is a series of multi-function magnets, not a CFM with several PS. Is this correct?
Configuring it today with N CombinedFunctionMagnet that point to the same PS would not work well I think.
For it to work, we could extend the serialized magnet proposal as:
serialized_magnet accepts several functions per member, e.g. functions: [B1, B2], with one curve per (magnet, function).
Each (magnet, function) is a virtual magnet. Setting its strength writes I = f_{i,m}⁻¹(x), following the same table as for
the single-function series.
For tuning tools, the whole family is one knob, as for any series.
Interesting cases ... I'll try to answer the best I can. Please correct me if my understanding of these particular cases are wrong.
In pyAML as it is now, a CombinedFunctionMagnet (with linear_cfm_model) is one magnet whose K coils are mixed into M multipoles by a matrix. This is the ESRF type, where each coil current contributes to several multipoles (crosstalk). Extra windings that each produce only their own multipole are not neccesarily a CFM in that sense. They can also be configured as independent magnets that happen to sit on the same lattice element.
BESSY II / MLS: covered by the proposal, not a limitation
* **Main coils** (sextupoles, quadrupoles): one `pyaml.magnet.serialized_magnet` per power supply, with one member per magnet.
* **Extra windings** (H/V correctors, skew quads): keep them as individual magnets (`HCorrector`, `VCorrector`, `SkewQuad`) on
the same lattice element, using `lattice_names`.
This becomes a limitation only if the windings have crosstalk with the main coil, e.g. the main current changes the skew or corrector field, or the reverse. That needs a CFM matrix containing a PS shared with other magnets ("series of CFMs"), which the proposal does not cover.
This sounds reasonable. I think the situation we have is quite common for third generation light sources. They might be crosstalk but if it exists there is anyway no model of it that can be put into pyAML.
MAX IV: a limitation today, but it fits the same concept
I understand that here each magnet has several components (e.g. quadrupole and sextupole) and the N magnets are on one PS. There is still one degree of freedom, I, for N × M strengths k_{i,m} = f_{i,m}(I). So this is a series of multi-function magnets, not a CFM with several PS. Is this correct?
Yes, one current -> several magnet components that can't be controlled individually per magnet. Then those magnets are connected together in series resulting in one current -> several magnet components on several magnets. Some individual adjustment of the different components and between magnets is possible with pole face strips and resistance shunts but how to implement that I think is a separate topic. They have something for it already in their MML.
They also for some things have separate "corrector" magnets. For example for the combined function quadrupole-sextupole if you want to change the quadrupole component, the sextupole component will also change but you can compensate it by at the same time change a separate much weaker sextupole. So I think it's kind of the ESRF type where you have several currents mapping to several magnet components except that it's between different physical magnets. As I have understood it they handle this in their MML by not setting some magnets directly but instead have a script that sets several magnets in iterative steps until you reach the situation you wanted.
* **Series of CFMs is not covered:** one power supply shared between several combined-function magnets (e.g. the main coils of a
sextupole family in series, with individual corrector coils). That needs a model where the power supply is a separate object
shared between magnets (closer to [@TeresiaOlsson](https://github.com/TeresiaOlsson)'s suggestion). I suggest a separate design issue if a lab needs it.
* A CFM with more multipoles than power supplies stays as today (least-squares compromise).
@GamelinAl I don't fully understand if this covers the cases I have been struggling with or not:
1. MAX IV: they have combined function magnets connected in series. It's one power supply controlling for example both quadrupole and sextupole component of several magnets. They currently have no idea how to configure it. I guess that is included in the limitation?
2. BESSY II and MLS: We have dipoles and sextupoles powered in series with correctors and skew quadrupoles with individual power supplies on top. I don't think of this as combined-function magnets but I have understood that you do. Are these also included in the limitations? I have so far not understood the correct way to configure these in pyAML so I have gone for the approach we currently use in MML and configure them as completely separate magnets.
Could you please create corresponding issues? and tag them as related to @GamelinAl issue
I think several things are mixed in this discussion.
You can have:
CFM that link N strengths to M currents for one single element with an invertible model. OK.
Serialized magnets with n independent models when the serialized magnets are not the same. OK (Except that the average strength might not be very convenient).
Then you have the case of corrected magnets, for instance quad in series with quadrupole corrector on top of them which needs an additional correction strength field (as discussed here) to get an invertible model. Not OK yet.
Complex combined function magnets that includes several elements, several multipoles and several power supplies. Not yet OK. The Max IV case enter in that case and an invertible model has to be written.
Activity
kparasch commentedon Oct 1, 2026
I agree except on the
family.strength. I don't see any use-case for the total integrated strength.Typically, all magnets that are serialized are the same type of magnets so they share the
I = f(x)relation. There it would make sense forfamily.strengthto return the strength that is equal to all magnets.For the funky case where the magnets don't have the same length, controlling by strength sounds awkward to me.
Perhaps a compromise could be to have
family.strengthequal to average strengthS = Σ f_i(I) / N?Then at least in the typical case,
family.strengthfalls back to the strength that is equal to all magnets.The same follows for its
setlogic, solveΣ f_i(I) / N = xfor oneI, write itTeresiaOlsson commentedon Oct 1, 2026
I don't think it is guaranteed that
I = f(x)is the same for shared magnets? I think there are labs which measure all magnets and have a separate excitation curve per magnet despite that they are powered in series.I like the idea to have
family.strengthreturn the average strength. Then if you want to know the strength of the individual magnet you need to domagnet.strengthinstead.kparasch commentedon Oct 1, 2026
You are right, then
I = f(x)is still approximately correct. I would still think thatS = Σ f_i(I) / Nis sensible in that case.TeresiaOlsson commentedon Oct 1, 2026
I agree. Then you can use
getandseton the family level to set the average and if you care about the individual strengths you can still read them on the magnet level. And if you at some point in the future buy more power supplies and start to split up families the values will not change much. You just gain the freedom to being able to control the individual strengths and not just read them.Returning the total integrated strength I don't really understand. That doesn't sound to me like a useful parameter?
GamelinAl commentedon Oct 1, 2026
I agree with you both, it make sense to go this way. The table is now:
get()set(x)family.hardwareII = xfamily.strengthS = Σ f_i(I) / NΣ f_i(I) / N = xfor oneI, write itmagnet[i].hardwareII = x(all magnets follow)magnet[i].strengthk_i = f_i(I)I = f_i⁻¹(x); the others follow asf_j(I). No length weighting.From this definition, do we agree that tuning tools should use the family, not the individual magnets?
Should we provide an accessor to the total integrated strength? It would avoid having to do
family.strength * len(magnets_inside_fam)and would make clear thatfamily.strengthis actually the average strength.kparasch commentedon Oct 1, 2026
I think this is important and I agree but it is not a simple matter.
From the point of view of configuration, the most straightforward way would be to use arrays. I am not fully up to date with how arrays work. Maybe it is already possible, but I believe it may be ok if an array can contain both individually-powered devices and a serialized family. (Here I mean that
set/getofstrength/hardwarecan be done on the array.)For example, imagine that to control the tune, you are using 8 different power converters attached to 8 quadrupole families. It should be possible to have a configuration that is not more complex than this one:
TeresiaOlsson commentedon Oct 1, 2026
I thought the specification was that arrays and elements should provide the same interface? So if the tuning tool makes
getandsetit doesn't matter if it's on an array or an element? It doesn't really make sense to me that you need to make arrays that just contain a single element if all your magnets are individually powered.kparasch commentedon Oct 1, 2026
If arrays and elements can provide the same interface, then great.
GamelinAl commentedon Oct 1, 2026
Sorry my question was too imprecise. I'll try to make it better and form a proposal.
Arrays mixing individual magnets and a serialized family
pyaml.arrays.magnetcan mix individually powered magnets with the individual magnets of a series (N entries for one PS) which are treated as the virtual magnets of CFM magnets.pyaml.arrays.magnetcannot hold the serialized magnet family itself.pyaml.arrays.serialized_magnetcan hold serialized_magnet families only.So today the only way to put a serialized family in a tuning tool is through its virtual magnets (i.e. individual component).
Proposal:
pyaml.arrays.magnetpyaml.arrays.magnetwith both a serialized magnet family and its own individual magnets in the same array.pyaml.arrays.serialized_magnetas inputTune correction example
Imagine the following measurement, using the same lattice but ran with different configuration of the quadrupoles:
Measure the response matrix with
tune_response_matrix, then calltune.add([0.01, 0.005]).The second case will not work with what we proposed so far:
Proposal:
Tuning tools need one knob per power supply, as in MML, where chromaticity and response matrices work on families:
TeresiaOlsson commentedon Oct 2, 2026
Hmm... I think none of those options are really good but rather a review is needed of how the serialized magnets have been implemented and see if it can be simplified or done in some other way. Maybe by looking at how magnets are linked together in the twin. Last time I tested them it was not possible to configure and use them in the way we need for BESSY II (or at least I couldn't understand how). But after we decided to use our own ophyd-async devices instead of the common pyAML devices I have not looked at it further.
I have still not understood why it is needed to have separate classes instead of just defining an individual magnet and if it's serialized link it to a power supply object which is the same for several magnets. For me the serialized magnet at the moment is a bit of a weird hybrid of an individual magnet and an array and if feels like it should be possible to make a simplified implementation.
GamelinAl commentedon Oct 13, 2026
I would like to move on with this as at SOLEIL this is preventing us from testing further pyAML on the machine.
Here is the proposal I would like to implement.
A serialized family has one degree of freedom, the current
Iof its power supply. Everything in pyAML (accessors,arrays, tuning tools) treats it that way, in
designand inlive.1. Accessors (as agreed)
Magnet
iof the series has strengthk_i = f_i(I).get()set(x)family.hardwareII = xfamily.strengthΣ f_i(I) / NΣ f_i(I) / N = xforI, write itmagnet[i].hardwareII = x(all magnets follow)magnet[i].strengthk_i = f_i(I)I = f_i⁻¹(x), the others follow asf_j(I). No length weighting.Two guarantees follow:
x.set(x.get())never changes the machine, for any of these accessors.designandlivereturn the same values for the sameI.2. A serialized family behaves like a special magnet array
A family is a group of magnets, so it behaves like a magnet array. It also has a family-level value:
A family name can also be used inside a
pyaml.arrays.magnetand stands for its magnets.3. Magnet arrays can mix everything
As today, a
pyaml.arrays.magnetcan hold any mix of:Writing through an array follows the table above. Changing one magnet of a series moves its power supply, and so the whole
series. If several magnets of the same series are in the array, the power supply gets the average of the currents they
request. Today, writing to one magnet moves the PS by only 1/N of the request. That is removed.
4. Tuning tools: one knob per power supply
Tuning tools (tune, chromaticity, orbit and their response matrices) only care about what can be moved independently.
Before measuring or correcting, a tool turns its input array into a list of knobs:
family.strength. It does not matter how it was listed: one of itsmagnets, all of them, or the family name all give the same knob,
This happens inside the tools. Users keep configuring and using normal magnet arrays. The only visible effect is that a series
appears under its family name in the response matrix (
variable_names). When a loaded response matrix does not match the knobs(for example an old matrix with one column per magnet of a series), the tool raises an error and asks for a new measurement,
instead of silently correcting wrong.
Back to the tune correction example (measure the TRM, then
tune.add([0.01, 0.005])):The tune config stays as simple as @kparasch asked:
5. Serialized magnets vs combined-function magnets
Both create "virtual magnets", but in opposite ways:
Mixing both in one array is fine. Each CFM multipole stays a knob, and each series collapses into one knob.
Known limitations
sextupole family in series, with individual corrector coils). That needs a model where the power supply is a separate object
shared between magnets (closer to @TeresiaOlsson's suggestion). I suggest a separate design issue if a lab needs it.
Implementation
Three sub-issues / PRs, each to be merge into a complete feature branch:
designandlive, fix the array write so it no longer moves 1/N. This alone fixes the main bug.pyaml.arrays.magnet.Do you agree with this direction?
I'll strat with 1. as this was already agreed.
designandlive#473TeresiaOlsson commentedon Oct 13, 2026
@GamelinAl I don't fully understand if this covers the cases I have been struggling with or not:
MAX IV: they have combined function magnets connected in series. It's one power supply controlling for example both quadrupole and sextupole component of several magnets. They currently have no idea how to configure it. I guess that is included in the limitation?
BESSY II and MLS: We have dipoles and sextupoles powered in series with correctors and skew quadrupoles with individual power supplies on top. I don't think of this as combined-function magnets but I have understood that you do. Are these also included in the limitations? I have so far not understood the correct way to configure these in pyAML so I have gone for the approach we currently use in MML and configure them as completely separate magnets.
GamelinAl commentedon Oct 13, 2026
Interesting cases ... I'll try to answer the best I can. Please correct me if my understanding of these particular cases are wrong.
In pyAML as it is now, a
CombinedFunctionMagnet(withlinear_cfm_model) is one magnet whose K coils are mixed into M multipoles by a matrix. This is the ESRF type, where each coil current contributes to several multipoles (crosstalk). Extra windings that each produce only their own multipole are not neccesarily a CFM in that sense. They can also be configured as independent magnets that happen to sit on the same lattice element.BESSY II / MLS: covered by the proposal, not a limitation
Main coils (sextupoles, quadrupoles): one
pyaml.magnet.serialized_magnetper power supply, with one member per magnet.Extra windings (H/V correctors, skew quads): keep them as individual magnets (
HCorrector,VCorrector,SkewQuad) onthe same lattice element, using
lattice_names.This becomes a limitation only if the windings have crosstalk with the main coil, e.g. the main current changes the skew
or corrector field, or the reverse. That needs a CFM matrix containing a PS shared with other magnets ("series of CFMs"), which
the proposal does not cover.
MAX IV: a limitation today, but it fits the same concept
I understand that here each magnet has several components (e.g. quadrupole and sextupole) and the N magnets are on one PS. There is still one degree of freedom,
I, for N × M strengthsk_{i,m} = f_{i,m}(I). So this is a series of multi-function magnets, not a CFM with several PS. Is this correct?Configuring it today with N
CombinedFunctionMagnetthat point to the same PS would not work well I think.For it to work, we could extend the serialized magnet proposal as:
serialized_magnetaccepts several functions per member, e.g.functions: [B1, B2], with one curve per (magnet, function).I = f_{i,m}⁻¹(x), following the same table as forthe single-function series.
It need more thinking but it could probably work.
How things would be with the proposal
serialized_magnetserialized_magnetfor the main coils + individual magnets on the same lattice elementserialized_magnetwith several functionsThe last two lines would need another architecture I think, with the power supply as a separate object shared between magnets.
TeresiaOlsson commentedon Oct 13, 2026
This sounds reasonable. I think the situation we have is quite common for third generation light sources. They might be crosstalk but if it exists there is anyway no model of it that can be put into pyAML.
Yes, one current -> several magnet components that can't be controlled individually per magnet. Then those magnets are connected together in series resulting in one current -> several magnet components on several magnets. Some individual adjustment of the different components and between magnets is possible with pole face strips and resistance shunts but how to implement that I think is a separate topic. They have something for it already in their MML.
They also for some things have separate "corrector" magnets. For example for the combined function quadrupole-sextupole if you want to change the quadrupole component, the sextupole component will also change but you can compensate it by at the same time change a separate much weaker sextupole. So I think it's kind of the ESRF type where you have several currents mapping to several magnet components except that it's between different physical magnets. As I have understood it they handle this in their MML by not setting some magnets directly but instead have a script that sets several magnets in iterative steps until you reach the situation you wanted.
gubaidulinvadim commentedon Oct 13, 2026
Could you please create corresponding issues? and tag them as related to @GamelinAl issue
JeanLucPons commentedon Oct 13, 2026
I think several things are mixed in this discussion.
You can have:
Then you have the case of corrected magnets, for instance quad in series with quadrupole corrector on top of them which needs an additional correction strength field (as discussed here) to get an invertible model. Not OK yet.
Complex combined function magnets that includes several elements, several multipoles and several power supplies. Not yet OK. The Max IV case enter in that case and an invertible model has to be written.
Fix serialized-magnet strength/hardware accessors per issue #461: sha…
Add per-magnet function lists, strengths/hardwares array accessors an…