Skip to content

Serialized magnets: mixed-function families, strengths/hardwares arrays and completed partial requests - #485

Draft
gupichon-soleil wants to merge 1 commit into
461-serializedmagnetsfrom
473-serialized-magnets-implement-the-agreed-accessor-convention-in-design-and-live_v2
Draft

gupichon-soleil wants to merge 1 commit into
461-serializedmagnetsfrom
473-serialized-magnets-implement-the-agreed-accessor-convention-in-design-and-live_v2

Conversation

@gupichon-soleil

@gupichon-soleil gupichon-soleil commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Description

Follow-up to #474 on the serialized-magnet accessors. It adds three things on top of the agreed accessor convention:

  • A serialized family can mix magnet functions (e.g. quadrupoles and sextupoles on one power supply): function accepts one value per element.
  • family.strengths / family.hardwares read or write every magnet of the series in one call, like CombinedFunctionMagnet.strengths / .hardwares.
  • Array writes that only cover part of a series complete the missing magnets with their current strength, and the completed request is solved exactly.

A series has a single degree of freedom, the power-supply current I. Magnet i has the strength k_i = f_i(I):

Accessor get() set(x)
family.hardware I write I = x
family.strength sum(f_i(I)) / N solve sum(f_i(I)) / N = x. Raises on a mixed family
family.hardwares [I, ..., I] write I = mean(x)
family.strengths [f_1(I), ..., f_N(I)] solve sum(f_i(I)) = sum(x_i)
magnet[i].hardware I write I = x
magnet[i].strength f_i(I) write I = f_i^-1(x), the others follow
array with some magnets of a series per magnet missing magnets keep f_j(I), then solve sum(f_i(I)) = sum(k_i)

Known limitations

  • A series has a single degree of freedom. Any write asking for strengths not reachable with one current gives a compromise, and a warning is logged ("Inconsistent strengths ..."). This is the same compromise as magnet[i].strength.set(x), which imposes f_i^-1(x) on the whole series.
  • An array that only covers part of a series moves the series by roughly the requested fraction, since the magnets outside the array keep their current strength in the equation. Writing one magnet of a series through an array moves the power supply by about 1/N of the change, not to f_i^-1(x). This supersedes the "writing one member no longer moves the PS by 1/N" behaviour of Implement the agreed serialized-magnet accessor convention #474, on purpose: the magnets
    outside the request are not driven to a large uncontrolled change. magnet[i].strength.set(x) is not affected.
  • The larger the gap between the requested magnets and the current values of the others, the further the solved current is from what the request alone would give. A solved current outside the excitation curve is clamped to the end of the curve (design and live). In live, if the power-supply device has a configured range, a current outside that range raises PyAMLException and nothing is written. This matches
    the physical situation: following the request would change the magnets outside it with no control over them.
  • If sum(f_i(I)) is not monotonic in I, the request cannot be inverted and PyAMLException is raised (existing behaviour of compute_hardware_from_mean_strength).
  • A mixed family still has a single unit / hardware_unit in LinearSerializedMagnetModel, so family.strengths.unit() reports the same strength unit for every magnet whatever its function.
  • Not covered: series of combined-function magnets, magnets with several functions on one power supply (MAX IV case), and one knob per power supply in the tuning tools.

Related Issue

Features/issues described there are:

  • new feature: function accepts a list with one function per element, so a series can mix magnet functions on one power supply. polynoms holds one polynom per element and the simulator uses each magnet's own polynom, otherwise the sextupole of a mixed family would write into the quadrupole slot. is_homogeneous() tells whether every magnet shares the same function.
  • new feature: family.strengths / family.hardwares (ReadWriteSerializedStrengthArray / ReadWriteSerializedHardwareArray), to read or write every magnet of a series in one call, as for CombinedFunctionMagnet. strengths.set(k) solves sum(f_i(I)) = sum(k_i) through the new LinearSerializedMagnetModel.compute_hardware_from_strengths(), which reuses the exact piecewise-linear inversion of
    compute_hardware_from_mean_strength. hardwares.set(x) applies mean(x).
  • new feature: family.strength raises PyAMLException on a family mixing functions, because a single value cannot be both a quadrupole and a sextupole strength. family.strengths, family.hardware(s) and per-magnet access keep working.
    • bugfix: an unknown function raised a KeyError, the key was read before being checked. It now raises PyAMLException.

