API Reference

Everything below is exported from the top-level palsparserpy package, so pp.parse_and_expand_pals(...) reaches it after import palsparserpy as pp.

The tree objects

class palsparserpy.YAMLNode(tree, node_id)[source]

Bases: object

A reference to a single node within a YAMLTree.

Holding a YAMLNode keeps its tree alive. Node ids are invalidated if the tree is deleted.

Parameters:
tree
id
is_map()[source]

Whether this node is a MAP (a collection of key/value pairs).

A node is exactly one of MAP, sequence, or scalar; use this to decide before accessing children by key.

Return type:

bool

is_sequence()[source]

Whether this node is a sequence (an ordered list of elements).

A node is exactly one of MAP, sequence, or scalar; use this to decide before accessing children by index.

Return type:

bool

is_scalar()[source]

Whether this node is a scalar (a leaf holding a single string, number or boolean value).

Scalar nodes have no children and their value is read with value, as_int(), as_float() or as_bool().

Return type:

bool

parent()[source]

The parent of this node. Raises ValueError for the root, which has no parent.

Return type:

YAMLNode

root()[source]

The root of the tree this node belongs to (this node itself if it is the root).

Return type:

YAMLNode

child(index)[source]

The index-th direct child of a MAP or sequence node, 0-based.

Unlike node[key], this reaches a MAP’s children by position, which is how a single-key map entry is opened without knowing its key.

Parameters:

index (int)

Return type:

YAMLNode

get(key, default=None)[source]

The child stored under key, or default if there is none.

Parameters:

key (str)

__getitem__(key)[source]

node[key] looks up a direct child of a MAP by its string key; node[i] returns the i-th direct child of a MAP or sequence.

Only direct children are searched (the lookup is not recursive). Raises KeyError if no child has the given key – test with key in node if it may be absent – and IndexError if the index is out of bounds.

Parameters:

key (str | int)

Return type:

YAMLNode

__contains__(key)[source]

Whether the MAP node has a direct child stored under key. Only direct children are checked; the search is not recursive.

Parameters:

key (str)

Return type:

bool

__len__()[source]

The number of direct children: the number of key/value pairs in a MAP, or the number of elements in a sequence. Scalar nodes report 0.

Return type:

int

keys()[source]

The keys of a MAP node, in document order. Empty for sequence and scalar nodes.

Return type:

list[str]

values()[source]

The children of this node, in document order.

Return type:

list[YAMLNode]

items()[source]

The (key, child) pairs of a MAP node, in document order.

Return type:

list[tuple[str, YAMLNode]]

__iter__()[source]

Iterate the node’s children: a sequence yields its elements, a MAP yields its keys (as dict does; use items() for pairs), and a scalar yields nothing.

Return type:

Iterator

node_key()[source]

The key under which this node is stored in its parent MAP, or None if it has none. Sequence elements and the tree root have no key.

Return type:

str | None

property value: str

The scalar value of this node, as raw text.

Raises ValueError if the node has no value (i.e. it is a MAP or a bare sequence). Use as_int(), as_float() or as_bool() for typed values.

as_int()[source]

The scalar value parsed as an int. Raises if the node is not a scalar or its text is not a valid integer.

Return type:

int

as_float()[source]

The scalar value parsed as a float. Raises if the node is not a scalar or its text is not a valid floating-point number.

Return type:

float

as_bool()[source]

The scalar value parsed as a bool.

Accepts exactly the text true or false; any other value (or a non-scalar node) raises ValueError.

Return type:

bool

add_scalar(value, key=None, index=None)[source]

Add a scalar child to this node.

Pass key for MAP parents; omit it for sequence elements. index selects the 0-based position among the existing children; the default appends at the end.

Parameters:
Return type:

YAMLNode

add_map(key=None, index=None)[source]

Add an empty MAP child to this node.

Pass key for MAP parents; omit it for sequence elements. index selects the 0-based position among the existing children; the default appends at the end.

Parameters:
Return type:

YAMLNode

add_sequence(key=None, index=None)[source]

Add an empty sequence child to this node.

Pass key for MAP parents; omit it for sequence elements. index selects the 0-based position among the existing children; the default appends at the end.

Parameters:
Return type:

YAMLNode

__setitem__(key, value)[source]

node[key] = value sets or updates a scalar value in a MAP node.

If key already exists its value is updated; otherwise a new scalar child is appended.

