Asphere Optimization

[1]:
import numpy as np

from optiland import analysis, optic, optimization

Define a starting lens:

[ ]:
lens = optic.Optic()

# add surfaces
lens.surfaces.add(index=0, thickness=np.inf)
lens.surfaces.add(
    index=1,
    thickness=7,
    radius=1000,
    material="N-SF11",
    is_stop=True,
    surface_type="even_asphere",
    coefficients=[0, 0, 0],
)
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)
../../_images/gallery_optimization_asphere_3_0.png

Define optimization problem:

[3]:
problem = optimization.OptimizationProblem()

Add operands (targets for optimization):

[ ]:
input_data = {
    "optic": lens,
    "surface_number": -1,
    "Hx": 0,
    "Hy": 0,
    "num_rays": 5,
    "wavelength": 0.55,
    "distribution": "hexapolar",
}

# add RMS spot size operand
problem.add_operand(
    operand_type="rms_spot_size",
    target=0,
    weight=1,
    input_data=input_data,
)

Define variables - let radius of curvature vary and the first 3 aspheric coefficients.

[5]:
problem.add_variable(lens, "radius", surface_number=1)
problem.add_variable(lens, "radius", surface_number=2)
problem.add_variable(lens, "asphere_coeff", surface_number=1, coeff_number=0)
problem.add_variable(lens, "asphere_coeff", surface_number=1, coeff_number=1)
problem.add_variable(lens, "asphere_coeff", surface_number=1, coeff_number=2)

Check initial merit function value and system properties:

[6]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │                30.0924 │                 0 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤════════════════╤══════════╤══════════╤═════════╤═════════╤════════════════════╕
│    │ Operand Type   │   Target │   Weight │   Value │   Delta │   Contribution (%) │
╞════╪════════════════╪══════════╪══════════╪═════════╪═════════╪════════════════════╡
│  0 │ rms spot size  │        0 │        1 │ 5.48566 │ 5.48566 │                100 │
╘════╧════════════════╧══════════╧══════════╧═════════╧═════════╧════════════════════╛
╒════╤═════════════════╤═══════════╤═════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │   Value │ Min. Bound   │ Max. Bound   │
╞════╪═════════════════╪═══════════╪═════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │    1000 │              │              │
│  1 │ radius          │         2 │   -1000 │              │              │
│  2 │ asphere_coeff   │         1 │       0 │              │              │
│  3 │ asphere_coeff   │         1 │       0 │              │              │
│  4 │ asphere_coeff   │         1 │       0 │              │              │
╘════╧═════════════════╧═══════════╧═════════╧══════════════╧══════════════╛

Define optimizer:

[7]:
optimizer = optimization.OptimizerGeneric(problem)

Run optimization:

[8]:
optimizer.optimize(tol=1e-6)
[8]:
  message: CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL
  success: True
   status: 0
      fun: 3.304334492892647e-10
        x: [-2.743e+01  2.416e+01  1.898e+02  2.174e+00 -2.770e-02]
      nit: 20
      jac: [-5.865e-09  3.570e-09  8.185e-08 -1.807e-07 -1.921e-07]
     nfev: 150
     njev: 25
 hess_inv: <5x5 LbfgsInvHessProduct with dtype=float64>

Print merit function value and system properties after optimization:

[9]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │            3.30432e-10 │               100 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤════════════════╤══════════╤══════════╤═════════════╤═════════════╤════════════════════╕
│    │ Operand Type   │   Target │   Weight │       Value │       Delta │   Contribution (%) │
╞════╪════════════════╪══════════╪══════════╪═════════════╪═════════════╪════════════════════╡
│  0 │ rms spot size  │        0 │        1 │ 1.81778e-05 │ 1.81778e-05 │                100 │
╘════╧════════════════╧══════════╧══════════╧═════════════╧═════════════╧════════════════════╛
╒════╤═════════════════╤═══════════╤═════════════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │           Value │ Min. Bound   │ Max. Bound   │
╞════╪═════════════════╪═══════════╪═════════════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │ -2642.94        │              │              │
│  1 │ radius          │         2 │  2515.97        │              │              │
│  2 │ asphere_coeff   │         1 │     0.0189832   │              │              │
│  3 │ asphere_coeff   │         1 │     2.17352e-06 │              │              │
│  4 │ asphere_coeff   │         1 │    -2.76952e-10 │              │              │
╘════╧═════════════════╧═══════════╧═════════════════╧══════════════╧══════════════╛

Draw final lens:

[10]:
lens.draw(num_rays=5)
../../_images/gallery_optimization_asphere_19_0.png

Viewing the spot diagram indicates that the spot size is indeed minimized and that the lens is diffraction limited.

[11]:
spot = analysis.SpotDiagram(lens)
spot.view()
../../_images/gallery_optimization_asphere_21_0.png