Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/src/basics/beams.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ This package implements the above method via the [`GaussianBeamlet`](@ref) and t

### Stigmatic Beamlets

The [`GaussianBeamlet`](@ref) implements the [`BeamletOptics.AbstractBeam`](@ref) interface and can be used to model the propagation of a monochromatic Gaussian (``\text{TEM}_{00}``-mode) through optical system where all optics lie on the optical axis, e.g. no tip and/or tilt dealignment, and abberations can be neglected. It is represented by a `chief` (red), `waist` (blue) and `divergence` (green) beam. See below how these beans are placed in relation to the envelope of the Gaussian beam.
The [`GaussianBeamlet`](@ref) implements the [`BeamletOptics.AbstractBeam`](@ref) interface and can be used to model the propagation of a monochromatic Gaussian (``\text{TEM}_{00}``-mode) through optical system where all optics lie on the optical axis, e.g. no tip and/or tilt dealignment, and abberations can be neglected. It is represented by a `chief` (red), `waist` (blue) and `divergence` (green) beam. See below how these beams are placed in relation to the envelope of the Gaussian beam.

![Complex ray tracing I](gbtest1.png)

Expand Down
31 changes: 29 additions & 2 deletions docs/src/basics/components/polarizers.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Polarizers
# Polarizing components

Polarizers in the context of this package are optical elements that select or modify the R³ polarization vector of a [`PolarizedRay`](@ref), e.g. filters or λ/2 waveplates. This is mainly done by two approaches:
Polarizing components in the context of this package are optical elements that select or modify the R³ polarization vector of a [`PolarizedRay`](@ref), e.g. filters or λ/2 waveplates. This is mainly done by two approaches:

1. 3D polarization ray-tracing calculus
2. 3D modified Jones matrix calculus
Expand Down Expand Up @@ -43,4 +43,31 @@ A polarisation filter or linear polarizer is the simplest practical polarizer an

```@docs; canonical=false
PolarizationFilter(::Real)
```

## Waveplates

A waveplate is a component which shifts the electric field components of a ray in phase relative to each other. The corresponding element is provided by the [`Waveplate`](@ref). For convenience the [`HalfWaveplate`](@ref) and [`QuarterWaveplate`](@ref) constructors are provided. A half waveplate is a component which mirrors the field components along the orientation axis of the waveplate, which can be used to continuously rotate a linearly polarized field vector. A quarter wave plate is typically used at a 45° angle with respect to the input polarization and will convert a linearly polarized beam of light into left-/right-handed circularly polarized light.


!!! tip Round vs. rectangular waveplates
The waveplate constructors accept either two arguments for their dimensions, which will spawn a rectangular waveplate. If you specify just one dimension, a circularly shaped waveplate will be constructed.

```@docs; canonical=false
Waveplate
HalfWaveplate
QuarterWaveplate
```

## Polarizing beam splitters

These components are the polarizing counterparts of the beamsplitters described in the [Beamsplitters](@ref) section. As a proto-component, the [PolarizingBeamSplitter](@ref) is provided, which is a thin (i.e thickness of zero) component. This component will transmit parallel polarized light (i.e. aligned with the x-axis of the component) and reflect perpendicular polarized light (aligned with the z-axis).

Futhermore a plate beamsplitter and polarizing beam splitter cubes can be constructed, which use the [PolarizingBeamSplitter](@ref) as a coating-type component but correspond better to real elements which also have dispersive effects besides their polarizatioon.

```@docs; canonical=false
PolarizingBeamSplitter
PolarizingCubeBeamsplitter
RectangularPolarizingPlateBeamsplitter
RoundPolarizingPlateBeamsplitter
```
4 changes: 4 additions & 0 deletions src/Exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export Detector, electric_field, intensity, spot_diagram, optical_power, Centroi

# splitters
export ThinBeamsplitter, RoundThinBeamsplitter, RectangularPlateBeamsplitter, RoundPlateBeamsplitter, CubeBeamsplitter, RectangularCompensatorPlate
export PolarizingBeamSplitter, PolarizingCubeBeamsplitter, RectangularPolarizingPlateBeamsplitter, RoundPolarizingPlateBeamsplitter

# polarizing components
export PolarizationFilter
Expand All @@ -45,5 +46,8 @@ export NonInteractableObject, MeshDummy, IntersectableObject
# misc
export Retroreflector

# polarization components
export Waveplate, HalfWaveplate, QuarterWaveplate

# render
export render!
1 change: 1 addition & 0 deletions src/OpticalComponents/Beamsplitters/Beamsplitters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ abstract type AbstractBeamsplitter{T} <: AbstractObject{T} end

