Beam Expander Design

[1]:
import numpy as np

from optiland import optic, optimization

Define a starting lens:

[2]:
lens = optic.Optic()

# define beam expander properties
radius_start = 5
radius_end = 15

# add surfaces
lens.surfaces.add(index=0, thickness=np.inf)
lens.surfaces.add(index=1, thickness=5, radius=-50, material="N-BK7", is_stop=True)
lens.surfaces.add(index=2, thickness=75, radius=np.inf)
lens.surfaces.add(index=3, thickness=5, radius=np.inf, material="N-BK7")
lens.surfaces.add(index=4, thickness=50, radius=-300)
lens.surfaces.add(index=5)

# set aperture
lens.set_aperture(aperture_type="EPD", value=2 * radius_start)

# add field
lens.fields.set_type(field_type="angle")
lens.fields.add(y=0)

# add wavelength
lens.wavelengths.add(value=0.633, is_primary=True)

# draw lens
lens.draw(num_rays=5)
../../_images/gallery_optimization_beam_expander_3_0.png

Define optimization problem:

[3]:
problem = optimization.OptimizationProblem()

Add operands (targets for optimization):

[ ]:
# Ray y-intersect at last lens surface
input_data = {
    "optic": lens,
    "surface_number": 4,
    "Hx": 0,
    "Hy": 0,
    "Px": 0,
    "Py": 1,
    "wavelength": 0.633,
}
problem.add_operand(
    operand_type="real_y_intercept",
    target=radius_end,
    weight=1,
    input_data=input_data,
)

# Ray y-intersect at image surface
input_data = {
    "optic": lens,
    "surface_number": 5,
    "Hx": 0,
    "Hy": 0,
    "Px": 0,
    "Py": 1,
    "wavelength": 0.633,
}
problem.add_operand(
    operand_type="real_y_intercept",
    target=radius_end,
    weight=1,
    input_data=input_data,
)

Define variables - let two radii of curvature vary:

[5]:
problem.add_variable(lens, "radius", surface_number=1)  # first surface of first lens
problem.add_variable(lens, "radius", surface_number=4)  # second surface of second lens

Check initial merit function value and system properties:

[6]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │                 49.144 │                 0 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤══════════════════╤══════════╤══════════╤══════════╤══════════╤════════════════════╕
│    │ Operand Type     │   Target │   Weight │    Value │    Delta │   Contribution (%) │
╞════╪══════════════════╪══════════╪══════════╪══════════╪══════════╪════════════════════╡
│  0 │ real y intercept │       15 │        1 │  9.22613 │ -5.77387 │            67.8366 │
│  1 │ real y intercept │       15 │        1 │ 11.0243  │ -3.97572 │            32.1634 │
╘════╧══════════════════╧══════════╧══════════╧══════════╧══════════╧════════════════════╛
╒════╤═════════════════╤═══════════╤═════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │   Value │ Min. Bound   │ Max. Bound   │
╞════╪═════════════════╪═══════════╪═════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │     -50 │              │              │
│  1 │ radius          │         4 │    -300 │              │              │
╘════╧═════════════════╧═══════════╧═════════╧══════════════╧══════════════╛

Define optimizer:

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

Run optimization:

[8]:
optimizer.optimize(tol=1e-6)
[8]:
  message: CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH
  success: True
   status: 0
      fun: 2.2236952958197887e-12
        x: [-1.214e+00 -1.641e+00]
      nit: 19
      jac: [-1.639e-04  2.945e-05]
     nfev: 111
     njev: 37
 hess_inv: <2x2 LbfgsInvHessProduct with dtype=float64>

Print merit function value and system properties after optimization:

[9]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │            2.51819e-12 │               100 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤══════════════════╤══════════╤══════════╤═════════╤══════════════╤════════════════════╕
│    │ Operand Type     │   Target │   Weight │   Value │        Delta │   Contribution (%) │
╞════╪══════════════════╪══════════╪══════════╪═════════╪══════════════╪════════════════════╡
│  0 │ real y intercept │       15 │        1 │      15 │ -7.01452e-07 │            19.5393 │
│  1 │ real y intercept │       15 │        1 │      15 │ -1.42343e-06 │            80.4607 │
╘════╧══════════════════╧══════════╧══════════╧═════════╧══════════════╧════════════════════╛
╒════╤═════════════════╤═══════════╤══════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │    Value │ Min. Bound   │ Max. Bound   │
╞════╪═════════════════╪═══════════╪══════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │ -21.3565 │              │              │
│  1 │ radius          │         4 │ -64.0695 │              │              │
╘════╧═════════════════╧═══════════╧══════════╧══════════════╧══════════════╛

Draw final lens:

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