Modifying lattices¶
We can modify single lattice elements or the lattice itself. In the previous section there was already a hint about how to replace specific lattice elements. This can be done via lattice[identifier] = ... where identifier must unambiguously identify a lattice element. That is lattice[identifier] (not setting, but getting the element) should return a single element, not a list of elements. Note that identifer can be a tuple as well, in order to narrow down the selection. For
example, let’s offset the Quadrupole with label "gte1qd11" and tilt the second Kicker:
[1]:
from importlib import resources
import warnings
from dipas.build import from_file
from dipas.elements import HKicker, Offset, Tilt
import dipas.test.sequences
warnings.simplefilter('ignore')
with resources.path(dipas.test.sequences, 'hades.seq') as path:
lattice = from_file(path) # Load a fresh lattice.
print(lattice['gte1qd11']) # Returns a single element, good.
lattice['gte1qd11'] = Offset(lattice['gte1qd11'], dx=0.25, dy=0.50)
print(lattice['gte1qd11'], end='\n\n')
print(lattice[HKicker, 1]) # Returns a single element, good.
lattice[HKicker, 1] = Tilt(lattice[HKicker, 1], psi=1.0)
print(lattice[HKicker, 1])
Quadrupole(l=tensor(0.6660), k1=Parameter containing: tensor(0.5668, requires_grad=True), dk1=tensor(0.), label='gte1qd11')
Offset(dx=tensor(0.2500), dy=tensor(0.5000),
target=Quadrupole(l=tensor(0.6660), k1=Parameter containing: tensor(0.5668, requires_grad=True), dk1=tensor(0.), label='gte1qd11'))
HKicker(l=tensor(0.), hkick=tensor(0.), vkick=tensor(0.), kick=tensor(0.), dkh=tensor(0.), dkv=tensor(0.), label='gth1kx1')
Tilt(psi=tensor(1.),
target=HKicker(l=tensor(0.), hkick=tensor(0.), vkick=tensor(0.), kick=tensor(0.), dkh=tensor(0.), dkv=tensor(0.), label='gth1kx1'))
We can of course also modify attributes of single elements. For example let’s introduce some random errors to the quadrupole gradient strengths:
[2]:
import numpy as np
from dipas.elements import Quadrupole
for quad in lattice[Quadrupole]:
quad.element.k1.data += np.random.normal(scale=0.1)
Two things are worth noting here:
We used
quad.element.k1instead of justquad.k1. This is becauselattice[Quadrupole]returns a list of allQuadrupoleelements, potentially wrapped by alignment error classes. Because we applied an offset to the first quadrupole beforehand, the firstquadis actually anOffsetobject. By usingquad.elementwe ensure that we always get the underlyingQuadrupoleobject. Usingelementon aQuadrupoleitself will just return the same object.We used
k1.datainstead of justk1. This is because the MADX sequence file that we used to parse the lattice from actually contained optimization parameter definition (see the next section for more details) and so we need to use.datato modify the actual number of the tensor.