Source code for rayoptics.seq.interface

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2020 Michael J. Hayford
"""Base class for Interfaces

.. Created on Sat Jun 13 22:04:27 2020

.. codeauthor: Michael J. Hayford
"""

from numpy import sqrt
from enum import Enum, auto


[docs]class InteractionMode(Enum): """ enum for different interact_mode specifications Retained to restore old files .. deprecated:: 0.4.5 """ Transmit = auto() #: propagate in transmission at this interface Reflect = auto() #: propagate in reflection at this interface
[docs]class Interface: """Basic part of a sequential model The :class:`~sequential.SequentialModel` is a sequence of Interfaces and Gaps. The Interface class is a boundary between two adjacent Gaps and their associated media. It specifies several methods that must be implemented to model the optical behavior of the interface. The Interface class addresses the following use cases: - support for ray intersection calculation during ray tracing - interfaces can be tilted and decentered wrt the adjacent gaps - support for getting and setting the optical power of the interface - support for various optical properties, i.e. does it reflect or transmit - supports a basic idea of size, the max_aperture Attributes: interact_mode: 'transmit' | 'reflect' | 'dummy' delta_n: refractive index difference across the interface decenter: :class:`~rayoptics.elem.surface.DecenterData` for the interface, if specified max_aperture: the maximum aperture radius on the interface """ def __init__(self, interact_mode='transmit', delta_n=0.0, max_ap=1.0, decenter=None, phase_element=None, **kwargs): self.interact_mode = interact_mode self.delta_n = delta_n self.decenter = decenter self.max_aperture = max_ap if phase_element is not None: self.phase_element = phase_element
[docs] def listobj_str(self): o_str = (f"{self.interact_mode} delta n={self.delta_n} " f"max aperture={self.max_aperture}\n") if hasattr(self, 'phase_element') and self.phase_element is not None: o_str += self.phase_element.listobj_str() if self.decenter is not None: o_str += self.decenter.listobj_str() return o_str
[docs] def update(self): if self.decenter is not None: self.decenter.update()
[docs] def interface_type(self): return type(self).__name__
[docs] def sync_to_restore(self, opt_model): if not hasattr(self, 'max_aperture'): self.max_aperture = 1.0 if hasattr(self, 'interact_mode'): # don't know why I need to test for the InteractionMode # enum like this, or have to compare enum values, but # that's what works... if isinstance(self.interact_mode, Enum): imode = self.interact_mode.value if imode == InteractionMode.Reflect.value: self.interact_mode = 'reflect' elif imode == InteractionMode.Transmit.value: self.interact_mode = 'transmit' if hasattr(self, 'refract_mode'): # really old models if self.refract_mode == 'REFL': self.interact_mode = 'reflect' else: self.interact_mode = 'transmit' delattr(self, 'refract_mode')
@property def profile_cv(self): return 0.0
[docs] def set_optical_power(self, pwr, n_before, n_after): pass
[docs] def surface_od(self): pass
[docs] def point_inside(self, x: float, y: float, fuzz: float = 1e-5) -> bool: """ Returns True if the point (x, y) is inside the clear aperture. Args: x: x coodinate of the test point y: y coodinate of the test point fuzz: tolerance on test pt/aperture comparison, i.e. pt fuzzy <= surface_od """ return sqrt(x*x + y*y) <= self.max_aperture + fuzz
[docs] def set_max_aperture(self, max_ap): """ max_ap is the max aperture radius """ self.max_aperture = max_ap
[docs] def intersect(self, p0, d, eps=1.0e-12, z_dir=1): ''' Intersect an :class:`~.Interface`, starting from an arbitrary point. Args: p0: start point of the ray in the interface's coordinate system d: direction cosine of the ray in the interface's coordinate system z_dir: +1 if propagation positive direction, -1 if otherwise eps: numeric tolerance for convergence of any iterative procedure Returns: tuple: distance to intersection point *s1*, intersection point *p* Raises: :exc:`~rayoptics.raytr.traceerror.TraceMissedSurfaceError` ''' pass
[docs] def normal(self, p): """Returns the unit normal of the interface at point *p*. """ pass
[docs] def phase(self, pt, in_dir, srf_nrml, ifc_cntxt): z_dir, wvl, n_in, n_out, interact_mode = ifc_cntxt """Returns a diffracted ray direction and phase increment. Args: pt: point of incidence in :class:`~.Interface` coordinates in_dir: direction cosine of incident ray srf_nrml: :class:`~.Interface` surface normal at pt ifc_cntxt: a tuple containing z_dir: -1 if after an odd # of reflections, +1 otherwise wl: wavelength in nm for ray, defaults to ref_wl n_in: refractive index preceding the interface n_out: refractive index following the interface interact_mode: 'transmit' or 'reflect' Returns: (**out_dir, dW**) - out_dir: direction cosine of the out going ray - dW: phase added by diffractive interaction """ if hasattr(self, 'phase_element'): return self.phase_element.phase(pt, in_dir, srf_nrml, ifc_cntxt)
[docs] def apply_scale_factor(self, scale_factor): self.max_aperture *= scale_factor if self.decenter: self.decenter.apply_scale_factor(scale_factor)