Parameters:
Return type:

None

set_scalar(value)[source]

Set or replace the scalar value of this node.

Operates on an existing node in place; to set a value by key within a MAP (adding the key if absent), use node[key] = value instead.

Parameters:

value (str)

Return type:

None

set_key(key)[source]

Set or replace the key under which this node is stored in its parent MAP. Only meaningful inside a MAP; sequence elements are keyless.

Parameters:

key (str)

Return type:

None

remove()[source]

Remove this node, together with all of its descendants, from its parent.

After removal the YAMLNode is stale and must not be used again. Intended for non-root nodes; the root has no parent to be removed from.

Return type:

None

__delitem__(key)[source]

del node[key] removes a child and all of its descendants.

Parameters:

key (str | int)

Return type:

None

deep_copy_node(src)[source]

Copy the type, key, value and all descendants of src into this node, overwriting whatever it previously held. Works across trees.

Parameters:

src (YAMLNode)

Return type:

None

deep_copy_children(src, index=None)[source]

Copy all children of src into this node at the 0-based position index among the existing children; the default appends them at the end. Works across trees.

Parameters:
Return type:

None

copy()[source]

An independent deep copy of this node, in a tree of its own.

Return type:

YAMLNode

to_yaml_string(exclude=())[source]

Emit this node and its descendants as a YAML string.

exclude is a key name, or a collection of key names, to be left out of the output: every MAP entry whose key matches, at any depth, is omitted along with its whole subtree. This is a display filter only – the node itself is never modified. For example, to print a lattice without the floor and reference subtrees:

print(lat.to_yaml_string(exclude=["FloorP", "ReferenceP"]))
Parameters:

exclude (str | Iterable[str])

Return type:

str

write_yaml(filename, exclude=())[source]

Write the entire tree that contains this node to a YAML file.

Returns True on success. exclude is a key name, or a collection of key names, to be left out of the file: every MAP entry whose key matches, at any depth, is omitted along with its whole subtree. The tree in memory is not modified. For example:

lat.write_yaml("out.pals.yaml", exclude=["FloorP", "ReferenceP"])
Parameters:

exclude (str | Iterable[str])

Return type:

bool

class palsparserpy.YAMLTree(handle)[source]

Bases: object

Owns a C YAMLTreeHandle. Freed automatically when the object is garbage collected. Do not use the handle after the tree has been freed.

handle
exception palsparserpy.PALSParseError[source]

Bases: ValueError

A YAML document could not be parsed.

The message carries what the C library reported – for a syntax error, prefixed with the offending line L, column C: – so the fault can be pinpointed instead of reported as a bare failure.

Parsing and building

palsparserpy.parse_file(filename)[source]

Parse a YAML file from disk. Returns a node pointing to the tree root.

Return type:

YAMLNode

palsparserpy.parse_string(yaml_str)[source]

Parse a YAML string. Returns a node pointing to the tree root.

Parameters:

yaml_str (str)

Return type:

YAMLNode

palsparserpy.create_empty_tree()[source]

Create an empty MAP tree. Returns a node pointing to the root MAP.

Return type:

YAMLNode

Function forms of the node operations

Each of these is the free-function spelling of the like-named YAMLNode method above.

palsparserpy.is_map(node)[source]

Whether node is a MAP. See YAMLNode.is_map().

Parameters:

node (YAMLNode)

Return type:

bool

palsparserpy.is_sequence(node)[source]

Whether node is a sequence. See YAMLNode.is_sequence().

Parameters:

node (YAMLNode)

Return type:

bool

palsparserpy.is_scalar(node)[source]

Whether node is a scalar. See YAMLNode.is_scalar().

Parameters:

node (YAMLNode)

Return type:

bool

palsparserpy.get_parent(node)[source]

The parent of node. See YAMLNode.parent().

Parameters:

node (YAMLNode)

Return type:

YAMLNode

palsparserpy.node_key(node)[source]

The key node is stored under. See YAMLNode.node_key().

Parameters:

node (YAMLNode)

Return type:

str | None

palsparserpy.add_scalar(parent, value, key=None, index=None)[source]

Add a scalar child to parent. See YAMLNode.add_scalar().

Parameters:
Return type:

YAMLNode

palsparserpy.add_map(parent, key=None, index=None)[source]

Add an empty MAP child to parent. See YAMLNode.add_map().

Parameters:
Return type:

YAMLNode

palsparserpy.add_sequence(parent, key=None, index=None)[source]

Add an empty sequence child to parent. See YAMLNode.add_sequence().

Parameters:
Return type:

YAMLNode

palsparserpy.set_scalar(node, value)[source]

Set the scalar value of node. See YAMLNode.set_scalar().

Parameters:
Return type:

None

palsparserpy.set_key(node, key)[source]

Set the key of node. See YAMLNode.set_key().

Parameters:
Return type:

None

palsparserpy.remove(node)[source]

Remove node from its parent. See YAMLNode.remove().

Parameters:

node (YAMLNode)

Return type:

None

palsparserpy.deep_copy_node(dst, src)[source]

Copy src into dst. See YAMLNode.deep_copy_node().

Parameters:
Return type:

None

palsparserpy.deep_copy_children(dst, src, index=None)[source]

Copy the children of src into dst. See YAMLNode.deep_copy_children().

Parameters:
Return type:

None

palsparserpy.to_yaml_string(node, exclude=())[source]

Emit node as YAML. See YAMLNode.to_yaml_string().

Parameters:
Return type:

str

palsparserpy.write_yaml(node, filename, exclude=())[source]

Write node’s tree to a file. See YAMLNode.write_yaml().

Parameters:
Return type:

bool

Lattices

palsparserpy.parse_and_expand_pals(filename, root_lattice='', *, problems='print')[source]

Parse a PALS lattice file and return its five views.

Returns a Lattices holding the original, combined, expanded, full_expanded and adjunct views together with the list of expansion problems.

Parameters:
  • filename – Path to the top-level YAML lattice file.

  • root_lattice (str) –

    Name of the lattice to expand. If empty (the default), the lattice to expand is chosen with the following priority:

    1. the lattice named by the last use statement, or

    2. the last lattice defined in the file if no use statement is present.

  • problems (str | PathLike) –

    What to do with the list of problems found while expanding (undefined lattice, dangling element/line references, undefined inherit/repeat/Fork targets, and expressions that could not be evaluated). One of:

    • "print" (the default) – print the problems to stderr (nothing is printed when there are none);

    • "none" – do nothing (no printing, no file);

    • any other path – write the problems to that file, printing nothing. Those two names are reserved, so a report cannot be written to a file called print or none.

Return type:

Lattices

The same problems handed to problems are also returned in the problems field regardless of the reporting mode, so "none" still lets the caller inspect them programmatically. Each entry carries a message, the path it was found at, a severity and an origin; only a PROBLEM_INPUT can be cleared by editing the lattice.

The five tree views are:

  • original: the tree as read in, mapping each file (including any file it includes or loads) to its unparsed contents.

  • combined: the tree with all include directives resolved and spliced inline, and every load merged in subnode by subnode.

  • full_expanded: the selected lattice fully expanded, and nothing else – scalars substituted with their full definitions, every repeat unrolled, every inherit merged in, forks resolved, set commands executed and ABSOLUTE controllers applied. It is rooted at a map holding the single name -> Lattice entry, without the PALS/ facility scaffolding the lattice was defined under, so the lattice is reached as lat.full_expanded["lat1"] rather than through ["PALS"]["facility"]. Its branches entries are branches, not the BeamLine``s they were built from, and so carry no ``kind; a BeamLine referenced inside a line is a sub-line whose contents are spliced directly into the enclosing line, so no nested BeamLine survives in the expanded tree. Elements of a multipass line carry a multipass_index giving their pass number – how many times a particle will have travelled through that physical element by that point – so every element of one traversal shares an index (the nearest enclosing multipass line wins when they nest). Every dependent parameter is computed and present: each element carries its element_index (its position, counting from one, in the branch line that holds it), its ReferenceP, FloorP and s_position, the derived members of every parameter family it uses, and the non-zero defaults of the groups it carries; each branch is capped with a branch_end Placeholder holding its final reference and floor, numbered with the rest.

  • expanded: the same lattice with all of that removed – what the author wrote decides which parameters stay. It is full_expanded with nodes pruned rather than an earlier snapshot, so a parameter present in both views holds the same value in both. Use it to see the inputs rather than their consequences, or to write a lattice back out without the computed values.

  • adjunct: everything the expanded views do not carry, keeping its PALS/facility scaffolding: element and beamline definitions, use statements, constants and variables, Controller``s, ``set commands, and any Lattice that was not the one expanded. A definition that expansion substituted into the lattice is copied, so it appears in both trees.

