Skip to content

4 implement magnet hardware link#25

Merged
JeanLucPons merged 6 commits intomainfrom
4-implement-magnet-hardware-link
Oct 10, 2025
Merged

4 implement magnet hardware link#25
JeanLucPons merged 6 commits intomainfrom
4-implement-magnet-hardware-link

Conversation

@gupichon
Copy link
Copy Markdown
Contributor

@gupichon gupichon commented Oct 1, 2025

Implementation of an identity model to access to hardware and/or physics values in the control system.

@gupichon gupichon requested a review from JeanLucPons October 1, 2025 08:58
@gupichon gupichon linked an issue Oct 1, 2025 that may be closed by this pull request
@JeanLucPons
Copy link
Copy Markdown
Contributor

JeanLucPons commented Oct 1, 2025

Thanks for the PR.

Regarding this code, it seems that there is a misunderstanding.

    def compute_hardware_values(self, strengths: np.array) -> np.array:
        raise PyAMLException("The identity model does not support computation")

    def compute_strengths(self, currents: np.array) -> np.array:
        raise PyAMLException("The identity model does not support computation")

When working in hardware units, to work with a simulator, you need a conversion model so when using an identity model it is not possible to compute_strengths(). But when working in physic units, then access to the simulator is possible as no conversion is required.

I do not see the point of the identity_cfm_model module. If your control system provides access to strength, a combined function magnet is necessarily already split into several single function magnets, so the simple identity model applies.

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 1, 2025

Thanks @JeanLucPons for the review. The simulator access is indeed handled via the get/set methods. The compute methods are only intended to delegate to a conversion model when one exists, which is not the case for an identity model.

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 1, 2025

The identity_cfm_model is clearly not mandatory but I think it's more user friendly to have it.

@JeanLucPons
Copy link
Copy Markdown
Contributor

JeanLucPons commented Oct 1, 2025

Thanks @JeanLucPons for the review. The simulator access is indeed handled via the get/set methods. The compute methods are only intended to delegate to a conversion model when one exists, which is not the case for an identity model.

Not only. The compute_strengths() is used if you want to use aggregator.
Working in hardware units on a control system that handle strengths is possible and means that hardware units are in fact strengths.
This is tricky and this is the purpose of the identity model.
Theoretically, an identity model should just map strength to hardware.
However to make the configuration clearer for the user and to know if link to the simulator is possible or not, we use 2 configuration fields: physics and hardware (or powerconverter).
So in our case:

  • If the powerconverted is defined, no link to simulator.
  • If the physics field is defined link to simulator is possible.
  • In any case, make 1 to 1 relationship strength<->hardware.

This is just a matter to implement correctly compute_hardware_values() and compute_strengths() in function of defined fields.

@JeanLucPons
Copy link
Copy Markdown
Contributor

JeanLucPons commented Oct 1, 2025

In the identity model, I expect that either a power supply or a magnet device (physics) is specified but not both.

Mapping strengh:

type: pyaml.magnet.quadrupole
name: QF1A-C01
model:
  type: pyaml.magnet.identity_model
  unit: 1/m
  physics:
    type: tango.pyaml.attribute
    attribute: srmag/m-qf1/c05-a/strength
# 2 following lines are equivalent
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010)
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(0.000010)

# 2 following lines are equivalent
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010)
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(0.000010)

print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").strength.unit()) # 1/m
print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").hardware.unit()) # 1/m

Mapping current (no access to simulator):

type: pyaml.magnet.quadrupole
name: QF1A-C01
model:
  type: pyaml.magnet.identity_model
  unit: A
  powerconverter:
    type: tango.pyaml.attribute
    attribute: srmag/vps-qf1/c05-a/current
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010) # throw an exception
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(82) #  throw an exception

sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010) # throw an exception
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(82) # Write 82A

