Calculating the reflection and transmission spectra of a stack¶
The section Creating a multilayer stack explains how to create the multilayer stack with three methods, which all enable to calculate the reflection and transmission spectra of the stack with different level of additional details:
- creating a multilayer stack from scratch with the classes
Structure
Layer
, and working directly with classes that handle the optical calculations. This method gives direct access to the partial waves inside each layer of the multilayer stack, to the transfer and scattering matrices, to the multilayer stack’s reflection and transmission coefficients and to the multilayer stack’s reflectance and transmittance for one wavelength. - creating multilayer stacks with the abstract class
Model
and its children, and writing one’s own child class when a different kind of stack is needed. This method gives direct access to the multilayer stack’s reflectance and transmittance for one wavelength. Additionally, the layer’s partial waves, the transfer and scattering matrices and the reflection and transmission coefficients can also be obtained since theModel
creates aStructure
. - using the class
Spectrum
that provides a higher level of automation. This method gives direct access to the multilayer stack’s reflectance and transmittance for a range of wavelength.
This section explains how to get the reflection spectrum of a multilayer stack which has been created through one of there three methods, following the tutorials Creating a multilayer stack.
From scratch: the technical way¶
When the user follows the method “from scratch” with the class Structure
to create a multilayer stack my_stack_structure
, they interact directly with the classes that handle the optics calculation. The Structure
that represents the multilayer stack contains a list of Layers
and the entry and exit HalfSpaces
(which are children of Layer
). Layers
and HalfSpaces
implement the calculation of Berreman’s matrix and of the layer’s eigenvalues and eigenvectors, used to calculate the layer’s partial waves. These are calculated immediately upon the creation of the Layer
or HalfSpace
and can be accessed through:
my_stack_structure.layers[k].D # layer’s Berreman’s matrix
my_stack_structure.layers[k].eigenvalues # layer’s eigenvalues
my_stack_structure.layers[k].eigenvectors # layer’s eigenvectors
my_stack_structure.layers[k].partial_waves # layer’s partial waves
where k
is the index of the Layer
in the Structure
my_stack_structure
.
A Structure
therefore automatically contains a series of four partial waves per layer, which are used to construct its transfer matrix or its scattering matrix (for the wavelength that was used to create the Structure
). The transfer and scattering matrices can be calculated the following way:
my_stack_structure.build_transfer_matrix() # transfer matrix
my_stack_structure.build_scattering_matrix() # scattering matrix
Reflection and transmission coefficients in the linear polarisation basis (for the wavelength that was used to create the Structure
) can be calculated with:
J_refl_lin, J_trans_lin = my_stack_structure.get_fresnel()
and converted to the circular polarisation basis with:
J_refl_circ, J_trans_circ = Structure.fresnel_to_fresnel_circ(J_lin)
The results are two Numpy arrays of reflection coefficients () and transmission coefficients () organised the following way:
in the linear polarisation basis:
in the circular polarisation basis:
For example, the user can access the reflection coefficient for incoming s-polarised light reflected as p-polarised light of the multilayer stack represented by the Structure
my_stack_structure
with:
J_lin, _ = my_stack_structure.get_fresnel()
J_lin[0, 1]
The reflectance and transmittance of the multilayer stack (for the wavelength that was used to create the Structure
) can be obtained with:
my_stack_structure.get_refl_trans(circ=<False|True>, method=<"SM"|"TM">)
where method
defines the matrix method used ("SM"
(default) for the scattering matrix method and "TM"
for the transfer matrix method) and circ=False
(default) calculates the reflectance and transmittance in the linear polarisation basis and circ=True
calculates them in the circular polarisation basis.
The results are two Numpy arrays of reflectances () organised the following way:
in the linear polarisation basis:
in the circular polarisation basis:
To calculate the reflection and transmission spectra of the stack over a range of wavelengths, the user must create a new Structure
for each wavelength and recalculate the reflectance, for example with:
# Creation of an empty variable
reflection_s_to_p = []
# Creation of the wavelengths
wl_nm_list = range(400, 800)
# Calculation of the reflectance for each wavelength
for wl_nm in wl_nm_list:
# Calculation of the wavevector
k0 = 2 * numpy.pi / wl_nm
Kx = n_entry * numpy.sin(theta_in_rad)
Ky = 0
Kz_entry = n_entry * numpy.cos(theta_in_rad)
theta_out_rad = numpy.arcsin((n_entry / n_exit) * numpy.sin(self.theta_in_rad))
Kz_exit = n_exit * numpy.cos(theta_out_rad)
# Creation of the entry and exit half-spaces and of the two layers
entry = HalfSpace(epsilon_entry, Kx, Kz_entry, k0)
exit = HalfSpace(epsilon_exit, Kx, Kz_exit, k0)
layer_a = Layer(eps_a, thick_a, Kx, k0)
layer_b = Layer(eps_b, thick_b, Kx, k0)
# Creation of the periodic stack
my_stack_structure = Structure(entry, exit, Kx, Ky, Kz_entry, Kz_exit, k0)
my_stack_structure.add_layers([layer_a, layer_b])
my_stack_structure.N_periods = N
# Calculation of the reflectance and storage
J_refl_lin, _ = my_stack_structure.get_refl_trans()
reflection_s_to_p.append(J_refl_lin[0, 1])
# Plotting
matplotlib.pyplot.plot(wl_nm_list, reflection_s_to_p)
where:
eps_a
andeps_b
are the permittivity tensors (3x3 Numpy array) of the layer, which can represent a material that is isotropic or anisotropic, absorbing or non-absorbingthick_a
andthick_b
are the thicknesses of the two layers of the periodic pattern, in nanometersN
is the number of periods- `` theta_in_rad`` is the angle of incidence upon the stack, in radians
eps_entry
andeps_exit
are the permittivities of the two isotropic half-spaces; they can be defined differently for each wavelength if the materials are dispersive
With the Model
class: the flexible way¶
When the user creates a multilayer stack my_stack_model
through one of the Model
children classes, the reflectance and transmittance of the multilayer stack (for the wavelength that was used to create the Structure
) can be obtained with:
my_stack_model.get_refl_trans(circ=<False|True>, method=<"SM"|"TM">)
where method
defines the matrix method used ("SM"
(default) for the scattering matrix method and "TM"
for the transfer matrix method) and circ=False
(default) calculates the reflectance and transmittance in the linear polarisation basis and circ=True
calculates them in the circular polarisation basis.
The results are two Numpy arrays of reflectances () organised the following way:
in the linear polarisation basis:
in the circular polarisation basis:
Note
Each children class of Model
contains a Structure
that can be accessed through my_stack_model.structure
and the the previous part of this tutorial can be applied to my_stack_model.structure
to access the partial waves, the transfer or scattering matrices and the reflection and transmission coefficients.
To calculate the reflection and transmission spectra of the stack over a range of wavelengths, the user must create a new Model
for each wavelength and recalculate the reflectance and transmittance, for example with:
# Creation of an empty variable
reflection_s_to_p = []
# Creation of the wavelengths
wl_nm_list = range(400, 800)
# Calculation of the reflectance for each wavelength
for wl_nm in wl_nm_list:
# Creation of the periodic stack
my_stack_model = StackModel([eps_a, eps_b],
[thick_a, thick_b],
n_entry,
n_exit,
wl_nm,
theta_in_rad,
N)
# Calculation of the reflectance and storage
J_refl_lin, _ = my_stack_model.get_refl_trans()
reflection_s_to_p.append(J_refl_lin[0, 1])
# Plotting
matplotlib.pyplot.plot(wl_nm_list, reflection_s_to_p)
where:
eps_a
andeps_b
are the permittivity tensors (3x3 Numpy array) of the layer, which can represent a material that is isotropic or anisotropic, absorbing or non-absorbingthick_a
andthick_b
are the thicknesses of the two layers of the periodic pattern, in nanometersN
is the number of periods- `` theta_in_rad`` is the angle of incidence upon the stack, in radians
n_entry
andn_exit
are the refractive indices of the two isotropic half-spaces; they can be defined differently for each wavelength if the materials are dispersive
With the Spectrum
class: the automated way¶
When the user creates a multilayer stack my_stack_spec
through the Spectrum
class, the reflection and transmission spectra of the multilayer stack (for the range of wavelength that was inputted in the Spectrum
) can be obtained with:
my_stack_spectrum.calculate_refl_trans(circ=<False|True>, method=<"SM"|"TM">, talk=<False|True>)
where method
defines the matrix method used ("SM"
(default) for the scattering matrix method and "TM"
for the transfer matrix method), circ=False
(default) calculates the reflectance and transmittance in the linear polarisation basis and circ=True
calculates them in the circular polarisation basis, and talk=True
enables to display the calculation progress on the screen (default is False
).
The calculated reflection spectra are stored into the dictionary my_stack_spectrum.data
and can be accessed with:
- in the linear polarisation basis:
my_stack_spectrum.data["R_p_to_p_to_p"]
,my_stack_spectrum.data["R_s_to_p"]
,my_stack_spectrum.data["R_p_to_s"]
,my_stack_spectrum.data["R_s_to_s"]
- in the circular polarisation basis:
my_stack_spectrum.data["R_R_to_R"]
,my_stack_spectrum.data["R_L_to_R"]
,my_stack_spectrum.data["R_R_to_L"]
,my_stack_spectrum.data["R_L_to_L"]
and similarly for the transmission spectra:
- in the linear polarisation basis: my_stack_spectrum.data["T_p_to_p"]
, my_stack_spectrum.data["T_s_to_p"]
, my_stack_spectrum.data["T_p_to_s"]
, my_stack_spectrum.data["T_s_to_s"]
- in the circular polarisation basis:
my_stack_spectrum.data["T_R_to_R"]
,my_stack_spectrum.data["T_L_to_R"]
,my_stack_spectrum.data["T_R_to_L"]
,my_stack_spectrum.data["T_L_to_L"]
The calculated spectra (everything stored in my_stack_spectrum.data
) can then be exported in MATLAB or Python-compatible format with:
my_stack_spectrum.export(path_out, with_param=<True|False>)
where:
path_out
is the name of the file. If it ends with.mat
, the export will be in MATLAB-compatible format, and if it ends with.pck
, the export will be in Python-compatible format (with Pickles)with_param
is set toTrue
(default) when the parameters user for the model are exported too and toFalse
when they are not exported
Note
Some Models
may take as input parameters objects that are created through the user’s custom-made libraries (for example, CholestericModel
requires an instance of a Cholesteric
as a parameter). These objects will be stored in the Model
’s parameters. MATLAB can import any unknown object in shape of MATLAB’s type struct
but Python can only import objects for whose it can load the libraries that created them. In this case, exporting the spectra without the parameters may be useful, but this is not the default option.
The calculation the reflection spectrum of the stack over a range of wavelengths is automatic, for example with:
# Creation of the wavelengths
wl_nm_list = range(400, 800)
# Parameters for the stack
model_type = "StackModel"
model_parameters = {"eps_list": [eps_a, eps_b],
"thickness_nm_list": [thick_a, thick_b],
"n_entry": n_entry,
"n_exit": n_exit,
"theta_in_rad": theta_in_rad,
"N_per": N}
# Creation of the periodic stack
my_stack_spec = Spectrum(wl_nm_list, model_type, model_parameters)
# Calculation of the reflectance spectrum in one go
my_stack_spec.calculate_refl_trans()
# Plotting
matplotlip.pyplot.plot(wl_nm_list, my_stack_spec.data["R_s_to_p"])
# Export for MATLAB
# All polarisation combinations are exported (p to p, s to p, p to p, s to s)
my_stack_spec.export("my_file_name.mat")
where:
eps_a
andeps_b
are the permittivity tensors (3x3 Numpy array) of the layer, which can represent a material that is isotropic or anisotropic, absorbing or non-absorbing; if the material is dispersive, aModel
different thanStackModel
must be used that is able to handle a list of permittivitiesthick_a
andthick_b
are the thicknesses of the two layers of the periodic pattern, in nanometersN
is the number of periodstheta_in_rad
is the angle of incidence upon the stack, in radiansn_entry
andn_exit
are the refractive indices of the two isotropic half-spaces; they can be defined differently for each wavelength if the materials are dispersive