Source code for at.load.file_output

from __future__ import annotations

__all__ = ["Exporter"]

import sys
from collections.abc import Sequence, Generator

from .file_input import ElementDescr
from ..lattice import Lattice, elements as elt


[docs] class Exporter: delimiter: str = ";" continuation: str = "" label_fmt = str.maketrans("*/+-", "..__") # Not allowed in destination format bool_fmt = None use_line = True def __init__(self, ring: Lattice, **kwargs): def store_elem(store, elem: ElementDescr): """Store an element in the selected dictionary""" def name_gen(name: str, max: int = 10000): yield name for i in range(1, max): yield ".".join((name, str(i))) def check(name: str) -> tuple[bool, bool]: for st in self.all_stores: if name in st: if st is store: if elem == st[name]: return True, False else: return False, False else: return False, False return True, True for nm in name_gen(elem.name.translate(self.label_fmt)): valid, okstore = check(nm) if valid: if okstore: store[nm] = elem return nm raise NameError(f"Cannot store {elem.name}") def scan(ring: Lattice) -> Generator[tuple[str, ElementDescr], None, None]: """Run through the lattice and store the converted elements""" end = 0.0 for atelem in ring: attyp = type(atelem) elms = self.generate_madelems(attyp, vars(atelem).copy()) if isinstance(elms, ElementDescr): elms = (elms,) for elem in elms: store = self.store.get(attyp, self.anystore) length = elem.get("L", 0.0) loc = end + 0.5 * length end += length if store is not None: name = store_elem(store, elem) yield name, loc use_line = kwargs.pop("use_line", self.use_line) self.seqname = kwargs.pop("use", ring.name if ring.name else "RING") self.anystore = {} self.store = { elt.Drift: {} if use_line else None, elt.Quadrupole: {}, elt.Sextupole: {}, elt.Dipole: {}, } self.all_stores = [st for st in self.store.values() if st is not None] + [ self.anystore ] ElementDescr.bool_fmt = self.bool_fmt self.seq = list(scan(ring)) self.length = ring.cell_length self.in_file = getattr(ring, "in_file", "<unknown>") self.in_use = getattr(ring, "use", "<unknown") self.energy = ring.energy self.particle = ring.particle self.is_6d = ring.is_6d # self.anystore[self.seqname] = None
[docs] def generate_madelems( self, eltype: type[elt.Element], elemdict: dict ) -> ElementDescr | list[ElementDescr]: pass
[docs] def print_beam(self, file): pass
[docs] def print_elems(self, store: dict, file) -> None: print(file=file) for elname, el in store.items(): if el is not None: print(f"{elname.ljust(10)}: {str(el)}{self.delimiter}", file=file)
[docs] def print_sequence(self, file) -> None: line = f"\n{self.seqname.ljust(10)}: SEQUENCE, L={self.length}{self.delimiter}" print(f"\n{line}{self.delimiter}", file=file) for elname, at in self.seq: print(f" {elname.ljust(10)}, AT={at}{self.delimiter}", file=file) print(f"ENDSEQUENCE{self.delimiter}", file=file)
[docs] def print_line(self, file) -> None: def elnames(subseq: Sequence): return ", ".join(ename.ljust(8) for ename, at in subseq) nl = int((len(self.seq) - 1) / 10) print(f"\n{self.seqname.ljust(10)}: LINE=( {self.continuation}", file=file) for lnum in range(nl): print( f" {elnames(self.seq[10*lnum:10*(lnum+1)])}, {self.continuation}", file=file, ) print(f" {elnames(self.seq[10*nl:])}){self.delimiter}\n", file=file)
[docs] def export(self, filename: str | None = None) -> None: def do_export(file): print( f"! Converted by PyAT from in_file={self.in_file}, use={self.in_use!r}\n", file=file, ) self.print_beam(file) for store in self.all_stores: if store is not None: self.print_elems(store, file) if self.store[elt.Drift] is None: self.print_sequence(file) else: self.print_line(file) if filename is None: do_export(sys.stdout) else: with open(filename, "w") as mfile: do_export(mfile)