print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").strength.unit()) #  throw an exception
print(sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").hardware.unit()) # A

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 2, 2025

I'll turn your example into a test.

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 6, 2025

@JeanLucPons, I'm coming back to you about the identity_cfm_model. It is actually necessary to address the element in the design, as there will be only one thick element in the lattice.
By the way, this also raises the question of how sub-elements should be retrieved. For example, if I have a multipole that contains a sextupole and correctors, will the correctors be found with a command like:

sr.live.get_magnets(MagnetType.HCorrector)`

Note that this last point should be addressed in a new issue if a change is needed.

@JeanLucPons
Copy link
Copy Markdown
Contributor

I'm not sure to fully understand.

For an arrays, the type is defined in the config file.
If you want an array of HCORR and SEXT coming from a single element (combined function magnet), you can have:

    arrays:
      - type: pyaml.arrays.hcorrector
        name: HCORR
        elements:
          - SD1A-C01-H
          - SD1A-C02-H
      - type: pyaml.arrays.sextupole
        name: SEXT
        elements:
          - SD1A-C01-S
          - SD1A-C02-S
   devices:
      type: pyaml.magnet.cfm_magnet
      name: SD1A-C01        #Name of the element in the lattice
      mapping:
        - [B0, SD1A-C01-H]
        - [A0, SD1A-C01-V]
        - [B2, SD1A-C01-S]
      model: 
         ...
      type: pyaml.magnet.cfm_magnet
      name: SD1A-C02        #Name of the element in the lattice
      mapping:
        - [B0, SD1A-C02-H]
        - [A0, SD1A-C02-V]
        - [B2, SD1A-C02-S]
      model: 
         ...
    sr.design.get_magnets("HCORR").strengths.set([0.000010,-0.000008])
    sr.design.get_magnets("SEXT").strengths.set([-14.103,-14.107])

If you want to use an identity model, it means that either:
-your control system supports strength
-each multipole are well separated
In that case:

    arrays:
      - type: pyaml.arrays.hcorrector
        name: HCORR
        elements:
          - SD1A-C01
          - SD1A-C02
      - type: pyaml.arrays.sextupole
        name: SEXT
        elements:
          - SD1A-C01
          - SD1A-C02
   devices:
      type: pyaml.magnet.hcorrector
      name: SD1A-C01        #Name of the element in the lattice
      model:
        type: pyaml.magnet.identity_model
        physics:
          type: tango.pyaml.attribute
          attribute: srmag/m-sd1a/c01-a/h_strength
      type: pyaml.magnet.sextupole
      name: SD1A-C01        #Name of the element in the lattice
      model:
        type: pyaml.magnet.identity_model
        physics:
          type: tango.pyaml.attribute
          attribute: srmag/m-sd1a/c01-a/strength
      type: pyaml.magnet.hcorrector
      name: SD1A-C02        #Name of the element in the lattice
      model:
        type: pyaml.magnet.identity_model
        physics:
          type: tango.pyaml.attribute
          attribute: srmag/m-sd1a/c02-a/h_strength
      type: pyaml.magnet.sextupole
      name: SD1A-C02        #Name of the element in the lattice
      model:
        type: pyaml.magnet.identity_model
        physics:
          type: tango.pyaml.attribute
          attribute: srmag/m-sd1a/c02-a/strength

Important: In the config file the element name is not unique. It is the couple type,name (i.e. HCorrector,SD1A-C01) which is unique.

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 6, 2025

@JeanLucPons, ok the file will be a bit long, but that's fine.

@JeanLucPons
Copy link
Copy Markdown
Contributor

In order to reduce the number of line, you can implement an identity_cfm_model as below:

devices:
      type: pyaml.magnet.cfm_magnet
      name: SD1A-C01        #Name of the element in the lattice
      mapping:
        - [B0, SD1A-C01-H]
        - [A0, SD1A-C01-V]
        - [B2, SD1A-C01-S]
     model: 
       type: pyaml.magnet.identity_cfm_model
       physics:
          - type: tango.pyaml.attribute
            attribute: srmag/m-sd1a/c01-a/h_strength
          - type: tango.pyaml.attribute
            attribute: srmag/m-sd1a/c01-a/v_strength
          - type: tango.pyaml.attribute
            attribute: srmag/m-sd1a/c01-a/strength

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 6, 2025

@JeanLucPons your last proposal (with a cfm_magnet) seems clearer to me, but I’ll create another issue for that so others can discuss it. Moreover, at SOLEIL, some correctors will be driven by a kick angle, which will imply further changes if i'm correct.

@JeanLucPons
Copy link
Copy Markdown
Contributor

To be coherent, the strength of a dipole should be without unit.
Unit should be 1, 1/m, 1/m^2, 1/m^3, etc...
If you want to convert dipole to angle it should be done outside but as AT can accept angle, this will require some mods to handle PolynomA/B[0] differently in order to map to KickAngle.

@gupichon
Copy link
Copy Markdown
Contributor Author

gupichon commented Oct 6, 2025

I’ll create the corresponding issues.
Regarding the behavior you described in your previous comment, I need to validate it first with @gubaidulinvadim and @GamelinAl.

In the identity model, I expect that either a power supply or a magnet device (physics) is specified but not both.

Mapping strengh:

type: pyaml.magnet.quadrupole
name: QF1A-C01
model:
  type: pyaml.magnet.identity_model
  unit: 1/m
  physics:
    type: tango.pyaml.attribute
    attribute: srmag/m-qf1/c05-a/strength
# 2 following lines are equivalent
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010)
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(0.000010)

# 2 following lines are equivalent
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010)
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(0.000010)

print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").strength.unit()) # 1/m
print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").hardware.unit()) # 1/m

Mapping current (no access to simulator):

type: pyaml.magnet.quadrupole
name: QF1A-C01
model:
  type: pyaml.magnet.identity_model
  unit: A
  powerconverter:
    type: tango.pyaml.attribute
    attribute: srmag/vps-qf1/c05-a/current
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010) # throw an exception
sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(82) #  throw an exception

sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").strength.set(0.000010) # throw an exception
sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1A-C01").hardware.set(82) # Write 82A

print(sr.design.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").strength.unit()) #  throw an exception
print(sr.live.get_magnet(MagnetType.QUADRUPOLE,"QF1E-C04").hardware.unit()) # A

@GamelinAl
Copy link
Copy Markdown
Contributor

@JeanLucPons it's fine to work with PolynomA/B[0] for correctors. I'll make the change in our test lattice but we might want to support this feature in the future as it is a AT/pyAT feature.

@JeanLucPons JeanLucPons merged commit 45d94d2 into main Oct 10, 2025
2 checks passed
@gupichon gupichon deleted the 4-implement-magnet-hardware-link branch October 10, 2025 08:41
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.

Implement magnet hardware link

4 participants