Example-03: Workflow (ELEGANT)

[1]:
from pathlib import Path

from model.command.external import load_lattice
from model.command.external import rift_lattice
from model.command.external import text_lattice
from model.command.external import load_sdds
from model.command.external import convert
from model.command.external import add_rc
[2]:
# Given some initial ELEGANT lattice file (FODO)

file = Path('initial.lte')

with file.open('r') as stream:
    print(stream.read())

# Several regular elements are defined
# HEAD and TAIL should appear as the first and the last elements
# All elements should be defined on a single line with numerical parameters
# Lattice should be defined using lines
# Comma after element type is mandatory
# Comments appearing after definitions should also represent an element definition
DR: DRIF,l=2

BM: CSBEND,angle=0.17453292519943295,fint=0,l=1.0
QD: QUAD,k1=-0.2,l=0.5
QF: QUAD,k1=0.2,l=1.0

M: MONI,

HEAD: MARK, ! TEST: DRIF,
TAIL: MARK, ! TEST: DRIF,

FODO: LINE=(HEAD, M, QD, DR, BM, DR, QF, DR, BM, DR, QD, TAIL)
[3]:
# If element and beamline definitions comply with the above requirements
# The lattice file can be loaded as a python dictionary

lattice = load_lattice(file)

for key, value in lattice.items():
    print(key, value)

# For each element and beamline, a key-value pair in created
# Value is itself a dictionary containing all information about the original elements
# Each element parameter is casted from string to int, float or string
# Comment after element definition is saved into RC (it has a special use case, see below)
DR {'KIND': 'DRIF', 'RC': '', 'L': 2}
BM {'KIND': 'CSBEND', 'RC': '', 'ANGLE': 0.17453292519943295, 'FINT': 0, 'L': 1.0}
QD {'KIND': 'QUAD', 'RC': '', 'K1': -0.2, 'L': 0.5}
QF {'KIND': 'QUAD', 'RC': '', 'K1': 0.2, 'L': 1.0}
M {'KIND': 'MONI', 'RC': ''}
HEAD {'KIND': 'MARK', 'RC': 'TEST: DRIF,'}
TAIL {'KIND': 'MARK', 'RC': 'TEST: DRIF,'}
FODO {'KIND': 'LINE', 'SEQUENCE': ['HEAD', 'M', 'QD', 'DR', 'BM', 'DR', 'QF', 'DR', 'BM', 'DR', 'QD', 'TAIL']}
[4]:
# Error lattice is defined by a set of linear transformations between selected locations
# Each locations can be a MONITOR (beam observation) or a VIRTUAL (error)
# Two special locatons (HEAD and TAIL) should present in the lattice
# Using the above dictionary representation, new observation locations can be inserted
# Locations are inserted at the middle of selected elements (selected by type or name)
# Selected elements are splitted in half and renamed, old names are binded to beamlines
# Original element definitions are added to created location RC
# Typicaly, monitor locations correspond to MONITOR elements, but new monitor elements can be also inserted
# Virtual locations can be inserted into quadrupole or other elements to represent errors

lattice = rift_lattice(lattice,
                       'MONI',
                       'MARK',
                       ['DRIF'],
                       ['CSBEND', 'QUAD'],
                       exclude_virtual=['QD'])

for key, value in lattice.items():
    print(key, value)
M_DR {'KIND': 'MONI', 'RC': ['DR', {'KIND': 'DRIF', 'L': 2}]}
H_DR {'KIND': 'DRIF', 'L': 1.0}
DR {'KIND': 'LINE', 'SEQUENCE': ['H_DR', 'M_DR', 'H_DR']}
V_BM {'KIND': 'MARK', 'RC': ['BM', {'KIND': 'CSBEND', 'ANGLE': 0.17453292519943295, 'FINT': 0, 'L': 1.0}]}
H_BM {'KIND': 'CSBEND', 'ANGLE': 0.08726646259971647, 'FINT': 0, 'L': 0.5}
BM {'KIND': 'LINE', 'SEQUENCE': ['H_BM', 'V_BM', 'H_BM']}
QD {'KIND': 'QUAD', 'RC': '', 'K1': -0.2, 'L': 0.5}
V_QF {'KIND': 'MARK', 'RC': ['QF', {'KIND': 'QUAD', 'K1': 0.2, 'L': 1.0}]}
H_QF {'KIND': 'QUAD', 'K1': 0.2, 'L': 0.5}
QF {'KIND': 'LINE', 'SEQUENCE': ['H_QF', 'V_QF', 'H_QF']}
M {'KIND': 'MONI', 'RC': ''}
HEAD {'KIND': 'MARK', 'RC': 'TEST: DRIF,'}
TAIL {'KIND': 'MARK', 'RC': 'TEST: DRIF,'}
FODO {'KIND': 'LINE', 'SEQUENCE': ['HEAD', 'M', 'QD', 'DR', 'BM', 'DR', 'QF', 'DR', 'BM', 'DR', 'QD', 'TAIL']}
[5]:
# Modified lattice can be converted to text
# Comments are added to locations while original comments are preserved

