Observables#
Observables provide a unified way to access a large quantity of figures resulting from various computations on lattices. They may be used in parameter scans, matching, response matrices…
Observables values may be scalars or numpy arrays of any shape.
AT provides a number of specific observables sharing a common interface, inherited from the
Observable
base class. They are:
RingObservable
: Any user-defined property depending upon ringElementObservable
: Any user-defined property at a specific location along the latticeOrbitObservable
: \(x_{co}\)…,GlobalOpticsObservable
: tunes, damping times…,LocalOpticsObservable
: \(\beta\), \(\eta\)…,MatrixObservable
: \(T_{ij}\)…,TrajectoryObservable
: \(x, p_x\)…,EmittanceObservable
: \(\epsilon_x\)…,LatticeObservable
: attributes of lattice elements,
An Observable has optional target
, weight
and bounds
attributes for matching. After evaluation, it has the following main properties:
weighted_value
:value / weight
deviation
:value - target
weighted_deviation
:(value - target)/weight
residual
:((value - target)/weight)**2
Custom Observables may be created by providing the adequate evaluation function.
For evaluation, observables must be grouped in an ObservableList
which optimises the computation, avoiding redundant function calls. ObservableList
provides the evaluate()
method, and the
values
, deviations
,
residuals
and sum_residuals
properties, among others.
This example shows how to declare various Observables, how to evaluate them and how to extract and display their values.
Setup the environment#
import at
import sys
import numpy as np
from importlib.resources import files, as_file
from at import (
Observable,
ObservableList,
RingObservable,
OrbitObservable,
GlobalOpticsObservable,
LocalOpticsObservable,
MatrixObservable,
TrajectoryObservable,
EmittanceObservable,
LatticeObservable,
GeometryObservable,
Need,
)
Load a test lattice#
fname = "hmba.mat"
with as_file(files("machine_data") / fname) as path:
hmba_lattice = at.load_lattice(path)
Create Observables#
Create an empty ObservableList:
obs1 = ObservableList()
Horizontal closed orbit on all Monitors:
obs1.append(OrbitObservable(at.Monitor, axis="x"))
Create a 2nd ObservableList:
obs2 = ObservableList()
Vertical \(\beta\) at all monitors, with a target and bounds.
The vertical \(\beta\) is constrained in the interval [target+low_bound target+up_bound], so here [-Infinity 7.0]
The residual will be zero within the interval.
obs2.append(
LocalOpticsObservable(
at.Monitor, "beta", plane=1, target=7.0, bounds=(-np.inf, 0.0)
)
)
check the concatenation of ObservableLists:
allobs = obs1 + obs2
Full transfer matrix to BPM02
:
allobs.append(MatrixObservable("BPM_02"))
Maximum of vertical beta on monitors:
allobs.append(LocalOpticsObservable(at.Monitor, "beta", plane="v", statfun=np.amax))
First 4 coordinates of the closed orbit at Quadrupoles:
allobs.append(
LocalOpticsObservable(
at.Quadrupole, "closed_orbit", plane=slice(4), target=0.0, weight=1.0e-6
)
)
Position along the lattice of all quadrupoles:
allobs.append(LocalOpticsObservable(at.Quadrupole, "s_pos"))
Phase advance between elements 33 and 101 in all planes:
First, let’s define a custom evaluation function:
def phase_advance(elemdata):
mu = elemdata.mu
return mu[-1] - mu[0]
Then create the Observable. The evaluation function should return one value per refpoint (2 here). Alternatively,
it may return a single value (the difference, here), but then one must set summary=True
. all_points
is set to True
to force the evaluation of the phase advance at all points, to avoid phase jumps.
allobs.append(
LocalOpticsObservable([33, 101], phase_advance, all_points=True, summary=True)
)
Horizontal tune with the integer part:
allobs.append(GlobalOpticsObservable("tune", plane=0, use_integer=True))
Total phase advance at the end of the lattice (all planes):
allobs.append(LocalOpticsObservable(at.End, "mu"))
Horizontal W-function:
allobs.append(LocalOpticsObservable(at.Sextupole, "W", plane='x'))
Chromaticity in all planes:
allobs.append(GlobalOpticsObservable("chromaticity"))
Average of sextupole strengths:
allobs.append(LatticeObservable(at.Sextupole, "H", statfun=np.mean))
Strengths of all sextupoles:
allobs.append(LatticeObservable(at.Sextupole, "PolynomB", index=2))
Horizontal emittance:
allobs.append(EmittanceObservable("emittances", plane="x"))
Ring circumference:
def circumference(ring):
return ring.get_s_pos(len(ring))[0]
allobs.append(RingObservable(circumference))
px component of the trajectory on all monitors:
allobs.append(TrajectoryObservable(at.Monitor, axis="px"))
allobs.append(GeometryObservable(at.Monitor, "x"))
Evaluation#
An input trajectory is required for the trajectory Observable
r_in = np.zeros(6)
r_in[0] = 0.001
r_in[2] = 0.001
allobs.evaluate(hmba_lattice.enable_6d(copy=True), r_in=r_in, dp=0.0, initial=True)
Extract a single Observable value#
(phase advance between elements 3 and 101):
allobs[6].value
array([ 9.38969042e+00, 2.99742405e+00, -4.29831951e-15])
Get the list of all Observable values:#
allobs.values
[array([-3.02197154e-09, 4.50706100e-07, 4.08215752e-07, 2.37905632e-08,
-1.31787026e-08, 2.47236653e-08, -2.95318224e-08, -4.05608197e-07,
-4.47409217e-07, -2.24856457e-09]),
array([5.30279703, 7.17604152, 6.55087808, 2.31448878, 3.40498444,
3.405044 , 2.3146451 , 6.55106241, 7.17614175, 5.30283837]),
array([[[-1.08194106e+00, 3.18809568e+00, 0.00000000e+00,
0.00000000e+00, 8.22407787e-02, -1.72158067e-05],
[-6.80522735e-01, 1.08099571e+00, 0.00000000e+00,
0.00000000e+00, 4.90131193e-02, -1.02601216e-05],
[ 0.00000000e+00, 0.00000000e+00, 7.55929650e-01,
3.87059271e+00, 0.00000000e+00, 0.00000000e+00],
[ 0.00000000e+00, 0.00000000e+00, -6.79279293e-01,
-2.15524755e+00, 0.00000000e+00, 0.00000000e+00],
[-1.13309291e-08, -1.08618451e-07, 0.00000000e+00,
0.00000000e+00, 9.99995907e-01, -2.09333332e-04],
[ 2.93742438e-03, 6.73567963e-02, 0.00000000e+00,
0.00000000e+00, 2.83582586e-04, 9.99999941e-01]]]),
np.float64(7.176141754884372),
array([[-3.02817765e-09, -1.45848774e-10, 0.00000000e+00,
0.00000000e+00],
[-1.78482705e-09, 2.17272051e-09, 0.00000000e+00,
0.00000000e+00],
[ 2.06043298e-07, 1.68974845e-07, 0.00000000e+00,
0.00000000e+00],
[ 4.63473231e-07, 2.65118678e-07, 0.00000000e+00,
0.00000000e+00],
[ 4.92858975e-07, -2.48835341e-09, 0.00000000e+00,
0.00000000e+00],
[ 2.39074030e-07, -2.69330095e-07, 0.00000000e+00,
0.00000000e+00],
[ 2.24952950e-08, -2.55618843e-08, 0.00000000e+00,
0.00000000e+00],
[-2.95810598e-08, -2.51349419e-08, 0.00000000e+00,
0.00000000e+00],
[ 3.86447213e-08, 4.66083373e-08, 0.00000000e+00,
0.00000000e+00],
[-1.14696048e-08, -5.89639322e-08, 0.00000000e+00,
0.00000000e+00],
[-1.92477071e-07, -1.36146237e-07, 0.00000000e+00,
0.00000000e+00],
[-4.58538826e-07, -2.67114037e-07, 0.00000000e+00,
0.00000000e+00],
[-4.90197685e-07, -2.06362953e-09, 0.00000000e+00,
0.00000000e+00],
[-2.42431088e-07, 2.63622248e-07, 0.00000000e+00,
0.00000000e+00],
[-8.04974095e-10, -1.24376478e-09, 0.00000000e+00,
0.00000000e+00],
[-1.92739962e-09, -1.83202802e-09, 0.00000000e+00,
0.00000000e+00]]),
array([ 2.693952 , 3.4295565 , 5.52309303, 6.52741246, 7.08941246,
8.14326589, 10.34278161, 11.93982486, 13.94182609, 15.63285034,
18.00333506, 19.05718849, 19.61918849, 20.67257592, 22.71704445,
23.36843995]),
array([ 9.38969042e+00, 2.99742405e+00, -4.29831951e-15]),
np.float64(2.3815630185939196),
array([[1.49638018e+01, 5.36820522e+00, 6.85246959e-04]]),
array([18.37111586, 25.91715269, 12.96214627, 9.66599267, 13.81023312,
24.25197581]),
array([1.79196882e-01, 1.22425551e-01, 1.70292084e-04]),
np.float64(-25.369212247139345),
array([-78.95535579, 77.03724443, -74.18952538, -74.18952538,
77.03724443, -78.95535579]),
np.float64(1.3203585666474837e-10),
np.float64(26.374287952316944),
array([ 0.00000000e+00, -6.94370475e-04, 6.07151650e-04, 2.38468289e-04,
-6.81824075e-04, -4.78921799e-04, 4.41491590e-04, 7.01582185e-04,
-6.05543948e-04, -9.78684826e-05]),
array([ 2.6514 , 6.4783308 , 7.51380991, 10.28830988, 12.71979153,
13.62739043, 16.04912109, 18.79203055, 19.81402164, 23.58054559])]
Get a pretty output of all Observables.#
As no variation was made, Actual values are always equal to Initial values.
The residual is zero for all Observables for which no target was specified
print(allobs)
location Initial Actual Low bound High bound residual
orbit[x]
BPM_01 -3.02197e-09 -3.02197e-09 - - 0.0
BPM_02 4.50706e-07 4.50706e-07 - - 0.0
BPM_03 4.08216e-07 4.08216e-07 - - 0.0
BPM_04 2.37906e-08 2.37906e-08 - - 0.0
BPM_05 -1.31787e-08 -1.31787e-08 - - 0.0
BPM_06 2.47237e-08 2.47237e-08 - - 0.0
BPM_07 -2.95318e-08 -2.95318e-08 - - 0.0
BPM_08 -4.05608e-07 -4.05608e-07 - - 0.0
BPM_09 -4.47409e-07 -4.47409e-07 - - 0.0
BPM_10 -2.24856e-09 -2.24856e-09 - - 0.0
beta[y]
BPM_01 5.3028 5.3028 -inf 7.0 0.0
BPM_02 7.17604 7.17604 -inf 7.0 0.0309906
BPM_03 6.55088 6.55088 -inf 7.0 0.0
BPM_04 2.31449 2.31449 -inf 7.0 0.0
BPM_05 3.40498 3.40498 -inf 7.0 0.0
BPM_06 3.40504 3.40504 -inf 7.0 0.0
BPM_07 2.31465 2.31465 -inf 7.0 0.0
BPM_08 6.55106 6.55106 -inf 7.0 0.0
BPM_09 7.17614 7.17614 -inf 7.0 0.0310259
BPM_10 5.30284 5.30284 -inf 7.0 0.0
matrix
BPM_02 [-1.082 ...] [-1.082 ...] - - [ 0.0 ...]
amax(beta[y])
7.17614 7.17614 - - 0.0
closed_orbit[slice(None, 4, None)]
QF1A [-3.028e-09 ...] [-3.028e-09 ...] [ 0.0 ...] [ 0.0 ...] [ 9.17e-06 ...]
QD2A [-1.785e-09 ...] [-1.785e-09 ...] [ 0.0 ...] [ 0.0 ...] [ 3.186e-06 ...]
QD3A [ 2.06e-07 ...] [ 2.06e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.04245 ...]
QF4A [ 4.635e-07 ...] [ 4.635e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.2148 ...]
QF4B [ 4.929e-07 ...] [ 4.929e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.2429 ...]
QD5B [ 2.391e-07 ...] [ 2.391e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.05716 ...]
QF6B [ 2.25e-08 ...] [ 2.25e-08 ...] [ 0.0 ...] [ 0.0 ...] [ 0.000506 ...]
QF8B [-2.958e-08 ...] [-2.958e-08 ...] [ 0.0 ...] [ 0.0 ...] [ 0.000875 ...]
QF8D [ 3.864e-08 ...] [ 3.864e-08 ...] [ 0.0 ...] [ 0.0 ...] [ 0.001493 ...]
QF6D [-1.147e-08 ...] [-1.147e-08 ...] [ 0.0 ...] [ 0.0 ...] [ 0.0001316 ...]
QD5D [-1.925e-07 ...] [-1.925e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.03705 ...]
QF4D [-4.585e-07 ...] [-4.585e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.2103 ...]
QF4E [-4.902e-07 ...] [-4.902e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.2403 ...]
QD3E [-2.424e-07 ...] [-2.424e-07 ...] [ 0.0 ...] [ 0.0 ...] [ 0.05877 ...]
QD2E [-8.05e-10 ...] [-8.05e-10 ...] [ 0.0 ...] [ 0.0 ...] [ 6.48e-07 ...]
QF1E [-1.927e-09 ...] [-1.927e-09 ...] [ 0.0 ...] [ 0.0 ...] [ 3.715e-06 ...]
s_pos
QF1A 2.69395 2.69395 - - 0.0
QD2A 3.42956 3.42956 - - 0.0
QD3A 5.52309 5.52309 - - 0.0
QF4A 6.52741 6.52741 - - 0.0
QF4B 7.08941 7.08941 - - 0.0
QD5B 8.14327 8.14327 - - 0.0
QF6B 10.3428 10.3428 - - 0.0
QF8B 11.9398 11.9398 - - 0.0
QF8D 13.9418 13.9418 - - 0.0
QF6D 15.6329 15.6329 - - 0.0
QD5D 18.0033 18.0033 - - 0.0
QF4D 19.0572 19.0572 - - 0.0
QF4E 19.6192 19.6192 - - 0.0
QD3E 20.6726 20.6726 - - 0.0
QD2E 22.717 22.717 - - 0.0
QF1E 23.3684 23.3684 - - 0.0
phase_advance
[ 9.39 ...] [ 9.39 ...] - - [ 0.0 ...]
tune[x]
2.38156 2.38156 - - 0.0
mu
End [ 14.96 ...] [ 14.96 ...] - - [ 0.0 ...]
W[x]
SD1A 18.3711 18.3711 - - 0.0
SF2A 25.9172 25.9172 - - 0.0
SD1B 12.9621 12.9621 - - 0.0
SD1D 9.66599 9.66599 - - 0.0
SF2E 13.8102 13.8102 - - 0.0
SD1E 24.252 24.252 - - 0.0
chromaticity
[ 0.1792 ...] [ 0.1792 ...] - - [ 0.0 ...]
mean(H)
-25.3692 -25.3692 - - 0.0
PolynomB[2]
SD1A -78.9554 -78.9554 - - 0.0
SF2A 77.0372 77.0372 - - 0.0
SD1B -74.1895 -74.1895 - - 0.0
SD1D -74.1895 -74.1895 - - 0.0
SF2E 77.0372 77.0372 - - 0.0
SD1E -78.9554 -78.9554 - - 0.0
emittances[x]
1.32036e-10 1.32036e-10 - - 0.0
circumference
26.3743 26.3743 - - 0.0
trajectory[px]
BPM_01 0.0 0.0 - - 0.0
BPM_02 -0.00069437 -0.00069437 - - 0.0
BPM_03 0.000607152 0.000607152 - - 0.0
BPM_04 0.000238468 0.000238468 - - 0.0
BPM_05 -0.000681824 -0.000681824 - - 0.0
BPM_06 -0.000478922 -0.000478922 - - 0.0
BPM_07 0.000441492 0.000441492 - - 0.0
BPM_08 0.000701582 0.000701582 - - 0.0
BPM_09 -0.000605544 -0.000605544 - - 0.0
BPM_10 -9.78685e-05 -9.78685e-05 - - 0.0
geometry[x]
BPM_01 2.6514 2.6514 - - 0.0
BPM_02 6.47833 6.47833 - - 0.0
BPM_03 7.51381 7.51381 - - 0.0
BPM_04 10.2883 10.2883 - - 0.0
BPM_05 12.7198 12.7198 - - 0.0
BPM_06 13.6274 13.6274 - - 0.0
BPM_07 16.0491 16.0491 - - 0.0
BPM_08 18.792 18.792 - - 0.0
BPM_09 19.814 19.814 - - 0.0
BPM_10 23.5805 23.5805 - - 0.0