@@ -113,6 +113,7 @@ class Lhc(Accelerator):
113113 """
114114
115115 NAME = "lhc"
116+ REPOSITORY = "acc-models-lhc"
116117 RE_DICT : Dict [str , str ] = {
117118 AccElementTypes .BPMS : r"BPM" ,
118119 AccElementTypes .MAGNETS : r"M" ,
@@ -132,15 +133,23 @@ def get_parameters():
132133 params .add_parameter (
133134 name = "year" ,
134135 type = str ,
135- required = True ,
136- choices = ("2012" , "2015" , "2016" , "2017" , "2018" , "2022" , "hllhc1.3" ),
137136 help = "Year of the optics (or hllhc1.x version)." ,
138137 )
139138 params .add_parameter (
140139 name = "ats" ,
141140 action = "store_true" ,
142141 help = "Force use of ATS macros and knobs for years which are not ATS by default." ,
143- )
142+ )
143+ params .add_parameter (
144+ name = "b2_errors" ,
145+ type = str ,
146+ help = "The B2 error table to load for the best knowledge model." ,
147+ )
148+ params .add_parameter (
149+ name = "list_b2_errors" ,
150+ action = "store_true" ,
151+ help = "Lists all available b2 error tables" ,
152+ )
144153 return params
145154
146155 def __init__ (self , * args , ** kwargs ):
@@ -150,36 +159,38 @@ def __init__(self, *args, **kwargs):
150159 self .correctors_dir = "2012"
151160 self .year = opt .year
152161 self .ats = opt .ats
162+ self .b2_errors = opt .b2_errors
163+ self .list_b2_errors = opt .list_b2_errors
153164 if self .year == "hllhc1.3" :
154165 self .correctors_dir = "hllhc1.3"
155166 self .beam = opt .beam
156167 beam_to_beam_direction = {1 : 1 , 2 : - 1 }
157168 self .beam_direction = beam_to_beam_direction [self .beam ]
158- self .verify_object ()
159169
160170 def verify_object (self ) -> None : # TODO: Maybe more checks?
161171 """
162172 Verifies if everything is defined which should be defined.
163173 Will Raise an ``AcceleratorDefinitionError`` if one of the checks is invalid.
164174 """
165175 LOGGER .debug ("Accelerator class verification" )
176+
177+ Accelerator .verify_object (self )
166178 _ = self .beam
167179
168180 if self .model_dir is None and self .xing is None :
169181 raise AcceleratorDefinitionError ("Crossing on or off not set." )
170182
171- if self .excitation is None :
172- raise AcceleratorDefinitionError ("Excitation mode not set." )
173- if (self .excitation != AccExcitationMode .FREE ) and (self .drv_tunes is None ):
174- raise AcceleratorDefinitionError ("An excitation mode was given but driven tunes are not set." )
175-
176183 # TODO: write more output prints
177- LOGGER .debug ("... verification passed. \n Some information about the accelerator:" )
184+ LOGGER .debug (
185+ "... verification passed. \n Some information about the accelerator:"
186+ )
178187 LOGGER .debug (f"Class name { self .__class__ .__name__ } " )
179188 LOGGER .debug (f"Beam { self .beam } " )
180189 LOGGER .debug (f"Beam direction { self .beam_direction } " )
181190 if self .modifiers :
182- LOGGER .debug (f"Modifiers { ', ' .join ([str (m ) for m in self .modifiers ])} " )
191+ LOGGER .debug (
192+ f"Modifiers { ', ' .join ([str (m ) for m in self .modifiers ])} "
193+ )
183194
184195 @property
185196 def beam (self ) -> int :
@@ -216,7 +227,11 @@ def get_variables(self, frm: float = None, to: float = None, classes: Iterable[s
216227 LOGGER .debug ("The following classes are not found as corrector/variable classes and "
217228 f"are assumed to be the variable names directly instead:\n { str (unknown_classes )} " )
218229
219- vars = list (set (_flatten_list (all_vars_by_class [corr_cls ] for corr_cls in known_classes )))
230+ vars = list ( set (
231+ _flatten_list (
232+ all_vars_by_class [corr_cls ]
233+ for corr_cls in known_classes ))
234+ )
220235 vars = vars + unknown_classes
221236
222237 # Sort variables by S (nice for comparing different files)
@@ -297,6 +312,11 @@ def log_status(self) -> None:
297312 LOGGER .info (f"> Driven Tune Y [{ self .drv_tunes [1 ]:10.3f} ]" )
298313
299314 def load_main_seq_madx (self ) -> str :
315+ if self .acc_model_path is not None :
316+ main_call = f'call, file = \' { self .acc_model_path / "lhc.seq" } \' ;'
317+ if self .year .startswith ('hl' ):
318+ main_call += f'\n call, file = \' { self .acc_model_path / "hllhc_sequence.madx" } \' ;'
319+ return main_call
300320 try :
301321 return _get_call_main_for_year (self .year )
302322 except AttributeError :
@@ -323,19 +343,28 @@ def get_exciter_bpm(self, plane: str, commonbpms: List[str]):
323343 if self .excitation == AccExcitationMode .ACD :
324344 try :
325345 return (
326- _is_one_of_in ([f"BPMY{ a_b } .6L4.B{ beam } " , f"BPM.7L4.B{ beam } " ], commonbpms ),
346+ _is_one_of_in (
347+ [f"BPMY{ a_b } .6L4.B{ beam } " , f"BPM.7L4.B{ beam } " ], commonbpms
348+ ),
327349 f"MKQA.6L4.B{ beam } " ,
328350 )
329351 except KeyError as e :
330- raise KeyError ("AC-Dipole BPM not found in the common BPMs. Maybe cleaned?" ) from e
352+ raise KeyError (
353+ "AC-Dipole BPM not found in the common BPMs. Maybe cleaned?"
354+ ) from e
331355 if self .excitation == AccExcitationMode .ADT :
332356 try :
333357 return (
334- _is_one_of_in ([f"BPMWA.B5{ l_r } 4.B{ beam } " , f"BPMWA.A5{ l_r } 4.B{ beam } " ], commonbpms ),
358+ _is_one_of_in (
359+ [f"BPMWA.B5{ l_r } 4.B{ beam } " , f"BPMWA.A5{ l_r } 4.B{ beam } " ],
360+ commonbpms ,
361+ ),
335362 f"ADTK{ adt } 5{ l_r } 4.B{ beam } " ,
336363 )
337364 except KeyError as e :
338- raise KeyError ("ADT BPM not found in the common BPMs. Maybe cleaned?" ) from e
365+ raise KeyError (
366+ "ADT BPM not found in the common BPMs. Maybe cleaned?"
367+ ) from e
339368 return None
340369
341370 def important_phase_advances (self ) -> List [List [str ]]:
@@ -379,34 +408,46 @@ def get_base_madx_script(self, best_knowledge: bool = False) -> str:
379408 high_beta = False
380409 madx_script = (
381410 f"{ self ._get_madx_script_info_comments ()} "
382- f"! ----- Calling Sequence and Optics -----\n "
383411 f"call, file = '{ self .model_dir / MACROS_DIR / GENERAL_MACROS } ';\n "
384412 f"call, file = '{ self .model_dir / MACROS_DIR / LHC_MACROS } ';\n "
385- )
413+ )
414+ madx_script += f"omc3_beam_energy = { self .energy } ;\n "
415+ madx_script += "exec, define_nominal_beams();\n \n "
386416 if self ._uses_run3_macros ():
387- LOGGER .debug ("According to the optics year, Run 3 versions of the macros will be used" )
417+ LOGGER .debug (
418+ "According to the optics year, Run 3 versions of the macros will be used"
419+ )
388420 madx_script += (
389421 f"call, file = '{ self .model_dir / MACROS_DIR / LHC_MACROS_RUN3 } ';\n "
390422 )
391423
392- madx_script += (
393- f"{ self .load_main_seq_madx ()} \n "
394- f"exec, define_nominal_beams();\n "
395- )
424+ madx_script += "! ----- Calling Sequence and Optics -----\n "
425+ madx_script += "option, -echo; ! suppress output from base sequence loading to keep the log small\n "
426+ madx_script += self .load_main_seq_madx ()
427+ madx_script += "\n \n "
428+
396429 if self .modifiers is not None :
397430 madx_script += "" .join (
398431 f"call, file = '{ self .model_dir / modifier } '; { MODIFIER_TAG } \n "
399432 for modifier in self .modifiers
400433 )
434+
435+ if self .year in ['2012' , '2015' , '2016' , '2017' , '2018' , '2021' , 'hllhc1.3' ]:
436+ # backwards compatibility with pre acc-models optics
437+ madx_script += (
438+ f"\n ! ----- Defining Configuration Specifics -----\n "
439+ f"xing_angles = { '1' if self .xing else '0' } ;\n "
440+ f"if(xing_angles==1){{\n "
441+ f" exec, set_crossing_scheme_ON();\n "
442+ f"}}else{{\n "
443+ f" exec, set_default_crossing_scheme();\n "
444+ f"}}\n "
445+ )
446+ else :
447+ madx_script += 'call, file="knobs.madx";\n \n '
448+
401449 madx_script += (
402- f"\n ! ----- Defining Configuration Specifics -----\n "
403- f"exec, cycle_sequences();\n "
404- f"xing_angles = { '1' if self .xing else '0' } ;\n "
405- f"if(xing_angles==1){{\n "
406- f" exec, set_crossing_scheme_ON();\n "
407- f"}}else{{\n "
408- f" exec, set_default_crossing_scheme();\n "
409- f"}}\n "
450+ "exec, cycle_sequences();\n "
410451 f"use, sequence = LHCB{ self .beam } ;\n "
411452 f"option, echo;\n "
412453 )
@@ -422,14 +463,19 @@ def get_base_madx_script(self, best_knowledge: bool = False) -> str:
422463 madx_script += "exec, high_beta_matcher();\n "
423464
424465 madx_script += f"\n ! ----- Matching Knobs and Output Files -----\n "
425- if self ._uses_ats_knobs ():
426- LOGGER .debug ("According to the optics year or the --ats flag being provided, ATS macros and knobs will be used" )
427- madx_script += f"exec, match_tunes_ats({ self .nat_tunes [0 ]} , { self .nat_tunes [1 ]} , { self .beam } );\n "
428- madx_script += f"exec, coupling_knob_ats({ self .beam } );\n "
429- else :
430- madx_script += f"exec, match_tunes({ self .nat_tunes [0 ]} , { self .nat_tunes [1 ]} , { self .beam } );\n "
431- madx_script += f"exec, coupling_knob({ self .beam } );\n "
432-
466+
467+ # in the best knowledge case, all knobs are loaded from actual knowledge
468+ if not best_knowledge :
469+ if self ._uses_ats_knobs ():
470+ LOGGER .debug (
471+ "According to the optics year or the --ats flag being provided, ATS macros and knobs will be used"
472+ )
473+ madx_script += f"exec, match_tunes_ats({ self .nat_tunes [0 ]} , { self .nat_tunes [1 ]} , { self .beam } );\n "
474+ madx_script += f"exec, coupling_knob_ats({ self .beam } );\n "
475+ else :
476+ madx_script += f"exec, match_tunes({ self .nat_tunes [0 ]} , { self .nat_tunes [1 ]} , { self .beam } );\n "
477+ madx_script += f"exec, coupling_knob({ self .beam } );\n "
478+
433479 if ats_md :
434480 madx_script += "exec, full_response_ats();\n "
435481
@@ -461,13 +507,16 @@ def _uses_run3_macros(self) -> bool:
461507 except ValueError : # if a "hllhc1.x" year is given
462508 return False
463509
510+
464511# General functions ##########################################################
465512
466513
467514def _get_call_main_for_year (year : str ) -> str :
468515 call_main = f"call, file = '{ _get_file_for_year (year , 'main.seq' )} ';\n "
469516 if year == "2012" :
470- call_main += f"call, file = '{ LHC_DIR / '2012' / 'install_additional_elements.madx' } ';\n "
517+ call_main += (
518+ f"call, file = '{ LHC_DIR / '2012' / 'install_additional_elements.madx' } ';\n "
519+ )
471520 if year == "hllhc1.3" :
472521 call_main += f"call, file = '{ LHC_DIR / 'hllhc1.3' / 'main_update.seq' } ';\n "
473522 return call_main
0 commit comments