@@ -328,6 +328,7 @@ def from_madx_sequence(
328328 exact_drift = False ,
329329 drift_threshold = 1e-6 ,
330330 install_apertures = False ,
331+ apply_madx_errors = False ,
331332 ):
332333
333334 line = cls (elements = [], element_names = [])
@@ -342,6 +343,9 @@ def from_madx_sequence(
342343 ):
343344 line .append_element (el , el_name )
344345
346+ if apply_madx_errors :
347+ line ._apply_madx_errors (sequence )
348+
345349 return line
346350
347351 # error handling (alignment, multipole orders, ...):
@@ -366,7 +370,7 @@ def find_element_ids(self, element_name):
366370 idx_after_el = idx_el + 1
367371 return idx_el , idx_after_el
368372
369- def add_offset_error_to (self , element_name , dx = 0 , dy = 0 ):
373+ def _add_offset_error_to (self , element_name , dx = 0 , dy = 0 ):
370374 idx_el , idx_after_el = self .find_element_ids (element_name )
371375 xyshift = elements .XYShift (dx = dx , dy = dy )
372376 inv_xyshift = elements .XYShift (dx = - dx , dy = - dy )
@@ -375,7 +379,7 @@ def add_offset_error_to(self, element_name, dx=0, dy=0):
375379 idx_after_el + 1 , inv_xyshift , element_name + "_offset_out"
376380 )
377381
378- def add_aperture_offset_error_to (self , element_name , arex = 0 , arey = 0 ):
382+ def _add_aperture_offset_error_to (self , element_name , arex = 0 , arey = 0 ):
379383 idx_el , idx_after_el = self .find_element_ids (element_name )
380384 idx_el_aper = idx_after_el - 1
381385 if not self .element_names [idx_el_aper ] == element_name + "_aperture" :
@@ -389,7 +393,7 @@ def add_aperture_offset_error_to(self, element_name, arex=0, arey=0):
389393 idx_after_el + 1 , inv_xyshift , element_name + "_aperture_offset_out"
390394 )
391395
392- def add_tilt_error_to (self , element_name , angle ):
396+ def _add_tilt_error_to (self , element_name , angle ):
393397 '''Alignment error of transverse rotation around s-axis.
394398 The element corresponding to the given `element_name`
395399 gets wrapped by SRotation elements with rotation angle
@@ -418,7 +422,7 @@ def add_tilt_error_to(self, element_name, angle):
418422 self .insert_element (idx_el , srot , element_name + "_tilt_in" )
419423 self .insert_element (idx_after_el + 1 , inv_srot , element_name + "_tilt_out" )
420424
421- def add_multipole_error_to (self , element_name , knl = [], ksl = []):
425+ def _add_multipole_error_to (self , element_name , knl = [], ksl = []):
422426 # will raise error if element not present:
423427 assert element_name in self .element_names
424428 element = self .elements [self .element_names .index (element_name )]
@@ -435,97 +439,72 @@ def add_multipole_error_to(self, element_name, knl=[], ksl=[]):
435439 for i , component in enumerate (ksl ):
436440 element .ksl [i ] += component
437441
438- def apply_madx_errors (self , error_table ):
439- """Applies MAD-X error_table (with multipole errors,
440- dx and dy offset errors and dpsi tilt errors)
441- to existing elements in this Line instance.
442+ def _apply_madx_errors (self , madx_sequence ):
443+ """Applies errors from MAD-X sequence to existing
444+ elements in this Line instance.
442445
443- Return error_table names which were not found in the
444- elements of this Line instance (and thus not treated).
446+ Return names of MAD-X elements with existing align_errors
447+ or field_errors which were not found in the elements of
448+ this Line instance (and thus not treated).
445449
446450 Example via cpymad:
447451 madx = cpymad.madx.Madx()
448452
449453 # (...set up lattice and errors in cpymad...)
450454
451455 seq = madx.sequence.some_lattice
452- # store already applied errors:
453- madx.command.esave(file='lattice_errors.err')
454- madx.command.readtable(
455- file='lattice_errors.err', table="errors")
456- errors = madx.table.errors
457-
458- pysixtrack_line = Line.from_madx_sequence(seq)
459- pysixtrack_line.apply_madx_errors(errors)
456+ pysixtrack_line = pysixtrack.Line.from_madx_sequence(
457+ seq,
458+ apply_madx_errors=True
459+ )
460460 """
461- max_multipole_err = 0
462- # check for errors in table which cannot be treated yet:
463- for error_type in error_table .keys ():
464- if error_type == "name" :
465- continue
466- if any (error_table [error_type ]):
467- if error_type in ["dx" , "dy" , "dpsi" , "arex" , "arey" ]:
468- # available alignment error
469- continue
470- elif error_type [:1 ] == "k" and error_type [- 1 :] == "l" :
471- # available multipole error
472- order = int ("" .join (c for c in error_type if c .isdigit ()))
473- max_multipole_err = max (max_multipole_err , order )
474- else :
475- print (
476- f'Warning: MAD-X error type "{ error_type } "'
477- " not implemented yet."
478- )
479-
480461 elements_not_found = []
481- for i_line , element_name in enumerate (error_table ["name" ]):
462+ for element , element_name in zip (
463+ madx_sequence .expanded_elements ,
464+ madx_sequence .expanded_element_names ()
465+ ):
482466 if element_name not in self .element_names :
483- elements_not_found .append (element_name )
484- continue
467+ if element .align_errors or element .field_errors :
468+ elements_not_found .append (element_name )
469+ continue
485470
486- # add offset
487- try :
488- dx = error_table ["dx" ][i_line ]
489- except KeyError :
490- dx = 0
491- try :
492- dy = error_table ["dy" ][i_line ]
493- except KeyError :
494- dy = 0
495- if dx or dy :
496- self .add_offset_error_to (element_name , dx , dy )
497-
498- # add tilt
499- try :
500- dpsi = error_table ["dpsi" ][i_line ]
501- except KeyError :
502- dpsi = 0
503- if dpsi :
504- self .add_tilt_error_to (element_name , angle = dpsi / deg2rad )
505-
506- # add aperture-only offset
507- try :
508- arex = error_table ["arex" ][i_line ]
509- except KeyError :
510- arex = 0
511- try :
512- arey = error_table ["arey" ][i_line ]
513- except KeyError :
514- arey = 0
515- if arex or arey :
516- self .add_aperture_offset_error_to (element_name , arex , arey )
517-
518- # add multipole error
519- knl = [
520- error_table [f"k{ o } l" ][i_line ]
521- for o in range (max_multipole_err + 1 )
522- ]
523- ksl = [
524- error_table [f"k{ o } sl" ][i_line ]
525- for o in range (max_multipole_err + 1 )
526- ]
527- if any (knl ) or any (ksl ):
528- self .add_multipole_error_to (element_name , knl , ksl )
471+ if element .align_errors :
472+ # add offset
473+ dx = element .align_errors .dx
474+ dy = element .align_errors .dy
475+ if dx or dy :
476+ self ._add_offset_error_to (element_name , dx , dy )
477+
478+ # add tilt
479+ dpsi = element .align_errors .dpsi
480+ if dpsi :
481+ self ._add_tilt_error_to (element_name , angle = dpsi / deg2rad )
482+
483+ # add aperture-only offset
484+ arex = element .align_errors .arex
485+ arey = element .align_errors .arey
486+ if arex or arey :
487+ self ._add_aperture_offset_error_to (element_name , arex , arey )
488+
489+ # check for errors which cannot be treated yet:
490+ for error_type in dir (element .align_errors ):
491+ if not error_type [0 ] == '_' and \
492+ error_type not in ['dx' , 'dy' , 'dpsi' , 'arex' ,
493+ 'arey' , 'count' , 'index' ]:
494+ print (
495+ f'Warning: MAD-X error type "{ error_type } "'
496+ " not implemented yet."
497+ )
498+
499+ if element .field_errors :
500+ # add multipole error
501+ if any (element .field_errors .dkn ) or \
502+ any (element .field_errors .dks ):
503+ knl = element .field_errors .dkn
504+ ksl = element .field_errors .dks
505+ knl = knl [:np .amax (np .where (knl )) + 1 ] # delete trailing zeros
506+ ksl = ksl [:np .amax (np .where (ksl )) + 1 ] # to keep order low
507+ self ._add_multipole_error_to (element_name , knl , ksl )
529508
530509 return elements_not_found
531510
0 commit comments