Skip to content

Commit

Permalink
Modified optika.materials.multilayer_efficiency() to use the refrac…
Browse files Browse the repository at this point in the history
…tive index of the layers instead of the chemcial formula.
  • Loading branch information
byrdie committed Jan 29, 2024
1 parent 9860a8b commit 5d6b471
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 42 deletions.
62 changes: 30 additions & 32 deletions optika/materials/_multilayers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


def multilayer_efficiency(
material_layers: na.AbstractScalarArray,
n: na.AbstractScalar,
thickness_layers: na.AbstractScalar,
axis_layers: str,
wavelength_ambient: u.Quantity | na.AbstractScalar,
Expand All @@ -32,8 +32,8 @@ def multilayer_efficiency(
Parameters
----------
material_layers
An array of chemical formulas for each layer.
n
The complex index of refraction for each layer
thickness_layers
An array of thicknesses for each layer.
axis_layers
Expand Down Expand Up @@ -69,18 +69,21 @@ def multilayer_efficiency(
import named_arrays as na
import optika
# Define the wavelengths of the incident light
wavelength = na.linspace(100, 150, axis="wavelength", num=501) * u.AA
# Define an array of chemical formulae for each layer.
material_layers = na.ScalarArray(np.array(["Zr"], dtype=object), axes="layer")
formula = na.ScalarArray(np.array(["Zr"]), axes="layer")
# Compute the complex index of refraction for each layer
n = optika.chemicals.Chemical(formula).n(wavelength)
# Define an array of thicknesses for each layer.
thickness_layers = na.ScalarArray([1500] * u.AA, axes="layer")
# Define the wavelengths of the incident light
wavelength = na.linspace(100, 150, axis="wavelength", num=501) * u.AA
# Compute the reflectivity and the transmissivity of this multilyaer
reflectivity, transmissivity = optika.materials.multilayer_efficiency(
material_layers=material_layers,
n=n,
thickness_layers=thickness_layers,
axis_layers="layer",
wavelength_ambient=wavelength,
Expand Down Expand Up @@ -117,11 +120,14 @@ def multilayer_efficiency(
N = 60
# Define an array of chemical formulas for each layer
material_layers = na.ScalarArray(
formula = na.ScalarArray(
ndarray=np.array(N * ["Si", "Mo"]),
axes="layer"
)
# Compute the complex index of refraction for each layer
n = optika.chemicals.Chemical(formula).n(wavelength)
# Define the thickness to period ratios for each layer
thickness_ratio = 0.6
Expand All @@ -138,7 +144,7 @@ def multilayer_efficiency(
# Compute the reflectivity and transmissivity of this multilayer stack
reflectivity, transmissivity = optika.materials.multilayer_efficiency(
material_layers=material_layers,
n=n,
thickness_layers=thickness_layers,
axis_layers="layer",
wavelength_ambient=wavelength,
Expand Down Expand Up @@ -175,12 +181,18 @@ def multilayer_efficiency(
# Number of periods
N = 40
# wavelength of the incident light
wavelength = na.linspace(170, 210, num=101, axis="wavelength") * u.AA
# array of chemical formulas for each layer
material_layers = na.ScalarArray(
formula = na.ScalarArray(
ndarray=np.array(N * ["Y", "Al"]),
axes="layer"
)
# Compute the complex index of refraction for each layer
n = optika.chemicals.Chemical(formula).n(wavelength)
# an array of thickness to period ratios for each layer
thickness_ratio = na.linspace(0.2, 0.6, axis="thickness_ratio", num=5)
Expand All @@ -190,16 +202,13 @@ def multilayer_efficiency(
axis="layer"
)
# wavelength of the incident light
wavelength = na.linspace(170, 210, num=101, axis="wavelength") * u.AA
# Compute the complex index of refraction for the silicon substrate
silicon = optika.chemicals.Chemical("Si")
n_substrate = silicon.n(wavelength)
# Compute the reflectivity and transmissivity of this multilayer stack
reflectivity, transmissivity = optika.materials.multilayer_efficiency(
material_layers=material_layers,
n=n,
thickness_layers=thickness_layers,
axis_layers="layer",
wavelength_ambient=wavelength,
Expand Down Expand Up @@ -355,8 +364,8 @@ def multilayer_efficiency(
The :class:`tuple` :math:`(R, T)` is the quantity returned by this function.
"""
shape_layers = na.shape_broadcasted(material_layers, thickness_layers)
material = material_layers
shape_layers = na.shape_broadcasted(n, thickness_layers)
n = n.broadcast_to(shape_layers)
thickness = thickness_layers.broadcast_to(shape_layers)
axis = axis_layers

Expand All @@ -374,33 +383,21 @@ def multilayer_efficiency(
q_si = q_sa
q_pi = q_pa

n_cache = dict()

m_s11 = m_p11 = 1
m_s12 = m_p12 = 0
m_s21 = m_p21 = 0
m_s22 = m_p22 = 1

num_layers = material.shape[axis]
num_layers = n.shape[axis]
num_interfaces = num_layers + 1

for j in range(num_interfaces):
if j == num_layers:
thickness_j = 0 * u.AA
n_j = n_substrate
else:
formula_j = material[{axis: j}].ndarray
thickness_j = thickness[{axis: j}]

if formula_j in n_cache:
n_j = n_cache[formula_j]
else:
chemical_j = optika.chemicals.Chemical(
formula=formula_j,
)

n_j = chemical_j.n(wavelength)
n_cache[formula_j] = n_j
n_j = n[{axis: j}]

direction_j = snells_law(
wavelength=wavelength / np.real(n_i),
Expand Down Expand Up @@ -566,10 +563,11 @@ def transmissivity(
the vector normal to the interface between successive layers
"""
wavelength = rays.wavelength
n = optika.chemicals.Chemical(self.material_layers).n(wavelength)
k_ambient = rays.attenuation * wavelength / (4 * np.pi)
n_ambient = rays.index_refraction + k_ambient * 1j
reflectivity, transmissivity = multilayer_efficiency(
material_layers=self.material_layers,
n=n,
thickness_layers=self.thickness_layers,
axis_layers=self.axis_layers,
wavelength_ambient=wavelength,
Expand Down
21 changes: 12 additions & 9 deletions optika/materials/_tests/test_multilayers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import optika
from . import test_materials

_wavelength = na.linspace(100, 200, axis="wavelength", num=4) * u.AA


@pytest.mark.parametrize(
argnames="material_layers,thickness_layers,axis_layers",
argnames="n,thickness_layers,axis_layers",
argvalues=[
(
na.ScalarArray(np.array(2 * ["Y", "Al"], dtype=object), axes="layer"),
optika.chemicals.Chemical(
na.ScalarArray(np.array(2 * ["Y", "Al"]), axes="layer"),
).n(_wavelength),
na.ScalarArray((2 * [10, 30]) * u.AA, axes="layer"),
"layer",
)
Expand All @@ -20,8 +24,7 @@
@pytest.mark.parametrize(
argnames="wavelength_ambient",
argvalues=[
200 * u.AA,
na.linspace(100, 200, axis="wavelength", num=4) * u.AA,
_wavelength,
],
)
@pytest.mark.parametrize(
Expand Down Expand Up @@ -61,7 +64,7 @@
],
)
def test_multilayer_efficiency(
material_layers: na.AbstractScalarArray,
n: na.AbstractScalarArray,
thickness_layers: na.AbstractScalarArray,
axis_layers: str,
wavelength_ambient: u.Quantity | na.AbstractScalar,
Expand All @@ -72,7 +75,7 @@ def test_multilayer_efficiency(
profile_interface: None | optika.materials.profiles.AbstractInterfaceProfile,
):
reflected, transmitted = optika.materials.multilayer_efficiency(
material_layers=material_layers,
n=n,
thickness_layers=thickness_layers,
axis_layers=axis_layers,
wavelength_ambient=wavelength_ambient,
Expand Down Expand Up @@ -156,14 +159,14 @@ def test_multilayer_transmissivity_vs_file(
skip_header=15,
unpack=True,
)
wavelength_ambient = na.ScalarArray(wavelength_ambient, axes=axis_layers) << u.AA
transmissivity_file = na.ScalarArray(transmissivity_file, axes=axis_layers)
wavelength_ambient = na.ScalarArray(wavelength_ambient, axes="wavelength") << u.AA
transmissivity_file = na.ScalarArray(transmissivity_file, axes="wavelength")

substrate = optika.chemicals.Chemical(material_substrate)
n_substrate = substrate.n(wavelength_ambient)

reflectivity, transmissivity = optika.materials.multilayer_efficiency(
material_layers=material_layers,
n=optika.chemicals.Chemical(material_layers).n(wavelength_ambient),
thickness_layers=thickness_layers,
axis_layers=axis_layers,
wavelength_ambient=wavelength_ambient,
Expand Down
5 changes: 4 additions & 1 deletion optika/sensors/_materials/_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,11 @@ def quantum_efficiency_effective(
if normal is None:
normal = na.Cartesian3dVectorArray(0, 0, -1)

n = optika.chemicals.Chemical(formula_oxide).n(wavelength)
n = n.broadcast_to(na.broadcast_shapes(n.shape, dict(_layer=1)))

reflectivity, transmissivity = optika.materials.multilayer_efficiency(
material_layers=na.ScalarArray(np.array([formula_oxide]), axes="_layer"),
n=n,
thickness_layers=na.stack([thickness_oxide], axis="_layer"),
axis_layers="_layer",
wavelength_ambient=wavelength,
Expand Down

0 comments on commit 5d6b471

Please sign in to comment.