Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,589 changes: 74 additions & 8,515 deletions examples/Basic Usage/Basic Usage.ipynb

Large diffs are not rendered by default.

187 changes: 104 additions & 83 deletions examples/Bragg-mirror/Bragg-Mirror.ipynb

Large diffs are not rendered by default.

140 changes: 79 additions & 61 deletions examples/Bragg-mirror/validation-Bragg.ipynb

Large diffs are not rendered by default.

105 changes: 88 additions & 17 deletions examples/Custom fitting/Custom fitting example.ipynb

Large diffs are not rendered by default.

89 changes: 61 additions & 28 deletions examples/Ellipsometry uniaxial materials/Fujiwara-641.ipynb

Large diffs are not rendered by default.

344 changes: 263 additions & 81 deletions examples/Ellipsometry uniaxial materials/Fujiwara-642.ipynb

Large diffs are not rendered by default.

136 changes: 111 additions & 25 deletions examples/Interfaces/Interferences.ipynb

Large diffs are not rendered by default.

421 changes: 299 additions & 122 deletions examples/Interfaces/interface-reflection.ipynb

Large diffs are not rendered by default.

518 changes: 404 additions & 114 deletions examples/Liquid crystals/cholesteric-liquid.ipynb

Large diffs are not rendered by default.

197 changes: 156 additions & 41 deletions examples/Liquid crystals/twisted-nematic.ipynb

Large diffs are not rendered by default.

265 changes: 0 additions & 265 deletions examples/Liquid crystals/validation-cholesteric.ipynb

This file was deleted.

1,774 changes: 1,583 additions & 191 deletions examples/SiO2_Si Mueller Matrix/SiO2_Si Mueller Matrix.ipynb

Large diffs are not rendered by default.

172 changes: 96 additions & 76 deletions examples/TiO2 Fit/TiO2 Multilayerfit.ipynb

Large diffs are not rendered by default.

281 changes: 0 additions & 281 deletions examples/Total internal reflection/FrustratedTIR-angle.ipynb

This file was deleted.

318 changes: 0 additions & 318 deletions examples/Total internal reflection/FrustratedTIR-thickness.ipynb

This file was deleted.

66 changes: 53 additions & 13 deletions examples/Total internal reflection/TIR.ipynb

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions examples/gallery/plot_01_basic_usage.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
Basic usage
===========
Basic usage of pyElli
=====================

Basic usage of building a model and fitting it to measurement data of SiO2 on Si.

"""

# %%
# %% Import required libraries
import elli
from elli.fitting import ParamsHist, fit

Expand All @@ -26,7 +26,7 @@
# This is because we're using literature values for Si,
# which are only defined in this wavelength range.
ANGLE = 70
psi_delta = elli.read_nexus_psi_delta("SiO2onSi.ellips.nxs").loc[ANGLE][210:800]
psi_delta = elli.read_nexus_psi_delta("SiO2onSi.ellips.nxs").loc[ANGLE].loc[210:800]

# %%
# Setting parameters
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery/plot_02_TiO2_multilayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#
# The sample is an ALD grown TiO2 sample (with 400 cycles)
# on commercially available SiO2 / Si substrate.
tss = elli.read_spectraray_psi_delta("TiO2_400cycles.txt").loc[70.06][400:800]
tss = elli.read_spectraray_psi_delta("TiO2_400cycles.txt").loc[70.06].loc[400:800]

# %%
# Set start parameters
Expand Down
8 changes: 6 additions & 2 deletions examples/gallery/plot_03_custom_fitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# %%
# Data import
# -----------
# Read Ψ (psi) and Δ (delta) ellipsometric spectra for different angles from a NeXus file, limited to a wavelength range of 210–800 nm, to be compatible with a tabulated Silicon dispersion.
data = elli.read_nexus_psi_delta("SiO2onSi.ellips.nxs").loc[
(slice(None), slice(210, 800)), :
]
Expand All @@ -30,6 +31,7 @@
# %%
# Setting up invariant materials and fitting parameters
# -----------------------------------------------------
# Set up the optical constants for the substrate from RII and define initial fit parameters for the Cauchy SiO₂ layer.
rii_db = elli.db.RII()
Si = rii_db.get_mat("Si", "Aspnes")

Expand Down Expand Up @@ -69,8 +71,8 @@ def model(lbda, angle, params):
# %%
# Defining the fit function
# -------------------------
# The fit function follows the protocol defined by the lmfit package and needs the parameters dictionary as first argument.
# It has to return a residual value, which will be minimized. Here psi and delta are used to calculate the residual, but could be changed to transmission or reflection data.
# The fit function follows the protocol defined by the lmfit package and needs the parameters dictionary as first argument. It has to return a residual value, which will be minimized.
# Here psi and delta are used across all angles to calculate the residual, but could be changed to any other measured quantity like transmission or reflection data.


def fit_function(params, lbda, data):
Expand All @@ -93,13 +95,15 @@ def fit_function(params, lbda, data):
# ---------------
# The fitting is performed by calling the minimize function with the fit_function and the needed arguments.
# It is possible to change the underlying algorithm by providing the method kwarg.
# The fit_report function provides fitted values, uncertainties, and goodness-of-fit statistics.

out = minimize(fit_function, params, args=(lbda, data), method="leastsq")
print(fit_report(out))

# %%
# Plotting the results
# ----------------------------------------------
# The measurent results are displayed as scatter plot and the PyElli results are overlayed as solid lines.

fit_50 = model(lbda, 50, out.params)
fit_60 = model(lbda, 60, out.params)
Expand Down
2 changes: 1 addition & 1 deletion examples/gallery/plot_SiO2_Si_MM.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Mueller matrix
==============

Mueller matrix fit to a SiO2 on Si measurement.
Exemplary fit of the complete Mueller matrix of a SiO2 on Si measurement.
"""

