import at
import at.plot
from importlib.resources import files, as_file
from at.future import VariableBase, VariableList, CustomVariable, match
from at import LocalOpticsObservable, ObservableList
Correlated variables#
In this example of correlation between variables, we vary the length of the two drifts surrounding a monitor but keep the sum of their lengths constant.
Using these 2 correlated variables, we will match a constraint on the monitor.
Load a test lattice#
fname = 'hmba.mat'
with as_file(files('machine_data') / fname) as path:
hmba_lattice = at.load_lattice(path)
Isolate the two drifts
dr1 = hmba_lattice["DR_01"][0]
dr2 = hmba_lattice["DR_02"][0]
Get the total length to be preserved
l1 = dr1.Length
l2 = dr2.Length
ltot = l1 + l2
Create a constraint \(\beta_y=3.0\) on BPM_01
obs1 = LocalOpticsObservable('BPM_01', 'beta', plane='v', target=3.0)
Method 1: using a CustomVariable
#
For this, we need to define the get and set function:
def _setfun(value, dr1, dr2, total_length, ring=None):
dr1.Length = value
dr2.Length = total_length - value
def _getfun(dr1, dr2, total_length, **kwargs):
return dr1.Length
Then we can create the :py:class:.CustomVariable
object:
var0 = CustomVariable(_setfun, _getfun, dr1, dr2, ltot, bounds=(0.0, ltot))
Run the matching#
variables = VariableList([var0])
constraints = ObservableList([obs1], ring=hmba_lattice)
match(hmba_lattice, variables, constraints, verbose=1)
1 constraints, 1 variables, using method trf
`gtol` termination condition is satisfied.
Function evaluations 8, initial cost 2.6515e+00, final cost 9.6605e-27, first-order optimality 9.88e-14.
Constraints:
location Initial Actual Low bound High bound deviation
beta[y]
BPM_01 5.30283 3.0 3.0 3.0 1.0924e-08
Variables:
Name Initial Final Variation
var1 2.651400e+00 9.693778e-01 -1.682022e+00
Show the modified lattice#
for elem in hmba_lattice.select([2,3,4]):
print(elem)
Drift:
FamName: DR_01
Length: 0.969377825260562
PassMethod: DriftPass
Monitor:
FamName: BPM_01
Length: 0.0
PassMethod: IdentityPass
Offset: [0 0]
Reading: [0 0]
Rotation: [0 0]
Scale: [1 1]
Drift:
FamName: DR_02
Length: 1.7245741747394379
PassMethod: DriftPass
hmba_lattice.plot_beta()
![../../_images/4d5fa410807b775f58e1b30dae3f364752af86c89e7e2cf0b45f61b4dc648604.png](../../_images/4d5fa410807b775f58e1b30dae3f364752af86c89e7e2cf0b45f61b4dc648604.png)
(<Axes: title={'left': 'S28d', 'center': 'Optical functions'}, xlabel='s [m]', ylabel='$\\beta$ [m]'>,
<Axes: ylabel='dispersion [m]'>,
<Axes: >)
The first BPM is moved to a location where \(\beta_y=3.0\)
Restore the lattice
dr1.Length = l1
dr2.Length = l2
Method 2: derivating the VariableBase
class#
We define a new variable class which will act on the two elements and fulfil the constraint
Define a variable coupling two drift lengths so that their sum is constant:#
class ElementShifter(VariableBase):
def __init__(self, dr1, dr2, total_length=None, **kwargs):
"""Varies the length of the elements *dr1* and *dr2*
keeping the sum of their lengths equal to *total_length*.
If *total_length* is None, it is set to the initial total length
"""
# store indexes of the 2 variable elements
self.dr1 = dr1
self.dr2 = dr2
# store the initial total length
if total_length is None:
total_length = dr1.Length + dr2.Length
self.length = total_length
super().__init__(bounds=(0.0, total_length), **kwargs)
def _setfun(self, value, ring=None):
dr1.Length = value
dr2.Length = self.length - value
def _getfun(self, ring=None):
return dr1.Length
This method is more powerful, for instance by allowing processing in the init method.
Create a variable moving the monitor BPM_01
var0 = ElementShifter(dr1, dr2, name='DR_01', total_length=ltot)
Run the matching#
variables = VariableList([var0])
constraints = ObservableList([obs1], ring=hmba_lattice)
match(hmba_lattice, variables, constraints, verbose=1)
1 constraints, 1 variables, using method trf
`gtol` termination condition is satisfied.
Function evaluations 8, initial cost 2.6515e+00, final cost 9.6605e-27, first-order optimality 9.88e-14.
Constraints:
location Initial Actual Low bound High bound deviation
beta[y]
BPM_01 5.30283 3.0 3.0 3.0 1.0924e-08
Variables:
Name Initial Final Variation
DR_01 2.651400e+00 9.693778e-01 -1.682022e+00
Show the modified lattice#
for elem in hmba_lattice.select([2,3,4]):
print(elem)
Drift:
FamName: DR_01
Length: 0.969377825260562
PassMethod: DriftPass
Monitor:
FamName: BPM_01
Length: 0.0
PassMethod: IdentityPass
Offset: [0 0]
Reading: [0 0]
Rotation: [0 0]
Scale: [1 1]
Drift:
FamName: DR_02
Length: 1.7245741747394379
PassMethod: DriftPass
hmba_lattice.plot_beta()
![../../_images/4d5fa410807b775f58e1b30dae3f364752af86c89e7e2cf0b45f61b4dc648604.png](../../_images/4d5fa410807b775f58e1b30dae3f364752af86c89e7e2cf0b45f61b4dc648604.png)
(<Axes: title={'left': 'S28d', 'center': 'Optical functions'}, xlabel='s [m]', ylabel='$\\beta$ [m]'>,
<Axes: ylabel='dispersion [m]'>,
<Axes: >)