Source code for elli.experiment

# Encoding: utf-8
import numpy as np
import numpy.typing as npt

from .solver4x4 import Solver4x4
from .solver import Solver
from .result import Result


[docs]class Experiment: """Description of a virtual experiment to simulate the behavior of a structure.""" structure = None jones_vector = None stokes_vector = None theta_i = None lbda = None def __init__(self, structure: "Structure", lbda: npt.ArrayLike, theta_i: float, vector: npt.ArrayLike = [1, 0, -1, 0]) -> None: """Creates a virtual experiment to simulate the behavior of a structure. Args: structure (Structure): Structure object to evaluate. lbda (npt.ArrayLike): Single value or array of wavelengths (in nm). theta_i (float): Incident angle (in degrees). vector (npt.ArrayLike, optional): Jones or Stokes vector of incident light. Defaults to [1, 0, -1, 0]. """ self.set_structure(structure) self.set_theta(theta_i) self.set_lbda(lbda) self.set_vector(vector)
[docs] def set_structure(self, structure: "Structure") -> None: """Defines the Structure to evaluate. Args: structure (Structure): Structure object to evaluate. """ self.structure = structure
[docs] def set_vector(self, vector: npt.ArrayLike) -> None: """Defines the Jones or Stokes vector of the incident Light. Jones: [1, 0]: horizontal polarized [0, 1]: vertical polarized [1/sqrt(2), 1/sqrt(2)]: diagonal polarized [1/sqrt(2),-1/sqrt(2)]: anti-diagonal polarized Stokes: [1,0,0,0]: unpolarized light [1,1,0,0]: horizontal polarized [1,-1,0,0]: vertical polarized [1,0,1,0]: diagonal polarized [1,0,-1,0]: anti-diagonal polarized Args: vector (npt.ArrayLike): Jones or Stokes vector of incident light. """ vector = np.asarray(vector) if vector.shape == (2,): self.jones_vector = vector self.stokes_vector = np.array([ np.abs(self.jones_vector[0])**2 + np.abs(self.jones_vector[1])**2, np.abs(self.jones_vector[0])**2 - np.abs(self.jones_vector[1])**2, 2 * np.real(self.jones_vector[0] * np.conjugate(self.jones_vector[1])), -2 * np.imag(self.jones_vector[0] * np.conjugate(self.jones_vector[1]))]) elif vector.shape == (4,): self.stokes_vector = vector p = np.sqrt(self.stokes_vector[1]**2 + self.stokes_vector[2]**2 + self.stokes_vector[3]**2) / self.stokes_vector[0] Q = self.stokes_vector[1] / (self.stokes_vector[0] * p) U = self.stokes_vector[2] / (self.stokes_vector[0] * p) V = self.stokes_vector[3] / (self.stokes_vector[0] * p) if Q == -1: a = 0 b = 1 else: a = np.sqrt((1 + Q) / 2) b = U / (2 * a) - 1j * V / (2 * a) self.jones_vector = np.array([a, b])
[docs] def set_theta(self, theta_i: float) -> None: """Set incident angle to evaluate. Args: theta_i (float): Incident angle (in degrees). """ self.theta_i = theta_i
[docs] def set_lbda(self, lbda: npt.ArrayLike) -> None: """Set experiment wavelengths. Args: lbda (npt.ArrayLike): single value or array of wavelengths (in nm). """ lbda_array = np.asarray(lbda) if np.shape(lbda_array) == (): lbda_array = np.asarray([lbda]) self.lbda = lbda_array
[docs] def evaluate(self, solver: Solver = Solver4x4, **solver_kwargs) -> Result: """Evaluates the experiment with the given solver. Args: solver (Solver, optional): Choose which solver class is used. Defaults to Solver4x4. solver_kwargs (optional): Keyword arguments for the Solver can be appended as arguments. Returns: Result: Result of the experiment. """ if solver_kwargs == {}: solv = solver(self) else: solv = solver(self, **solver_kwargs) return solv.calculate()