Skip to content

Commit 8e1d432

Browse files
authored
Merge pull request #60 from roman-martin/mad_loader_errors
loader of MAD-X errors
2 parents 4ab545d + 82b94d0 commit 8e1d432

File tree

3 files changed

+232
-107
lines changed

3 files changed

+232
-107
lines changed

pysixtrack/line.py

Lines changed: 62 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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

tests/test_line.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,24 @@ def test_line():
3434
n_elements += 1
3535
assert len(line) == n_elements
3636

37-
line.add_offset_error_to(multipole_name, dx=0, dy=0)
37+
line._add_offset_error_to(multipole_name, dx=0, dy=0)
3838
n_elements += 2
3939
assert len(line) == n_elements
4040

41-
line.add_offset_error_to(multipole_name, dx=0.2, dy=-0.003)
41+
line._add_offset_error_to(multipole_name, dx=0.2, dy=-0.003)
4242
n_elements += 2
4343
assert len(line) == n_elements
4444

45-
line.add_tilt_error_to(multipole_name, angle=0)
45+
line._add_tilt_error_to(multipole_name, angle=0)
4646
n_elements += 2
4747
assert len(line) == n_elements
4848

49-
line.add_tilt_error_to(multipole_name, angle=0.1)
49+
line._add_tilt_error_to(multipole_name, angle=0.1)
5050
n_elements += 2
5151
assert len(line) == n_elements
5252

53-
line.add_multipole_error_to(multipole_name, knl=[0, 0.1], ksl=[-0.03, 0.01])
54-
# line.add_multipole_error_to(drift_exact,knl=[0,0.1],ksl=[-0.03,0.01])
53+
line._add_multipole_error_to(multipole_name, knl=[0, 0.1], ksl=[-0.03, 0.01])
54+
# line._add_multipole_error_to(drift_exact,knl=[0,0.1],ksl=[-0.03,0.01])
5555

5656
line_dict = line.to_dict()
5757
line = pysixtrack.Line.from_dict(line_dict)

0 commit comments

Comments
 (0)