text = text_lattice('LTE', lattice, rc=True)

print(text)
M_DR: MONI, ! DR: DRIF, L=2,
H_DR: DRIF, L=1.0,
DR: LINE=(H_DR, M_DR, H_DR)
V_BM: MARK, ! BM: CSBEND, ANGLE=0.17453292519943295, FINT=0, L=1.0,
H_BM: CSBEND, ANGLE=0.08726646259971647, FINT=0, L=0.5,
BM: LINE=(H_BM, V_BM, H_BM)
QD: QUAD, K1=-0.2, L=0.5,
V_QF: MARK, ! QF: QUAD, K1=0.2, L=1.0,
H_QF: QUAD, K1=0.2, L=0.5,
QF: LINE=(H_QF, V_QF, H_QF)
M: MONI,
HEAD: MARK, ! TEST: DRIF,
TAIL: MARK, ! TEST: DRIF,
FODO: LINE=(HEAD, M, QD, DR, BM, DR, QF, DR, BM, DR, QD, TAIL)

[6]:
# Compute TWISS parameters using ELEGANT
# Separate command file is created

with Path('final.lte').open('w') as stream:
    stream.write(text)

task = """
&run_setup
  use_beamline="FODO",
  lattice = "final.lte",
  p_central_mev = 1000
&end

&run_control
&end

&twiss_output
  filename = "binary.twiss",
  output_at_each_step = 1
&end

&bunched_beam
&end

&track
&end
""" ;

with Path('final.ele').open('w') as stream:
    stream.write(task)

!elegant final.ele > /dev/null
!sddsconvert -ascii binary.twiss final.twiss
[7]:
# Load lattice can be also loaded from file
# Original comments will be parsed as elements (look at HEAD and TAIL)
# Empty RC will be nested in this case

file = Path('final.lte')

with file.open('w') as stream:
    stream.write(text)

lattice = load_lattice(file, rc=True)

for key, value in lattice.items():
    print(key, value)
M_DR {'KIND': 'MONI', 'RC': ['DR', {'KIND': 'DRIF', 'RC': '', 'L': 2}]}
H_DR {'KIND': 'DRIF', 'RC': ['', {'KIND': '', 'RC': ''}], 'L': 1.0}
DR {'KIND': 'LINE', 'SEQUENCE': ['H_DR', 'M_DR', 'H_DR']}
V_BM {'KIND': 'MARK', 'RC': ['BM', {'KIND': 'CSBEND', 'RC': '', 'ANGLE': 0.17453292519943295, 'FINT': 0, 'L': 1.0}]}
H_BM {'KIND': 'CSBEND', 'RC': ['', {'KIND': '', 'RC': ''}], 'ANGLE': 0.08726646259971647, 'FINT': 0, 'L': 0.5}
BM {'KIND': 'LINE', 'SEQUENCE': ['H_BM', 'V_BM', 'H_BM']}
QD {'KIND': 'QUAD', 'RC': ['', {'KIND': '', 'RC': ''}], 'K1': -0.2, 'L': 0.5}
V_QF {'KIND': 'MARK', 'RC': ['QF', {'KIND': 'QUAD', 'RC': '', 'K1': 0.2, 'L': 1.0}]}
H_QF {'KIND': 'QUAD', 'RC': ['', {'KIND': '', 'RC': ''}], 'K1': 0.2, 'L': 0.5}
QF {'KIND': 'LINE', 'SEQUENCE': ['H_QF', 'V_QF', 'H_QF']}
M {'KIND': 'MONI', 'RC': ['', {'KIND': '', 'RC': ''}]}
HEAD {'KIND': 'MARK', 'RC': ['TEST', {'KIND': 'DRIF', 'RC': ''}]}
TAIL {'KIND': 'MARK', 'RC': ['TEST', {'KIND': 'DRIF', 'RC': ''}]}
FODO {'KIND': 'LINE', 'SEQUENCE': ['HEAD', 'M', 'QD', 'DR', 'BM', 'DR', 'QF', 'DR', 'BM', 'DR', 'QD', 'TAIL']}
[8]:
# TWISS results can be loaded into python dictionaries

