Global Optimization (Particle Swarm)

[1]:
from optiland import optic, optimization

Define a starting lens:

[2]:
lens = optic.Optic()

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

# set aperture
lens.set_aperture(aperture_type="EPD", value=12)

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

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

# draw lens
lens.draw(num_rays=5)
[2]:
(<Figure size 1000x400 with 1 Axes>, <Axes: xlabel='Z [mm]', ylabel='Y [mm]'>)
../../_images/gallery_optimization_particle_swarm_optimization_3_1.png

Define optimization problem:

[3]:
problem = optimization.OptimizationProblem()

Add operands (targets for optimization):

[4]:
# RMS spot size target
for field in lens.fields.get_field_coords():
    input_data = {
        "optic": lens,
        "Hx": field[0],
        "Hy": field[1],
        "surface_number": -1,
        "num_rays": 5,
        "wavelength": 0.55,
        "distribution": "hexapolar",
    }
    problem.add_operand(
        operand_type="rms_spot_size",
        target=0,
        weight=1,
        input_data=input_data,
    )

Define variables - we let the radii vary. Note that PSO requires finite bounds for all variables:

[5]:
problem.add_variable(lens, "radius", surface_number=1, min_val=25, max_val=100)
problem.add_variable(lens, "radius", surface_number=2, min_val=-100, max_val=-25)

Check initial merit function value and system properties:

[6]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │                9.89095 │                 0 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤════════════════╤══════════╤══════════════╤══════════════╤══════════╤═══════════════╤═════════╤═════════╤════════════════╕
│    │ Operand Type   │   Target │ Min. Bound   │ Max. Bound   │   Weight │   Eff. Weight │   Value │   Delta │   Contrib. [%] │
╞════╪════════════════╪══════════╪══════════════╪══════════════╪══════════╪═══════════════╪═════════╪═════════╪════════════════╡
│  0 │ rms spot size  │        0 │              │              │        1 │             1 │   3.145 │   3.145 │            100 │
╘════╧════════════════╧══════════╧══════════════╧══════════════╧══════════╧═══════════════╧═════════╧═════════╧════════════════╛
╒════╤═════════════════╤═══════════╤═════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │   Value │   Min. Bound │   Max. Bound │
╞════╪═════════════════╪═══════════╪═════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │      40 │           25 │          100 │
│  1 │ radius          │         2 │     -40 │         -100 │          -25 │
╘════╧═════════════════╧═══════════╧═════════╧══════════════╧══════════════╛

Define optimizer:

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

Run optimization:

[8]:
optimizer.optimize(maxiter=30, swarm_size=20, seed=42)
PSO start: best merit = 0.495756518209, swarm_size = 20, ndim = 2
Iter    1 | best merit = 0.385379232348 | improvement = 0.110377
Iter    2 | best merit = 0.0342386453248 | improvement = 0.351141
Iter    3 | best merit = 0.025628852796 | improvement = 0.00860979
Iter    4 | best merit = 0.025628852796 | improvement = 0
Iter    5 | best merit = 0.0238220692892 | improvement = 0.00180678
Iter    6 | best merit = 0.0238220692892 | improvement = 0
Iter    7 | best merit = 0.0232647160272 | improvement = 0.000557353
Iter    8 | best merit = 0.0232647160272 | improvement = 0
Iter    9 | best merit = 0.0232647160272 | improvement = 0
Iter   10 | best merit = 0.0232647160272 | improvement = 0
Iter   11 | best merit = 0.0232647160272 | improvement = 0
Iter   12 | best merit = 0.0232647160272 | improvement = 0
Iter   13 | best merit = 0.0232647160272 | improvement = 0
Iter   14 | best merit = 0.0229899364483 | improvement = 0.00027478
Iter   15 | best merit = 0.0229899364483 | improvement = 0
Iter   16 | best merit = 0.0229899364483 | improvement = 0
Iter   17 | best merit = 0.0229512509028 | improvement = 3.86855e-05
Iter   18 | best merit = 0.0229512509028 | improvement = 0
Iter   19 | best merit = 0.0229512509028 | improvement = 0
Iter   20 | best merit = 0.0229512509028 | improvement = 0
Iter   21 | best merit = 0.0229472840767 | improvement = 3.96683e-06
Iter   22 | best merit = 0.0229472840767 | improvement = 0
Iter   23 | best merit = 0.0229472840767 | improvement = 0
Iter   24 | best merit = 0.0229472840767 | improvement = 0
Iter   25 | best merit = 0.0229472840767 | improvement = 0
[8]:
    message: Optimization converged: global best stalled within tol=0.001 for 20 iterations.
    success: True
        fun: 0.02294728407671323
          x: [-7.306e-01 -1.275e+00]
        nit: 25
       nfev: 520
 swarm_size: 20
    inertia: 0.7
 individual: 1.5
     social: 1.5

Print merit function value and system properties after optimization:

[9]:
problem.info()
╒════╤════════════════════════╤═══════════════════╕
│    │   Merit Function Value │   Improvement (%) │
╞════╪════════════════════════╪═══════════════════╡
│  0 │              0.0229473 │            99.768 │
╘════╧════════════════════════╧═══════════════════╛
╒════╤════════════════╤══════════╤══════════════╤══════════════╤══════════╤═══════════════╤═════════╤═════════╤════════════════╕
│    │ Operand Type   │   Target │ Min. Bound   │ Max. Bound   │   Weight │   Eff. Weight │   Value │   Delta │   Contrib. [%] │
╞════╪════════════════╪══════════╪══════════════╪══════════════╪══════════╪═══════════════╪═════════╪═════════╪════════════════╡
│  0 │ rms spot size  │        0 │              │              │        1 │             1 │   0.151 │   0.151 │            100 │
╘════╧════════════════╧══════════╧══════════════╧══════════════╧══════════╧═══════════════╧═════════╧═════════╧════════════════╛
╒════╤═════════════════╤═══════════╤══════════╤══════════════╤══════════════╕
│    │ Variable Type   │   Surface │    Value │   Min. Bound │   Max. Bound │
╞════╪═════════════════╪═══════════╪══════════╪══════════════╪══════════════╡
│  0 │ radius          │         1 │  26.9429 │           25 │          100 │
│  1 │ radius          │         2 │ -27.4896 │         -100 │          -25 │
╘════╧═════════════════╧═══════════╧══════════╧══════════════╧══════════════╛

Draw final lens:

[10]:
lens.draw(num_rays=5)
[10]:
(<Figure size 1000x400 with 1 Axes>, <Axes: xlabel='Z [mm]', ylabel='Y [mm]'>)
../../_images/gallery_optimization_particle_swarm_optimization_19_1.png