Skip to content

Commit 28b4491

Browse files
authored
Handle two ring lenses (#7)
* Handle two ring lenses * Improve ring code * Implement a bunch of fixes to lens rings... * Remove forgotten debug statements * Add ring test cases to avoid regression * up vn to 0.8.3
1 parent 972b5be commit 28b4491

File tree

5 files changed

+141
-44
lines changed

5 files changed

+141
-44
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "BeamletOptics"
22
uuid = "c387492b-ffec-4e51-9a46-bd230226031c"
33
authors = ["Hugo Uittenbosch <hugo.uittenbosch@dlr.de>, Oliver Kliebisch <oliver.kliebisch@dlr.de> and Thomas Dekorsy <thomas.dekorsy@dlr.de>"]
4-
version = "0.8.2"
4+
version = "0.8.3"
55

66

77
[deps]

src/OpticalComponents/Lenses.jl

Lines changed: 99 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,12 @@ function Lens(
184184

185185
# Initialize remaining cylindrical section length.
186186
l0 = center_thickness
187-
188187
# Front Surface
189188
front = sdf(front_surface, ForwardOrientation())
190189
l0 -= isnothing(front) ? zero(l0) : thickness(front)
191-
192190
# Back Surface
193191
back = sdf(back_surface, BackwardOrientation())
194192
l0 -= isnothing(back) ? zero(l0) : thickness(back)
195-
196193
# Use MeniscusLensSDF if cylinder length is non-positive
197194
if l0 0
198195
if sign(radius(front_surface)) == sign(radius(back_surface))
@@ -222,39 +219,89 @@ function Lens(
222219
end
223220
shape = mid
224221

225-
# Add mechanical ring if md_mid > d_mid
226-
if md_mid > d_mid
227-
ring_thickness = thickness(mid)
228-
ring_center = position(mid)[2] + ring_thickness / 2
229-
if front !== nothing
230-
s = edge_sag(front_surface, front)
231-
ring_thickness -= s
232-
ring_center += s / 2
222+
d_front = diameter(front_surface)
223+
d_back = diameter(back_surface)
224+
d_min = min(d_front, d_back)
225+
d_max = max(d_front, d_back)
226+
227+
if md_mid < d_min
228+
@warn "Mechanical diameter is less than clear aperture; parameter md has been ignored."
229+
else
230+
# add leveling ring if there is a step between front and back clear apertures
231+
if d_front != d_back
232+
if d_back > d_front
233+
# Step exists on the front side: level front to match back.
234+
leveling_thickness = l0
235+
if front !== nothing
236+
s_front = edge_sag(front_surface, front)
237+
if s_front < 0
238+
# edge curves towards negative so it is a concave type shape,
239+
# which has to be covered by the ring
240+
leveling_thickness += abs(s_front) + thickness(front)
241+
end
242+
end
243+
244+
ring = RingSDF(d_front / 2, (d_back - d_front) / 2, leveling_thickness)
245+
translate3d!(ring, [0, edge_sag(front_surface, front) + leveling_thickness / 2, 0])
246+
shape += ring
247+
else # d_front > d_back
248+
# Step exists on the back side: level back to match front.
249+
leveling_thickness = l0
250+
if back !== nothing
251+
s_back = edge_sag(back_surface, back)
252+
if (s_back - thickness(back)) > 0
253+
# edge curves towards positive so it is a concave type shape,
254+
# which has to be covered by the ring
255+
leveling_thickness += abs(s_back) + thickness(back)
256+
end
257+
end
258+
leveling_center = position(mid)[2] +
259+
(l0/2 + (back !== nothing ? edge_sag(back_surface, back) : 0))
260+
if back !== nothing
261+
leveling_center += s_back / 2
262+
end
263+
ring = RingSDF(d_back / 2, (d_front - d_back) / 2, leveling_thickness)
264+
translate3d!(ring, [0, thickness(front) + leveling_thickness/2, 0])
265+
shape += ring
266+
end
233267
end
234-
if back !== nothing
235-
s = edge_sag(back_surface, back)
236-
ring_thickness += s
237-
ring_center += s / 2
268+
269+
# add outer ring if the mechanical diameter exceeds the larger clear aperture.
270+
if md_mid > d_max
271+
outer_thickness = thickness(mid)
272+
outer_center = position(mid)[2] + outer_thickness / 2
273+
if front !== nothing
274+
s_front = edge_sag(front_surface, front)
275+
outer_thickness -= s_front
276+
outer_center += s_front / 2
277+
end
278+
if back !== nothing
279+
s_back = edge_sag(back_surface, back)
280+
outer_thickness += s_back
281+
outer_center += s_back / 2
282+
end
283+
ring = RingSDF(d_max / 2, (md_mid - d_max) / 2, outer_thickness)
284+
translate3d!(ring, [0, outer_center, 0])
285+
shape += ring
238286
end
239-
ring = RingSDF(d_mid / 2, (md_mid - d_mid) / 2, ring_thickness)
240-
translate3d!(ring, [0, ring_center, 0])
241-
shape += ring
242-
elseif md_mid < d_mid
243-
@warn "Mechanical diameter is less than clear aperture; parameter md has been ignored."
244287
end
245288
end
246289

247290
return Lens(shape, n)
248291
end
249292

250-
Lens(front_surface::AbstractRotationallySymmetricSurface, center_thickness::Real, n::RefractiveIndex) = Lens(
251-
front_surface,
252-
CircularFlatSurface(diameter(front_surface)),
253-
center_thickness,
254-
n
255-
)
293+
function Lens(front_surface::AbstractRotationallySymmetricSurface,
294+
center_thickness::Real, n::RefractiveIndex)
295+
Lens(
296+
front_surface,
297+
CircularFlatSurface(diameter(front_surface)),
298+
center_thickness,
299+
n
300+
)
301+
end
256302

257-
function Lens(front_surface::CircularFlatSurface, back_surface::CircularFlatSurface, center_thickness::Real, n::RefractiveIndex)
303+
function Lens(front_surface::CircularFlatSurface, back_surface::CircularFlatSurface,
304+
center_thickness::Real, n::RefractiveIndex)
258305
d_mid = min(diameter(front_surface), diameter(back_surface))
259306

260307
return Lens(
@@ -306,7 +353,7 @@ function Lens(
306353
else
307354
# Construct central box and add front/back surfaces
308355
mid = BoxSDF(h, l0, d_mid)
309-
translate3d!(mid, [0, l0/2, 0])
356+
translate3d!(mid, [0, l0 / 2, 0])
310357
if front !== nothing
311358
translate3d!(mid, [0, thickness(front), 0])
312359
mid += front
@@ -342,15 +389,20 @@ function Lens(
342389
return Lens(shape, n)
343390
end
344391

345-
Lens(front_surface::AbstractCylindricalSurface, center_thickness::Real, n::RefractiveIndex) = Lens(
346-
front_surface,
347-
RectangularFlatSurface(diameter(front_surface)),
348-
center_thickness,
349-
n
350-
)
392+
function Lens(front_surface::AbstractCylindricalSurface,
393+
center_thickness::Real, n::RefractiveIndex)
394+
Lens(
395+
front_surface,
396+
RectangularFlatSurface(diameter(front_surface)),
397+
center_thickness,
398+
n
399+
)
400+
end
351401

352-
function cylindric_lens_outer_parameters(f::AbstractCylindricalSurface, b::AbstractCylindricalSurface)
353-
height(f) != height(b) && throw(ArgumentError("height of front and back surface have to match for cylindric lenses"))
402+
function cylindric_lens_outer_parameters(
403+
f::AbstractCylindricalSurface, b::AbstractCylindricalSurface)
404+
height(f) != height(b) &&
405+
throw(ArgumentError("height of front and back surface have to match for cylindric lenses"))
354406

355407
d_mid = min(diameter(f), diameter(b))
356408
md_mid = max(mechanical_diameter(f), mechanical_diameter(b))
@@ -359,27 +411,33 @@ function cylindric_lens_outer_parameters(f::AbstractCylindricalSurface, b::Abstr
359411
return d_mid, md_mid, h
360412
end
361413

362-
function cylindric_lens_outer_parameters(f::AbstractCylindricalSurface, ::RectangularFlatSurface)
414+
function cylindric_lens_outer_parameters(
415+
f::AbstractCylindricalSurface, ::RectangularFlatSurface)
363416
d_mid = diameter(f)
364417
md_mid = mechanical_diameter(f)
365418
h = height(f)
366419

367420
return d_mid, md_mid, h
368421
end
369422

370-
cylindric_lens_outer_parameters(f::RectangularFlatSurface, b::AbstractCylindricalSurface) = cylindric_lens_outer_parameters(b, f)
423+
function cylindric_lens_outer_parameters(
424+
f::RectangularFlatSurface, b::AbstractCylindricalSurface)
425+
cylindric_lens_outer_parameters(b, f)
426+
end
371427

372-
function cylindric_lens_outer_parameters(f::RectangularFlatSurface, b::RectangularFlatSurface)
428+
function cylindric_lens_outer_parameters(
429+
f::RectangularFlatSurface, b::RectangularFlatSurface)
373430
d_mid = diameter(f)
374431
md_mid = mechanical_diameter(f)
375432

376433
return d_mid, md_mid, d_mid
377434
end
378435

379-
function Lens(front_surface::RectangularFlatSurface, back_surface::RectangularFlatSurface, center_thickness::Real, n::RefractiveIndex)
436+
function Lens(front_surface::RectangularFlatSurface, back_surface::RectangularFlatSurface,
437+
center_thickness::Real, n::RefractiveIndex)
380438
d_mid = min(diameter(front_surface), diameter(back_surface))
381439
mid = BoxSDF(d_mid, center_thickness, d_mid)
382-
translate3d!(mid, [0, center_thickness/2, 0])
440+
translate3d!(mid, [0, center_thickness / 2, 0])
383441

384442
return Lens(
385443
mid,

src/SDFs/AsphericalLensSDF.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ mutable struct ConvexAsphericalSurfaceSDF{T} <: AbstractAsphericalSurfaceSDF{T}
2727
end
2828

2929
function thickness(s::ConvexAsphericalSurfaceSDF)
30-
abs(aspheric_equation(s.diameter / 2, 1 / s.radius, s.conic_constant, s.coefficients))
30+
sag = aspheric_equation(s.diameter / 2, 1 / s.radius, s.conic_constant, s.coefficients)
31+
return s.max_sag[1] > 0 && sag < 0 ? s.max_sag[1] : abs(sag)
3132
end
3233

3334
# Constructor for ConvexAsphericalSurfaceSDF

src/SDFs/SphericalLensSDF.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ end
465465

466466
mechanical_diameter(s::SphericalSurface) = s.mechanical_diameter
467467

468-
edge_sag(::SphericalSurface, sd::AbstractSphericalSurfaceSDF) = abs(sag(sd))
468+
edge_sag(::SphericalSurface, sd::AbstractSphericalSurfaceSDF) = sag(sd)
469469

470470
function sdf(s::SphericalSurface, ot::AbstractOrientationType)
471471
isinf(radius(s)) && return nothing

test/runtests.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,6 +1316,39 @@ end
13161316

13171317
# test lens thickness
13181318
@test BMO.thickness(lens) l
1319+
1320+
# test ring generation
1321+
NBK7 = DiscreteRefractiveIndex([532e-9, 1064e-9], [1.5195, 1.5066])
1322+
mm = 1e-3
1323+
1324+
s1 = Lens(
1325+
SphericalSurface(38.184mm, 2*1.840mm, 2*2.380mm),
1326+
SphericalSurface(3.467mm, 2*2.060mm, 2*2.380mm),
1327+
0.5mm,
1328+
NBK7
1329+
)
1330+
1331+
@test 2*s1.shape.sdfs[5].hthickness 0.001134 atol=1e-6
1332+
1333+
s2 = Lens(
1334+
SphericalSurface(3.467mm, 2*2.060mm, 2*2.380mm),
1335+
SphericalSurface(-5.020mm, 2*2.380mm, 2*2.380mm),
1336+
2.5mm,
1337+
NBK7
1338+
)
1339+
1340+
@test 2*s2.shape.sdfs[4].hthickness 0.001221590 atol=1e-8
1341+
1342+
# doublet test case
1343+
s1 = SphericalSurface(7.744mm, 2*2.812mm, 2*3mm)
1344+
s2 = SphericalSurface(-3.642mm, 2*3mm)
1345+
s3 = SphericalSurface(-14.413mm, 2*2.812mm, 2*3mm)
1346+
1347+
dl21 = Lens(s1, s2, 3.4mm, NBK7)
1348+
dl22 = Lens(s2, s3, 1.0mm, NBK7)
1349+
1350+
@test 2*dl21.shape.sdfs[4].hthickness 0.001294398 atol=1e-6
1351+
@test 2*dl22.shape.sdfs[4].hthickness 0.000723025 atol=1e-6
13191352
end
13201353
end
13211354

@@ -1486,6 +1519,11 @@ end
14861519
# test if the beam is correctly focussed
14871520
@test f_pos[3]0 atol=1e-7
14881521
end
1522+
1523+
# test rings
1524+
@test 2*L1.shape.sdfs[4].hthickness 0.00060839 atol=1e-6
1525+
@test 2*L2.shape.sdfs[4].hthickness 0.00057497 atol=1e-6
1526+
@test 2*L3.shape.sdfs[4].hthickness 0.00048395 atol=1e-6
14891527
end
14901528
end
14911529

0 commit comments

Comments
 (0)