data = Path('final.twiss')
parameters, columns = load_sdds(data)
[9]:
# Optics data can be converted into model table
# Note, all locations have different name
# If an element appear several times in a line, locations are renamed

table = convert(columns, 'SDDS', ['MONI'], ['MARK'], rc=True)
table
[9]:
{'HEAD': {'S': 0.0,
  'BX': 4.287017734831204,
  'AX': -1.321304551729011e-16,
  'FX': 0.0,
  'DQX': 1.549040841795901,
  'DPX': 2.775557561562891e-17,
  'BY': 19.81848926815186,
  'AY': 6.545730027929358e-16,
  'FY': 0.0,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None},
 'M': {'S': 0.0,
  'BX': 4.287017734831204,
  'AX': -1.321304551729011e-16,
  'FX': 0.0,
  'DQX': 1.549040841795901,
  'DPX': 2.775557561562891e-17,
  'BY': 19.81848926815186,
  'AY': 6.545730027929358e-16,
  'FY': 0.0,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'M_DR': {'S': 1.5,
  'BX': 5.980356479284525,
  'AX': -0.8524040348212205,
  'FX': 0.3068185834444499,
  'DQX': 1.744126672993481,
  'DPX': 0.1561981825607101,
  'BY': 15.31515988971357,
  'AY': 1.649167846239909,
  'FY': 0.08453149253790615,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'V_BM': {'S': 3.0,
  'BX': 9.120629409314306,
  'AX': -1.146568740048648,
  'FX': 0.5107301355818847,
  'DQX': 1.99289632225274,
  'DPX': 0.2138526637243729,
  'BY': 10.91413760701325,
  'AY': 1.284847009200138,
  'FY': 0.2008141505892614,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None},
 'M_DR_1': {'S': 4.5,
  'BX': 12.70896979491113,
  'AX': -1.336396672789745,
  'FX': 0.6500917126795847,
  'DQX': 2.383785789407781,
  'DPX': 0.2698795969893243,
  'BY': 7.606077834992553,
  'AY': 0.9205261718281931,
  'FY': 0.3661997933967667,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'V_QF': {'S': 6.0,
  'BX': 16.39200719526896,
  'AX': 3.608224830031759e-16,
  'FX': 0.7521811119743597,
  'DQX': 2.721417822995524,
  'DPX': -5.551115123125783e-17,
  'BY': 5.674619589422572,
  'AY': 8.326672684688672e-16,
  'FY': 0.6011311668647427,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None},
 'M_DR_2': {'S': 7.5,
  'BX': 12.70896979491113,
  'AX': 1.336396672789746,
  'FX': 0.8542705112691347,
  'DQX': 2.383785789407781,
  'DPX': -0.2698795969893243,
  'BY': 7.606077834992548,
  'AY': -0.920526171828191,
  'FY': 0.8360625403327188,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'V_BM_1': {'S': 9.0,
  'BX': 9.120629409314306,
  'AX': 1.146568740048649,
  'FX': 0.9936320883668346,
  'DQX': 1.992896322252739,
  'DPX': -0.2138526637243729,
  'BY': 10.91413760701323,
  'AY': -1.284847009200136,
  'FY': 1.001448183140224,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None},
 'M_DR_3': {'S': 10.5,
  'BX': 5.980356479284523,
  'AX': 0.852404034821221,
  'FX': 1.197543640504269,
  'DQX': 1.744126672993481,
  'DPX': -0.1561981825607101,
  'BY': 15.31515988971355,
  'AY': -1.649167846239906,
  'FY': 1.11773084119158,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'TAIL': {'S': 12.0,
  'BX': 4.287017734831201,
  'AX': 5.273559366969493e-16,
  'FX': 1.50436222394872,
  'DQX': 1.549040841795901,
  'DPX': -1.110223024625157e-16,
  'BY': 19.81848926815184,
  'AY': 1.387778780781446e-16,
  'FY': 1.202262333729486,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None}}
[10]:
# RC parameter from lattice data can be added to model table
# Configuration table can be saved using util.save

table = add_rc(table, lattice)
table
[10]:
{'HEAD': {'S': 0.0,
  'BX': 4.287017734831204,
  'AX': -1.321304551729011e-16,
  'FX': 0.0,
  'DQX': 1.549040841795901,
  'DPX': 2.775557561562891e-17,
  'BY': 19.81848926815186,
  'AY': 6.545730027929358e-16,
  'FY': 0.0,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None},
 'M': {'S': 0.0,
  'BX': 4.287017734831204,
  'AX': -1.321304551729011e-16,
  'FX': 0.0,
  'DQX': 1.549040841795901,
  'DPX': 2.775557561562891e-17,
  'BY': 19.81848926815186,
  'AY': 6.545730027929358e-16,
  'FY': 0.0,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': None},
 'M_DR': {'S': 1.5,
  'BX': 5.980356479284525,
  'AX': -0.8524040348212205,
  'FX': 0.3068185834444499,
  'DQX': 1.744126672993481,
  'DPX': 0.1561981825607101,
  'BY': 15.31515988971357,
  'AY': 1.649167846239909,
  'FY': 0.08453149253790615,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': ['DR', {'KIND': 'DRIF', 'L': 2}]},
 'V_BM': {'S': 3.0,
  'BX': 9.120629409314306,
  'AX': -1.146568740048648,
  'FX': 0.5107301355818847,
  'DQX': 1.99289632225274,
  'DPX': 0.2138526637243729,
  'BY': 10.91413760701325,
  'AY': 1.284847009200138,
  'FY': 0.2008141505892614,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': ['BM',
   {'KIND': 'CSBEND', 'ANGLE': 0.17453292519943295, 'FINT': 0, 'L': 1.0}]},
 'M_DR_1': {'S': 4.5,
  'BX': 12.70896979491113,
  'AX': -1.336396672789745,
  'FX': 0.6500917126795847,
  'DQX': 2.383785789407781,
  'DPX': 0.2698795969893243,
  'BY': 7.606077834992553,
  'AY': 0.9205261718281931,
  'FY': 0.3661997933967667,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': ['DR', {'KIND': 'DRIF', 'L': 2}]},
 'V_QF': {'S': 6.0,
  'BX': 16.39200719526896,
  'AX': 3.608224830031759e-16,
  'FX': 0.7521811119743597,
  'DQX': 2.721417822995524,
  'DPX': -5.551115123125783e-17,
  'BY': 5.674619589422572,
  'AY': 8.326672684688672e-16,
  'FY': 0.6011311668647427,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': ['QF', {'KIND': 'QUAD', 'K1': 0.2, 'L': 1.0}]},
 'M_DR_2': {'S': 7.5,
  'BX': 12.70896979491113,
  'AX': 1.336396672789746,
  'FX': 0.8542705112691347,
  'DQX': 2.383785789407781,
  'DPX': -0.2698795969893243,
  'BY': 7.606077834992548,
  'AY': -0.920526171828191,
  'FY': 0.8360625403327188,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': ['DR', {'KIND': 'DRIF', 'L': 2}]},
 'V_BM_1': {'S': 9.0,
  'BX': 9.120629409314306,
  'AX': 1.146568740048649,
  'FX': 0.9936320883668346,
  'DQX': 1.992896322252739,
  'DPX': -0.2138526637243729,
  'BY': 10.91413760701323,
  'AY': -1.284847009200136,
  'FY': 1.001448183140224,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': ['BM',
   {'KIND': 'CSBEND', 'ANGLE': 0.17453292519943295, 'FINT': 0, 'L': 1.0}]},
 'M_DR_3': {'S': 10.5,
  'BX': 5.980356479284523,
  'AX': 0.852404034821221,
  'FX': 1.197543640504269,
  'DQX': 1.744126672993481,
  'DPX': -0.1561981825607101,
  'BY': 15.31515988971355,
  'AY': -1.649167846239906,
  'FY': 1.11773084119158,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'MONITOR',
  'RC': ['DR', {'KIND': 'DRIF', 'L': 2}]},
 'TAIL': {'S': 12.0,
  'BX': 4.287017734831201,
  'AX': 5.273559366969493e-16,
  'FX': 1.50436222394872,
  'DQX': 1.549040841795901,
  'DPX': -1.110223024625157e-16,
  'BY': 19.81848926815184,
  'AY': 1.387778780781446e-16,
  'FY': 1.202262333729486,
  'DQY': 0.0,
  'DPY': 0.0,
  'TYPE': 'VIRTUAL',
  'RC': None}}