Crossed-Grating RCWA API¶
rcwa2d
¶
Differentiable RCWA for 2D-periodic (crossed) gratings of full-tensor media.
Any Bravais lattice (:class:Lattice); each patterned layer is a background
and non-overlapping polygons, each with its own 3×3 ε and μ. Polygons enter
through their exact Fourier transforms (a closed sum over edges), so every
coefficient is differentiable in every vertex. Harmonics G = m·b₁ + n·b₂
are kept for |m| ≤ M₁, |n| ≤ M₂ (truncation="parallelogram") or
|G| ≤ max(M₁, M₂)·g_min ("circular", independent of the primitive
vectors chosen).
Fourier factorisation¶
factorization="laurent" uses Toeplitz matrices of ε directly: correct, but
slow to converge where the normal component of E jumps at an edge.
factorization="normal" (default) is the normal-vector method generalised to
full tensors. At every point the constitutive relation is written in a local
frame (n, t, z) whose n is normal to the pattern's edges, and Li's
anisotropic rearrangement (see :mod:hyperbolic_optics.rcwa) is applied there:
(E_n, D_t, D_z) in terms of the edge-continuous (D_n, E_t, E_z), with
the inverse rule on the normal component only. For isotropic media this is the
textbook normal-vector method; for stripes, n = x̂ and it is the 1D solver's
Li rule exactly. The normal field is the gradient direction of the pattern
smoothed over a tenth of the cell.
Coefficient functions that depend on the frame are products of a shape's indicator -- whose coefficients stay exact -- with a smooth function of the frame, whose coefficients come from a fine grid; the product is a convolution in Fourier space. The assembly is averaged with its product-reversed twin, which keeps it Hermitian for lossless media: energy is conserved to rounding at every truncation.
Conventions follow :mod:hyperbolic_optics.rcwa: order (m, n) has in-plane
wavevector k∥₀ + (m·b₁ + n·b₂)/k₀ (on a rectangular lattice,
(kx₀ + m·λ/Λx, ky₀ + n·λ/Λy)), resolved into that order's own p and s;
results are [..., order, out, in] with 0 = p and 1 = s.
Classes:
-
Lattice–A 2D Bravais lattice: primitive vectors
a1,a2as(x, y)in µm. -
Shape–A polygon of one material within the unit cell.
-
PatternedLayer–One layer: a background material and non-overlapping :class:
Shapes. -
CrossedGratingResult–Amplitudes and efficiencies
[..., order, out, in].
Functions:
-
uniform–An unpatterned layer.
-
rectangle–Vertices
[4, 2]of an axis-aligned rectangle (differentiable in both). -
ellipse–Vertices
[n, 2]of an ellipse, as a polygon of equal area. -
polygon_fourier–∫_P exp(−i(gx·x + gy·y)) dAover a polygon, exactly. -
crossed_grating_smatrix–The zeroth-order, four-port scattering matrix of a 2D-periodic stack.
-
solve_crossed_grating–Diffraction of a plane wave by a stack of 2D-periodic anisotropic layers.
Lattice
¶
Bases: NamedTuple
A 2D Bravais lattice: primitive vectors a1, a2 as (x, y) in µm.
Use the constructors: :meth:rectangular, :meth:square, :meth:hexagonal
(the triangular lattice) and :meth:oblique. A (Λx, Λy) tuple passed as
a period means :meth:rectangular. Components may be JAX values (to
optimise the lattice) except under truncation="circular".
Methods:
-
hexagonal–Triangular lattice of nearest-neighbour distance
period;a1along x, rotated. -
oblique–|a1| = aalong x and|a2| = batangle_radfrom it.
hexagonal
classmethod
¶
Triangular lattice of nearest-neighbour distance period; a1 along x, rotated.
Source code in hyperbolic_optics/rcwa2d.py
oblique
classmethod
¶
|a1| = a along x and |a2| = b at angle_rad from it.
Shape
¶
Bases: NamedTuple
A polygon of one material within the unit cell.
Attributes:
-
vertices(Array) –[..., V, 2]in µm, in cell coordinates (either winding). Shapes may cross the cell edge; they are periodised. They must not overlap one another or their periodic images (overlaps add). -
eps(Array) –Permittivity tensor in the lab frame,
[..., 3, 3]. -
mu(Array | None) –Permeability tensor, or
Nonefor μ = 1.
PatternedLayer
¶
Bases: NamedTuple
One layer: a background material and non-overlapping :class:Shape s.
CrossedGratingResult
¶
Bases: NamedTuple
Amplitudes and efficiencies [..., order, out, in].
orders is [N, 2], a NumPy array (static, so it can index inside jit).
uniform
¶
rectangle
¶
Vertices [4, 2] of an axis-aligned rectangle (differentiable in both).
Source code in hyperbolic_optics/rcwa2d.py
ellipse
¶
Vertices [n, 2] of an ellipse, as a polygon of equal area.
The radius is scaled so the polygon's area equals the ellipse's, which removes the leading-order polygon error in the zeroth Fourier coefficient.
Source code in hyperbolic_optics/rcwa2d.py
polygon_fourier
¶
∫_P exp(−i(gx·x + gy·y)) dA over a polygon, exactly.
By the divergence theorem, (i/|g|²) Σ_edges (g·N_j) ∫_edge exp(−i g·r) dl
with N_j the edge's outward normal scaled by its length; each edge
integral is closed-form. g = 0 gives the area.
Parameters:
-
vertices(Array) –[..., V, 2](either winding). -
gx, gy–Wavevector components
[K].
Returns:
-
Array–[..., K].
Source code in hyperbolic_optics/rcwa2d.py
crossed_grating_smatrix
¶
crossed_grating_smatrix(
layers,
period_um,
wavelength_um,
incidence_rad,
eps_top,
eps_bottom,
max_order,
azimuth_rad=0.0,
factorization="normal",
doublings=None,
grid=None,
truncation="parallelogram",
*,
kx=None,
)
The zeroth-order, four-port scattering matrix of a 2D-periodic stack.
A metasurface as a circuit element: light from either side, in either
polarization, into the zeroth order on either side, power-normalised over
:data:hyperbolic_optics.bcm.PORTS as :func:hyperbolic_optics.bcm.stack_smatrix
is. The higher orders are solved for but are not ports. Unitarity requires
lossless media, propagating zeroth orders and evanescent higher orders.
Arguments as in :func:solve_crossed_grating, with incidence_rad in the
top medium. Alternatively, kx supplies the conserved in-plane wavevector
over k₀ and overrides incidence_rad, including evanescent top ports.
Evanescent ports retain BCM's complex √kz normalization; |s|² is not power there.
A crystal eps_bottom (3×3) makes the bottom ports its power-normalised modes.
Returns:
-
–
class:
hyperbolic_optics.bcm.PlanarSMatrix.
Source code in hyperbolic_optics/rcwa2d.py
solve_crossed_grating
¶
solve_crossed_grating(
layers,
period_um,
wavelength_um,
incidence_rad,
eps_incident,
eps_exit,
max_order,
azimuth_rad=0.0,
factorization="normal",
doublings=None,
grid=None,
truncation="parallelogram",
)
Diffraction of a plane wave by a stack of 2D-periodic anisotropic layers.
Parameters:
-
layers(list[PatternedLayer]) –:class:
PatternedLayers from the incident side down. -
period_um(tuple[float, float]) –A :class:
Lattice, or(Λx, Λy)in µm for a rectangular one. -
wavelength_um(Array) –Vacuum wavelength in µm.
-
incidence_rad(Array) –Polar angle of incidence in the incident medium.
-
eps_incident(Array) –Real, positive permittivity of the incident half-space.
-
eps_exit(Array) –The exit half-space: a real, positive permittivity, or a 3×3 tensor for a crystal substrate (anisotropic, hyperbolic or lossy, any orientation). Its orders are then the crystal's two transmitted modes, each power-normalised, in place of p and s.
-
max_order(tuple[int, int]) –(M₁, M₂): orders|m| ≤ M₁,|n| ≤ M₂alongb₁,b₂(static). -
azimuth_rad(Array, default:0.0) –Plane of incidence, from the x axis.
-
factorization(str, default:'normal') –"normal"(default) or"laurent"(static). -
doublings(int | None, default:None) –Doublings per layer (static); by default grows with the order.
-
grid(tuple[int, int] | None, default:None) –Sampling
(G₁, G₂)of the cell (alonga₁,a₂) for the normal-vector method's smooth parts. -
truncation(str, default:'parallelogram') –"parallelogram"(default) or"circular"(static). Circular keeps|G| ≤ max(M₁, M₂)·g_min, withg_minthe shortest reciprocal lattice vector: it respects the lattice's symmetry (hexagonal included), and the results do not depend on the primitive vectors chosen to describe it.
Returns:
-
CrossedGratingResult–class:
CrossedGratingResult:orders[N, 2]andr,t, -
CrossedGratingResult–R,T[..., N, out, in]. Only order (0, 0) is incident.