Example-15: BPM (element)

[1]:
from pathlib import Path
from os import system

import torch
from model.library.drift import Drift
from model.library.bpm import BPM
[2]:
# BPM acts as identity transformation with calibration error

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)

B = BPM('B', direction='forward')
B(state)
[2]:
tensor([ 0.0100, -0.0050, -0.0050,  0.0010], dtype=torch.float64)
[3]:
# Calibration errors can be passed as deviation variables

# qx -> (1 + xx) qx + xy qy
# qy -> yx qx + (1 + yy) qy

B.data()
[3]:
{'xx': tensor(0., dtype=torch.float64),
 'xy': tensor(0., dtype=torch.float64),
 'yx': tensor(0., dtype=torch.float64),
 'yy': tensor(0., dtype=torch.float64),
 'dp': tensor(0., dtype=torch.float64),
 'dx': tensor(0., dtype=torch.float64),
 'dy': tensor(0., dtype=torch.float64),
 'dz': tensor(0., dtype=torch.float64),
 'wx': tensor(0., dtype=torch.float64),
 'wy': tensor(0., dtype=torch.float64),
 'wz': tensor(0., dtype=torch.float64)}
[4]:
# Transform to BPM frame and back to beam frame

xx = torch.tensor(+0.05, dtype=torch.float64)
xy = torch.tensor(+0.01, dtype=torch.float64)
yx = torch.tensor(+0.05, dtype=torch.float64)
yy = torch.tensor(-0.06, dtype=torch.float64)

B = BPM('B', direction='forward')

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)
print(state)

state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
print(state)

B.direction = 'inverse'

state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
print(state)
tensor([ 0.0100, -0.0050, -0.0050,  0.0010], dtype=torch.float64)
tensor([ 0.0105, -0.0048, -0.0042,  0.0011], dtype=torch.float64)
tensor([ 0.0100, -0.0050, -0.0050,  0.0010], dtype=torch.float64)
[5]:
# Transform to BPM frame and back to beam frame using a pair of BPMS

xx = torch.tensor(+0.05, dtype=torch.float64)
xy = torch.tensor(+0.01, dtype=torch.float64)
yx = torch.tensor(+0.05, dtype=torch.float64)
yy = torch.tensor(-0.06, dtype=torch.float64)

BA = BPM('B', direction='forward')
BB = BPM('B', direction='inverse')

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)
print(state)

state = BA(state, data={**BA.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
print(state)

state = BB(state, data={**BB.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
print(state)
tensor([ 0.0100, -0.0050, -0.0050,  0.0010], dtype=torch.float64)
tensor([ 0.0105, -0.0048, -0.0042,  0.0011], dtype=torch.float64)
tensor([ 0.0100, -0.0050, -0.0050,  0.0010], dtype=torch.float64)
[6]:
# Differentiability

B = BPM('B', direction='forward')
D = Drift('D', 1.0)

xx = torch.tensor(+0.05, dtype=torch.float64)
xy = torch.tensor(+0.01, dtype=torch.float64)
yx = torch.tensor(+0.05, dtype=torch.float64)
yy = torch.tensor(-0.06, dtype=torch.float64)

error = torch.stack([xx, xy, yx, yy])

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)

def line(state, error):
    xx, xy, yx, yy = error
    state = D(state)
    state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
    return state

print(torch.func.jacrev(line, 1)(state, error))

def line(state, error):
    xx, xy, yx, yy = error
    state = D(state)
    B.direction = 'forward'
    state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
    B.direction = 'inverse'
    state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}})
    return state

print(torch.func.jacrev(line, 1)(state, error))
tensor([[ 5.0000e-03, -4.0000e-03,  0.0000e+00,  0.0000e+00],
        [ 4.5880e-03, -2.4404e-04, -1.0625e-03,  5.6516e-05],
        [ 0.0000e+00,  0.0000e+00,  5.0000e-03, -4.0000e-03],
        [-4.8809e-05,  5.1249e-03,  1.1303e-05, -1.1868e-03]],
       dtype=torch.float64)
tensor([[ 0.0000e+00,  8.6736e-19,  0.0000e+00, -5.4888e-19],
        [ 0.0000e+00,  0.0000e+00,  3.3881e-20,  0.0000e+00],
        [-2.7105e-19,  0.0000e+00,  8.6736e-19,  0.0000e+00],
        [ 2.1684e-19,  3.9302e-19, -3.3881e-21,  2.1684e-19]],
       dtype=torch.float64)
[7]:
# Alignment support

xx = torch.tensor(+0.05, dtype=torch.float64)
xy = torch.tensor(+0.01, dtype=torch.float64)
yx = torch.tensor(+0.05, dtype=torch.float64)
yy = torch.tensor(-0.06, dtype=torch.float64)

dx = torch.tensor(0.05, dtype=torch.float64)
dy = torch.tensor(-0.02, dtype=torch.float64)
dz = torch.tensor(0.05, dtype=torch.float64)

wx = torch.tensor(0.005, dtype=torch.float64)
wy = torch.tensor(-0.005, dtype=torch.float64)
wz = torch.tensor(0.1, dtype=torch.float64)

error = {'dx': dx, 'dy': dy, 'dz': dz, 'wx': wx, 'wy': wy, 'wz': wz}

B = BPM('B', direction='forward')

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)
state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}, **error})
print(state)

state = torch.tensor([0.01, -0.005, -0.005, 0.001], dtype=torch.float64)
state = B(state, data={**B.data(), **{'xx': xx, 'xy': xy, 'yx': yx, 'yy': yy}, **error}, alignment=True)
print(state)
tensor([ 0.0105, -0.0048, -0.0042,  0.0011], dtype=torch.float64)
tensor([ 0.0086, -0.0048, -0.0082,  0.0008], dtype=torch.float64)