Source code for sirepo.template.elegant_lattice_parser

# -*- coding: utf-8 -*-
"""elegant lattice parser.

:copyright: Copyright (c) 2015 RadiaSoft LLC.  All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
from pykern.pkcollections import PKDict
from pykern.pkdebug import pkdc, pkdlog, pkdp
import re

from sirepo.template.line_parser import LineParser

# a map of old elegant names to the new name
_FIELD_ALIAS = PKDict(bmax="b_max")


[docs] def parse_file(lattice_text, rpn_variables, maxId=0): parser = LineParser(maxId) lines = lattice_text.replace("\r", "").split("\n") prev_line = "" models = PKDict( beamlines=[], elements=[], default_beamline_name=None, rpnVariables=PKDict(), ) for line in lines: parser.increment_line_number() if re.search(r"^\s*\!", line): continue if re.search(r"\&\s*$", line): prev_line += re.sub(r"(\s*\&\s*)$", "", line) continue if not _parse_line(parser, prev_line + line, models): break prev_line = "" models["rpnVariables"] = [ PKDict(name=k, value=v) for k, v in models.rpnVariables.items() ] + rpn_variables return models
def _parse_beamline(parser, name): parser.assert_char("=") return PKDict( name=name, id=parser.next_id(), items=_parse_beamline_items(parser), ) def _parse_beamline_items(parser): parser.assert_char("(") items = [] while True: value = parser.parse_value() if not value: if parser.peek_char() == ",": parser.assert_char(",") continue parser.raise_error("expecting beamline element") if re.search(r"^[0-9]+$", value): repeat_count = int(value) parser.assert_char("*") if parser.peek_char() == "(": repeat_items = _parse_beamline_items(parser) else: repeat_items = [parser.parse_value()] for _ in range(repeat_count): for item in repeat_items: items.append(item) else: items.append(value) if parser.peek_char() == ",": parser.assert_char(",") else: break parser.assert_char(")") return items def _parse_element(parser, name, type): el = PKDict( _id=parser.next_id(), type=type, name=name, ) while parser.peek_char() == ",": parser.assert_char(",") field = parser.parse_value() if not field: parser.assert_end_of_line() if parser.peek_char() == "=": parser.assert_char("=") f = field.lower() if f in _FIELD_ALIAS: f = _FIELD_ALIAS[f] el[f] = parser.parse_value() return el def _parse_line(parser, line, models): line = line.lstrip() # strip comments line = re.sub(r"\s!.*$", "", line) # ignore end of line ';' line = re.sub(r";\s*$", "", line) parser.set_line(line) name = "" while parser.peek_char() == ":": # need to strip leading ':' and add to name, used as value break below parser.assert_char(":") name += ":" name += parser.parse_value(r"[:\s,=)*]") if re.search(r"^\%", name): # rpn value line = re.sub(r"\s*%\s*", "", line) line = re.sub(r"\s+", " ", line) _save_rpn_variables(line, models["rpnVariables"]) return True if not name or not re.search(r"[:0-9A-Z]", name[0], re.IGNORECASE): if name and name.upper() == "#INCLUDE": parser.raise_error("#INCLUDE files not supported") return True if parser.peek_char() != ":": if name.upper() == "USE" and parser.peek_char() == ",": parser.assert_char(",") models["default_beamline_name"] = parser.parse_value() return True if name.upper() == "RETURN": return False # ignore non-definition lines return True parser.assert_char(":") type = parser.parse_value() if not type: parser.raise_error("expected type") if type.upper() == "LINE": models["beamlines"].append(_parse_beamline(parser, name)) else: models["elements"].append(_parse_element(parser, name, type)) parser.assert_end_of_line() return True def _save_rpn_variables(line, rpn_variables): m = re.match(r"(.*) sto ((\S+).*)", line) if m: val = _save_rpn_variables(m.group(1), rpn_variables) var = m.group(3) rpn_variables[var] = val return m.group(2) return line