Freeform Optimization
[1]:
import numpy as np
from optiland import optic, optimization
Define a starting lens:
We define a singlet lens, which has a freeform as its first surface.
The freeform surface is defined as:
\(z(x, y) = \frac{r^2}{R \cdot (1 + \sqrt{(1 - (1 + k) \cdot r^2 / R^2)})} + \sum\limits_{i}\sum\limits_{j}{C_{i, j} \cdot x^i \cdot y^j}\)
where \(x\) and \(y\) are the local surface coordinates, \(r^2 = x^2 + y^2\), \(R\) is the radius of curvature, \(k\) is the conic constant and \(C_{i, j}\) is the polynomial coefficient for indices \(i, j\).
[ ]:
lens = optic.Optic()
# add surfaces
lens.surfaces.add(index=0, thickness=np.inf)
lens.surfaces.add(
index=1,
radius=100,
thickness=5,
surface_type="polynomial",
is_stop=True,
material="SF11",
coefficients=[],
)
lens.surfaces.add(index=2, thickness=30, radius=-1000)
lens.surfaces.add(index=3)
# set aperture
lens.set_aperture(aperture_type="EPD", value=15)
# add field
lens.fields.set_type(field_type="angle")
lens.fields.add(y=0)
# add wavelength
lens.wavelengths.add(value=0.55, is_primary=True)
# draw lens
lens.draw(num_rays=5)
Define optimization problem:
[3]:
problem = optimization.OptimizationProblem()
Add operands (targets for optimization). We will minimize the RMS spot size on-axis and force the on-axis field chief ray to intersect the image plane at y = 3 mm.
[ ]:
# RMS spot size operand
input_data = {
"optic": lens,
"surface_number": -1,
"Hx": 0,
"Hy": 0,
"wavelength": 0.55,
"num_rays": 5,
}
problem.add_operand(
operand_type="rms_spot_size",
target=0,
weight=1,
input_data=input_data,
)
# Real y-intercept operand
input_data = {
"optic": lens,
"surface_number": -1,
"Hx": 0,
"Hy": 0,
"Px": 0,
"Py": 0,
"wavelength": 0.55,
}
problem.add_operand(
operand_type="real_y_intercept",
target=3,
weight=1, # <-- target=3
input_data=input_data,
)
Define variables - let the first 9 coefficients of the polynomial coefficients vary.
[ ]:
for i in range(3):
for j in range(3):
problem.add_variable(
lens,
"polynomial_coeff",
surface_number=1,
coeff_index=(i, j),
)
Check initial merit function value and system properties:
[6]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│ │ Merit Function Value │ Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│ 0 │ 26.1803 │ 0 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤══════════════════╤══════════╤══════════╤═════════╤══════════╤════════════════════╕
│ │ Operand Type │ Target │ Weight │ Value │ Delta │ Contribution (%) │
╞════╪══════════════════╪══════════╪══════════╪═════════╪══════════╪════════════════════╡
│ 0 │ rms spot size │ 0 │ 1 │ 4.14491 │ 4.14491 │ 65.623 │
│ 1 │ real y intercept │ 3 │ 1 │ 0 │ -3 │ 34.377 │
╘════╧══════════════════╧══════════╧══════════╧═════════╧══════════╧════════════════════╛
╒════╤══════════════════╤═══════════╤═════════╤══════════════╤══════════════╕
│ │ Variable Type │ Surface │ Value │ Min. Bound │ Max. Bound │
╞════╪══════════════════╪═══════════╪═════════╪══════════════╪══════════════╡
│ 0 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 1 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 2 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 3 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 4 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 5 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 6 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 7 │ polynomial_coeff │ 1 │ 0 │ │ │
│ 8 │ polynomial_coeff │ 1 │ 0 │ │ │
╘════╧══════════════════╧═══════════╧═════════╧══════════════╧══════════════╛
Define optimizer:
[7]:
optimizer = optimization.OptimizerGeneric(problem)
Run optimization:
[8]:
optimizer.optimize(tol=1e-9)
[8]:
message: CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
success: True
status: 0
fun: 0.0007136726720011206
x: [-4.565e-06 -1.158e-01 1.400e-02 -7.709e-09 1.591e-07
-7.314e-09 1.394e-02 -1.418e-05 9.539e-07]
nit: 16
jac: [-5.123e-06 1.932e-04 -6.649e-04 9.056e-06 7.249e-03
-2.941e-03 -1.224e-04 1.634e-03 1.562e-04]
nfev: 370
njev: 37
hess_inv: <9x9 LbfgsInvHessProduct with dtype=float64>
Print merit function value and system properties after optimization:
[9]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│ │ Merit Function Value │ Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│ 0 │ 0.000713673 │ 99.9973 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤══════════════════╤══════════╤══════════╤══════════╤══════════════╤════════════════════╕
│ │ Operand Type │ Target │ Weight │ Value │ Delta │ Contribution (%) │
╞════╪══════════════════╪══════════╪══════════╪══════════╪══════════════╪════════════════════╡
│ 0 │ rms spot size │ 0 │ 1 │ 0.026714 │ 0.026714 │ 99.9949 │
│ 1 │ real y intercept │ 3 │ 1 │ 2.99981 │ -0.000190397 │ 0.00507948 │
╘════╧══════════════════╧══════════╧══════════╧══════════╧══════════════╧════════════════════╛
╒════╤══════════════════╤═══════════╤══════════════╤══════════════╤══════════════╕
│ │ Variable Type │ Surface │ Value │ Min. Bound │ Max. Bound │
╞════╪══════════════════╪═══════════╪══════════════╪══════════════╪══════════════╡
│ 0 │ polynomial_coeff │ 1 │ -4.56505e-06 │ │ │
│ 1 │ polynomial_coeff │ 1 │ -0.115752 │ │ │
│ 2 │ polynomial_coeff │ 1 │ 0.0140048 │ │ │
│ 3 │ polynomial_coeff │ 1 │ -7.70891e-09 │ │ │
│ 4 │ polynomial_coeff │ 1 │ 1.5914e-07 │ │ │
│ 5 │ polynomial_coeff │ 1 │ -7.31429e-09 │ │ │
│ 6 │ polynomial_coeff │ 1 │ 0.0139404 │ │ │
│ 7 │ polynomial_coeff │ 1 │ -1.41761e-05 │ │ │
│ 8 │ polynomial_coeff │ 1 │ 9.63853e-07 │ │ │
╘════╧══════════════════╧═══════════╧══════════════╧══════════════╧══════════════╛
Draw final lens:
[10]:
lens.draw(num_rays=5)