Layers API¶
layers
¶
Layer construction and transfer matrix calculation.
This module implements various layer types for multilayer optical structures:
- Ambient media (incident prism, exit medium)
- Isotropic layers (air gaps, dielectric layers)
- Anisotropic crystal layers (finite thickness)
- Semi-infinite anisotropic layers
Each layer type calculates its own transfer matrix using the 4×4 formalism, which relates electromagnetic field components at the layer boundaries.
Classes:
-
AmbientMedium–Base class for ambient mediums (incident and exit).
-
AmbientIncidentMedium–Class representing the ambient incident medium.
-
AmbientExitMedium–Class representing the ambient exit medium.
-
Layer–Abstract base class for a layer in the device.
-
PrismLayer–The incident coupling prism layer.
-
AirGapLayer–The airgap/isotropic middle layer.
-
CrystalLayer–Anisotropic crystal of arbitrary orientation and thickness.
-
SemiInfiniteCrystalLayer–Anisotropic semi-infinite crystal layer.
-
IsotropicSemiInfiniteLayer–Isotropic semi-infinite layer with a given permittivity.
-
LayerFactory–Factory class for creating layers.
AmbientMedium
¶
AmbientIncidentMedium
¶
Bases: AmbientMedium
Class representing the ambient incident medium. Moved from material_params.py to better organize layer-related functionality.
Initialize the ambient incident medium (prism).
Parameters:
-
permittivity(float) –Relative permittivity of the incident medium
-
kx(ndarray) –x-component of the wavevector (parallel to interface)
Methods:
-
construct_tensor–Construct the transfer matrix for the ambient incident medium.
Source code in hyperbolic_optics/layers.py
construct_tensor
¶
Construct the transfer matrix for the ambient incident medium.
Builds the 4×4 transfer matrix relating incident and reflected field components in the incident medium. The matrix accounts for both s and p polarizations.
Returns:
-
ndarray–Transfer matrix with shape [180, 4, 4] for incident scenario or
-
ndarray–[1, 1, 4, 4] for azimuthal scenario
Note
This implements the boundary condition matrix for a semi-infinite incident medium (prism) as described in the 4×4 formalism.
Source code in hyperbolic_optics/layers.py
AmbientExitMedium
¶
Bases: AmbientMedium
Class representing the ambient exit medium. Moved from material_params.py to better organize layer-related functionality.
Initialize the ambient exit medium.
Parameters:
-
incident_angle(float) –Incident angle at the first interface in radians
-
permittivity_incident(float) –Permittivity of the incident medium
-
permittivity_exit(float) –Permittivity of the exit medium
Methods:
-
construct_tensor–Construct the transfer matrix for the ambient exit medium.
-
construct_tensor_singular–Construct transfer matrix for single-point exit medium.
Source code in hyperbolic_optics/layers.py
construct_tensor
¶
Construct the transfer matrix for the ambient exit medium.
Builds the 4×4 transfer matrix for the semi-infinite exit layer, accounting for refraction at the final interface.
Returns:
-
ndarray–Transfer matrix accounting for transmitted waves only
Note
The exit medium has no reflected waves (semi-infinite), so only forward-propagating modes are included.
Source code in hyperbolic_optics/layers.py
construct_tensor_singular
¶
Construct transfer matrix for single-point exit medium.
Returns:
-
ndarray–Transfer matrix with shape [4, 4] for scalar case
Source code in hyperbolic_optics/layers.py
Layer
¶
Bases: ABC
Abstract base class for a layer in the device.
Initialize a generic layer.
Parameters:
-
data(dict[str, Any]) –Dictionary containing layer parameters (type, material, rotations, etc.)
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber (2π/λ)
Note
This is an abstract base class. Use specific layer types like PrismLayer, AirGapLayer, or CrystalLayer instead.
Methods:
-
material_factory–Resolve
self.material(a name or arbitrary-tensor dict) to an instance. -
calculate_z_rotation–Calculate the z-axis rotation based on scenario type and rotation mode.
-
calculate_tensors–Calculate both permittivity and permeability tensors for the layer.
-
rotate_tensors–Rotate ε/μ by the Euler angles and emit canonical
[A, B, F, 3, 3]. -
create–Create the layer's transfer matrix and wave profile.
Source code in hyperbolic_optics/layers.py
material_factory
¶
Resolve self.material (a name or arbitrary-tensor dict) to an instance.
Raises:
-
NotImplementedError–If the material name is not recognized.
Source code in hyperbolic_optics/layers.py
calculate_z_rotation
¶
Calculate the z-axis rotation based on scenario type and rotation mode.
Determines whether the z-rotation is relative to the azimuthal angle or static (fixed in space). For dispersion and azimuthal scenarios, adds the azimuthal angle to relative rotations.
Note
The rotationZType attribute controls whether rotation is 'relative' (rotates with sample) or 'static' (fixed in lab frame).
Source code in hyperbolic_optics/layers.py
calculate_tensors
¶
Calculate both permittivity and permeability tensors for the layer.
Fetches the material's permittivity (ε) and permeability (μ) tensors for the appropriate frequency or frequency range based on scenario type.
Note
The material is evaluated over the scenario's frequency array (length 1 for single-frequency scenarios, length F otherwise), so eps/mu and k0 always share the same frequencies. Scenario-agnostic.
Source code in hyperbolic_optics/layers.py
rotate_tensors
¶
Rotate ε/μ by the Euler angles and emit canonical [A, B, F, 3, 3].
Scenario-agnostic: the fetched tensors and the z-rotation angle are
normalised to the canonical layout by rank, then a single broadcasting
rotation (hyperbolic_optics.anisotropy_utils.rotate_tensor) produces
canonical output. rotationX/Y are scalar crystal orientations and
broadcast for free.
Source code in hyperbolic_optics/layers.py
create
abstractmethod
¶
Create the layer's transfer matrix and wave profile.
This method must be implemented by concrete layer classes to construct the layer-specific transfer matrix.
Raises:
-
NotImplementedError–Must be implemented by subclasses
Source code in hyperbolic_optics/layers.py
PrismLayer
¶
Bases: Layer
The incident coupling prism layer.
Initialize the incident coupling prism layer.
Parameters:
-
data(dict[str, Any]) –Dictionary containing 'permittivity' key for prism permittivity
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Methods:
-
create–Create the prism transfer matrix in canonical
[A, 1, 1, 4, 4]form.
Source code in hyperbolic_optics/layers.py
create
¶
Create the prism transfer matrix in canonical [A, 1, 1, 4, 4] form.
The prism varies with incident angle only; the size-1 azimuth/frequency axes broadcast against the rest of the stack during the matrix product.
Source code in hyperbolic_optics/layers.py
AirGapLayer
¶
Bases: Layer
The airgap/isotropic middle layer.
Initialize an isotropic middle-stack layer (air gap or dielectric).
Parameters:
-
data(dict[str, Any]) –Dictionary with 'thickness', 'permittivity', and optionally 'permeability'
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Note
Permittivity and permeability can be specified as scalars or as dictionaries with 'real' and 'imag' components.
Methods:
-
create–Create the air gap layer transfer matrix and wave profile.
Source code in hyperbolic_optics/layers.py
create
¶
Create the air gap layer transfer matrix and wave profile.
An air gap is just an isotropic finite layer; with canonical inputs the
Wave produces a canonical [A, 1, F, 4, 4] matrix directly, so no
per-scenario reshaping is needed.
Source code in hyperbolic_optics/layers.py
CrystalLayer
¶
Bases: Layer
Anisotropic crystal of arbitrary orientation and thickness.
Initialize an anisotropic crystal layer with finite thickness.
Parameters:
-
data(dict[str, Any]) –Dictionary with 'material', 'thickness', and rotation angles
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Note
The crystal can be rotated using rotationX, rotationY, and rotationZ Euler angles specified in degrees.
Methods:
-
create–Create the crystal layer transfer matrix and wave profile.
Source code in hyperbolic_optics/layers.py
create
¶
Create the crystal layer transfer matrix and wave profile.
Solves for the wave modes in the anisotropic layer and constructs the transfer matrix accounting for phase accumulation through the layer.
Source code in hyperbolic_optics/layers.py
SemiInfiniteCrystalLayer
¶
Bases: Layer
Anisotropic semi-infinite crystal layer.
Initialize a semi-infinite anisotropic crystal layer.
Parameters:
-
data(dict[str, Any]) –Dictionary with 'material' and rotation angles
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Note
Semi-infinite layers have no thickness parameter as they extend infinitely in the +z direction. Only forward-propagating modes exist.
Methods:
-
create–Create the semi-infinite crystal transfer matrix.
Source code in hyperbolic_optics/layers.py
create
¶
Create the semi-infinite crystal transfer matrix.
Constructs a transfer matrix that includes only the eigenvectors without phase propagation (no thickness dependence).
Source code in hyperbolic_optics/layers.py
IsotropicSemiInfiniteLayer
¶
Bases: Layer
Isotropic semi-infinite layer with a given permittivity.
Initialize a semi-infinite isotropic exit layer.
Parameters:
-
data(dict[str, Any]) –Dictionary with 'permittivity' for exit medium
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Raises:
-
ValueError–If exit permittivity is not provided
Methods:
-
create–Create the isotropic exit layer transfer matrix in canonical form.
Source code in hyperbolic_optics/layers.py
create
¶
Create the isotropic exit layer transfer matrix in canonical form.
Emits [A, 1, 1, 4, 4] (the exit medium varies with incident angle
only); the size-1 azimuth/frequency axes broadcast against the stack.
This works for every scenario, including FullSweep, via broadcasting.
Source code in hyperbolic_optics/layers.py
LayerFactory
¶
Factory class for creating layers.
Initialize the layer factory with available layer types.
Registers all available layer classes for creation based on type string.
Methods:
-
create_layer–Create a layer instance from configuration data.
Source code in hyperbolic_optics/layers.py
create_layer
¶
Create a layer instance from configuration data.
Parameters:
-
layer_data(dict[str, Any]) –Dictionary containing layer type and parameters
-
scenario(ScenarioSetup) –The simulation scenario configuration
-
kx(ndarray) –x-component of wavevector
-
k0(ndarray) –Free-space wavenumber
Returns:
-
Layer–An instance of the appropriate Layer subclass
Raises:
-
ValueError–If layer type is not recognized
Example
factory = LayerFactory() layer_data = {"type": "Ambient Incident Layer", "permittivity": 50.0} layer = factory.create_layer(layer_data, scenario, kx, k0)