# order of inclusion matters
include("ThinBeamsplitter.jl")
include("PolarizingBeamSplitter.jl")
include("PlateBeamsplitter.jl")
include("CubeBeamsplitter.jl")
include("Compensators.jl")
103 changes: 88 additions & 15 deletions src/OpticalComponents/Beamsplitters/CubeBeamsplitter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,37 +34,37 @@ refractive_index(cbs::CubeBeamsplitter, λ::Real) = refractive_index(cbs.front,
"""
CubeBeamsplitter(leg_length, n; reflectance=0.5)

Creates a [`CubeBeamsplitter`](@ref). The cuboid is centered at the origin. The splitter
Creates a [`CubeBeamsplitter`](@ref). The cuboid is centered at the origin. The splitter
coating is orientated at a 45° angle with respect to the y-axis.

# Inputs

- `leg_length`: the x-, y- and z-edge length in [m]
- `n`: the [`RefractiveIndex`](@ref) of the front and back prism

# Keywords
# Keywords

- `reflectance`: defines the splitting ratio in [-], i.e. R = 0 ... 1.0
"""
function CubeBeamsplitter(
leg_length::Real,
n::RefractiveIndex;
reflectance::Real=0.5
)
reflectance::Real = 0.5
)
front = RightAnglePrism(leg_length, leg_length, n)
back = RightAnglePrism(leg_length, leg_length, n)
bs = ThinBeamsplitter(√2*leg_length, leg_length; reflectance)
bs = ThinBeamsplitter(√2 * leg_length, leg_length; reflectance)
zrotate3d!(back, deg2rad(180))
zrotate3d!(bs, deg2rad(180-45))
zrotate3d!(bs, deg2rad(180 - 45))
set_new_origin3d!(shape(bs))
return CubeBeamsplitter(front, back, bs)
end

function interact3d(
system::AbstractSystem,
cbs::CubeBeamsplitter,
beam::Beam{T, R},
ray::R) where {T <: Real, R <: AbstractRay{T}}
system::AbstractSystem,
cbs::CubeBeamsplitter,
beam::Beam{T, R},
ray::R) where {T <: Real, R <: AbstractRay{T}}
# Front prism interaction
if shape(intersection(ray)) === shape(cbs.front)
interaction = interact3d(system, cbs.front, beam, ray)
Expand Down Expand Up @@ -92,10 +92,10 @@ function interact3d(
end

function interact3d(
system::AbstractSystem,
cbs::CubeBeamsplitter,
gauss::GaussianBeamlet,
id::Int)
system::AbstractSystem,
cbs::CubeBeamsplitter,
gauss::GaussianBeamlet,
id::Int)
_shape = shape(intersection(rays(gauss.chief)[id]))
# Front prism interaction
if _shape === shape(cbs.front)
Expand All @@ -118,4 +118,77 @@ function interact3d(
hint!(interaction, Hint(cbs, shape(cbs.coating)))
return interaction
end
end
end

"""
PolarizingCubeBeamsplitter <: AbstractBeamsplitter

A cuboid beamsplitter that uses an ideal polarization‑dependent splitting
coating. The internal coating behaves like a [`PolarizingBeamSplitter`](@ref):
its local `x`‑axis transmits and the `z`‑axis reflects the incoming
polarization components. The coating is mounted at 45° relative to the
incoming `y` direction of the cube, so rotating the cube rotates these axes
accordingly.
"""
struct PolarizingCubeBeamsplitter{T} <: AbstractBeamsplitter{T}
front::Prism{T, RightAnglePrismSDF{T}}
back::Prism{T, RightAnglePrismSDF{T}}
coating::PolarizingBeamSplitter{T, Mesh{T}}
end

shape_trait_of(::PolarizingCubeBeamsplitter) = MultiShape()

shape(cbs::PolarizingCubeBeamsplitter) = (cbs.front, cbs.back, cbs.coating)

refractive_index(cbs::PolarizingCubeBeamsplitter, λ::Real) = refractive_index(cbs.front, λ)

"""
PolarizingCubeBeamsplitter(leg_length, n)

Creates a `PolarizingCubeBeamsplitter`. The cuboid is centered at the origin and
the coating is orientated at 45° with respect to the y-axis.

# Inputs

- `leg_length`: the x-, y- and z-edge length in [m]
- `n`: the [`RefractiveIndex`](@ref) of the front and back prism
"""
function PolarizingCubeBeamsplitter(leg_length::Real, n::RefractiveIndex)
front = RightAnglePrism(leg_length, leg_length, n)
back = RightAnglePrism(leg_length, leg_length, n)
bs = PolarizingBeamSplitter(√2 * leg_length, leg_length)
zrotate3d!(back, deg2rad(180))
zrotate3d!(bs, deg2rad(180 - 45))
set_new_origin3d!(shape(bs))
return PolarizingCubeBeamsplitter(front, back, bs)
end

function interact3d(
system::AbstractSystem,
cbs::PolarizingCubeBeamsplitter,
beam::Beam{T, R},
ray::R) where {T <: Real, R <: PolarizedRay{T}}
if shape(intersection(ray)) === shape(cbs.front)
# Use proper refraction on entering the front face
interaction = interact3d(system, cbs.front, beam, ray)
hint!(interaction, Hint(cbs, shape(cbs.coating)))
return interaction
end
if shape(intersection(ray)) === shape(cbs.coating)
# We are INSIDE the cube. The coating sits between front and back prisms.
# So we split the beam, but the refractive index stays `n` (the glass index).
interact3d(system, cbs.coating, beam, ray)
_n = refractive_index(cbs, wavelength(ray))
refractive_index!(first(rays(beam.children[1])), _n)
refractive_index!(first(rays(beam.children[2])), _n)
return nothing
end
if shape(intersection(ray)) === shape(cbs.back)
# Ensure we only interact with the back prism if we are actually at the back surface
# A normal `CubeBeamsplitter` delegates to `cbs.back` entirely, but we need to ensure
# that ray direction correctly triggers the exit refraction instead of internal reflection.
interaction = interact3d(system, cbs.back, beam, ray)
hint!(interaction, Hint(cbs, shape(cbs.coating)))
return interaction
end
end
Loading