Conception de maille avec Xsuite¶
Recréons la maille PIMMS
développée par la collaboration TERA pour la thérapie par protons et ions (voir : CERN/PS 99-010) et sur laquelle sont basés les synchrotrons médicaux CNAO
et MEDAUSTRON
.
In [1]:
import matplotlib.pyplot as plt
import numpy as np
import xtrack as xt
%config InlineBackend.figure_format = "retina"
Création d'Environement and définition de la particule de référence¶
In [2]:
env = xt.Environment()
env.particle_ref = xt.Particles(kinetic_energy0=200e6) # proton, 200MeV
env.vars.default_to_zero = True # Variables non définies sont à zéro
Définition des élements¶
In [3]:
# Géometries des éléments
n_bends = 16
env["ang_mb"] = 2 * np.pi / n_bends
env["l_mb"] = 1.65
env["l_mq"] = 0.35
# Créations de dipoles et quadripôles génériques
env.new("mb", parent=xt.RBend, length="l_mb", angle="ang_mb", k0_from_h=True)
env.new("mq", parent=xt.Quadrupole, length="l_mq");
In [4]:
# Différentes familles de quadripôles
env.new("qfa", parent="mq", k1="kqfa")
env.new("qfb", parent="mq", k1="kqfb")
env.new("qd", parent="mq", k1="kqd");
Conception d'une cellule¶
In [5]:
# Cellule FODO (focalisant-défocalisant-focalisant)
cell_a = env.new_line(
length=7.405,
components=[
env.place("qfa", at=0.3875),
env.place("mb", at=1.8125),
env.place("qd", at=3.2925),
env.place("mb", at=5.0475),
env.place("qfa", at=6.3275),
],
)
cell_a.survey().plot()
Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.
In [6]:
# Cellule similaire avec la seconde famille de quadripôles focalisants
cell_b = env.new_line(
name="cell_b",
length=8.405,
components=[
env.place("qfb", at=1.2725),
env.place("mb", at=2.7275),
env.place("qd", at=4.8575),
env.place("mb", at=6.5125),
env.place("qfb", at=7.7925),
],
)
Conception d'un arc¶
In [7]:
# Concaténation des deux cellules en un arc
arc = cell_a + cell_b
arc.survey().plot()
Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
Conception de sections droites¶
In [8]:
long_straight = env.new_line(length=2.0, components=[env.new("mid.lss", parent=xt.Marker, at=1.0)])
short_straight = env.new_line(length=1.0, components=[env.new("mid.sss", parent=xt.Marker, at=0.5)])
Assemblage de l'anneau¶
In [9]:
half_ring = long_straight + arc + short_straight - arc # pour une maille symmétrique
ring = 2 * half_ring
ring.survey().plot()
Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
Replacement des éléments répétés¶
In [10]:
# Déduplication en donnant des noms uniques
ring.replace_all_repeated_elements()
Inspection de la table¶
In [11]:
table = ring.get_table()
table.cols["element_type", "s_start", "s_center", "s_end"]
Out[11]:
Table: 101 rows, 5 cols name element_type s_start s_center s_end drift_13.0 Drift 0 0.5 1 mid.lss.0 Marker 1 1 1 drift_14.0 Drift 1 1.5 2 drift_1.0 Drift 2 2.10625 2.2125 qfa.0 Quadrupole 2.2125 2.3875 2.5625 drift_2.0 Drift 2.5625 2.775 2.9875 mb.0 RBend 2.9875 3.8125 4.6375 drift_3.0 Drift 4.6375 4.8775 5.1175 qd.0 Quadrupole 5.1175 5.2925 5.4675 drift_4.0 Drift 5.4675 5.845 6.2225 ... drift_5.3 Drift 63.0875 63.2275 63.3675 mb.14 RBend 63.3675 64.1925 65.0175 drift_4.3 Drift 65.0175 65.395 65.7725 qd.7 Quadrupole 65.7725 65.9475 66.1225 drift_3.3 Drift 66.1225 66.3625 66.6025 mb.15 RBend 66.6025 67.4275 68.2525 drift_2.3 Drift 68.2525 68.465 68.6775 qfa.7 Quadrupole 68.6775 68.8525 69.0275 drift_1.3 Drift 69.0275 69.1338 69.24 _end_point 69.24 69.24 69.24
In [12]:
# Séléction des quadripôles uniquement
table_quads = table.rows[table.element_type == "Quadrupole"]
table_quads.cols["s_start", "s_center", "s_end"]
Out[12]:
Table: 24 rows, 4 cols name s_start s_center s_end qfa.0 2.2125 2.3875 2.5625 qd.0 5.1175 5.2925 5.4675 qfa.1 8.1525 8.3275 8.5025 qfb.0 10.5025 10.6775 10.8525 qd.1 14.0875 14.2625 14.4375 qfb.1 17.0225 17.1975 17.3725 qfb.2 19.2475 19.4225 19.5975 qd.2 22.1825 22.3575 22.5325 qfb.3 25.7675 25.9425 26.1175 qfa.2 28.1175 28.2925 28.4675 qd.3 31.1525 31.3275 31.5025 qfa.3 34.0575 34.2325 34.4075 qfa.4 36.8325 37.0075 37.1825 qd.4 39.7375 39.9125 40.0875 qfa.5 42.7725 42.9475 43.1225 qfb.4 45.1225 45.2975 45.4725 qd.5 48.7075 48.8825 49.0575 qfb.5 51.6425 51.8175 51.9925 qfb.6 53.8675 54.0425 54.2175 qd.6 56.8025 56.9775 57.1525 qfb.7 60.3875 60.5625 60.7375 qfa.6 62.7375 62.9125 63.0875 qd.7 65.7725 65.9475 66.1225 qfa.7 68.6775 68.8525 69.0275
In [13]:
# Mise en exergue de leurs positions dans la maille
sv = ring.survey()
sv.plot(labels=table_quads.name);
Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
Definition et installation des sextupôles¶
In [14]:
# Aimant sextupôles générique
env.new("ms", parent=xt.Sextupole, length=0.2)
# Les sextupôles eux-mêmes
env.new("msf.1", parent="ms", k2="ksf") # focalisant
env.new("msf.2", parent="ms", k2="ksf") # focalisant
env.new("msd.1", parent="ms", k2="ksd") # défocalisant
env.new("msd.2", parent="ms", k2="ksd") # défocalisant
env.new("mse", parent="ms", k2="kse") # pour l'extraction
Out[14]:
'mse'
In [15]:
# Insertion dans l'anneau, en positions relatives
ring.insert(
[
env.place("msf.1", at=-0.2, from_="qfb.0@start"),
env.place("msf.2", at=-0.2, from_="qfb.4@start"),
env.place("msd.1", at=0.3, from_="qd.2@end"),
env.place("msd.2", at=0.3, from_="qd.6@end"),
env.place("mse", at=-0.3, from_="qfa.4@start"),
]
)
In [16]:
# Mise en exergue dans la maille
survey = ring.survey()
survey.plot(labels=["msf.1", "msf.2", "msd.1", "msd.2", "mse"])
Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
Inspection de la structure des circuits¶
In [17]:
# Éléments contrôlés par une variable
env.info("ksf")
# vars['ksf']._get_value() vars['ksf'] = 0.0 # vars['ksf']._expr is None # vars['ksf']._find_dependant_targets() element_refs['msf.2'].k2 element_refs['msf.1'].k2
Installation d'une cavité RF¶
In [18]:
env.new("rf1", parent=xt.Cavity, voltage="vrf", frequency="frf")
ring.insert("rf1", at=0.5, from_="qfa.3@start")
survey = ring.survey()
survey.plot(labels=["rf1"])
Ignoring fixed x limits to fulfill fixed data aspect with adjustable data limits.
Export de la maille en fichier JSON¶
In [19]:
env["ring"] = ring
env.to_json("pimms.json")