# %%
Expand Down
59 changes: 34 additions & 25 deletions examples/gallery/plot_bragg_mirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
"""

# %%
# Example of a TiO2/SiO2 Bragg mirror with 8.5 periods
# ----------------------------------------------------
# TiO2/SiO2 Bragg mirror simulation
# ---------------------------------
#
# Authors: O. Castany, M.Müller
#
# This notebook simulates a Bragg mirror composed of alternating layers of TiO₂ and SiO₂, each a quarter-wavelength thick at a central wavelength of 1550 nm.
# The mirror contains 8.5 periods, with air as the incident medium and glass as the substrate.

# %%
import elli
Expand All @@ -20,25 +23,20 @@
# %%
# Material definition
# -------------------
# We define air as incidence material and glass as exit material.
# SiO2 and TiO2 are defined by simplified dispersion relations.
# We define all required materials with constant (non-dispersive) refractive indicies.
# Air as incidence material and glass as exit material. The Bragg mirror materials are SiO2 and TiO2.

air = elli.AIR
glass = elli.ConstantRefractiveIndex(1.5).get_mat()

n_SiO2 = 1.47
n_TiO2 = 2.23 + 1j * 5.2e-4

SiO2 = elli.ConstantRefractiveIndex(n_SiO2).get_mat()
TiO2 = elli.ConstantRefractiveIndex(n_TiO2).get_mat()
SiO2 = elli.ConstantRefractiveIndex(1.47).get_mat()
TiO2 = elli.ConstantRefractiveIndex(2.23 + 1j * 5.2e-4).get_mat()

# %%
# Create layers and structure
# ---------------------------
# The SiO2 and TiO2 layers are set to the thickness of an
# quarterwaveplate of the respective material at 1550 nm.
#
# The layers are then stacked alternatingly and put into the
# complete structure with air and the glass substrate.

lbda0 = 1550

d_SiO2 = elli.get_qwp_thickness(SiO2, lbda0)
Expand All @@ -50,14 +48,31 @@
L_SiO2 = elli.Layer(SiO2, d_SiO2)
L_TiO2 = elli.Layer(TiO2, d_TiO2)

# Repeated layers: 8.5 periods

# %%
# Create layers and structure
# ---------------------------
# We now build the multilayer stack:
# Alternating layers of TiO2 / SiO2:
# - 8 full periods + 1 TiO2 layer at the end → "8.5 periods"
# - Placed between air (front) and glass (back)

# Define periodic stack
# Repeated layers: 8.5 periods: Parameters (Substructure, repetitions, number of layers before, number of layers after the stack)
layerstack = elli.RepeatedLayers([L_TiO2, L_SiO2], 8, 0, 1)

# Build full structure
s = elli.Structure(air, [layerstack], glass)

# %%
# Calculation
# -----------
# Structure Graph: Visualization of the refractive index profile in z-direction.
# ------------------------------------------------------------------------------
elliplot.draw_structure(s)

# %%
# Optical calculation
# -------------------
# Calculation of the reflection and transmission of the structure at normal incidence (0°).
(lbda1, lbda2) = (1100, 2500)
lbda_list = np.linspace(lbda1, lbda2, 200)

Expand All @@ -66,16 +81,10 @@
R = data.R
T = data.T


# %%
# Structure Graph
# ---------------
# Schema of the variation of the refractive index in z-direction.
elliplot.draw_structure(s)

# %%
# Reflection and Transmission Graph
# ---------------------------------
# Reflection and Transmission data
# --------------------------------
# The plot shows the high reflection in the stopband region around the design wavelength and the interference patterns around it.
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(lbda_list, T, label="$T$")
Expand Down
74 changes: 60 additions & 14 deletions examples/gallery/plot_cholesteric_lq.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"""
Cholesteric Liquid Crystal
==========================
Cholesteric Liquid Crystal Simulation
=====================================
"""

# %%
# Example of a cholesteric liquid crystal
# ---------------------------------------
# Authors: O. Castany, C. Molinaro, M. Müller
#
# This notebook demonstrates how to model and simulate the optical properties of a cholesteric liquid crystal using pyElli.
# We will build a helical structure and observe its characteristic selective reflection of circularly polarized light.

# %%
import elli
Expand All @@ -16,21 +19,40 @@
from scipy.constants import c, pi

# %%
# Setup materials and structure
# -----------------------------
# Setup materials
# ---------------
# We start by defining the materials for our model.
# The liquid crystal will be sandwiched between two layers of isotropic glass with a constant refractive index of 1.55.
#
# The liquid crystal (LC) itself is uniaxial and will be rotated to have the extraordinary axis orientated in x-direction.

glass = elli.IsotropicMaterial(elli.ConstantRefractiveIndex(1.55))
front = back = glass

# Liquid crystal oriented along the x direction
# Define the ordinary (no) and extraordinary (ne) refractive indices for the LC
(no, ne) = (1.5, 1.7)
Dn = ne - no
n_med = (ne + no) / 2

# Create a uniaxial material with ne oriented along the z-axis by default
LC = elli.UniaxialMaterial(
elli.ConstantRefractiveIndex(no), elli.ConstantRefractiveIndex(ne)
) # ne is along z
)

# Rotate the material so the extraordinary axis is along x instead of z
R = elli.rotation_v_theta(elli.E_Y, 90) # rotation of pi/2 along y
LC.set_rotation(R) # apply rotation from z to x

# %%
# Building the Helical Structure
# ------------------------------
#
# The defining feature of a cholesteric liquid crystal is its helical structure.
# The distance over which the director rotates by 360° is known as the cholesteric pitch (p).
#
# We model this by first creating a single TwistedLayer that represents one half-turn of the helix (180° rotation over a distance of p/2).
# We then stack this layer multiple times using RepeatedLayers to build the full thickness (7.5p) of the liquid crystal cell.

# Cholesteric pitch (nm):
p = 650

Expand All @@ -43,39 +65,55 @@
L = elli.RepeatedLayers([TN], N)
s = elli.Structure(front, [L], back)

# Calculation parameters
lbda_min, lbda_max = 800, 1200 # (nm)
lbda_B = p * n_med
# %%
# Setting Calculation Parameters
# ------------------------------
#
# Finally, we define the wavelength range for our simulation around the central wavelength of the reflection band,
# which is determined by the average refractive index and the pitch.

# Define wavelength range in nm for the calculation
lbda_min, lbda_max = 800, 1200
lbda_B = p * n_med # Expected center of the reflection band
lbda_list = np.linspace(lbda_min, lbda_max, 100)

# %%
# Analytical calculation for the maximal reflection
# -------------------------------------------------
# For a cholesteric liquid crystal, we can analytically calculate the approximate edges of the reflection band and the maximum reflectance.
# This serves as a good check for our full simulation.

# Theoretical maximum reflectance
R_th = np.tanh(Dn / n_med * pi * h / p) ** 2

# Theoretical wavelength edges of the reflection band
lbda_B1, lbda_B2 = p * no, p * ne

# %%
# Calculation with pyElli
# -----------------------
# Now we run the simulation using the s.evaluate() method. This calculates the Jones matrix elements for transmission and reflection.
# They are extracted for linear (s and p), as well as circular polarized light (R and L)

# Run the full optical simulation for the defined structure and wavelength list
data = s.evaluate(lbda_list, 0)

# Extract transmission coefficients for linear polarization
T_pp = data.T_pp
T_ps = data.T_ps
T_ss = data.T_ss
T_sp = data.T_sp

# Transmission coefficients for incident unpolarized light:
T_pn = 0.5 * (T_pp + T_ps)
T_sn = 0.5 * (T_sp + T_ss)
T_nn = T_sn + T_pn
# Calculate transmission for unpolarized incident light
T_nn = 0.5 * (T_pp + T_ps + T_sp + T_ss)

# Transmission coefficients for 's' and 'p' polarized light, with
# unpolarized measurement.
T_ns = T_ps + T_ss
T_np = T_pp + T_sp

# Right-circular wave is reflected in the stop-band.
# R_LR, T_LR close to zero.
# A right-handed helix reflects right-circular (RR) light.
R_RR = data.Rc_RR
R_LR = data.Rc_LR
T_RR = data.Tc_RR
Expand All @@ -89,6 +127,12 @@
# %%
# Plotting
# --------
# Finally, we plot the results. The plot will show the transmission and reflection spectra for various polarizations.
#
# We also draw a shaded rectangle representing the analytically calculated photonic stop-band.
# Inside this band, we expect to see strong reflection for a specific circular polarization.
# As our model is a right-handed helix, it should strongly reflect right-circularly polarized light (R_RR).

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

Expand All @@ -112,4 +156,6 @@
ax.set_ylabel(r"Power transmission $T$ and reflexion $R$")
plt.show()

# %%
# Additionally we can visualize the refractive index n x direction of the structure in dependance of z position.
elliplot.draw_structure(s)
Loading