15
15
from pyhdtoolkit .cpymadtools import lhc
16
16
17
17
18
- def prepare_lhc_run2 (opticsfile : str , beam : int = 1 , energy : float = 6500 , slicefactor : int = None , ** kwargs ) -> Madx :
18
+ def prepare_lhc_run2 (
19
+ opticsfile : str , beam : int = 1 , use_b4 : bool = False , energy : float = 6500 , slicefactor : int = None , ** kwargs
20
+ ) -> Madx :
19
21
"""
20
22
.. versionadded:: 1.0.0
21
23
@@ -37,6 +39,8 @@ def prepare_lhc_run2(opticsfile: str, beam: int = 1, energy: float = 6500, slice
37
39
opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile
38
40
name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path.
39
41
beam (int): which beam to set up for. Defaults to beam 1.
42
+ use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking
43
+ purposes. Defaults to `False`.
40
44
energy (float): beam energy to set up for, in GeV. Defaults to 6500.
41
45
slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`,
42
46
which leads to an unsliced sequence.
@@ -54,17 +58,24 @@ def prepare_lhc_run2(opticsfile: str, beam: int = 1, energy: float = 6500, slice
54
58
... "/afs/cern.ch/eng/lhc/optics/runII/2018/PROTON/opticsfile.22", beam=2, stdout=True
55
59
... )
56
60
"""
61
+ if use_b4 and beam != 2 :
62
+ logger .error ("Cannot use beam 4 sequence file for beam 1" )
63
+ raise ValueError ("Cannot use beam 4 sequence file for beam 1" )
57
64
58
- def _run2_sequence_from_opticsfile (opticsfile : Path ) -> Path :
59
- return opticsfile .parent .parent / "lhc_as-built.seq"
65
+ def _run2_sequence_from_opticsfile (opticsfile : Path , use_b4 : bool = False ) -> Path :
66
+ filename = "lhc_as-built.seq" if not use_b4 else "lhcb4_as-built.seq"
67
+ seqfile_path = opticsfile .parent .parent / filename
68
+ if not seqfile_path .is_file ():
69
+ logger .error ("Could not find sequence file '{filename}' at expected location '{seqfile_path}'" )
70
+ return seqfile_path
60
71
61
72
logger .debug ("Creating Run 3 setup MAD-X instance" )
62
73
echo , warn = kwargs .pop ("echo" , False ), kwargs .pop ("warn" , False )
63
74
64
75
madx = Madx (** kwargs )
65
76
madx .option (echo = echo , warn = warn )
66
77
logger .debug ("Calling sequence" )
67
- madx .call (_fullpath (_run2_sequence_from_opticsfile (Path (opticsfile ))))
78
+ madx .call (_fullpath (_run2_sequence_from_opticsfile (Path (opticsfile )), use_b4 = use_b4 ))
68
79
lhc .make_lhc_beams (madx , energy = energy )
69
80
70
81
if slicefactor :
@@ -82,7 +93,9 @@ def _run2_sequence_from_opticsfile(opticsfile: Path) -> Path:
82
93
return madx
83
94
84
95
85
- def prepare_lhc_run3 (opticsfile : str , beam : int = 1 , energy : float = 6800 , slicefactor : int = None , ** kwargs ) -> Madx :
96
+ def prepare_lhc_run3 (
97
+ opticsfile : str , beam : int = 1 , use_b4 : bool = False , energy : float = 6800 , slicefactor : int = None , ** kwargs
98
+ ) -> Madx :
86
99
"""
87
100
.. versionadded:: 1.0.0
88
101
@@ -102,6 +115,8 @@ def prepare_lhc_run3(opticsfile: str, beam: int = 1, energy: float = 6800, slice
102
115
opticsfile (str): name of the optics file to be used. Can be the string path to the file or only the opticsfile
103
116
name itself, which would be looked for at the **acc-models-lhc/operation/optics/** path.
104
117
beam (int): which beam to set up for. Defaults to beam 1.
118
+ use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking
119
+ purposes. Defaults to `False`.
105
120
energy (float): beam energy to set up for, in GeV. Defaults to 6800.
106
121
slicefactor (int): if provided, the sequence will be sliced and made thin. Defaults to `None`,
107
122
which leads to an unsliced sequence.
@@ -118,13 +133,19 @@ def prepare_lhc_run3(opticsfile: str, beam: int = 1, energy: float = 6800, slice
118
133
... "R2022a_A30cmC30cmA10mL200cm.madx", slicefactor=4, stdout=True
119
134
... )
120
135
"""
136
+ if use_b4 and beam != 2 :
137
+ logger .error ("Cannot use beam 4 sequence file for beam 1" )
138
+ raise ValueError ("Cannot use beam 4 sequence file for beam 1" )
139
+
121
140
logger .debug ("Creating Run 3 setup MAD-X instance" )
122
141
echo , warn = kwargs .pop ("echo" , False ), kwargs .pop ("warn" , False )
123
142
124
143
madx = Madx (** kwargs )
125
144
madx .option (echo = echo , warn = warn )
126
- logger .debug ("Calling sequence" )
127
- madx .call ("acc-models-lhc/lhc.seq" )
145
+
146
+ sequence = "lhc.seq" if not use_b4 else "lhcb4.seq"
147
+ logger .debug (f"Calling sequence file '{ sequence } '" )
148
+ madx .call (f"acc-models-lhc/{ sequence } " )
128
149
lhc .make_lhc_beams (madx , energy = energy )
129
150
130
151
if slicefactor :
@@ -160,14 +181,19 @@ class LHCSetup:
160
181
Matching is **not** performed by this setup and should be taken care of by the user, but the working
161
182
point should be set by the definitions in the *opticsfile*.
162
183
184
+ .. note::
185
+ If you intend to do tracking for beam 2, remember that the ``lhcb4`` sequence needs to be called.
186
+ This is handled by giving the ``use_b4`` argument as `True` to the constructor.
187
+
163
188
Args:
164
189
run (int): which run to set up for, should be 2 or 3. Defaults to run 3.
165
190
opticsfile (str): name of the opticsfile to be used. For a Run 2 setup, should be the string path to the file.
166
191
For a Run 3 setup, can be the string path to the file or only the opticsfile name itself, which would be
167
192
looked for at the **acc-models-lhc/operation/optics/** path. Defaults to `None`, which will raise an error.
168
193
beam (int): which beam to set up for. Defaults to beam 1.
169
- energy (float): beam energy to set up for, in GeV. Defaults to `None`, and is handled by either `~prepare_lhc_run2`
170
- or `~prepare_lhc_run3`. This means the default actually depends on the value of the **run** argument.
194
+ use_b4 (bool): if `True`, the lhcb4 sequence file will be used. This is the beam 2 sequence but for tracking
195
+ purposes. Defaults to `False`.
196
+ energy (float): beam energy to set up for, in GeV. Defaults to 6800, to match the default of run 3.
171
197
slicefactor (int): if provided, the sequence will be sliced and "made thin". Defaults to `None`,
172
198
which leads to an unsliced sequence.
173
199
**kwargs: if `echo` or `warn` are found in the keyword arguments they will be transmitted as options to ``MAD-X``.
@@ -202,20 +228,25 @@ def __init__(
202
228
run : int = 3 ,
203
229
opticsfile : str = None ,
204
230
beam : int = 1 ,
231
+ use_b4 : bool = False ,
205
232
energy : float = 6800 ,
206
233
slicefactor : int = None ,
207
234
** kwargs ,
208
235
):
209
236
assert opticsfile is not None , "An opticsfile must be provided"
237
+ if use_b4 and beam != 2 :
238
+ logger .error ("Cannot use beam 4 sequence file for beam 1" )
239
+ raise ValueError ("Cannot use beam 4 sequence file for beam 1" )
240
+
210
241
if int (run ) not in (2 , 3 ):
211
242
raise NotImplementedError ("This setup is only possible for Run 2 and Run 3 configurations." )
212
243
elif run == 2 :
213
244
self .madx = prepare_lhc_run2 (
214
- opticsfile = opticsfile , beam = beam , energy = energy , slicefactor = slicefactor , ** kwargs
245
+ opticsfile = opticsfile , beam = beam , use_b4 = use_b4 , energy = energy , slicefactor = slicefactor , ** kwargs
215
246
)
216
247
else :
217
248
self .madx = prepare_lhc_run3 (
218
- opticsfile = opticsfile , beam = beam , energy = energy , slicefactor = slicefactor , ** kwargs
249
+ opticsfile = opticsfile , beam = beam , use_b4 = use_b4 , energy = energy , slicefactor = slicefactor , ** kwargs
219
250
)
220
251
221
252
def __enter__ (self ):
0 commit comments