Changes to existing functionality

  • compute_hardware_values_partial (array writes covering part of a series): reimplemented to complete the magnets that are not requested with the strength given by the current hardware value, then delegate to compute_hardware_from_strengths, because the previous rule, the mean of the currents implied by each requested strength (sum(f_i^-1(k_i)) / N), is only exact when every f_i is the same, or
    affine with the same slope. It now checks that it receives one hardware value per power supply and returns an array of the same shape. The inconsistency warning is shortened to the largest gap and the magnet concerned.
  • RWMagnetStrength.set() (design arrays, no aggregator): passes the current hardware value instead of None, needed for the completion. The single-member shortcut (magnet.strength.set()) is removed, so design and live arrays follow the same rule (live arrays already went through the aggregator).

Testing

The following tests (compatible with pytest) were added:

  • tests/config/sr_serialized_magnets.yaml: new mixedFunctionSeries family (quadrupole QF6D-C01 and sextupole SD1A-C01 on one power supply)
  • tests/magnet/test_serialized_magnets.py: homogeneity, family.strength refused on the mixed family, hardware and per-magnet access kept, each magnet written in its own polynom, exact convergence of a consistent strengths.set() request, warning on an inconsistent one, shape check of compute_hardware_values_partial
  • tests/magnet/test_serialized_magnets_cs.py, in design and live: strengths / hardwares read and write, set(get()) leaves the machine unchanged, an array with two magnets of a series is completed with the current strength of the others
  • Updated from Implement the agreed serialized-magnet accessor convention #474: test_array_with_inconsistent_magnets_of_a_series now expects the exact solution of the average strength, and the single-member array test now expects the completed request and its warning

Verify that your checklist complies with the project

  • New and existing unit tests pass locally (483 passed with -m "not integration"; test_tuning_orm fails on Windows only, temporary file lock, unrelated)
  • Tests were added to prove that all features/changes are effective
  • The code is commented where appropriate
  • Any existing features are not broken (unless there is an explicit change to an existing functionality)

…d completed partial requests for serialized magnets (#461)
@gupichon-soleil gupichon-soleil self-assigned this Oct 15, 2026
@gupichon-soleil gupichon-soleil changed the title Add per-magnet function lists, strengths/hardwares array accessors an… Serialized magnets: mixed-function families, strengths/hardwares arrays and completed partial requests Oct 15, 2026
@GamelinAl

GamelinAl commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

An array that only covers part of a series moves the series by roughly the requested fraction, since the magnets outside the array keep their current strength in the equation. Writing one magnet of a series through an array moves the power supply by about 1/N of the change, not to f_i^-1(x)

I think this drives a difference of behavior when changing the values directly using the array and if a tuning tool with the planned knob implementation in #461 :

  • with your proposal the array containing j/N magnets in series getting an average change of k will actually go k*j/N
  • the same thing in the tuning tool with the knob implementation will just change it to k

@gupichon-soleil

gupichon-soleil commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

I think this drives a difference of behavior when changing the values directly using the array and if a tuning tool with the planned knob implementation in #461 :

* with your proposal the array containing j/N magnets in series getting an average change of k will actually go k*j/N

* the same thing in the tuning tool with the knob implementation will just change it to k

Yes. An intermediate slution would be to use only the referenced magnet to compute the current (like if it was a sub-serie) but it might lead to errors for the others magnets of the serie. I don't see a good solution here, it's a matter of choice in my opinion.

@GamelinAl

Copy link
Copy Markdown
Member

I think this drives a difference of behavior when changing the values directly using the array and if a tuning tool with the planned knob implementation in #461 :

* with your proposal the array containing j/N magnets in series getting an average change of k will actually go k*j/N

* the same thing in the tuning tool with the knob implementation will just change it to k

Yes. An intermediate slution would be to use only the referenced magnet to compute the current (like if it was a sub-serie) but it might lead to errors for the others magnets of the serie. I don't see a good solution here, it's a matter of choice in my opinion.

For me the second behavior is what we want.

@gupichon-soleil

Copy link
Copy Markdown
Contributor Author

Ok, I'll do it tomorrow.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants