diff --git a/samples/notebooks/EmittersIntro.jl b/samples/notebooks/EmittersIntro.jl index 99705a281..204a67b17 100644 --- a/samples/notebooks/EmittersIntro.jl +++ b/samples/notebooks/EmittersIntro.jl @@ -28,7 +28,7 @@ begin # defining the optical system sys = AxisymmetricOpticalSystem( - DataFrame(Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Standard", "Stop", "Standard", "Standard", "Image"], Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf], Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SF2, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], diff --git a/samples/notebooks/Samples.jl b/samples/notebooks/Samples.jl index 7d475f1cc..723c104f4 100644 --- a/samples/notebooks/Samples.jl +++ b/samples/notebooks/Samples.jl @@ -28,7 +28,7 @@ begin # defining the optical system sys_cooke = AxisymmetricOpticalSystem( - DataFrame(Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image], + DataFrame(SurfaceType= ["Object", "Standard", "Standard", "Standard", "Stop", "Standard", "Standard", "Image"], Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf], Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SF2, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], diff --git a/src/Examples/docs_examples.jl b/src/Examples/docs_examples.jl index 4be52e69c..c4a89d568 100644 --- a/src/Examples/docs_examples.jl +++ b/src/Examples/docs_examples.jl @@ -8,11 +8,11 @@ export draw_cooketriplet, draw_schmidtcassegraintelescope, draw_lensconstruction function draw_cooketriplet(filename::Union{Nothing,AbstractString} = nothing) g1, g2 = SCHOTT.N_SK16, SCHOTT.N_SF2 sys = AxisymmetricOpticalSystem{Float64}(DataFrame( - Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image ], - Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf ], - Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], - Material = [Air, g1, Air, g2, Air, g1, Air, missing], - SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0 ], + SurfaceType = ["Object", "Standard", "Standard", "Standard", "Stop", "Standard", "Standard", "Image"], + Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf ], + Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], + Material = [Air, g1, Air, g2, Air, g1, Air, missing], + SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0 ], )) origins = Origins.Hexapolar(8, 15.0, 15.0) @@ -40,11 +40,16 @@ function draw_zoomlenses(filenames::Vector{<:Union{Nothing,AbstractString}} = re directions = Directions.Constant(0.0, 0.0, -1.0) raygenerator = Sources.Source(; transform, origins, directions) + aspherics = [ + [4 => 1.0386E-04, 6 => 1.4209E-07, 8 => -8.8495E-09, 10 => 1.2477E-10, 12 => -1.0367E-12, 14 => 3.6556E-15], + [4 => 4.2721E-05, 6 => 1.2484E-07, 8 => 9.7079E-09, 10 => -1.8444E-10, 12 => 1.8644E-12, 14 => -7.7975E-15], + [4 => 1.1339E-04, 6 => 4.8165E-07, 8 => 1.8778E-08, 10 => -5.7571E-10, 12 => 8.9994E-12, 14 => -4.6768E-14], + ] syss = [ AxisymmetricOpticalSystem{Float64}(DataFrame( - Surface = [:Object, :Stop, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, :Image], + SurfaceType = ["Object", "Stop", "Standard", "Standard", "Standard", "Aspheric", "Standard", "Standard", "Aspheric", "Aspheric", "Standard", "Standard", "Standard", "Standard", "Standard", "Standard", "Image"], Radius = [Inf64, Inf64, -1.6202203499676E+01, -4.8875855327468E+01, 1.5666614444619E+01, -4.2955326460481E+01, 1.0869565217391E+02, 2.3623907394283E+01, -1.6059097478722E+01, -4.2553191489362E+02, -3.5435861091425E+01, -1.4146272457208E+01, -2.5125628140704E+02, -2.2502250225023E+01, -1.0583130489999E+01, -4.4444444444444E+01, Inf64], - Aspherics = [missing, missing, missing, missing, missing, [(4, 1.0386E-04), (6, 1.4209E-07), (8, -8.8495E-09), (10, 1.2477E-10), (12, -1.0367E-12), (14, 3.6556E-15)], missing, missing, [(4, 4.2721E-05), (6, 1.2484E-07), (8, 9.7079E-09), (10, -1.8444E-10), (12, 1.8644E-12), (14, -7.7975E-15)], [(4, 1.1339E-04), (6, 4.8165E-07), (8, 1.8778E-08), (10, -5.7571E-10), (12, 8.9994E-12), (14, -4.6768E-14)], missing, missing, missing, missing, missing, missing, missing], + Parameters = [missing, missing, missing, missing, missing, aspherics[1], missing, missing, aspherics[2], aspherics[3], missing, missing, missing, missing, missing, missing, missing], Thickness = [Inf64, 0.0, 5.18, 0.10, 4.40, 0.16, 1.0, 4.96, zoom, 4.04, 1.35, 1.0, 2.80, 3.0, 1.22, dist, missing], Material = [Air, Air, OHARA.S_LAH66, Air, NIKON.LLF6, Air, OHARA.S_TIH6, OHARA.S_FSL5, Air, OHARA.S_FSL5, Air, OHARA.S_LAL8, OHARA.S_FSL5, Air, OHARA.S_LAH66, Air, missing], SemiDiameter = [Inf64, stop, 3.85433218451, 3.85433218451, 4.36304692871, 4.36304692871, 4.72505505439, 4.72505505439, 4.72505505439, 4.45240784026, 4.45240784026, 4.50974054117, 4.50974054117, 4.50974054117, 4.76271114409, 4.76271114409, 15.0])) diff --git a/src/Examples/other_examples.jl b/src/Examples/other_examples.jl index 5e9c7c031..9ef9592f2 100644 --- a/src/Examples/other_examples.jl +++ b/src/Examples/other_examples.jl @@ -4,119 +4,186 @@ export cooketriplet, doubleconvexlensonly -# Create a geometric hemisphere +""" + hemisphere() + +Create a geometric hemisphere +""" function hemisphere()::CSGTree sph = Sphere(10.0) pln = Plane(0.0, 0.0, -1.0, 0.0, 0.0, 0.0) - csgintersection(sph, pln)() #csg operations create a csggenerator which instantiates the csg tree after applying a rigid body transformation. This allows you to make as many instances of the object as you want with different transformations. We just want the CSGTree object rather than a generator. + # CSV operations create a csggenerator which instantiates the csg tree after applying a rigid body transformation. + # This allows you to make as many instances of the object as you want with different transformations. We just want + # the CSGTree object rather than a generator. + return csgintersection(sph, pln)() end -# Create an optical hemisphere that has optical material properties so it will reflect and refract light. In the previous example the hemisphere object had optical properties of OpticSim.GlassCat.Air, which is the default optical interface, so it won't refract or reflect light. +""" + opticalhemisphere() + +Create an optical hemisphere that has optical material properties so it will reflect and refract light. In the previous +example the hemisphere object had optical properties of Air, which is the default optical interface, so it won't refract +or reflect light. +""" function opticalhemisphere()::CSGOpticalSystem - sph = Sphere(10.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)) - pln = Plane(0.0, 0.0, -1.0, 0.0, 0.0, 0.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)) + sph = Sphere(10.0, interface = FresnelInterface{Float64}(SCHOTT.N_BK7, Air)) + pln = Plane(0.0, 0.0, -1.0, 0.0, 0.0, 0.0, interface = FresnelInterface{Float64}(SCHOTT.N_BK7, Air)) assy = LensAssembly{Float64}(csgintersection(sph, pln)()) return CSGOpticalSystem(assy, Rectangle(1.0, 1.0, SVector{3,Float64}(0.0, 0.0, 1.0), SVector{3,Float64}(0.0, 0.0, -11.0))) end -#! format: off - -cooketriplet(::Type{T} = Float64, detpix::Int = 1000) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image], - Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf], - OptimizeRadius = [false,true,true,true,true,true,true,false], - Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], - OptimizeThickness = [false,true,true,true,true,true,true,false], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SF2, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0]), detpix, detpix) - -cooketripletfirstelement(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf, -35.571, 35.571, Inf], - Thickness = [Inf, 4.0, 44.748, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf, 7.054, 6.033, 15.0])) - -convexplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf, 60.0, Inf, Inf], - Thickness = [Inf, 10.0, 57.8, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf, 9.0, 9.0, 15.0])) - -doubleconvex(frontradius::T,rearradius::T) where{T<:Real} = -AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [T(Inf64), frontradius, rearradius, T(Inf64)], - OptimizeRadius = [false,true,true,false], - Thickness = [T(Inf64), T(10.0), T(57.8), missing], - OptimizeThickness = [false,false,false,false], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [T(Inf64), T(9.0), T(9.0), T(15.0)])) - -doubleconvexconic(::Type{T} = Float64) where {T<:Real} = - AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, 60, -60, Inf64], - OptimizeRadius = [false,true,true,false], - Thickness = [Inf64, 10.0, 57.8, missing], - OptimizeThickness = [false,false,false,false], - Conic = [missing, 0.01, 0.01, missing], - OptimizeConic = [false, true, true, false], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) - -doubleconvexlensonly(frontradius::T,rearradius::T) where{T<:Real} = -AxisymmetricLens{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [T(Inf64), frontradius, rearradius, T(Inf64)], - OptimizeRadius = [false,true,true,false], - Thickness = [T(Inf64), T(10.0), T(57.8), missing], - OptimizeThickness = [false,false,false,false], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [T(Inf64), T(9.0), T(9.0), T(15.0)])) - -doubleconvexprescription() = DataFrame( - Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, 60, -60, Inf64], - OptimizeRadius = [false,true,true,false], - Thickness = [Inf64, 10.0, 57.8, missing], - OptimizeThickness = [false,true,true,false], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 15.0]) - -doubleconvex(::Type{T} = Float64; temperature::Unitful.Temperature = OpticSim.GlassCat.TEMP_REF_UNITFUL, pressure::T = T(OpticSim.GlassCat.PRESSURE_REF)) where {T<:Real} = AxisymmetricOpticalSystem{T}(doubleconvexprescription(),temperature = temperature, pressure = pressure) - -doubleconcave(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, -41.0, 41.0, Inf64], - Thickness = [Inf64, 10.0, 57.8, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) - -planoconcaverefl(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, Inf64, -41.0, Inf64], - Thickness = [Inf64, 10.0, -57.8, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 25.0], - Reflectance = [missing, missing, 1.0, missing])) - -concaveplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, -41.0, Inf64, Inf64], - Thickness = [Inf64, 10.0, 57.8, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) - -planoplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], - Radius = [Inf64, Inf64, Inf64, Inf64], - Thickness = [Inf64, 10.0, 57.8, missing], - Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], - SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) - -#! format: on +function cooketriplet(::Type{T} = Float64, detpix::Int = 1000) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Standard", "Stop", "Standard", "Standard", "Image"], + Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf], + # OptimizeRadius = [false, true, true, true, true, true, true, false], + Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], + # OptimizeThickness = [false, true, true, true, true, true, true, false], + Material = [Air, SCHOTT.N_SK16, Air, SCHOTT.N_SF2, Air, SCHOTT.N_SK16, Air, missing], + SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0] + ), + detpix, + detpix + ) +end + +function cooketripletfirstelement(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf, -35.571, 35.571, Inf], + Thickness = [Inf, 4.0, 44.748, missing], + Material = [Air, SCHOTT.N_SK16, Air, missing], + SemiDiameter = [Inf, 7.054, 6.033, 15.0] + ) + ) +end + +function convexplano(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf, 60.0, Inf, Inf], + Thickness = [Inf, 10.0, 57.8, missing], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf, 9.0, 9.0, 15.0] + ) + ) +end + +function doubleconvex(frontradius::T,rearradius::T) where{T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [convert(T, Inf64), frontradius, rearradius, convert(T, Inf64)], + # OptimizeRadius = [false, true, true, false], + Thickness = [convert(T, Inf64), convert(T, 10.0), convert(T, 57.8), missing], + # OptimizeThickness = [false, false, false, false], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [convert(T, Inf64), convert(T, 9.0), convert(T, 9.0), convert(T, 15.0)] + ) + ) +end + +function doubleconvexconic(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf64, 60, -60, Inf64], + # OptimizeRadius = [false, true, true, false], + Thickness = [Inf64, 10.0, 57.8, missing], + # OptimizeThickness = [false, false, false, false], + Conic = [missing, 0.01, 0.01, missing], + # OptimizeConic = [false, true, true, false], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 15.0] + ) + ) +end + +function doubleconvexlensonly(frontradius::T,rearradius::T) where{T<:Real} + AxisymmetricLens{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [convert(T, Inf64), frontradius, rearradius, convert(T, Inf64)], + # OptimizeRadius = [false, true, true, false], + Thickness = [convert(T, Inf64), convert(T, 10.0), convert(T, 57.8), missing], + # OptimizeThickness = [false, false, false, false], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [convert(T, Inf64), convert(T, 9.0), convert(T, 9.0), convert(T, 15.0)] + ) + ) +end + +function doubleconvex( + ::Type{T} = Float64; + temperature::Unitful.Temperature = GlassCat.TEMP_REF_UNITFUL, + pressure::T = convert(T, PRESSURE_REF) +) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf64, 60, -60, Inf64], + # OptimizeRadius = [false, true, true, false], + Thickness = [Inf64, 10.0, 57.8, missing], + # OptimizeThickness = [false, true, true, false], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 15.0] + ); + temperature, + pressure + ) +end + +function doubleconcave(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf64, -41.0, 41.0, Inf64], + Thickness = [Inf64, 10.0, 57.8, missing], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 15.0] + ) + ) +end + +function planoconcaverefl(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf64, Inf64, -41.0, Inf64], + Thickness = [Inf64, 10.0, -57.8, missing], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 25.0], + Reflectance = [missing, missing, 1.0, missing] + ) + ) +end + +function concaveplano(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", "Standard", "Standard", "Image"], + Radius = [Inf64, -41.0, Inf64, Inf64], + Thickness = [Inf64, 10.0, 57.8, missing], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 15.0] + ) + ) +end + +function planoplano(::Type{T} = Float64) where {T<:Real} + AxisymmetricOpticalSystem{T}( + DataFrame( + SurfaceType = ["Object", 1, 2, "Image"], + Radius = [Inf64, Inf64, Inf64, Inf64], + Thickness = [Inf64, 10.0, 57.8, missing], + Material = [Air, SCHOTT.N_BK7, Air, missing], + SemiDiameter = [Inf64, 9.0, 9.0, 15.0] + ) + ) +end function autodrawrays(lens::AxisymmetricOpticalSystem = cooketriplet(), angle = 10; kwargs...) f1 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourcenum = 1) @@ -143,7 +210,7 @@ end function prism_refraction() # build the triangular prism - int = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_SF14, OpticSim.GlassCat.Air) + int = FresnelInterface{Float64}(SCHOTT.N_SF14, Air) s = 2.0 prism = csgintersection(leaf(Plane(SVector(0.0, -1.0, 0.0), SVector(0.0, -s, 0.0), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s)), csgintersection(Plane(SVector(0.0, sind(30), cosd(30)), SVector(0.0, s * sind(30), s * cosd(30)), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s), Plane(SVector(0.0, sind(30), -cosd(30)), SVector(0.0, s * sind(30), -s * cosd(30)), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s))) sys = CSGOpticalSystem(LensAssembly(prism()), Rectangle(15.0, 15.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -20.0), interface = opaqueinterface())) @@ -160,13 +227,13 @@ function prism_refraction() end function fresnel(convex = true; kwargs...) - lens = FresnelLens(OpticSim.GlassCat.SCHOTT.N_BK7, 0.0, convex ? 15.0 : -15.0, 1.0, 8.0, 0.8, conic = 0.1) + lens = FresnelLens(SCHOTT.N_BK7, 0.0, convex ? 15.0 : -15.0, 1.0, 8.0, 0.8, conic = 0.1) sys = CSGOpticalSystem(LensAssembly(lens()), Rectangle(15.0, 15.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0), interface = opaqueinterface())) Vis.drawtracerays(sys; test = true, trackallrays = true, numdivisions = 30, kwargs...) end function grating(; period = 1.0, θ = 0.0, λ = 0.55, kwargs...) - int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, minorder = -2, maxorder = 2, reflectance = [0.0, 0.0, 0.1, 0.0, 0.0], transmission = [0.05, 0.1, 0.4, 0.1, 0.05]) + int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, Air, Air, minorder = -2, maxorder = 2, reflectance = [0.0, 0.0, 0.1, 0.0, 0.0], transmission = [0.05, 0.1, 0.4, 0.1, 0.05]) grating = ThinGratingSurface(Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0)), int) back = Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0)) sys = CSGOpticalSystem(LensAssembly(grating, back), Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0), interface = opaqueinterface())) @@ -174,7 +241,7 @@ function grating(; period = 1.0, θ = 0.0, λ = 0.55, kwargs...) end function reflgrating(; period = 1.0, θ = 0.0, λ = 0.55, kwargs...) - int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, minorder = -2, maxorder = 2, transmission = [0.0, 0.0, 0.1, 0.0, 0.0], reflectance = [0.05, 0.1, 0.4, 0.1, 0.05]) + int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, Air, Air, minorder = -2, maxorder = 2, transmission = [0.0, 0.0, 0.1, 0.0, 0.0], reflectance = [0.05, 0.1, 0.4, 0.1, 0.05]) grating = ThinGratingSurface(Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0)), int) back = Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0)) sys = CSGOpticalSystem(LensAssembly(grating, back), Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0), interface = opaqueinterface())) @@ -184,9 +251,9 @@ end function HOE(refl = false, firstorderonly = false; kwargs...) rect = Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0)) if refl - int = HologramInterface(SVector(0.0, -10.0, 20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 9.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, !firstorderonly) + int = HologramInterface(SVector(0.0, -10.0, 20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 9.0, Air, SCHOTT.N_BK7, Air, Air, Air, 0.05, !firstorderonly) else - int = HologramInterface(SVector(0.0, -10.0, -20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 5.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, !firstorderonly) + int = HologramInterface(SVector(0.0, -10.0, -20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 5.0, Air, SCHOTT.N_BK7, Air, Air, Air, 0.05, !firstorderonly) end obj = HologramSurface(rect, int) back = Rectangle(50.0, 50.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0)) @@ -213,21 +280,21 @@ function eyetrackHOE(nrays = 5000, det = false, showhead = true, zeroorder = fal # offset = SVector(-5.0, 10.0, -10.0) # for θ in 0:(π / 6):(2π) # ledloc = SVector(20 * cos(θ) + offset[1], 0 + offset[2], 15 * sin(θ) + offset[3]) - # int = HologramInterface(ledloc, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder) + # int = HologramInterface(ledloc, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, Air, SCHOTT.N_BK7, Air, Air, Air, 0.05, zeroorder) # push!(interfaces, int) # end dirs = [SVector(0.7713, 0.6350, -0.0437), SVector(0.5667, 0.8111, -0.1445), SVector(0.3400, 0.9349, -0.1017), SVector(0.1492, 0.9878, 0.0445), SVector(0.0249, 0.9686, 0.2474), SVector(-0.0184, 0.8855, 0.4643), SVector(0.0254, 0.7537, 0.6567), SVector(0.1548, 0.5964, 0.7876), SVector(0.3570, 0.4462, 0.8207), SVector(0.5959, 0.3470, 0.7242), SVector(0.7976, 0.3449, 0.4948), SVector(0.8680, 0.4555, 0.1978)] for d in dirs - int = HologramInterface(normalize(d), CollimatedBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder) - # int = HologramInterface(corneavertex - 10 * d, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder) + int = HologramInterface(normalize(d), CollimatedBeam, sourceloc, DivergingBeam, 0.78, 100.0, Air, SCHOTT.N_BK7, Air, Air, Air, 0.05, zeroorder) + # int = HologramInterface(corneavertex - 10 * d, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, Air, SCHOTT.N_BK7, Air, Air, Air, 0.05, zeroorder) push!(interfaces, int) end mint = MultiHologramInterface(interfaces...) obj = MultiHologramSurface(rect, mint) - cornea = leaf(Sphere(cornea_rad, interface = FresnelInterface{Float64}(OpticSim.GlassCat.EYE.CORNEA, OpticSim.GlassCat.Air, reflectance = 1.0, transmission = 0.0)), translation(0.0, er + cornea_rad, 0.0))() + cornea = leaf(Sphere(cornea_rad, interface = FresnelInterface{Float64}(EYE.CORNEA, Air, reflectance = 1.0, transmission = 0.0)), translation(0.0, er + cornea_rad, 0.0))() # cam settings fnum = 2.0 diff --git a/src/Optical/Eye.jl b/src/Optical/Eye.jl index 46dc394c6..ad66fb5b2 100644 --- a/src/Optical/Eye.jl +++ b/src/Optical/Eye.jl @@ -54,7 +54,7 @@ function ArizonaEye(::Type{T} = Float64; accommodation::T = 0.0) where {T<:Real} # from https://photonengr.com/wp-content/uploads/kbasefiles/ArizonaEyeModel.pdf also in our documentation/papers directory return DataFrame( Name = ["Air", "Cornea", "Aqueous", "Lens", "Vitreous", "Retina"], - Surface = [:Object, 1, 2, 3, 4, :Image], + Surface = ["Object", "Standard", "Standard", "Standard", "Standard", "Image"], Radius = [Inf64, 7.8, 6.5, 12.0 - 0.4*accommodation, -5.22 + 0.2*accommodation, -13.4], Conic = [missing, -.25, -.25, -7.52 + 1.29*accommodation, -1.35 - 0.43*accommodation, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.modelglass(1.377, 57.1, 0.0), OpticSim.GlassCat.modelglass(1.337, 61.3, 0.0), OpticSim.GlassCat.modelglass(1.42 + 0.0026 * accommodation - 0.00022 * accommodation^2, 51.9, 0.0), OpticSim.GlassCat.modelglass(1.336, 61.1, 0.0), missing], diff --git a/src/Optical/Lenses.jl b/src/Optical/Lenses.jl index ca998cb7f..00df159ae 100644 --- a/src/Optical/Lenses.jl +++ b/src/Optical/Lenses.jl @@ -35,7 +35,7 @@ export ConicLens Cosntructs a simple cylindrical lens with front and back surfaces with a radius, conic and apsheric terms. The side walls of the lens are absorbing. """ -function AsphericLens(insidematerial::T, frontvertex::S, frontradius::S, frontconic::S, frontaspherics::Union{Nothing,Vector{Tuple{Int,S}}}, backradius::S, backconic::S, backaspherics::Union{Nothing,Vector{Tuple{Int,S}}}, thickness::S, semidiameter::S; lastmaterial::Q = OpticSim.GlassCat.Air, nextmaterial::R = OpticSim.GlassCat.Air, frontsurfacereflectance::S = zero(S), backsurfacereflectance::S = zero(S), nsamples::Int = 17, frontdecenter::Tuple{S,S} = (zero(S), zero(S)), backdecenter::Tuple{S,S} = (zero(S), zero(S)), interfacemode = ReflectOrTransmit) where {R<:OpticSim.GlassCat.AbstractGlass,Q<:OpticSim.GlassCat.AbstractGlass,T<:OpticSim.GlassCat.AbstractGlass,S<:Real} +function AsphericLens(insidematerial::T, frontvertex::S, frontradius::S, frontconic::S, frontaspherics::Union{Nothing,Vector{Pair{Int,S}}}, backradius::S, backconic::S, backaspherics::Union{Nothing,Vector{Pair{Int,S}}}, thickness::S, semidiameter::S; lastmaterial::Q = OpticSim.GlassCat.Air, nextmaterial::R = OpticSim.GlassCat.Air, frontsurfacereflectance::S = zero(S), backsurfacereflectance::S = zero(S), nsamples::Int = 17, frontdecenter::Tuple{S,S} = (zero(S), zero(S)), backdecenter::Tuple{S,S} = (zero(S), zero(S)), interfacemode = ReflectOrTransmit) where {R<:OpticSim.GlassCat.AbstractGlass,Q<:OpticSim.GlassCat.AbstractGlass,T<:OpticSim.GlassCat.AbstractGlass,S<:Real} @assert semidiameter > zero(S) @assert !isnan(frontradius) @@ -118,7 +118,7 @@ export AsphericLens Create a Fresnel lens as a CSG object, can be concave or convex. Groove positions are found iteratively based on `groovedepth`. For negative radii the vertex on the central surface is at `frontvertex`, so the total thickness of the lens is `thickness` + `groovedepth`. **Aspherics currently not supported**. """ -function FresnelLens(insidematerial::G, frontvertex::T, radius::T, thickness::T, semidiameter::T, groovedepth::T; conic::T = 0.0, aspherics::Union{Nothing,Vector{Tuple{Int,T}}} = nothing, outsidematerial::H = OpticSim.GlassCat.Air, reverse::Bool = false) where {T<:Real,G<:OpticSim.GlassCat.AbstractGlass,H<:OpticSim.GlassCat.AbstractGlass} +function FresnelLens(insidematerial::G, frontvertex::T, radius::T, thickness::T, semidiameter::T, groovedepth::T; conic::T = 0.0, aspherics::Union{Nothing,Vector{Pair{Int,T}}} = nothing, outsidematerial::H = OpticSim.GlassCat.Air, reverse::Bool = false) where {T<:Real,G<:OpticSim.GlassCat.AbstractGlass,H<:OpticSim.GlassCat.AbstractGlass} @assert abs(radius) > semidiameter interface = FresnelInterface{T}(insidematerial, outsidematerial) diff --git a/src/Optical/OpticalSystem.jl b/src/Optical/OpticalSystem.jl index 6c4481d65..78e4dc18c 100644 --- a/src/Optical/OpticalSystem.jl +++ b/src/Optical/OpticalSystem.jl @@ -2,26 +2,44 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # See LICENSE in the project root for full license information. +export AbstractOpticalSystem +export CSGOpticalSystem, temperature, pressure, detectorimage, resetdetector!, assembly +export AxisymmetricOpticalSystem, semidiameter +export trace, traceMT, tracehits, tracehitsMT + +using DataFrames +using Unitful.DefaultSymbols + """ AbstractOpticalSystem{T<:Real} Abstract type for any optical system, must parameterized by the datatype of entities within the system `T`. """ abstract type AbstractOpticalSystem{T<:Real} end -export AbstractOpticalSystem """ CSGOpticalSystem{T,D<:Real,S<:Surface{T},L<:LensAssembly{T}} <: AbstractOpticalSystem{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. +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. +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`](@ref) which implements [`uv`](@ref), [`uvtopix`](@ref) and [`onsurface`](@ref), typically this is one of [`Rectangle`](@ref), [`Ellipse`](@ref) or [`SphericalCap`](@ref). +The detector can be any [`Surface`](@ref) which implements [`uv`](@ref), [`uvtopix`](@ref) and [`onsurface`](@ref), +typically this is one of [`Rectangle`](@ref), [`Ellipse`](@ref) or [`SphericalCap`](@ref). ```julia -CSGOpticalSystem(assembly::LensAssembly, detector::Surface, detectorpixelsx = 1000, detectorpixelsy = 1000, ::Type{D} = Float32; temperature = OpticSim.GlassCat.TEMP_REF, pressure = OpticSim.GlassCat.PRESSURE_REF) +CSGOpticalSystem( + assembly::LensAssembly, + detector::Surface, + detectorpixelsx = 1000, + detectorpixelsy = 1000, ::Type{D} = Float32; + temperature = OpticSim.GlassCat.TEMP_REF, + pressure = OpticSim.GlassCat.PRESSURE_REF +) ``` """ struct CSGOpticalSystem{T,D<:Number,S<:Surface{T},L<:LensAssembly{T}} <: AbstractOpticalSystem{T} @@ -30,7 +48,16 @@ struct CSGOpticalSystem{T,D<:Number,S<:Surface{T},L<:LensAssembly{T}} <: Abstrac detectorimage::HierarchicalImage{D} temperature::T pressure::T - function CSGOpticalSystem(assembly::L, detector::S, detectorpixelsx::Int = 1000, detectorpixelsy::Int = 1000, ::Type{D} = Float32; temperature::Union{T,Unitful.Temperature} = T(OpticSim.GlassCat.TEMP_REF), pressure::T = T(OpticSim.GlassCat.PRESSURE_REF)) where {T<:Real,S<:Surface{T},L<:LensAssembly{T},D<:Number} + + function CSGOpticalSystem( + assembly::L, + detector::S, + detectorpixelsx::Int = 1000, + detectorpixelsy::Int = 1000, + ::Type{D} = Float32; + temperature::Union{T,Unitful.Temperature} = convert(T, OpticSim.GlassCat.TEMP_REF), + pressure::T = convert(T, OpticSim.GlassCat.PRESSURE_REF) + ) where {T<:Real,S<:Surface{T},L<:LensAssembly{T},D<:Number} @assert hasmethod(uv, (S, SVector{3,T})) "Detector must implement uv()" @assert hasmethod(uvtopix, (S, SVector{2,T}, Tuple{Int,Int})) "Detector must implement uvtopix()" @assert hasmethod(onsurface, (S, SVector{3,T})) "Detector must implement onsurface()" @@ -39,17 +66,25 @@ struct CSGOpticalSystem{T,D<:Number,S<:Surface{T},L<:LensAssembly{T}} <: Abstrac @assert interface(detector) !== NullInterface(T) "Detector can't have null interface" image = HierarchicalImage{D}(detectorpixelsy, detectorpixelsx) if temperature isa Unitful.Temperature - temperature = Unitful.ustrip(T, Unitful.u"°C", temperature) + temperature = Unitful.ustrip(T, °C, temperature) end - return new{T,D,S,L}(assembly, detector, image, temperature, T(pressure)) + return new{T,D,S,L}(assembly, detector, image, temperature, convert(T, pressure)) end end -export CSGOpticalSystem - -Base.copy(a::CSGOpticalSystem) = CSGOpticalSystem(a.assembly, a.detector, size(a.detectorimage)..., temperature = a.temperature * Unitful.u"°C", pressure = a.pressure) -#added this show method because the type of CSGOpticalSystem is gigantic and printing it in the REPL can crash the system. -Base.show(io::IO, a::CSGOpticalSystem{T}) where {T} = print(io, "CSGOpticalSystem{$T}($(temperature(a)), $(pressure(a)), $(assembly(a)), $(detector(a)))") +Base.copy(a::CSGOpticalSystem) = CSGOpticalSystem( + a.assembly, + a.detector, + size(a.detectorimage)..., + temperature = (a.temperature)°C, + pressure = a.pressure +) + +# added this show method because the type of CSGOpticalSystem is gigantic and printing it in the REPL can crash the +# system +function Base.show(io::IO, a::CSGOpticalSystem{T}) where {T} + print(io, "CSGOpticalSystem{$T}($(temperature(a)), $(pressure(a)), $(assembly(a)), $(detector(a)))") +end """ assembly(system::AbstractOpticalSystem{T}) -> LensAssembly{T} @@ -57,7 +92,9 @@ Base.show(io::IO, a::CSGOpticalSystem{T}) where {T} = print(io, "CSGOpticalSyste Get the [`LensAssembly`](@ref) of `system`. """ assembly(system::CSGOpticalSystem{T}) where {T<:Real} = system.assembly + detector(system::CSGOpticalSystem) = system.detector + """ detectorimage(system::AbstractOpticalSystem{T}) -> HierarchicalImage{D} @@ -65,13 +102,16 @@ 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`. """ detectorimage(system::CSGOpticalSystem) = system.detectorimage + detectorsize(system::CSGOpticalSystem) = size(system.detectorimage) + """ temperature(system::AbstractOpticalSystem{T}) -> T Get the temperature of `system` in °C. """ temperature(system::CSGOpticalSystem{T}) where {T<:Real} = system.temperature + """ pressure(system::AbstractOpticalSystem{T}) -> T @@ -84,20 +124,24 @@ pressure(system::CSGOpticalSystem{T}) where {T<:Real} = system.pressure Reset the deterctor image of `system` to zero. """ resetdetector!(system::CSGOpticalSystem{T}) where {T<:Real} = reset!(system.detectorimage) -export temperature, pressure, detectorimage, resetdetector!, assembly - Base.Float32(a::T) where {T<:ForwardDiff.Dual} = Float32(ForwardDiff.value(a)) """ trace(system::AbstractOpticalSystem{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`](@ref) if the ray hits the detector or `nothing` otherwise. +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`](@ref) 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. +`trackrays` can be passed an empty vector to accumulate the `LensTrace` objects at each intersection of `ray` with a +surface in the system. """ -function trace(system::CSGOpticalSystem{T,D}, r::OpticalRay{T,N}; trackrays::Union{Nothing,Vector{LensTrace{T,N}}} = nothing, test::Bool = false) where {T<:Real,N,D<:Number} +function trace( + system::CSGOpticalSystem{T,D}, + r::OpticalRay{T,N}; + trackrays::Union{Nothing,Vector{LensTrace{T,N}}} = nothing, + test::Bool = false +) where {T<:Real,N,D<:Number} if power(r) < POWER_THRESHOLD return nothing end @@ -133,7 +177,8 @@ function trace(system::CSGOpticalSystem{T,D}, r::OpticalRay{T,N}; trackrays::Uni m = outsidematerialid(opticalinterface) # compute updated power based on absorption coefficient of material using Beer's law - # this will almost always not apply as the detector will be in air, but it's possible that the detector is not in air, in which case this is necessary + # this will almost always not apply as the detector will be in air, but it's possible that the detector is + # not in air, in which case this is necessary if !isair(m) mat = glassforid(m)::OpticSim.GlassCat.Glass nᵢ = index(mat, λ, temperature = temperature(system), pressure = pressure(system))::T @@ -148,16 +193,28 @@ function trace(system::CSGOpticalSystem{T,D}, r::OpticalRay{T,N}; trackrays::Uni opticalpathlength = nᵢ * geometricpathlength end - temp = LensTrace{T,N}(OpticalRay(ray(ray(result)), pow, wavelength(result), opl = pathlength(result) + opticalpathlength, nhits = nhits(result) + 1, sourcenum = sourcenum(r), sourcepower = sourcepower(r)), detintsct) + temp = LensTrace{T,N}( + OpticalRay( + ray(ray(result)), + pow, + wavelength(result), + opl = pathlength(result) + opticalpathlength, + nhits = nhits(result) + 1, + sourcenum = sourcenum(r), + sourcepower = sourcepower(r)), + detintsct + ) if trackrays !== nothing push!(trackrays, temp) end - # incerement the detector image + # increment the detector image pixu, pixv = uvtopix(detector(system), uv(detintsct), size(system.detectorimage)) - system.detectorimage[pixv, pixu] += D(sourcepower(r)) # TODO will need to handle different detector image types a bit better than this + system.detectorimage[pixv, pixu] += convert(D, sourcepower(r)) # TODO will need to handle different detector + # image types a bit better than this - # should be okay to assume intersection will not be a DisjointUnion for all the types of detectors we will be using. + # should be okay to assume intersection will not be a DisjointUnion for all the types of detectors we will + # be using emptyintervalpool!(T) return temp end @@ -166,134 +223,224 @@ end ###################################################################################################################### +function validate_axisymmetricopticalsystem_dataframe(prescription::DataFrame) + # note: there's a slight difference between `col_types` and `surface_types` below: the former refers to the types of + # the prescription DataFrame columns; the former refers to the actual `surface_type` values, which are all strings + required_cols = ["SurfaceType", "Radius", "Thickness", "Material", "SemiDiameter"] + supported_col_types = Dict( + "SurfaceType" => String, + "Radius" => Real, + "Thickness" => Real, + "Material" => GlassCat.AbstractGlass, + "SemiDiameter" => Real, + "Conic" => Real, + "Reflectance" => Real, + "Parameters" => Vector{<:Real}, + ) + cols = names(prescription) + + supported_surface_types = ["Object", "Stop", "Image", "Standard", "Aspheric", "Zernike"] + surface_types = prescription[!, "SurfaceType"] + + comma_join(l::Vector{<:AbstractString}) = join(l, ", ", " and ") + + missing_cols = setdiff(required_cols, cols) + @assert isempty(missing_cols) "missing required columns: $(comma_join(missing_cols))" + + unsupported_cols = setdiff(cols, keys(supported_col_types)) + @assert isempty(unsupported_cols) "unsupported columns: $(comma_join(unsupported_cols))" + + col_type_errors = ["$col: $T1 should be $T2" for (col, T1, T2) in + [(col, eltype(prescription[!, col]), supported_col_types[col]) for col in cols] + if !(T1 <: Union{Missing, T2}) + ] + @assert isempty(col_type_errors) "incorrect column types: $(comma_join(col_type_errors))" + + unsupported_surface_types = setdiff(surface_types, supported_surface_types) + @assert isempty(unsupported_surface_types) "unsupported surface types: $(comma_join(unsupported_surface_types))" + + @assert( + findall(s->s==="Object", surface_types) == [1], + "there should only be one Object surface and it should be the first row" + ) + + @assert( + findall(s->s==="Image", surface_types) == [nrow(prescription)], + "there should only be one Image surface and it should be the last row" + ) +end + +function get_front_back_property(prescription::DataFrame, rownum::Int, property::String, default=nothing) + properties = ( + property ∈ names(prescription) ? + [prescription[rownum, property], prescription[rownum + 1, property]] : repeat([missing], 2) + ) + return replace(properties, missing => default) +end + """ AxisymmetricOpticalSystem{T,C<:CSGOpticalSystem{T}} <: AbstractOpticalSystem{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`. +These tags are supported for columns: `:Radius`, `:SemiDiameter`, `:SurfaceType`, `:Thickness`, `:Conic`, `:Parameters`, +`:Reflectance`, `:Material`. + +These tags are supported for entries in a `SurfaceType` column: `Object`, `Image`, `Stop`. Assumes the `Image` row will +be the last row in the `DataFrame`. In practice a [`CSGOpticalSystem`](@ref) is generated automatically and stored within this system. ```julia -AxisymmetricOpticalSystem{T}(prescription::DataFrame, detectorpixelsx = 1000, detectorpixelsy:: = 1000, ::Type{D} = Float32; temperature = OpticSim.GlassCat.TEMP_REF, pressure = OpticSim.GlassCat.PRESSURE_REF) +AxisymmetricOpticalSystem{T}( + prescription::DataFrame, + detectorpixelsx = 1000, + detectorpixelsy:: = 1000, + ::Type{D} = Float32; + temperature = OpticSim.GlassCat.TEMP_REF, + pressure = OpticSim.GlassCat.PRESSURE_REF +) ``` """ struct AxisymmetricOpticalSystem{T,C<:CSGOpticalSystem{T}} <: AbstractOpticalSystem{T} - system::C + system::C # CSGOpticalSystem prescription::DataFrame - semidiameter::T - - function AxisymmetricOpticalSystem{T}(prescription::DataFrame, detectorpixelsx::Int = 1000, detectorpixelsy::Int = 1000, ::Type{D} = Float32; temperature::Union{T,Unitful.Temperature} = T(OpticSim.GlassCat.TEMP_REF), pressure::T = T(OpticSim.GlassCat.PRESSURE_REF)) where {T<:Real,D<:Number} - pr = prescription - elements = Array{Union{Surface{T},CSGTree{T}},1}(undef, 0) - (rows, cols) = size(pr) + semidiameter::T # semidiameter of first element (default = 0.0) + + function AxisymmetricOpticalSystem{T}( + prescription::DataFrame, + detectorpixelsx::Int = 1000, + detectorpixelsy::Int = 1000, + ::Type{D} = Float32; + temperature::Union{T,Unitful.Temperature} = convert(T, OpticSim.GlassCat.TEMP_REF), + pressure::T = convert(T, OpticSim.GlassCat.PRESSURE_REF) + ) where {T<:Real,D<:Number} + validate_axisymmetricopticalsystem_dataframe(prescription) + + elements = Vector{Union{Surface{T},CSGTree{T}}}() systemsemidiameter = zero(T) + firstelement = true + + # track sequential movement along the z-axis + vertices = convert(Vector{T}, -cumsum(replace(prescription[!, "Thickness"], Inf => 0, missing => 0))) + + # pre-construct list of rows which we will skip over (e.g. air gaps, but never Stop surfaces) + # later on, this may get more complicated as we add in compound surfaces + function skip_row(i::Int) + return ( + prescription[i, "SurfaceType"] != "Stop" && + (prescription[i, "Material"] === missing || prescription[i, "Material"] == GlassCat.Air) + ) + end + skips = skip_row.(1:nrow(prescription)) - let sumstart = 1 - if pr[1, :Surface] == :Object - sumstart = 2 + for i in 2:nrow(prescription)-1 + if skips[i] + continue end - firstelement = true - for i in 1:(rows - 1) - if pr[i, :Surface] == :Stop - stop = CircularAperture(T(pr[i, :SemiDiameter]), SVector{3,T}(0.0, 0.0, 1.0), SVector{3,T}(0.0, 0.0, T(-sum(pr[sumstart:(i - 1), :Thickness])))) - push!(elements, stop) + surface_type = prescription[i, "SurfaceType"] + lastmaterial, material, nextmaterial = prescription[i-1:i+1, "Material"] + thickness = convert(T, prescription[i, "Thickness"]) + + frontradius, backradius = get_front_back_property(prescription, i, "Radius") + frontsurfacereflectance, backsurfacereflectance = get_front_back_property( + prescription, i, "Reflectance", zero(T) + ) + + semidiameter = NaN + + if surface_type == "Stop" + newelement = CircularAperture( + convert(T, prescription[i, "SemiDiameter"]), + SVector{3,T}(0.0, 0.0, 1.0), + SVector{3,T}(0.0, 0.0, vertices[i-1]) + ) + elseif surface_type == "Standard" + semidiameter = convert(T, max(get_front_back_property(prescription, i, "SemiDiameter", zero(T))...)) + frontconic, backconic = get_front_back_property(prescription, i, "Conic", zero(T)) + + if frontconic != zero(T) || backconic != zero(T) + newelement = ConicLens( + material, vertices[i-1], frontradius, frontconic, backradius, backconic, thickness, + semidiameter; lastmaterial, nextmaterial, frontsurfacereflectance, backsurfacereflectance + )() else - material = pr[i, :Material] - frontreflection = zero(T) - backreflection = zero(T) - frontconic = zero(T) - backconic = zero(T) - frontaspherics = nothing - backaspherics = nothing - if material != OpticSim.GlassCat.Air && !isequal(material, missing) - semidiameter::T = max(pr[i, :SemiDiameter], pr[i + 1, :SemiDiameter]) - if firstelement - systemsemidiameter = semidiameter - firstelement = false - end - - vertex::T = -sum(pr[sumstart:(i - 1), :Thickness]) - frontradius::T = pr[i, :Radius] - backradius::T = pr[i + 1, :Radius] - if "Reflectance" in names(prescription) - temp = pr[i, :Reflectance] - if !ismissing(temp) - frontreflection = temp - end - temp = pr[i + 1, :Reflectance] - if !ismissing(temp) - backreflection = temp - end - end - if "Conic" in names(prescription) - temp = pr[i, :Conic] - if !ismissing(temp) - frontconic = temp - end - temp = pr[i + 1, :Conic] - if !ismissing(temp) - backconic = temp - end - end - if "Aspherics" in names(prescription) - temp = pr[i, :Aspherics] - if !ismissing(temp) - frontaspherics = temp - end - temp = pr[i + 1, :Aspherics] - if !ismissing(temp) - backaspherics = temp - end - end - - lastmaterial = pr[i - 1, :Material] - nextmaterial = pr[i + 1, :Material] - - thickness = T(pr[i, :Thickness]) - - if frontaspherics !== nothing || backaspherics !== nothing - newelt = AsphericLens(material, vertex, frontradius, frontconic, frontaspherics, backradius, backconic, backaspherics, thickness, semidiameter, lastmaterial = lastmaterial, nextmaterial = nextmaterial, frontsurfacereflectance = frontreflection, backsurfacereflectance = backreflection) - elseif frontconic != zero(T) || backconic != zero(T) - newelt = ConicLens(material, vertex, frontradius, frontconic, backradius, backconic, thickness, semidiameter, lastmaterial = lastmaterial, nextmaterial = nextmaterial, frontsurfacereflectance = frontreflection, backsurfacereflectance = backreflection) - else - newelt = SphericalLens(material, vertex, frontradius, backradius, thickness, semidiameter, lastmaterial = lastmaterial, nextmaterial = nextmaterial, frontsurfacereflectance = frontreflection, backsurfacereflectance = backreflection) - end - - push!(elements, newelt()) - end + newelement = SphericalLens( + material, vertices[i-1], frontradius, backradius, thickness, semidiameter; + lastmaterial, nextmaterial, frontsurfacereflectance, backsurfacereflectance + )() end + elseif surface_type == "Aspheric" + semidiameter = convert(T, max(get_front_back_property(prescription, i, "SemiDiameter", zero(T))...)) + frontconic, backconic = get_front_back_property(prescription, i, "Conic", zero(T)) + frontaspherics, backaspherics = get_front_back_property(prescription, i, "Parameters", Vector{Pair{Int,Float64}}()) + + newelement = AsphericLens( + material, vertices[i-1], frontradius, frontconic, frontaspherics, backradius, backconic, + backaspherics, thickness, semidiameter; lastmaterial, nextmaterial, frontsurfacereflectance, + backsurfacereflectance + )() + else + error( + "Unsupported surface type \"$surface_type\". If you'd like to add support for this surface, ", + "please create an issue at https://github.com/microsoft/OpticSim.jl/issues/new." + ) end - indexofimage = findfirst(isequal(:Image), prescription[!, :Surface]) - imagesize = prescription[indexofimage, :SemiDiameter] - vertextoimage = T(-sum(pr[sumstart:(indexofimage - 1), :Thickness])) - imagerad = prescription[indexofimage, :Radius] - - if imagerad != zero(T) && imagerad != typemax(T) - det = SphericalCap(abs(imagerad), NaNsafeasin(imagesize / abs(imagerad)), imagerad < 0 ? SVector{3,T}(0, 0, 1) : SVector{3,T}(0, 0, -1), SVector{3,T}(0, 0, vertextoimage), interface = opaqueinterface(T)) - else - det = Rectangle(T(imagesize), T(imagesize), SVector{3,T}(0, 0, 1), SVector{3,T}(0, 0, vertextoimage), interface = opaqueinterface(T)) + if firstelement && semidiameter !== NaN + systemsemidiameter = semidiameter + firstelement = false end - system = CSGOpticalSystem(OpticSim.LensAssembly(elements...), det, detectorpixelsx, detectorpixelsy, D, temperature = temperature, pressure = pressure) + push!(elements, newelement) + end - return new{T,typeof(system)}(system, prescription, systemsemidiameter) + # make the detector (Image) + imagesize = prescription[end, "SemiDiameter"] + imagerad = prescription[end, "Radius"] + if imagerad != zero(T) && imagerad != typemax(T) + det = SphericalCap( + abs(imagerad), + NaNsafeasin(imagesize / abs(imagerad)), + imagerad < 0 ? SVector{3,T}(0, 0, 1) : SVector{3,T}(0, 0, -1), + SVector{3,T}(0, 0, vertices[end-1]), + interface = opaqueinterface(T) + ) + else + det = Rectangle( + convert(T, imagesize), + convert(T, imagesize), + SVector{3,T}(0, 0, 1), + SVector{3,T}(0, 0, vertices[end-1]), + interface = opaqueinterface(T) + ) end + + system = CSGOpticalSystem( + OpticSim.LensAssembly(elements...), det, detectorpixelsx, detectorpixelsy, D; temperature, pressure + ) + return new{T,typeof(system)}(system, prescription, systemsemidiameter) end AxisymmetricOpticalSystem(prescription::DataFrame) = AxisymmetricOpticalSystem{Float64}(prescription) end -export AxisymmetricOpticalSystem Base.show(io::IO, a::AxisymmetricOpticalSystem) = print(io, a.prescription) -Base.copy(a::AxisymmetricOpticalSystem) = AxisymmetricOpticalSystem(a.prescription, size(detectorimage(a))..., temperature = temperature(a), pressure = pressure(a)) +function Base.copy(a::AxisymmetricOpticalSystem) + temperature = temperature(a) + pressure = pressure(a) + AxisymmetricOpticalSystem(a.prescription, size(detectorimage(a))...; temperature, pressure) +end -trace(system::AxisymmetricOpticalSystem{T,C}, r::OpticalRay{T,N}; trackrays::Union{Nothing,Vector{LensTrace{T,N}}} = nothing, test::Bool = false) where {T<:Real,N,C<:CSGOpticalSystem{T}} = trace(system.system, r, trackrays = trackrays, test = test) +function trace( + system::AxisymmetricOpticalSystem{T,C}, + r::OpticalRay{T,N}; + trackrays::Union{Nothing,Vector{LensTrace{T,N}}} = nothing, + test::Bool = false +) where {T<:Real,N,C<:CSGOpticalSystem{T}} + trace(system.system, r, trackrays = trackrays, test = test) +end """ semidiameter(system::AxisymmetricOpticalSystem{T}) -> T @@ -308,11 +455,18 @@ detectorsize(system::AxisymmetricOpticalSystem) = detectorsize(system.system) resetdetector!(system::AxisymmetricOpticalSystem) = resetdetector!(system.system) temperature(system::AxisymmetricOpticalSystem) = temperature(system.system) pressure(system::AxisymmetricOpticalSystem) = pressure(system.system) -export semidiameter ###################################################################################################################### -trace(system::AxisymmetricOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false, outpath::Union{Nothing,String} = nothing) where {T<:Real} = trace(system.system, raygenerator, printprog = printprog, test = test, outpath = outpath) +function trace( + system::AxisymmetricOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false, + outpath::Union{Nothing,String} = nothing +) where {T<:Real} + trace(system.system, raygenerator; printprog, test, outpath) +end """ trace(system::AbstractOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false) @@ -324,7 +478,13 @@ If `outpath` is specified then the result will be saved to this path. Returns the detector image of the system. """ -function trace(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false, outpath::Union{Nothing,String} = nothing) where {T<:Real} +function trace( + system::CSGOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false, + outpath::Union{Nothing,String} = nothing +) where {T<:Real} start_time = time() update_timesteps = 1000 total_traced = 0 @@ -358,8 +518,13 @@ function trace(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenerator{T} return det end - -function traceMT(system::AxisymmetricOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false, outpath::Union{Nothing,String} = nothing) where {T<:Real} +function traceMT( + system::AxisymmetricOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false, + outpath::Union{Nothing,String} = nothing +) where {T<:Real} traceMT(system.system, raygenerator, printprog = printprog, test = test, outpath = outpath) end @@ -373,7 +538,13 @@ If `outpath` is specified then the result will be saved to this path. Returns the accumulated detector image from all threads. """ -function traceMT(system::CSGOpticalSystem{T,S}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false, outpath::Union{Nothing,String} = nothing) where {T<:Real,S<:Number} +function traceMT( + system::CSGOpticalSystem{T,S}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false, + outpath::Union{Nothing,String} = nothing +) where {T<:Real,S<:Number} if printprog println("Initialising...") end @@ -465,7 +636,11 @@ function traceMT(system::CSGOpticalSystem{T,S}, raygenerator::OpticalRayGenerato return det end -function tracehitsMT(system::AxisymmetricOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false) where {T<:Real} +function tracehitsMT( + system::AxisymmetricOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, test::Bool = false +) where {T<:Real} tracehitsMT(system.system, raygenerator, printprog = printprog, test = test) end @@ -478,7 +653,12 @@ If `test` is enabled then fresnel reflections are disabled and the power distrib Returns a list of [`LensTrace`](@ref)s which hit the detector, accumulated from all threads. """ -function tracehitsMT(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false) where {T<:Real} +function tracehitsMT( + system::CSGOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false +) where {T<:Real} if printprog println("Initialising...") end @@ -575,7 +755,14 @@ function tracehitsMT(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenera end -tracehits(system::AxisymmetricOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false) where {T<:Real} = tracehits(system.system, raygenerator, printprog = printprog, test = test) +function tracehits( + system::AxisymmetricOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false +) where {T<:Real} + tracehits(system.system, raygenerator; printprog, test) +end """ tracehits(system::AbstractOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog = true, test = false) @@ -586,7 +773,12 @@ If `test` is enabled then fresnel reflections are disabled and the power distrib Returns a list of [`LensTrace`](@ref)s which hit the detector. """ -function tracehits(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenerator{T}; printprog::Bool = true, test::Bool = false) where {T<:Real} +function tracehits( + system::CSGOpticalSystem{T}, + raygenerator::OpticalRayGenerator{T}; + printprog::Bool = true, + test::Bool = false +) where {T<:Real} start_time = time() update_timesteps = 1000 total_traced = 0 @@ -617,6 +809,3 @@ function tracehits(system::CSGOpticalSystem{T}, raygenerator::OpticalRayGenerato return res end - - -export trace, traceMT, tracehits, tracehitsMT diff --git a/test/Diagnostics/Diagnostics.jl b/test/Diagnostics/Diagnostics.jl index 2b61e773d..e74aa6e39 100644 --- a/test/Diagnostics/Diagnostics.jl +++ b/test/Diagnostics/Diagnostics.jl @@ -136,14 +136,14 @@ using Ipopt using Zygote using NLopt -doubleconvexprescription() = DataFrame(Surface = [:Object, 1, 2, :Image], Radius = [(Inf64), 60.0, -60.0, (Inf64)], Thickness = [(Inf64), (10.0), (77.8), missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], SemiDiameter = [(Inf64), (9.0), (9.0), (15.0)]) +doubleconvexprescription() = DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [(Inf64), 60.0, -60.0, (Inf64)], Thickness = [(Inf64), (10.0), (77.8), missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], SemiDiameter = [(Inf64), (9.0), (9.0), (15.0)]) function doubleconvex(a::AbstractVector{T}; detpix::Int = 100) where {T<:Real} frontradius = a[1] rearradius = a[2] #! format: off AxisymmetricOpticalSystem{T}(DataFrame( - Surface = [:Object, 1, 2, :Image], + SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [T(Inf64), frontradius, rearradius, T(Inf64)], Conic = [missing, -1.0, 1.0, missing], Thickness = [T(Inf64), T(10.0), T(77.8), missing], diff --git a/test/TestData/TestData.jl b/test/TestData/TestData.jl index 7d1236f9a..ad8fbaecf 100644 --- a/test/TestData/TestData.jl +++ b/test/TestData/TestData.jl @@ -211,21 +211,21 @@ end #! format: off cooketriplet(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Standard", "Stop", "Standard", "Standard", "Image"], Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf], Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SF2, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0])) cooketripletfirstelement(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf, -35.571, 35.571, Inf], Thickness = [Inf, 4.0, 44.748, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing], SemiDiameter = [Inf, 7.054, 6.033, 15.0])) convexplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf, 60.0, Inf, Inf], Thickness = [Inf, 10.0, 57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], @@ -233,7 +233,7 @@ convexplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( doubleconvex(frontradius::T,rearradius::T) where{T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [T(Inf64), frontradius, rearradius, T(Inf64)], Thickness = [T(Inf64), T(10.0), T(57.8), missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], @@ -242,7 +242,7 @@ AxisymmetricOpticalSystem{T}( doubleconvex(::Type{T} = Float64; temperature::Unitful.Temperature = OpticSim.GlassCat.TEMP_REF_UNITFUL, pressure::Float64 = OpticSim.GlassCat.PRESSURE_REF) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf64, 60, -60, Inf64], Thickness = [Inf64, 10.0, 57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], @@ -250,14 +250,14 @@ AxisymmetricOpticalSystem{T}( temperature = temperature, pressure = T(pressure)) doubleconcave(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf64, -41.0, 41.0, Inf64], Thickness = [Inf64, 10.0, 57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) planoconcaverefl(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf64, Inf64, -41.0, Inf64], Thickness = [Inf64, 10.0, -57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], @@ -265,14 +265,14 @@ planoconcaverefl(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSyste Reflectance = [missing, missing, 1.0, missing])) concaveplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf64, -41.0, Inf64, Inf64], Thickness = [Inf64, 10.0, 57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing], SemiDiameter = [Inf64, 9.0, 9.0, 15.0])) planoplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}( - DataFrame(Surface = [:Object, 1, 2, :Image], + DataFrame(SurfaceType = ["Object", "Standard", "Standard", "Image"], Radius = [Inf64, Inf64, Inf64, Inf64], Thickness = [Inf64, 10.0, 57.8, missing], Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],