#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2023 Michael J. Hayford
""" Module for parsing a sequential model into elements
The grammar is as follows::
seq_model = object space optics image
optics = (part space)*
part = mangin / cemented / lens / mirror / surface / dummy / thin_lens
space = phantom / air / thickness
surface = "i"
lens = "iti"
mirror = "r"
air = "a"
thickness = "t"
cemented = "ititi"("ti")*
mangin = ~r"it(?:r|(?R))*ti"
thin_lens = "l"
dummy = "d"
phantom = "apa"
object = ~r"^d"
image = ~r"d$"
.. Created on Sun Sep 27 22:10:01 2023
.. codeauthor: Michael J. Hayford
"""
from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
sgz2ele_spec = \
r"""
seq_model = object space optics image
optics = (part space)*
part = mangin / cemented / lens / mirror / surface / dummy / thin_lens
space = phantom / air / thickness
surface = "i"
lens = "iti"
mirror = "r"
air = "a"
thickness = "t"
cemented = "ititi"("ti")*
mangin = ~r"it(?:r|(?R))*ti"
thin_lens = "l"
dummy = "d"
phantom = "apa"
object = ~r"^d"
image = ~r"d$"
"""
sgz2ele_grammar = Grammar(sgz2ele_spec)
[docs]
def flatten_visit(visit_output):
elements = []
_flatten_visit_(elements, visit_output)
return elements
def _flatten_visit_(elements, visit_output):
for i,o in enumerate(visit_output):
if isinstance(o, tuple):
elements.append(o)
if isinstance(o, list):
_flatten_visit_(elements, o)
[docs]
class SMVisitor(NodeVisitor):
def __init__(self, do_print_visit=False):
self.do_print_visit = do_print_visit
[docs]
def print_visit(self, node, part_name, idx_list, gap_list):
if self.do_print_visit:
# print(f"{part_name[0]}: {part_name[2]} {idx_list} {gap_list}")
print(f"{part_name} {idx_list} {gap_list} {node.start} {node.end}")
[docs]
def visit_seq_model(self, node, visited_children):
""" Returns the overall output. """
sg2ele_visit = []
for child in visited_children:
sg2ele_visit.append(child)
return sg2ele_visit
def _visit_surface_(self, node, part_name):
""" handle single interface tokens. """
idx_list = (node.start >> 1,)
gap_list = ()
self.print_visit(node, part_name, idx_list, gap_list)
part_def = part_name, idx_list, gap_list
return part_def
def _visit_space_(self, node, part_name):
""" handle space tokens. """
idx_list = ()
gap_list = (node.start >> 1,)
self.print_visit(node, part_name, idx_list, gap_list)
part_def = part_name, idx_list, gap_list
return part_def
def _visit_element_(self, node, part_name):
""" handle multi-surface, element, tokens. """
idx1 = node.start >> 1
idxk = node.end >> 1
idx_list = tuple(idx for idx in range(idx1, idxk+1))
gap_list = tuple(idx for idx in range(idx1, idxk))
self.print_visit(node, part_name, idx_list, gap_list)
part_def = part_name, idx_list, gap_list
return part_def
[docs]
def visit_surface(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'surface', 'rayoptics.elem.elements', 'SurfaceInterface'
return self._visit_surface_(node, part_name)
[docs]
def visit_lens(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'lens', 'rayoptics.elem.elements', 'Element'
return self._visit_element_(node, part_name)
[docs]
def visit_mirror(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'mirror', 'rayoptics.elem.elements', 'Mirror'
return self._visit_surface_(node, part_name)
[docs]
def visit_air(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'air', 'rayoptics.elem.elements', 'AirGap'
return self._visit_space_(node, part_name)
[docs]
def visit_thickness(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'space', 'rayoptics.elem.elements', 'Space'
return self._visit_space_(node, part_name)
[docs]
def visit_cemented(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'cemented', 'rayoptics.elem.elements', 'CementedElement'
return self._visit_element_(node, part_name)
[docs]
def visit_mangin(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'mangin', 'rayoptics.elem.elements', 'CementedElement'
return self._visit_element_(node, part_name)
[docs]
def visit_thin_lens(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'thin_lens', 'rayoptics.elem.elements', 'ThinElement'
return self._visit_surface_(node, part_name)
[docs]
def visit_dummy(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'dummy', 'rayoptics.elem.elements', 'DummyInterface'
return self._visit_surface_(node, part_name)
[docs]
def visit_phantom(self, node, visited_children):
""" Create an AirGap that encompasses the phantom interface. """
idx1 = node.start >> 1
idxk = node.end >> 1
idx_list = ()
gap_list = tuple(idx for idx in range(idx1, idxk))
part_name = 'air', 'rayoptics.elem.elements', 'AirGap'
part_def = part_name, idx_list, gap_list
self.print_visit(node, part_name, idx_list, gap_list)
return part_def
[docs]
def visit_object(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'object', 'rayoptics.elem.elements', 'DummyInterface'
return self._visit_surface_(node, part_name)
[docs]
def visit_image(self, node, visited_children):
""" Gets each key/value pair, returns a tuple. """
part_name = 'image', 'rayoptics.elem.elements', 'DummyInterface'
# idx_list = (-1,)
# gap_list = ()
# self.print_visit(node, part_name, idx_list, gap_list)
# part_def = part_name, idx_list, gap_list
# return part_def
return self._visit_surface_(node, part_name)
[docs]
def generic_visit(self, node, visited_children):
""" The generic visit method. """
return visited_children or node