pyoptics.lens_optimization¶
Damped least squares optimization of raytrace.System lenses.
A LensOptimizer varies curvatures and thicknesses of a system and
minimizes the sum of squares of the residuals of a list of operands, with
scipy’s trust region least squares (finite difference Jacobian). Each
operand is a function of the system that returns residuals, already divided
by their tolerance, so that 1 means “at the tolerance”. Factories for the
usual operands:
ray_errors(): transverse ray aberrations relative to the chief ray in the image plane on rings of the pupil (the spot sizes; zero defocus, spherical aberration, coma, astigmatism, field curvature),distortion(): chief ray image height against the nominal magnification,image_telecentricity(),object_telecentricity(): chief ray slopes in image and object space,paraxial_target(): any attribute ofraytrace.Paraxial(magnification, efl, NA…),clearances(): penalties for overlapping lenses, too thin centres and edges and negative air spaces at the rim of the beam.
Constraints that should hold exactly are kept by the optimizer rather than
by operands: a total length (object to image) by solving the image
distance (or another thickness), and an object_na by setting the semi
diameter of the stop from the paraxial marginal ray in every step.
Lens design is a non-convex problem and a local optimizer starting from a
first order layout easily runs into total internal reflection or rays that
miss surfaces at full aperture and field. LensOptimizer.run() therefore
takes stages of increasing aperture and field (a curriculum, as in
end-to-end lens design by gradient descent, e.g. X. Yang, Q. Fu and W.
Heidrich, “Curriculum learning for ab initio deep learned refractive
optics”, Nature Communications (2024)): the system is first corrected at a
small NA and field, which then grow to the specification.
Rays are traced without vignetting (clip=False); a ray that fails (it misses a surface or is totally reflected) gives a large residual.
References¶
K. Levenberg, “A method for the solution of certain non-linear problems in least squares”, Q. Appl. Math. 2, 164-168 (1944).
D. W. Marquardt, “An algorithm for least-squares estimation of nonlinear parameters”, J. Soc. Ind. Appl. Math. 11, 431-441 (1963).
M. A. Branch, T. F. Coleman and Y. Li, “A subspace, interior, and conjugate gradient method for large-scale bound-constrained minimization problems”, SIAM J. Sci. Comput. 21, 1-23 (1999).
X. Yang, Q. Fu and W. Heidrich, “Curriculum learning for ab initio deep learned refractive optics”, Nat. Commun. 15 (2024).
R. Kingslake and R. B. Johnson, “Lens Design Fundamentals”, 2nd ed., Academic Press (2010).
Classes
Least squares optimization of curvatures and thicknesses. |
|
Result of LensOptimizer.run(): the optimized system (at the full aperture and field), the final cost (half the sum of squares of the residuals), per stage (aperture fraction, field fraction, cost, function evaluations) and whether the last stage converged. |
Functions
Penalties for lenses that are too thin and air spaces that close. |
|
Chief ray image height minus magnification*object height (finite objects). |
|
Image space chief ray slopes dy/dz. |
|
Object space chief ray slope (finite objects): zero for an entrance pupil at infinity. |
|
Attribute |
|
Transverse ray aberrations relative to the chief ray. |
- class pyoptics.lens_optimization.OptimizationResult(system, cost, stages, success)¶
Bases:
tupleResult of LensOptimizer.run(): the optimized system (at the full aperture and field), the final cost (half the sum of squares of the residuals), per stage (aperture fraction, field fraction, cost, function evaluations) and whether the last stage converged.
- cost¶
Alias for field number 1
- stages¶
Alias for field number 2
- success¶
Alias for field number 3
- system¶
Alias for field number 0
- pyoptics.lens_optimization.ray_errors(fields=(0.0, 0.5, 0.75, 1.0), rings=(0.4, 0.7, 0.9, 1.0), spokes=6, tolerance=0.0001)[source]¶
Transverse ray aberrations relative to the chief ray.
- Parameters:
- fieldssequence, optional
Fields as fractions of the maximum field of the system (y fields).
- rings, spokesoptional
Normalized pupil radii of the rings and the number of rays per unit radius on each (half) ring.
- tolerancenumber, optional
Tolerance in the length unit of the system (default 0.1 um for mm).
- Returns:
- operandcallable
operand(system) returns the x and y errors of all rays / tolerance.
- pyoptics.lens_optimization.distortion(magnification, fields=(0.5, 0.75, 1.0), tolerance=1e-05, aim=False)[source]¶
Chief ray image height minus magnification*object height (finite objects).
- Parameters:
- magnificationnumber
Nominal lateral magnification.
- fieldssequence, optional
Fields as fractions of the maximum object height.
- tolerancenumber, optional
Tolerance in the length unit (default 10 nm for mm).
- aimbool, optional
Use the real chief ray through the centre of the stop (ray aiming for this ray only) instead of the system’s chief ray (which, without ray aiming, is aimed at the paraxial entrance pupil).
- Returns:
- operandcallable
- pyoptics.lens_optimization.image_telecentricity(fields=(0.5, 0.75, 1.0), tolerance=0.001, aim=False)[source]¶
Image space chief ray slopes dy/dz.
- Parameters:
- fieldssequence, optional
Fields as fractions of the maximum field.
- tolerancenumber, optional
Tolerance in radians (default 1 mrad).
- aimbool, optional
Use the real chief ray through the centre of the stop (see
distortion()). Without ray aiming the system’s chief ray is aimed at the paraxial entrance pupil, and the pupil aberrations of a high NA lens make its slopes differ from those of the real chief ray by tens of mrad.
- Returns:
- operandcallable
- pyoptics.lens_optimization.object_telecentricity(tolerance=0.0001, aim=False, fields=(0.5, 0.75, 1.0))[source]¶
Object space chief ray slope (finite objects): zero for an entrance pupil at infinity.
- Parameters:
- tolerancenumber, optional
Tolerance in radians.
- aimbool, optional
False (default): the paraxial chief ray slope at the maximum field. True: the slopes of the real chief rays through the centre of the stop at
fields(seeimage_telecentricity()).- fieldssequence, optional
Fields as fractions of the maximum field (with aim).
- Returns:
- operandcallable
- pyoptics.lens_optimization.paraxial_target(name, value, tolerance)[source]¶
Attribute
nameofSystem.paraxial()(e.g. “magnification”, “efl”, “na”) against a target value.- Parameters:
- namestr
Attribute of
raytrace.Paraxial.- valuenumber
Target.
- tolerancenumber
Tolerance.
- Returns:
- operandcallable
- pyoptics.lens_optimization.clearances(min_air=1.0, min_center=None, min_edge=3.0, margin=1.05, tolerance=0.01, min_object_distance=None, min_image_distance=None)[source]¶
Penalties for lenses that are too thin and air spaces that close.
Thicknesses are checked on the axis and at the rim of the beam, the paraxial
|y| + |ybar|(at the maximum field) times margin, the larger of the two surfaces of each space. During the stages ofLensOptimizer.run()the rim is that of the full aperture and field.- Parameters:
- min_airnumber, optional
Smallest air space, on axis and at the rim (also object and image distance).
- min_centernumber, optional
Smallest centre thickness of a lens (default: min_edge).
- min_edgenumber, optional
Smallest edge thickness of a lens.
- marginnumber, optional
Rim height relative to the paraxial beam.
- tolerancenumber, optional
A violation by tolerance gives a residual of 1 (default 10 um for mm); satisfied constraints give 0.
- min_object_distance, min_image_distancenumber, optional
Smallest distances from the object to the first vertex and from the last vertex to the image (working distance); default min_air.
- Returns:
- operandcallable
- class pyoptics.lens_optimization.LensOptimizer(system, operands, curvatures=None, thicknesses=None, object_distance=False, length=None, solve=-1, object_na=None, aspheres=(), asphere_orders=(4, 6))[source]¶
Bases:
objectLeast squares optimization of curvatures and thicknesses.
- Parameters:
- systemraytrace.System
Starting system (copied).
- operandssequence of callables
Functions of the system that return residuals (see the factories of this module).
- curvaturessequence of int, optional
Indices of the surfaces whose curvature varies. Default: all refracting and reflecting surfaces (stops and dummy surfaces that do not change the medium, ideal lenses and coordinate breaks stay).
- thicknessessequence of int, optional
Indices of the surfaces whose thickness (to the next surface) varies. Default: all air spaces, except the solved one.
- object_distancebool, optional
Vary the object distance (finite objects).
- lengthnumber, optional
Keep the distance from object (finite objects; else the first vertex) to image at this value by solving the thickness of surface
solve.- solveint, optional
Surface whose thickness is solved for the length (default: the last one, the image distance).
- object_nanumber, optional
Keep the object space NA
n*|u|of the paraxial marginal ray (finite objects) by setting the semi diameter of the stop.- aspheressequence of int, optional
Surfaces whose aspheric coefficients vary (even aspheres, see
raytrace.Surface).- asphere_orderssequence of int, optional
Powers of r that vary on these surfaces (default r**4 and r**6). Internally the variables are the sags A_k r**k at the rim of the paraxial full field beam.
- property x¶
Current values of the variables.
- system_at(x)[source]¶
Copy of the system with the variables x.
- Parameters:
- xarray
Variables in the order of
x.
- Returns:
- raytrace.System
- residuals(x=None)[source]¶
All operand residuals at x (default: the current variables).
- Parameters:
- xarray, optional
Variables.
- Returns:
- array
- run(stages=((1.0, 1.0),), max_nfev=100, **kwargs)[source]¶
Optimize, in stages of growing aperture and field.
- Parameters:
- stagessequence of (aperture_fraction, field_fraction), optional
Fractions of object_na and of the maximum field per stage (default: one stage at the full values). The aperture fraction needs object_na.
- max_nfevint, optional
Function evaluations per stage (without those of the Jacobian).
- **kwargs
Passed to scipy.optimize.least_squares (e.g. x_scale=”jac” instead of the default scales: the median curvature and thickness, 100 wavelengths for the aspheric sags).
- Returns:
- OptimizationResult