Every mathematical expression is evaluated to a number across the expanded views and adjunct (see evaluate_pals_expression(); random()/random_gauss() are left as text). Controller elements are evaluated against their own scoped variable tables, with each control expression computed and stored back in its control entry; controllers are facility-level, so they are found in adjunct.

Each view is backed by its own tree; all five are freed independently when their nodes are garbage collected.

palsparserpy.evaluate_pals_expression(expr)[source]

Evaluate a single PALS mathematical expression to a float.

Supports the full PALS expression grammar: arithmetic (+ - * / ^), unary signs, parentheses, the built-in constants (pi, c_light, r_electron, …), the math functions (sqrt, log, sin, floor, modulo, …), and the particle-data functions mass_of, charge_of and anomalous_moment_of (backed by AtomicAndPhysicalConstantsCLib), whose species-name argument must be quoted, e.g. mass_of("#3He") (a mass number carries a leading #). A leading expr(...) wrapper is accepted and unwrapped.

This evaluates a standalone string, so user-defined constants and variables are not in scope – use parse_and_expand_pals() for whole-lattice evaluation, whose expanded trees already have every expression resolved to a number. Raises ValueError if expr is not evaluable: a parse error, an unknown identifier or species, a random()/random_gauss() expression (which is intentionally deferred), or a non-finite result.

Example

>>> evaluate_pals_expression("3.75e7 / c_light^2")     # 4.172...e-10
>>> evaluate_pals_expression('mass_of("electron")')    # 510998.95069...
>>> evaluate_pals_expression("expr(2 * pi)")           # 6.283...
Parameters:

expr (str)

Return type:

float

palsparserpy.node_correspondence(lat)[source]

Map every node of a lattice to the nodes it corresponds to across the original, combined, full_expanded and adjunct trees.

The correspondence is exact: it is computed from provenance recorded while the trees were derived from one another (original -> combined -> full_expanded and adjunct), not by re-matching after the fact. Because expansion can duplicate a node (scalar substitution, repeat, inherit, forks), the correspondence is one-to-many – a single combined/original node can map to several full_expanded copies – so each field of the returned value is a list of nodes.

Expansion splits the document, so a node of combined may land in full_expanded, in adjunct, or in both: a definition that was substituted into the lattice is copied there while its definition stays behind. Those copies share one equivalence class, tied together through the combined node they came from.

The expanded view takes no part in the correspondence: it is a pruned copy of full_expanded rather than a step in the derivation chain, so a node in it is found by the path it sits at, not by a recorded link.

Returns:

A dict keyed by node. For any node that participates in the correspondence, corr[node] is a NodeCorrespondence(original, combined, full_expanded, adjunct) – listing every corresponding node grouped by tree. The queried node appears in its own tree’s list, so the four lists together are the full equivalence class of node. A list is empty when a tree has no corresponding node (e.g. the synthesised destination_pointer scalar exists only in full_expanded, and a constant that the lattice never references exists only in adjunct).

Parameters:

lat (Lattices)

Return type:

Dict[YAMLNode, NodeCorrespondence]

Example

>>> lat = parse_and_expand_pals("lattice.pals.yaml")
>>> corr = node_correspondence(lat)
>>> a_const = lat.combined["PALS"]["facility"][0]["constants"]["a_const"]
>>> corr[a_const].original        # the same constant in the original tree
>>> corr[a_const].adjunct         # constants are not part of the lattice
>>> corr[a_const].full_expanded   # empty unless the lattice referenced it
palsparserpy.match_names(node, match_string)[source]

Every named construct in node’s tree that is matched by match_string, following PALS Name Matching.

node may be any node of the tree to search (typically a lattice-view root such as lat.full_expanded); the whole tree is searched and the returned nodes belong to that same tree.

match_string has the form:

[{lattice}>>>][{branch}>>][{kind}::]{name}[>{group}.{sub}. ... .{parameter}]

{lattice}, {branch} and {name} are PCRE2 patterns matched against the whole name (anchored at both ends); {kind} is matched exactly; the parameter path after the single > is matched exactly, key by key. An omitted or empty pattern matches any name at that level. {branch} matches an element if any enclosing BeamLine/Branch name matches, so elements in sub-lines are included.

The node returned for each match is whatever the string resolves to: the element node (no parameter path), the parameter-group or parameter node (with a path), or – for a bare name (no lattice/branch/kind qualifier and no parameter path) – additionally each matching constant and variable defined directly under the PALS or facility node (both the full kind: constant/kind: variable and the compact constants:/variables: forms). Lattice parameters therefore include constant and variable names.

Which tree to search follows from that: elements are in lat.full_expanded, while constants and variables are defined at facility level and so are found in lat.adjunct. Searching lat.full_expanded for a constant matches nothing, since the PALS/facility node it would be defined under is not part of that tree.

Not yet implemented from Element Name Matching: #N instance selection, {e1}:{e2} ranges, , unions, and & intersections.

Results are de-duplicated and returned in document order. A malformed pattern yields an empty list.

Example

>>> lat = parse_and_expand_pals("lattice.pals.yaml")
>>> match_names(lat.full_expanded, "B1.*>BendP.e1")   # e1 of every B1... bend
>>> match_names(lat.full_expanded, "Quadrupole::.*")  # every quadrupole
>>> match_names(lat.full_expanded, "inj>>>arc>>Q.*>length")
>>> match_names(lat.adjunct, "a_.*")                  # constants/variables
Parameters:
Return type:

List[YAMLNode]

palsparserpy.parameter_value(lat, match_string)[source]

The value of the lattice parameter named by match_string, looked up in the expanded lattice lat.

match_string uses the same PALS Name Matching syntax as match_names(). It names either an element parameter (with a >{group}.{sub}. ... .{parameter} path) or, as a bare name (no lattice/branch/kind qualifier and no path), a constant or variable – the same constructs match_names() resolves.

Only two of lat’s five views are searched: lat.full_expanded, which holds the element parameters, and then, if the name is not found there, lat.adjunct, which holds the facility-level constants, variables, and any definitions not spliced into the lattice. The raw lat.original and lat.combined views are not searched – they carry unevaluated, pre-expansion text. lat.expanded is not searched either: a dependent parameter is a legitimate thing to ask for, and only full_expanded carries one.

Because both searched views are post-expansion, values come back already evaluated: a numeric value as a float, and a non-numeric one (e.g. a species name like "#3He", or an expression expansion left unevaluated such as one using random()) verbatim as a str.

The value is resolved as follows:

  • Element parameter, set: its value – a float, or a str when non-numeric.

  • Element parameter, not set: the parameter’s default is returned (0.0 for every parameter, for now – real per-parameter defaults come later).

  • Constant or variable (bare name): its value, the same way.

  • Nothing identified: None, when the name matches nothing in either view, names a bare element (an element has no single scalar value), stops on a whole parameter group, or several matches carry conflicting values.

Example

>>> lat = parse_and_expand_pals("lattice.pals.yaml")
>>> parameter_value(lat, "quad1>MagneticMultipoleP.Bn1")  # 1.0
>>> parameter_value(lat, "quad1>BendP.g")                 # 0.0 (unset)
>>> parameter_value(lat, "a_const")                       # from adjunct
>>> parameter_value(lat, "quad1>nope.nope")               # None
Parameters:
Return type:

float | str | None

What expansion hands back

class palsparserpy.Lattices(original, combined, expanded, full_expanded, adjunct, problems=<factory>)[source]

Bases: object

Five representations of a lattice, each as a root YAMLNode, plus the list of problems found while expanding it.

expanded and full_expanded are the same expanded lattice holding the same values; full_expanded additionally carries every parameter the bookkeeper computed, while expanded keeps only what the author wrote. See palsparserpy.parse_and_expand_pals() for what each view holds.

problems is a list of Problem – one entry per problem encountered during expansion (undefined lattice, dangling element/line references, undefined inherit/repeat/Fork targets, misspelled names, and expressions that could not be evaluated). It is empty when expansion was clean. Filter it on severity or origin to decide what is worth acting on:

lat = parse_and_expand_pals("ex.pals.yaml", problems="none")
mine = [p for p in lat.problems if p.origin is PROBLEM_INPUT]
Parameters:
original: YAMLNode
combined: YAMLNode
expanded: YAMLNode
full_expanded: YAMLNode
adjunct: YAMLNode
problems: List[Problem]
class palsparserpy.Problem(message, path, severity, origin)[source]

Bases: object

One problem found while reading or expanding a document.

  • message – human-readable description, always present.

  • path – the logical spot it was found at, such as "q1>ApertureP.shape". Empty when the problem is not tied to one place. This is a location within the document, not a file name or a line number; message already names the file where the file is the point.

  • severity – a ProblemSeverity: can the trees still be trusted?

  • origin – a ProblemOrigin: whose problem is it?

Only a PROBLEM_INPUT can be cleared by editing the lattice, which is what makes the last field worth reading: a tool that fails on any problem at all will fail on lattices whose author has nothing left to fix.

Parameters:
message: str
path: str
severity: ProblemSeverity
origin: ProblemOrigin
class palsparserpy.ProblemSeverity(*values)[source]

Bases: IntEnum

Whether a problem leaves the expanded trees trustworthy.

  • ERROR – the document is wrong here and expansion could not work around it. Do not trust the affected part of the trees.

  • WARNING – expansion produced a usable result; something was assumed or skipped, but the trees are still sound.

Mirrors enum problem_severity in PALSParserCpp.h.

ERROR = 0
WARNING = 1
class palsparserpy.ProblemOrigin(*values)[source]

Bases: IntEnum

Who has to act on a problem.

  • INPUT – the document is wrong; the lattice author can fix it.

  • UNSUPPORTED – valid PALS that PALSParserCpp does not implement yet. Editing the lattice will not clear it.

  • UNSPECIFIED – the PALS standard does not define the case, so nothing was invented. Neither the author nor the library is in the wrong.

Mirrors enum problem_origin in PALSParserCpp.h.

INPUT = 0
UNSUPPORTED = 1
UNSPECIFIED = 2
class palsparserpy.NodeCorrespondence(original, combined, full_expanded, adjunct)[source]

Bases: NamedTuple

The nodes one logical entity maps to in each of the four derivation-chain trees, grouped by tree.

expanded takes no part – it is a pruned copy of full_expanded, not a step in the chain. A field is empty when a tree has no corresponding node.

Parameters:
original: List[YAMLNode]

Alias for field number 0

combined: List[YAMLNode]

Alias for field number 1

full_expanded: List[YAMLNode]

Alias for field number 2

adjunct: List[YAMLNode]

Alias for field number 3

Translation

palsparserpy.pals_to_bmad(yaml)[source]

Translate a parsed PALS lattice yaml (as returned by parse_file()) into a BmadLattice.

The returned structure is an in-memory model of the Bmad lattice (elements, beamlines, parameters), not the input PALS tree. Translation is a three-step process: parse the PALS file with parse_file, build the target model with pals_to_bmad, then emit the Bmad lattice file with write_bmad_file():

yaml = parse_file(file_dir)
write_bmad_file(pals_to_bmad(yaml), filename)
Parameters:

yaml (YAMLNode)

Return type:

BmadLattice

palsparserpy.write_bmad_file(lat, filename)[source]

Serialize the BmadLattice lat to filename as a Bmad lattice file.

Write the constant and variable definitions, the global, beginning-Twiss and particle-start parameters, the element definitions, the overlay/group definitions, the beamline (line) definitions, and the branch (use) statement, each in its own labelled section. The constants come first because Bmad, unlike PALS, resolves a name against what the file has defined above the point of use.

Parameters:

lat (BmadLattice)

Return type:

None

class palsparserpy.BmadLattice(constants=<factory>, parameters=<factory>, beginning=<factory>, particle_start=<factory>, elements=<factory>, controllers=<factory>, beamlines=<factory>, use=<factory>)[source]

Bases: object

An in-memory model of a Bmad lattice.

Produced by pals_to_bmad() and serialized to a file by write_bmad_file(). The fields mirror the sections of a Bmad lattice file:

  • constants: name = value definitions, in definition order.

  • parameters: global parameter[...] = ... settings (species, energy, geometry).

  • beginning: beginning[...] = ... initial Twiss, coupling and dispersion settings.

  • particle_start: particle_start[...] = ... initial-coordinate settings.

  • elements: element definitions (BmadEleDef).

  • controllers: overlay/group definitions (BmadController).

  • beamlines: line definitions (BmadBeamline).

  • use: branch names for the final use, ... statement.

Parameters:
constants: List[str]
parameters: List[str]
beginning: List[str]
particle_start: List[str]
elements: List[BmadEleDef]
controllers: List[BmadController]
beamlines: List[BmadBeamline]
use: List[str]
class palsparserpy.BmadEleDef(name, type, attrs=<factory>)[source]

Bases: object

A single Bmad element definition.

  • name: the element name.

  • type: the Bmad element-type name (e.g. Drift, Quadrupole).

  • attrs: already-translated attribute fragments, each an "attribute = value" string.

Parameters:
name: str
type: str
attrs: List[str]
class palsparserpy.BmadBeamline(name, members=<factory>)[source]

Bases: object

A Bmad line definition: its name and the ordered list of member element members (by name).

Parameters:
name: str
members: List[str]
class palsparserpy.BmadController(name, type, slaves=<factory>, vars=<factory>, inits=<factory>)[source]

Bases: object

A Bmad overlay or group element: what a PALS Controller becomes.

  • name: the controller name.

  • type: "overlay" for control_type: ABSOLUTE, "group" for RELATIVE. Bmad’s overlay sets the slave parameter and its group adds to it, which is the same split PALS makes.

  • slaves: the controlled parameters, each an "ele[attribute]: expression" string.

  • vars: the variable names, in definition order.

  • inits: the variables’ initial values, each a "name = value" string.

Parameters:
name: str
type: str
slaves: List[str]
vars: List[str]
inits: List[str]
palsparserpy.pals_to_madx(yaml)[source]

Translate a parsed PALS lattice yaml (as returned by parse_file()) into a MadxLattice.

The returned structure is an in-memory model of the MAD-X lattice (elements, lines, beam), not the input PALS tree. Translation is a three-step process: parse the PALS file with parse_file, build the target model with pals_to_madx, then emit the MAD-X lattice file with write_madx_file():

yaml = parse_file(file_dir)
write_madx_file(pals_to_madx(yaml), filename)

Controllers are translated after the elements, in a second pass: a control_type: RELATIVE controller adds to the value the element already carries, and the only place that value is written down is the element definition this pass has just built.

Parameters:

yaml (YAMLNode)

Return type:

MadxLattice

palsparserpy.write_madx_file(lat, filename)[source]

Serialize the MadxLattice lat to filename as a MAD-X lattice file.

Write the constant and variable definitions, the BEAM command and initial conditions, the element definitions, the controller variables and their deferred assignments, the line definitions, the use statement, and the EALIGN misalignments, each in its own labelled section.

The order of the sections is the order MAD-X needs them in, which is stricter than Bmad’s: a name has to be defined above the point of use, BEAM has to come before USE, and the SELECT/EALIGN pairs have to come after it, because there is no sequence to apply an error to until one has been expanded.

Parameters:

lat (MadxLattice)

Return type:

None

class palsparserpy.MadxLattice(constants=<factory>, beam=<factory>, beta0=<factory>, particle_start=<factory>, elements=<factory>, controllers=<factory>, alignments=<factory>, beamlines=<factory>, use=<factory>, rigidity=False)[source]

Bases: object

An in-memory model of a MAD-X lattice.

Produced by pals_to_madx() and serialized to a file by write_madx_file(). The fields mirror the sections of a MAD-X lattice file:

  • constants: name = value; definitions, in definition order.

  • beam: the attributes of the BEAM command (species and energy).

  • beta0: the attributes of the initial-conditions BETA0 block (Twiss and dispersion).

  • particle_start: initial particle coordinates, which MAD-X takes in the TRACK module rather than in a lattice file, and which are written out as a comment.

  • elements: element definitions (MadxEleDef).

  • controllers: variables and deferred assignments (MadxController).

  • alignments: EALIGN misalignments (MadxAlignment).

  • beamlines: line definitions (MadxBeamline).

  • use: the branches, each a (name, periodic) pair, for the use statement.

  • rigidity: whether anything written refers to the rigidity variable, which then has to be defined ahead of it.

Parameters:
constants: List[str]
beam: List[str]
beta0: List[str]
particle_start: List[str]
elements: List[MadxEleDef]
controllers: List[MadxController]
alignments: List[MadxAlignment]
beamlines: List[MadxBeamline]
use: List[Tuple[str, bool]]
rigidity: bool = False
class palsparserpy.MadxEleDef(name, type, attrs=<factory>, notes=<factory>)[source]

Bases: object

A single MAD-X element definition.

  • name: the element name.

  • type: the MAD-X element-type keyword (e.g. drift, quadrupole).

  • attrs: already-translated attribute fragments, each an "attribute = value" string.

  • notes: comment lines to write above the definition. MAD-X elements carry no metadata strings of their own, so a PALS MetaP becomes a comment here, as does anything else worth saying about the element in the file it is written to.

Parameters:
name: str
type: str
attrs: List[str]
notes: List[str]
class palsparserpy.MadxBeamline(name, members=<factory>)[source]

Bases: object

A MAD-X line definition: its name and the ordered list of member element members (by name).

Parameters:
name: str
members: List[str]
class palsparserpy.MadxController(name, vars=<factory>, controls=<factory>, notes=<factory>)[source]

Bases: object

A MAD-X rendering of a PALS Controller.

MAD-X has no controller element. What it has instead is the deferred assignment :=, which makes an element attribute depend on a variable rather than take its value once, and that is what a controller becomes: its variables become ordinary MAD-X variables and each of its controls becomes a deferred assignment to the attribute it drives.

  • name: the controller name, written out as a comment heading.

  • vars: the variables’ initial values, each a "name = value" string.

  • controls: the deferred assignments, each an "ele->attribute := expression" string.

  • notes: comment lines to write above the definitions, holding the controller’s MetaP.

Parameters:
name: str
vars: List[str]
controls: List[str]
notes: List[str]
class palsparserpy.MadxAlignment(name, attrs=<factory>)[source]

Bases: object

The misalignment of one element: what a PALS BodyShiftP becomes.

MAD-X keeps a misalignment apart from the element definition, in an EALIGN command applied to whatever the preceding SELECT, FLAG=ERROR picked out. name is the element the errors belong to and attrs the EALIGN attribute fragments.

Parameters:
name: str
attrs: List[str]
palsparserpy.pals_to_scibmad(yaml)[source]

Translate a parsed PALS lattice yaml (as returned by parse_file()) into a SciBmadLattice.

The returned structure is an in-memory model of the SciBmad lattice (elements, beamlines, lattice lists), not the input PALS tree. Translation is a three-step process: parse the PALS file with parse_file, build the target model with pals_to_scibmad, then emit the SciBmad lattice file with write_scibmad_file():

yaml = parse_file(file_dir)
write_scibmad_file(pals_to_scibmad(yaml), filename)
Parameters:

yaml (YAMLNode)

Return type:

SciBmadLattice

palsparserpy.write_scibmad_file(lat, filename)[source]

Serialize the SciBmadLattice lat to filename as a SciBmad lattice file.

Write the particle-start block, the @elements block of LineElement``s, the ``Controller definitions, the Beamline definitions, and the lattice lists.

Parameters:

lat (SciBmadLattice)

Return type:

None

class palsparserpy.SciBmadLattice(particle=<factory>, elements=<factory>, controllers=<factory>, beamlines=<factory>, lattices=<factory>)[source]

Bases: object

An in-memory model of a SciBmad lattice.

Produced by pals_to_scibmad() and serialized to a file by write_scibmad_file():

Parameters:
particle: List[str]
elements: List[SciBmadEle]
controllers: List[SciBmadController]
beamlines: List[SciBmadBeamline]
lattices: List[SciBmadLatticeList]
class palsparserpy.SciBmadEle(name, attrs=<factory>)[source]

Bases: object

A single SciBmad LineElement: its name and the already-translated keyword-argument fragments (attrs, each a "keyword = value" string).

Parameters:
name: str
attrs: List[str]
class palsparserpy.SciBmadBeamline(name, members=<factory>, ref=<factory>)[source]

Bases: object

A SciBmad Beamline: its name, the ordered member element members (by name), and the reference-parameter fragments ref taken from the line’s first entry.

Parameters:
name: str
members: List[str]
ref: List[str]
class palsparserpy.SciBmadLatticeList(name, branches=<factory>)[source]

Bases: object

A SciBmad lattice list: its name and the ordered branch/beamline branches (by name).

Parameters:
name: str
branches: List[str]
class palsparserpy.SciBmadController(name, slaves=<factory>, vars=<factory>)[source]

Bases: object

A SciBmad Controller: what a PALS Controller becomes.

  • name: the controller name.

  • slaves: the controlled properties, each a "(ele, :prop) => (ele; vars...) -> expr" pair-and-function string.

  • vars: the variables’ initial values, each a "name = value" string.

Parameters:
name: str
slaves: List[str]
vars: List[str]