Optical Systems
Assemblies
All systems are made up of a LensAssembly
which contains all the optical components in the system, excluding any sources (see Emitters) and the detector (see below).
OpticSim.LensAssembly
— TypeLensAssembly{T<:Real}
Structure which contains the elements of the optical system, these can be CSGTree
or Surface
objects.
In order to prevent type ambiguities bespoke structs are created for each possible number of elements e.g. LensAssembly3
. These are parameterized by the types of the elements to prevent ambiguities. Basic surface types such as Rectangle
(which can occur in large numbers) are stored independently in Vector
s, so type paramters are only needed for CSG objects.
Each struct looks like this:
struct LensAssemblyN{T,T1,T2,...,TN} <: LensAssembly{T}
axis::SVector{3,T}
rectangles::Vector{Rectangle{T}}
ellipses::Vector{Ellipse{T}}
hexagons::Vector{Hexagon{T}}
paraxials::Vector{ParaxialLens{T}}
E1::T1
E2::T2
...
EN::TN
end
Where Ti <: Union{Surface{T},CSGTree{T}}
.
To create a LensAssembly object the following functions can be used:
LensAssembly(elements::Vararg{Union{Surface{T},CSGTree{T},LensAssembly{T}}}; axis = SVector(0.0, 0.0, 1.0)) where {T<:Real}
Images
The detector image is stored within the system as a HierarchicalImage
for memory efficiency.
OpticSim.HierarchicalImage
— TypeHierarchicalImage{T<:Number} <: AbstractArray{T,2}
Image type which dynamically allocated memory for pixels when their value is set, the value of unset pixels is assumed to be zero.
This is used for the detector image of OpticalSystem
s which can typically be very high resolution, but often have a large proportion of the image blank.
OpticSim.reset!
— Functionreset!(a::HierarchicalImage{T})
Resets the pixels in the image to zero(T)
. Do this rather than image .= zero(T)
because that will cause every pixel to be accessed, and therefore allocated. For large images this can cause huge memory traffic.
OpticSim.sum!
— Functionsum!(a::HierarchicalImage{T}, b::HierarchicalImage{T})
Add the contents of b
to a
in an efficient way.
Systems
There are two types of OpticalSystem
which can be used depending on the requirements.
OpticSim.OpticalSystem
— TypeOpticalSystem{T<:Real}
Abstract type for any optical system, must parameterized by the datatype of entities within the system T
.
OpticSim.CSGOpticalSystem
— TypeCSGOpticalSystem{T,D<:Real,S<:Surface{T},L<:LensAssembly{T}} <: OpticalSystem{T}
An optical system containing a lens assembly with all optical elements and a detector surface with associated image. The system can be at a specified temperature and pressure.
There are two number types in the type signature. The T
type parameter is the numeric type for geometry in the optical system, the D
type parameter is the numeric type of the pixels in the detector image. This way you can have Float64
geometry, where high precision is essential, but the pixels in the detector can be Float32
since precision is much less critical for image data.
The detector can be any Surface
which implements uv
, uvtopix
and onsurface
, typically this is one of Rectangle
, Ellipse
or SphericalCap
.
CSGOpticalSystem(assembly::LensAssembly, detector::Surface, detectorpixelsx = 1000, detectorpixelsy = 1000, ::Type{D} = Float32; temperature = OpticSim.GlassCat.TEMP_REF, pressure = OpticSim.GlassCat.PRESSURE_REF)
OpticSim.AxisymmetricOpticalSystem
— TypeAxisymmetricOpticalSystem{T,C<:CSGOpticalSystem{T}} <: OpticalSystem{T}
Optical system which has lens elements and an image detector, created from a DataFrame
containing prescription data.
These tags are supported for columns: :Radius
, :SemiDiameter
, :Surface
, :Thickness
, :Conic
, :Aspherics
, :Reflectance
, :Material
, :OptimizeRadius
, :OptimizeThickness
, :OptimizeConic
. These tags are supported for entries in a :Surface
column: :Object
, :Image
, :Stop
Assumes the :Image
row will be the last row in the DataFrame
.
In practice a CSGOpticalSystem
is generated automatically and stored within this system.
AxisymmetricOpticalSystem{T}(prescription::DataFrame, detectorpixelsx = 1000, detectorpixelsy:: = 1000, ::Type{D} = Float32; temperature = OpticSim.GlassCat.TEMP_REF, pressure = OpticSim.GlassCat.PRESSURE_REF)
OpticSim.temperature
— Functiontemperature(system::OpticalSystem{T}) -> T
Get the temperature of system
in °C.
OpticSim.pressure
— Functionpressure(system::OpticalSystem{T}) -> T
Get the pressure of system
in Atm.
OpticSim.detectorimage
— Functiondetectorimage(system::OpticalSystem{T}) -> HierarchicalImage{D}
Get the detector image of system
. D
is the datatype of the detector image and is not necessarily the same as the datatype of the system T
.
OpticSim.resetdetector!
— Functionresetdetector!(system::OpticalSystem{T})
Reset the deterctor image of system
to zero.
OpticSim.assembly
— Functionassembly(system::OpticalSystem{T}) -> LensAssembly{T}
Get the LensAssembly
of system
.
OpticSim.semidiameter
— Functionsemidiameter(system::AxisymmetricOpticalSystem{T}) -> T
Get the semidiameter of system
, that is the semidiameter of the entrance pupil (i.e. first surface) of the system.
Tracing
We can trace an individual OpticalRay
through the system (or directly through a LensAssembly
), or we can trace using an OpticalRayGenerator
to create a large number of rays.
OpticSim.trace
— Functiontrace(assembly::LensAssembly{T}, r::OpticalRay{T}, temperature::T = 20.0, pressure::T = 1.0; trackrays = nothing, test = false)
Returns the ray as it exits the assembly in the form of a LensTrace
object if it hits any element in the assembly, otherwise nothing
. Recursive rays are offset by a small amount (RAY_OFFSET
) to prevent it from immediately reintersecting the same lens element.
trackrays
can be passed an empty vector to accumulate the LensTrace
objects at each intersection of ray
with a surface in the assembly.
trace(system::OpticalSystem{T}, ray::OpticalRay{T}; trackrays = nothing, test = false)
Traces system
with ray
, if test
is enabled then fresnel reflections are disabled and the power distribution will not be correct. Returns either a LensTrace
if the ray hits the detector or nothing
otherwise.
trackrays
can be passed an empty vector to accumulate the LensTrace
objects at each intersection of ray
with a surface in the system.
trace(system::OpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false)
Traces system
with rays generated by raygenerator
on a single thread. Optionally the progress can be printed to the REPL. If test
is enabled then fresnel reflections are disabled and the power distribution will not be correct. If outpath
is specified then the result will be saved to this path.
Returns the detector image of the system.
OpticSim.traceMT
— FunctiontraceMT(system::OpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false)
Traces system
with rays generated by raygenerator
using as many threads as possible. Optionally the progress can be printed to the REPL. If test
is enabled then fresnel reflections are disabled and the power distribution will not be correct. If outpath
is specified then the result will be saved to this path.
Returns the accumulated detector image from all threads.
OpticSim.tracehits
— Functiontracehits(system::OpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false)
Traces system
with rays generated by raygenerator
on a single thread. Optionally the progress can be printed to the REPL. If test
is enabled then fresnel reflections are disabled and the power distribution will not be correct.
Returns a list of LensTrace
s which hit the detector.
OpticSim.tracehitsMT
— FunctiontracehitsMT(system::OpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false)
Traces system
with rays generated by raygenerator
using as many threads as possible. Optionally the progress can be printed to the REPL. If test
is enabled then fresnel reflections are disabled and the power distribution will not be correct.
Returns a list of LensTrace
s which hit the detector, accumulated from all threads.
OpticSim.LensTrace
— TypeLensTrace{T<:Real,N}
Contains an intersection point and the ray segment leading to it from within an optical trace. The ray carries the path length, power, wavelength, number of intersections and source number, all of which are accessible directly on this class too.
Has the following accessor methods:
ray(a::LensTrace{T,N}) -> OpticalRay{T,N}
intersection(a::LensTrace{T,N}) -> Intersection{T,N}
power(a::LensTrace{T,N}) -> T
wavelength(a::LensTrace{T,N}) -> T
pathlength(a::LensTrace{T,N}) -> T
point(a::LensTrace{T,N}) -> SVector{N,T}
uv(a::LensTrace{T,N}) -> SVector{2,T}
sourcenum(a::LensTrace{T,N}) -> Int
nhits(a::LensTrace{T,N}) -> Int