Skip to content

Optics API Reference

The deeplens.optics module is the core of DeepLens. It provides differentiable lens models, optical surface primitives, light representations, and image simulation utilities. All components are PyTorch-based and support gradient backpropagation for end-to-end optimization.


Lens Models

All lens types inherit from Lens and share a common PSF/rendering API. The table below summarises the available models and their intended use cases.

Lens Type Description Use Case
GeoLens Differentiable refractive ray tracing High-accuracy simulation; automated lens design
HybridLens Ray tracing + wave optics (DOE) Hybrid refractive-diffractive systems
DiffractiveLens Pure wave-optics propagation DOEs and metasurfaces (no geometric aberrations)
PSFNetLens Neural PSF surrogate Fast inference; depth/field-varying PSF
ParaxialLens Circle-of-Confusion thin lens Quick defocus simulation, no aberrations

Lens (base)

Base class inherited by every lens type. Defines the public API for PSF computation, image rendering, and sensor configuration.

deeplens.optics.lens.Lens

Lens(dtype=torch.float32, device=None)

Bases: DeepObj

Initialize a lens class.

Parameters:

Name Type Description Default
dtype dtype

Data type. Defaults to torch.float32.

float32
device str

Device to run the lens. Defaults to None.

None
device instance-attribute
device = init_device()
dtype instance-attribute
dtype = dtype
read_lens_json
read_lens_json(filename)

Read lens from a json file.

write_lens_json
write_lens_json(filename)

Write lens to a json file.

set_sensor
set_sensor(sensor_size, sensor_res)

Set sensor size and resolution.

Parameters:

Name Type Description Default
sensor_size tuple

Sensor size (w, h) in [mm].

required
sensor_res tuple

Sensor resolution (W, H) in [pixels].

required
set_sensor_res
set_sensor_res(sensor_res)

Set sensor resolution (and aspect ratio) while keeping sensor radius unchanged.

Parameters:

Name Type Description Default
sensor_res tuple

Sensor resolution (W, H) in [pixels].

required
calc_fov
calc_fov()

Compute FoV (radian) of the lens.

Reference

[1] https://en.wikipedia.org/wiki/Angle_of_view_(photography)

psf
psf(points, wvln=DEFAULT_WAVE, ks=PSF_KS, **kwargs)

Compute the monochromatic PSF for one or more point sources.

Subclasses must override this method with a differentiable implementation. Three computation models are common in practice: geometric ray binning, coherent ray-wave, and Huygens spherical-wave integration.

Parameters:

Name Type Description Default
points Tensor

Point source coordinates, shape [N, 3] or [3]. x, y are normalised to [-1, 1] (relative to the sensor half-diagonal); z is depth in mm (must be negative, i.e. in front of the lens).

required
wvln float

Wavelength in micrometers. Defaults to DEFAULT_WAVE (0.587 µm, d-line).

DEFAULT_WAVE
ks int

Output PSF kernel size in pixels. Defaults to PSF_KS (64).

PSF_KS
**kwargs

Additional keyword arguments forwarded to the underlying PSF computation (e.g. spp, model, recenter).

{}

Returns:

Type Description

torch.Tensor: PSF intensity map, shape [ks, ks] for a single

point or [N, ks, ks] for a batch.

Raises:

Type Description
NotImplementedError

This base implementation must be overridden.

Notes

The method is differentiable with respect to all optimisable lens parameters so it can be used directly inside a training loop.

Example

point = torch.tensor([0.0, 0.0, -10000.0]) psf = lens.psf(points=point, ks=64, model="geometric") print(psf.shape) # torch.Size([64, 64])

psf_rgb
psf_rgb(points, ks=PSF_KS, **kwargs)

Compute the RGB (tri-chromatic) PSF by stacking three wavelength calls.

Calls :meth:psf three times for the RGB primary wavelengths defined in WAVE_RGB and stacks the results along the channel axis.

Parameters:

Name Type Description Default
points Tensor

Point source coordinates, shape [N, 3] or [3]. Same convention as :meth:psf.

required
ks int

PSF kernel size. Defaults to PSF_KS.

PSF_KS
**kwargs

Forwarded to :meth:psf (e.g. spp, model).

{}

Returns:

Type Description

torch.Tensor: RGB PSF, shape [3, ks, ks] for a single point

or [N, 3, ks, ks] for a batch.

point_source_grid
point_source_grid(depth, grid=(9, 9), normalized=True, quater=False, center=True)

Generate point source grid for PSF calculation.

Parameters:

Name Type Description Default
depth float

Depth of the point source.

required
grid tuple

Grid size (grid_w, grid_h). Defaults to (9, 9), meaning 9x9 grid.

(9, 9)
normalized bool

Return normalized object source coordinates. Defaults to True, meaning object sources xy coordinates range from [-1, 1].

True
quater bool

Use quater of the sensor plane to save memory. Defaults to False.

False
center bool

Use center of each patch. Defaults to True.

True

Returns:

Name Type Description
point_source

Normalized object source coordinates. Shape of [grid_h, grid_w, 3], [-1, 1], [-1, 1], [-Inf, 0].

psf_map
psf_map(grid=(5, 5), wvln=DEFAULT_WAVE, depth=DEPTH, ks=PSF_KS, **kwargs)

Compute monochrome PSF map.

Parameters:

Name Type Description Default
grid tuple

Grid size (grid_w, grid_h). Defaults to (5, 5), meaning 5x5 grid.

(5, 5)
wvln float

Wavelength. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
ks int

Kernel size. Defaults to PSF_KS.

PSF_KS

Returns:

Name Type Description
psf_map

Shape of [grid_h, grid_w, 3, ks, ks].

psf_map_rgb
psf_map_rgb(grid=(5, 5), ks=PSF_KS, depth=DEPTH, **kwargs)

Compute RGB PSF map.

Parameters:

Name Type Description Default
grid tuple

Grid size (grid_w, grid_h). Defaults to (5, 5), meaning 5x5 grid.

(5, 5)
ks int

Kernel size. Defaults to PSF_KS, meaning PSF_KS x PSF_KS kernel size.

PSF_KS
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
**kwargs

Additional arguments for psf_map().

{}

Returns:

Name Type Description
psf_map

Shape of [grid_h, grid_w, 3, ks, ks].

draw_psf_map
draw_psf_map(grid=(7, 7), ks=PSF_KS, depth=DEPTH, log_scale=False, save_name='./psf_map.png', show=False)

Draw RGB PSF map of the lens.

point_source_radial
point_source_radial(depth, grid=9, center=False)

Compute point radial [0, 1] in the object space to compute PSF grid.

Parameters:

Name Type Description Default
grid int

Grid size. Defaults to 9.

9

Returns:

Name Type Description
point_source

Shape of [grid, 3].

draw_psf_radial
draw_psf_radial(M=3, depth=DEPTH, ks=PSF_KS, log_scale=False, save_name='./psf_radial.png')

Draw radial PSF (45 deg). Will draw M PSFs, each of size ks x ks.

render
render(img_obj, depth=DEPTH, method='psf_patch', **kwargs)

Differentiable image simulation for a 2D (flat) scene.

Performs only the optical component of image simulation and is fully differentiable. Sensor noise is handled separately by the :class:~deeplens.camera.Camera class.

For incoherent imaging the intensity PSF is convolved with the object-space image. For coherent imaging the complex PSF is convolved with the complex object image before squaring for intensity.

Parameters:

Name Type Description Default
img_obj Tensor

Input image in linear (raw) space, shape [B, C, H, W].

required
depth float

Object depth in mm (negative value). Defaults to DEPTH (-20 000 mm, i.e. infinity).

DEPTH
method str

Rendering method. One of:

  • "psf_patch" – convolve a single PSF evaluated at patch_center (default).
  • "psf_map" – spatially-varying PSF block convolution.
'psf_patch'
**kwargs

Method-specific keyword arguments:

  • For "psf_map": psf_grid (tuple, default (10, 10)), psf_ks (int, default PSF_KS).
  • For "psf_patch": patch_center (tuple or Tensor, default (0.0, 0.0)), psf_ks (int).
{}

Returns:

Type Description

torch.Tensor: Rendered image, shape [B, C, H, W].

Raises:

Type Description
AssertionError

If method is "psf_map" and the image resolution does not match the sensor resolution.

Exception

If method is not recognised.

References

[1] "Optical Aberration Correction in Postprocessing using Imaging Simulation", TOG 2021. [2] "Efficient depth- and spatially-varying image simulation for defocus deblur", ICCVW 2025.

Example

img_rendered = lens.render(img, depth=-10000.0, method="psf_patch", ... patch_center=(0.3, 0.0), psf_ks=64)

render_psf
render_psf(img_obj, depth=DEPTH, patch_center=(0, 0), psf_ks=PSF_KS)

Render image patch using PSF convolution. Better not use this function to avoid confusion.

render_psf_patch
render_psf_patch(img_obj, depth=DEPTH, patch_center=(0, 0), psf_ks=PSF_KS)

Render an image patch using PSF convolution, and return positional encoding channel.

Parameters:

Name Type Description Default
img_obj tensor

Input image object in raw space. Shape of [B, C, H, W].

required
depth float

Depth of the object.

DEPTH
patch_center tensor

Center of the image patch. Shape of [2] or [B, 2].

(0, 0)
psf_ks int

PSF kernel size. Defaults to PSF_KS.

PSF_KS

Returns:

Name Type Description
img_render

Rendered image. Shape of [B, C, H, W].

render_psf_map
render_psf_map(img_obj, depth=DEPTH, psf_grid=7, psf_ks=PSF_KS)

Render image using PSF block convolution.

Note

Larger psf_grid and psf_ks are typically better for more accurate rendering, but slower.

Parameters:

Name Type Description Default
img_obj tensor

Input image object in raw space. Shape of [B, C, H, W].

required
depth float

Depth of the object.

DEPTH
psf_grid int

PSF grid size.

7
psf_ks int

PSF kernel size. Defaults to PSF_KS.

PSF_KS

Returns:

Name Type Description
img_render

Rendered image. Shape of [B, C, H, W].

_sample_depth_layers
_sample_depth_layers(depth_min, depth_max, num_layers)

Sample depth layers centered on the focal plane in disparity space.

If the lens has a calc_focal_plane method, samples are split around the focal plane so that it is always an explicit sample point. Otherwise falls back to uniform disparity sampling.

Parameters:

Name Type Description Default
depth_min float

Minimum (nearest) depth in mm (positive).

required
depth_max float

Maximum (farthest) depth in mm (positive).

required
num_layers int

Number of depth layers to sample.

required

Returns:

Name Type Description
tuple

(disp_ref, depths_ref) where disp_ref has shape (num_layers,) in disparity space and depths_ref = -1/disp_ref (negative, for PSF).

render_rgbd
render_rgbd(img_obj, depth_map, method='psf_patch', **kwargs)

Render RGBD image.

TODO: add obstruction-aware image simulation.

Parameters:

Name Type Description Default
img_obj tensor

Object image. Shape of [B, C, H, W].

required
depth_map tensor

Depth map [mm]. Shape of [B, 1, H, W]. Values should be positive.

required
method str

Image simulation method. Defaults to "psf_patch".

'psf_patch'
**kwargs

Additional arguments for different methods. - interp_mode (str): "depth" or "disparity". Defaults to "depth".

{}

Returns:

Name Type Description
img_render

Rendered image. Shape of [B, C, H, W].

Reference

[1] "Aberration-Aware Depth-from-Focus", TPAMI 2023. [2] "Efficient Depth- and Spatially-Varying Image Simulation for Defocus Deblur", ICCVW 2025.

activate_grad
activate_grad(activate=True)

Activate gradient for each surface.

get_optimizer_params
get_optimizer_params(lr=[0.0001, 0.0001, 0.1, 0.001])

Get optimizer parameters for different lens parameters.

get_optimizer
get_optimizer(lr=[0.0001, 0.0001, 0, 0.001])

Get optimizer.

GeoLens

The primary differentiable lens model. Uses vectorised PyTorch ray tracing through multi-element refractive surfaces.

from deeplens import GeoLens

lens = GeoLens(filename='./datasets/lenses/camera/ef50mm_f1.8.json', device='cuda')

# PSF at a point
import torch
psf = lens.psf(points=torch.tensor([0.0, 0.0, -10000.0]), ks=64, spp=4096)

# Image rendering
img_rendered = lens.render(img, depth=-10000.0, method='psf_map', psf_grid=(7, 7))

# Gradient-based optimisation
optimizer = lens.get_optimizer(lrs=[1e-3, 1e-4, 0, 0], decay=0.01)

Note

Parenthesised keys like "(d)" in JSON lens files mark optimisable parameters.

deeplens.optics.geolens.GeoLens

GeoLens(filename=None, device=None, dtype=torch.float32)

Bases: Lens, GeoLensEval, GeoLensOptim, GeoLensVis, GeoLensIO, GeoLensTolerance, GeoLensVis3D

Differentiable geometric lens using vectorised ray tracing.

The primary lens model in DeepLens. Supports multi-element refractive (and partially reflective) systems loaded from JSON, Zemax .zmx, or Code V .seq files. Accuracy is aligned with Zemax OpticStudio.

Uses a mixin architecture – six specialised mixin classes are composed at class definition time to keep each concern isolated:

  • :class:~deeplens.optics.geolens_pkg.eval.GeoLensEval – optical performance evaluation (spot, MTF, distortion, vignetting).
  • :class:~deeplens.optics.geolens_pkg.optim.GeoLensOptim – loss functions and gradient-based optimisation.
  • :class:~deeplens.optics.geolens_pkg.vis.GeoLensVis – 2-D layout and ray visualisation.
  • :class:~deeplens.optics.geolens_pkg.io.GeoLensIO – read/write JSON, Zemax .zmx.
  • :class:~deeplens.optics.geolens_pkg.tolerance.GeoLensTolerance – manufacturing tolerance analysis.
  • :class:~deeplens.optics.geolens_pkg.view_3d.GeoLensVis3D – 3-D mesh visualisation.

Key differentiability trick: Ray-surface intersection (:meth:~deeplens.optics.geometric_surface.base.Surface.newtons_method) uses a non-differentiable Newton loop followed by one differentiable Newton step to enable gradient flow.

Attributes:

Name Type Description
surfaces list[Surface]

Ordered list of optical surfaces.

materials list[Material]

Optical materials between surfaces.

d_sensor Tensor

Back focal distance [mm].

foclen float

Effective focal length [mm].

fnum float

F-number.

rfov float

Half-diagonal field of view [radians].

sensor_size tuple

Physical sensor size (W, H) [mm].

sensor_res tuple

Sensor resolution (W, H) [pixels].

pixel_size float

Pixel pitch [mm].

References

Xinge Yang et al., "Curriculum learning for ab initio deep learned refractive optics," Nature Communications 2024.

Initialize a refractive lens.

There are two ways to initialize a GeoLens
  1. Read a lens from .json/.zmx/.seq file
  2. Initialize a lens with no lens file, then manually add surfaces and materials

Parameters:

Name Type Description Default
filename str

Path to lens file (.json, .zmx, or .seq). Defaults to None.

None
device device

Device for tensor computations. Defaults to None.

None
dtype dtype

Data type for computations. Defaults to torch.float32.

float32
surfaces instance-attribute
surfaces = []
materials instance-attribute
materials = []
sensor_size instance-attribute
sensor_size = (8.0, 8.0)
sensor_res instance-attribute
sensor_res = (2000, 2000)
read_lens
read_lens(filename)

Read a GeoLens from a file.

Supported file formats
  • .json: DeepLens native JSON format
  • .zmx: Zemax lens file format
  • .seq: CODE V sequence file format

Parameters:

Name Type Description Default
filename str

Path to the lens file.

required
Note

Sensor size and resolution will usually be overwritten by values from the file.

post_computation
post_computation()

Compute derived optical properties after loading or modifying lens.

Calculates and caches
  • Effective focal length (EFL)
  • Entrance and exit pupil positions and radii
  • Field of view (FoV) in horizontal, vertical, and diagonal directions
  • F-number
Note

This method should be called after any changes to the lens geometry.

__call__
__call__(ray)

Trace rays through the lens system.

Makes the GeoLens callable, allowing ray tracing with function call syntax.

sample_grid_rays
sample_grid_rays(depth=float('inf'), num_grid=(11, 11), num_rays=SPP_PSF, wvln=DEFAULT_WAVE, uniform_fov=True, sample_more_off_axis=False, scale_pupil=1.0)

Sample grid rays from object space. (1) If depth is infinite, sample parallel rays at different field angles. (2) If depth is finite, sample point source rays from the object plane.

This function is usually used for (1) PSF map, (2) RMS error map, and (3) spot diagram calculation.

Parameters:

Name Type Description Default
depth float

sampling depth. Defaults to float("inf").

float('inf')
num_grid tuple

number of grid points. Defaults to [11, 11].

(11, 11)
num_rays int

number of rays. Defaults to SPP_PSF.

SPP_PSF
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
uniform_fov bool

If True, sample uniform FoV angles.

True
sample_more_off_axis bool

If True, sample more off-axis rays.

False
scale_pupil float

Scale factor for pupil radius.

1.0

Returns:

Name Type Description
ray Ray object

Ray object. Shape [num_grid[1], num_grid[0], num_rays, 3]

sample_radial_rays
sample_radial_rays(num_field=5, depth=float('inf'), num_rays=SPP_PSF, wvln=DEFAULT_WAVE)

Sample radial (meridional, y direction) rays at different field angles.

This function is usually used for (1) PSF radial map, and (2) RMS error radial map calculation.

Parameters:

Name Type Description Default
num_field int

number of field angles. Defaults to 5.

5
depth float

sampling depth. Defaults to float("inf").

float('inf')
num_rays int

number of rays. Defaults to SPP_PSF.

SPP_PSF
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE

Returns:

Name Type Description
ray Ray object

Ray object. Shape [num_field, num_rays, 3]

sample_from_points
sample_from_points(points=[[0.0, 0.0, -10000.0]], num_rays=SPP_PSF, wvln=DEFAULT_WAVE, scale_pupil=1.0)

Sample rays from point sources in object space (absolute physical coordinates).

Used for PSF and chief ray calculation.

Parameters:

Name Type Description Default
points list or Tensor

Ray origins in shape [3], [N, 3], or [Nx, Ny, 3].

[[0.0, 0.0, -10000.0]]
num_rays int

Number of rays per point. Default: SPP_PSF.

SPP_PSF
wvln float

Wavelength of rays. Default: DEFAULT_WAVE.

DEFAULT_WAVE
scale_pupil float

Scale factor for pupil radius.

1.0

Returns:

Name Type Description
Ray

Sampled rays with shape (\*points.shape[:-1], num_rays, 3).

sample_parallel
sample_parallel(fov_x=[0.0], fov_y=[0.0], num_rays=SPP_CALC, wvln=DEFAULT_WAVE, entrance_pupil=True, depth=-1.0, scale_pupil=1.0)

Sample parallel rays in object space for geometric optics calculations.

Parameters:

Name Type Description Default
fov_x float or list

Field angle(s) in the xz plane (degrees). Default: [0.0].

[0.0]
fov_y float or list

Field angle(s) in the yz plane (degrees). Default: [0.0].

[0.0]
num_rays int

Number of rays per field point. Default: SPP_CALC.

SPP_CALC
wvln float

Wavelength of rays. Default: DEFAULT_WAVE.

DEFAULT_WAVE
entrance_pupil bool

If True, sample origins on entrance pupil; otherwise, on surface 0. Default: True.

True
depth float

Propagation depth in z. Default: -1.0.

-1.0
scale_pupil float

Scale factor for pupil radius. Default: 1.0.

1.0

Returns:

Name Type Description
Ray

Rays with shape [..., num_rays, 3], where leading dims are: - both fov_x and fov_y scalars: [num_rays, 3] - fov_x scalar: [len(fov_y), num_rays, 3] - fov_y scalar: [len(fov_x), num_rays, 3] - both lists: [len(fov_y), len(fov_x), num_rays, 3] Ordered as (u, v).

sample_point_source
sample_point_source(fov_x=[0.0], fov_y=[0.0], depth=DEPTH, num_rays=SPP_PSF, wvln=DEFAULT_WAVE, entrance_pupil=True, scale_pupil=1.0)

Sample point source rays from object space with given field angles.

Used for (1) spot/rms/magnification calculation, (2) distortion/sensor sampling.

This function is equivalent to self.point_source_grid() + self.sample_from_points().

Parameters:

Name Type Description Default
fov_x float or list

field angle in x0z plane.

[0.0]
fov_y float or list

field angle in y0z plane.

[0.0]
depth float

sample plane z position. Defaults to -10.0.

DEPTH
num_rays int

number of rays sampled from each grid point. Defaults to 16.

SPP_PSF
entrance_pupil bool

whether to use entrance pupil. Defaults to False.

True
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE

Returns:

Name Type Description
ray Ray object

Ray object. Shape [len(fov_y), len(fov_x), num_rays, 3], arranged in uv order.

sample_sensor
sample_sensor(spp=64, wvln=DEFAULT_WAVE, sub_pixel=False)

Sample rays from sensor pixels (backward rays). Used for ray tracing rendering.

Parameters:

Name Type Description Default
spp int

sample per pixel. Defaults to 64.

64
pupil bool

whether to use pupil. Defaults to True.

required
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
sub_pixel bool

whether to sample multiple points inside the pixel. Defaults to False.

False

Returns:

Name Type Description
ray Ray object

Ray object. Shape [H, W, spp, 3]

sample_circle
sample_circle(r, z, shape=[16, 16, 512])

Sample points inside a circle.

Parameters:

Name Type Description Default
r float

Radius of the circle.

required
z float

Z-coordinate for all sampled points.

required
shape list

Shape of the output tensor.

[16, 16, 512]

Returns:

Type Description

torch.Tensor: Sampled points, shape (\*shape, 3).

trace
trace(ray, surf_range=None, record=False)

Trace rays through the lens.

Forward or backward tracing is automatically determined by the ray direction.

Parameters:

Name Type Description Default
ray Ray object

Ray object.

required
surf_range list

Surface index range.

None
record bool

record ray path or not.

False

Returns:

Name Type Description
ray_final Ray object

ray after optical system.

ray_o_rec list

list of intersection points.

trace2obj
trace2obj(ray)

Traces rays backwards through all lens surfaces from sensor side to object side.

Parameters:

Name Type Description Default
ray Ray

Ray object to trace backwards.

required

Returns:

Name Type Description
Ray

Ray object after backward propagation through the lens.

trace2sensor
trace2sensor(ray, record=False)

Forward trace rays through the lens to sensor plane.

Parameters:

Name Type Description Default
ray Ray object

Ray object.

required
record bool

record ray path or not.

False

Returns:

Name Type Description
ray_out Ray object

ray after optical system.

ray_o_record list

list of intersection points.

trace2exit_pupil
trace2exit_pupil(ray)

Forward trace rays through the lens to exit pupil plane.

Parameters:

Name Type Description Default
ray Ray

Ray object to trace.

required

Returns:

Name Type Description
Ray

Ray object propagated to the exit pupil plane.

forward_tracing
forward_tracing(ray, surf_range, record)

Forward traces rays through each surface in the specified range from object side to image side.

Parameters:

Name Type Description Default
ray Ray

Ray object to trace.

required
surf_range range

Range of surface indices to trace through.

required
record bool

If True, record ray positions at each surface.

required

Returns:

Name Type Description
tuple

(ray_out, ray_o_record) where: - ray_out (Ray): Ray after propagation through all surfaces. - ray_o_record (list or None): List of ray positions at each surface, or None if record is False.

backward_tracing
backward_tracing(ray, surf_range, record)

Backward traces rays through each surface in reverse order from image side to object side.

Parameters:

Name Type Description Default
ray Ray

Ray object to trace.

required
surf_range range

Range of surface indices to trace through.

required
record bool

If True, record ray positions at each surface.

required

Returns:

Name Type Description
tuple

(ray_out, ray_o_record) where: - ray_out (Ray): Ray after backward propagation through all surfaces. - ray_o_record (list or None): List of ray positions at each surface, or None if record is False.

render
render(img_obj, depth=DEPTH, method='ray_tracing', **kwargs)

Differentiable image simulation.

Image simulation methods

[1] PSF map block convolution. [2] PSF patch convolution. [3] Ray tracing rendering.

Parameters:

Name Type Description Default
img_obj Tensor

Input image object in raw space. Shape of [N, C, H, W].

required
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
method str

Image simulation method. One of 'psf_map', 'psf_patch', or 'ray_tracing'. Defaults to 'ray_tracing'.

'ray_tracing'
**kwargs

Additional arguments for different methods: - psf_grid (tuple): Grid size for PSF map method. Defaults to (10, 10). - psf_ks (int): Kernel size for PSF methods. Defaults to PSF_KS. - patch_center (tuple): Center position for PSF patch method. - spp (int): Samples per pixel for ray tracing. Defaults to SPP_RENDER.

{}

Returns:

Name Type Description
Tensor

Rendered image tensor. Shape of [N, C, H, W].

render_raytracing
render_raytracing(img, depth=DEPTH, spp=SPP_RENDER, vignetting=False)

Render RGB image using ray tracing rendering.

Parameters:

Name Type Description Default
img tensor

RGB image tensor. Shape of [N, 3, H, W].

required
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
spp int

Sample per pixel. Defaults to 64.

SPP_RENDER
vignetting bool

whether to consider vignetting effect. Defaults to False.

False

Returns:

Name Type Description
img_render tensor

Rendered RGB image tensor. Shape of [N, 3, H, W].

render_raytracing_mono
render_raytracing_mono(img, wvln, depth=DEPTH, spp=64, vignetting=False)

Render monochrome image using ray tracing rendering.

Parameters:

Name Type Description Default
img tensor

Monochrome image tensor. Shape of [N, 1, H, W] or [N, H, W].

required
wvln float

Wavelength of the light.

required
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
spp int

Sample per pixel. Defaults to 64.

64

Returns:

Name Type Description
img_mono tensor

Rendered monochrome image tensor. Shape of [N, 1, H, W] or [N, H, W].

render_compute_image
render_compute_image(img, depth, scale, ray, vignetting=False)

Computes the intersection points between rays and the object image plane, then generates the rendered image following rendering equation.

Back-propagation gradient flow: image -> w_i -> u -> p -> ray -> surface

Parameters:

Name Type Description Default
img tensor

[N, C, H, W] or [N, H, W] shape image tensor.

required
depth float

depth of the object.

required
scale float

scale factor.

required
ray Ray object

Ray object. Shape [H, W, spp, 3].

required
vignetting bool

whether to consider vignetting effect.

False

Returns:

Name Type Description
image tensor

[N, C, H, W] or [N, H, W] shape rendered image tensor.

unwarp
unwarp(img, depth=DEPTH, num_grid=128, crop=True, flip=True)

Unwarp rendered images using distortion map.

Parameters:

Name Type Description Default
img tensor

Rendered image tensor. Shape of [N, C, H, W].

required
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
grid_size int

Grid size. Defaults to 256.

required
crop bool

Whether to crop the image. Defaults to True.

True

Returns:

Name Type Description
img_unwarpped tensor

Unwarped image tensor. Shape of [N, C, H, W].

analysis_rendering
analysis_rendering(img_org, save_name=None, depth=DEPTH, spp=SPP_RENDER, unwarp=False, noise=0.0, method='ray_tracing', show=False)

Render a single image for visualization and analysis.

Parameters:

Name Type Description Default
img_org Tensor

Original image with shape [H, W, 3].

required
save_name str

Path prefix for saving rendered images. Defaults to None.

None
depth float

Depth of object image. Defaults to DEPTH.

DEPTH
spp int

Sample per pixel. Defaults to SPP_RENDER.

SPP_RENDER
unwarp bool

If True, unwarp the image to correct distortion. Defaults to False.

False
noise float

Gaussian noise standard deviation. Defaults to 0.0.

0.0
method str

Rendering method ('ray_tracing', etc.). Defaults to 'ray_tracing'.

'ray_tracing'
show bool

If True, display the rendered image. Defaults to False.

False

Returns:

Name Type Description
Tensor

Rendered image tensor with shape [1, 3, H, W].

psf
psf(points, ks=PSF_KS, wvln=DEFAULT_WAVE, spp=None, recenter=True, model='geometric')

Calculate Point Spread Function (PSF) for given point sources.

Supports multiple PSF calculation models
  • geometric: Incoherent intensity ray tracing (fast, differentiable)
  • coherent: Coherent ray tracing with free-space propagation (accurate, differentiable)
  • huygens: Huygens-Fresnel integration (accurate, not differentiable)

Parameters:

Name Type Description Default
points Tensor

Point source positions. Shape [N, 3] with x, y in [-1, 1] and z in [-Inf, 0]. Normalized coordinates.

required
ks int

Output kernel size in pixels. Defaults to PSF_KS.

PSF_KS
wvln float

Wavelength in [um]. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
spp int

Samples per pixel. If None, uses model-specific default.

None
recenter bool

If True, center PSF using chief ray. Defaults to True.

True
model str

PSF model type. One of 'geometric', 'coherent', 'huygens'. Defaults to 'geometric'.

'geometric'

Returns:

Name Type Description
Tensor

PSF normalized to sum to 1. Shape [ks, ks] or [N, ks, ks].

psf_geometric
psf_geometric(points, ks=PSF_KS, wvln=DEFAULT_WAVE, spp=SPP_PSF, recenter=True)

Single wavelength geometric PSF calculation.

Parameters:

Name Type Description Default
points Tensor

Normalized point source position. Shape of [N, 3], x, y in range [-1, 1], z in range [-Inf, 0].

required
ks int

Output kernel size.

PSF_KS
wvln float

Wavelength.

DEFAULT_WAVE
spp int

Sample per pixel.

SPP_PSF
recenter bool

Recenter PSF using chief ray.

True

Returns:

Name Type Description
psf

Shape of [ks, ks] or [N, ks, ks].

References

[1] https://optics.ansys.com/hc/en-us/articles/42661723066515-What-is-a-Point-Spread-Function

psf_coherent
psf_coherent(points, ks=PSF_KS, wvln=DEFAULT_WAVE, spp=SPP_COHERENT, recenter=True)

Alias for psf_pupil_prop. Calculates PSF by coherent ray tracing to exit pupil followed by Angular Spectrum Method (ASM) propagation.

psf_pupil_prop
psf_pupil_prop(points, ks=PSF_KS, wvln=DEFAULT_WAVE, spp=SPP_COHERENT, recenter=True)

Single point monochromatic PSF using exit-pupil diffraction model. This function is differentiable.

Steps

1, Calculate complex wavefield at exit-pupil plane by coherent ray tracing. 2, Free-space propagation to sensor plane and calculate intensity PSF.

Parameters:

Name Type Description Default
points Tensor

[x, y, z] coordinates of the point source. Defaults to torch.Tensor([0,0,-10000]).

required
ks int

size of the PSF patch. Defaults to PSF_KS.

PSF_KS
wvln float

wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
spp int

number of rays to sample. Defaults to SPP_COHERENT.

SPP_COHERENT
recenter bool

Recenter PSF using chief ray. Defaults to True.

True

Returns:

Name Type Description
psf_out Tensor

PSF patch. Normalized to sum to 1. Shape [ks, ks]

Reference

[1] "End-to-End Hybrid Refractive-Diffractive Lens Design with Differentiable Ray-Wave Model", SIGGRAPH Asia 2024.

Note

[1] This function is similar to ZEMAX FFT_PSF but implement free-space propagation with Angular Spectrum Method (ASM) rather than FFT transform. Free-space propagation using ASM is more accurate than doing FFT, because FFT (as used in ZEMAX) assumes far-field condition (e.g., chief ray perpendicular to image plane).

pupil_field
pupil_field(points, wvln=DEFAULT_WAVE, spp=SPP_COHERENT, recenter=True)

Compute complex wavefront at exit pupil plane by coherent ray tracing.

The wavefront is flipped for subsequent PSF calculation and has the same size as the image sensor. This function is differentiable.

Parameters:

Name Type Description Default
points Tensor or list

Single point source position. Shape [3] or [1, 3], with x, y in [-1, 1] and z in [-Inf, 0].

required
wvln float

Wavelength in [um]. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
spp int

Number of rays to sample. Must be >= 1,000,000 for accurate coherent simulation. Defaults to SPP_COHERENT.

SPP_COHERENT
recenter bool

If True, center using chief ray. Defaults to True.

True

Returns:

Name Type Description
tuple

(wavefront, psf_center) where: - wavefront (Tensor): Complex wavefront at exit pupil. Shape [H, H]. - psf_center (list): Normalized PSF center coordinates [x, y] in [-1, 1].

Note

Default dtype must be torch.float64 for accurate phase calculation.

psf_huygens
psf_huygens(points, ks=PSF_KS, wvln=DEFAULT_WAVE, spp=SPP_COHERENT, recenter=True)

Single wavelength Huygens PSF calculation.

This function is not differentiable due to its heavy computational cost.

Steps

1, Trace coherent rays to exit-pupil plane. 2, Treat every ray as a secondary point source emitting a spherical wave.

Parameters:

Name Type Description Default
points Tensor

Normalized point source position. Shape of [N, 3], x, y in range [-1, 1], z in range [-Inf, 0].

required
ks int

Output kernel size.

PSF_KS
wvln float

Wavelength.

DEFAULT_WAVE
spp int

Sample per pixel.

SPP_COHERENT
recenter bool

Recenter PSF using chief ray.

True

Returns:

Name Type Description
psf

Shape of [ks, ks] or [N, ks, ks].

References

[1] "Optical Aberrations Correction in Postprocessing Using Imaging Simulation", TOG 2021

Note

This is different from ZEMAX Huygens PSF, which traces rays to image plane and do plane wave integration.

psf_map
psf_map(depth=DEPTH, grid=(7, 7), ks=PSF_KS, spp=SPP_PSF, wvln=DEFAULT_WAVE, recenter=True)

Compute the geometric PSF map at given depth.

Overrides the base method in Lens class to improve efficiency by parallel ray tracing over different field points.

Parameters:

Name Type Description Default
depth float

Depth of the object plane. Defaults to DEPTH.

DEPTH
grid (int, tuple)

Grid size (grid_w, grid_h). Defaults to 7.

(7, 7)
ks int

Kernel size. Defaults to PSF_KS.

PSF_KS
spp int

Sample per pixel. Defaults to SPP_PSF.

SPP_PSF
recenter bool

Recenter PSF using chief ray. Defaults to True.

True

Returns:

Name Type Description
psf_map

PSF map. Shape of [grid_h, grid_w, 1, ks, ks].

psf_center
psf_center(points_obj, method='chief_ray')

Compute reference PSF center (flipped to match the original point) for given point source.

Parameters:

Name Type Description Default
points_obj

[..., 3] un-normalized point in object plane. [-Inf, Inf] * [-Inf, Inf] * [-Inf, 0]

required
method

"chief_ray" or "pinhole". Defaults to "chief_ray".

'chief_ray'

Returns:

Name Type Description
psf_center

[..., 2] un-normalized psf center in sensor plane.

analysis_spot
analysis_spot(num_field=3, depth=float('inf'))

Compute sensor plane ray spot RMS error and radius.

Analyzes spot sizes across the field of view for multiple wavelengths (red, green, blue) and reports statistics.

Parameters:

Name Type Description Default
num_field int

Number of field positions to analyze along the radial direction. Defaults to 3.

3
depth float

Depth of the point source. Use float('inf') for collimated light. Defaults to float('inf').

float('inf')

Returns:

Name Type Description
dict

Spot analysis results keyed by field position (e.g., 'fov0.0', 'fov0.5'). Each entry contains 'rms' (RMS radius in um) and 'radius' (geometric radius in um).

find_diff_surf
find_diff_surf()

Get differentiable/optimizable surface indices.

Returns a list of surface indices that can be optimized during lens design. Excludes the aperture surface from optimization.

Returns:

Type Description

list or range: Surface indices excluding the aperture.

calc_foclen
calc_foclen()

Compute effective focal length (EFL).

Traces a paraxial chief ray and computes the image height, then uses the image height to compute the EFL.

Updates

self.efl: Effective focal length. self.foclen: Alias for effective focal length. self.bfl: Back focal length (distance from last surface to sensor).

Reference

[1] https://wp.optics.arizona.edu/optomech/wp-content/uploads/sites/53/2016/10/Tutorial_MorelSophie.pdf [2] https://rafcamera.com/info/imaging-theory/back-focal-length

calc_numerical_aperture
calc_numerical_aperture(n=1.0)

Compute numerical aperture (NA).

Parameters:

Name Type Description Default
n float

Refractive index. Defaults to 1.0.

1.0

Returns:

Name Type Description
NA float

Numerical aperture.

Reference

[1] https://en.wikipedia.org/wiki/Numerical_aperture

calc_focal_plane
calc_focal_plane(wvln=DEFAULT_WAVE)

Compute the focus distance in the object space. Ray starts from sensor center and traces to the object space.

Parameters:

Name Type Description Default
wvln float

Wavelength. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE

Returns:

Name Type Description
focal_plane float

Focal plane in the object space.

calc_sensor_plane
calc_sensor_plane(depth=float('inf'))

Calculate in-focus sensor plane.

Parameters:

Name Type Description Default
depth float

Depth of the object plane. Defaults to float("inf").

float('inf')

Returns:

Name Type Description
d_sensor Tensor

Sensor plane in the image space.

calc_fov
calc_fov()

Compute FoV (radian) of the lens.

We implement two types of FoV calculation
  1. Perspective projection from focal length and sensor size.
  2. Ray tracing to compute output ray angle.
Reference

[1] https://en.wikipedia.org/wiki/Angle_of_view_(photography)

calc_scale
calc_scale(depth)

Calculate the scale factor (object height / image height).

Uses the pinhole camera model to compute magnification.

Parameters:

Name Type Description Default
depth float

Object distance from the lens (negative z direction).

required

Returns:

Name Type Description
float

Scale factor relating object height to image height.

calc_pupil
calc_pupil()

Compute entrance and exit pupil positions and radii.

The entrance and exit pupils must be recalculated whenever
  • First-order parameters change (e.g., field of view, object height, image height),
  • Lens geometry or materials change (e.g., surface curvatures, refractive indices, thicknesses),
  • Or generally, any time the lens configuration is modified.
Updates

self.aper_idx: Index of the aperture surface. self.exit_pupilz, self.exit_pupilr: Exit pupil position and radius. self.entr_pupilz, self.entr_pupilr: Entrance pupil position and radius. self.exit_pupilz_parax, self.exit_pupilr_parax: Paraxial exit pupil. self.entr_pupilz_parax, self.entr_pupilr_parax: Paraxial entrance pupil. self.fnum: F-number calculated from focal length and entrance pupil.

get_entrance_pupil
get_entrance_pupil(paraxial=False)

Get entrance pupil location and radius.

Parameters:

Name Type Description Default
paraxial bool

If True, return paraxial approximation values. If False, return real ray-traced values. Defaults to False.

False

Returns:

Name Type Description
tuple

(z_position, radius) of the entrance pupil in [mm].

get_exit_pupil
get_exit_pupil(paraxial=False)

Get exit pupil location and radius.

Parameters:

Name Type Description Default
paraxial bool

If True, return paraxial approximation values. If False, return real ray-traced values. Defaults to False.

False

Returns:

Name Type Description
tuple

(z_position, radius) of the exit pupil in [mm].

calc_exit_pupil
calc_exit_pupil(paraxial=False)

Calculate exit pupil location and radius.

Paraxial mode

Rays are emitted from near the center of the aperture stop and are close to the optical axis. This mode estimates the exit pupil position and radius under ideal (first-order) optical assumptions. It is fast and stable.

Non-paraxial mode

Rays are emitted from the edge of the aperture stop in large quantities. The exit pupil position and radius are determined based on the intersection points of these rays. This mode is slower and affected by aperture-related aberrations.

Use paraxial mode unless precise ray aiming is required.

Parameters:

Name Type Description Default
paraxial bool

center (True) or edge (False).

False

Returns:

Name Type Description
avg_pupilz float

z coordinate of exit pupil.

avg_pupilr float

radius of exit pupil.

Reference

[1] Exit pupil: how many rays can come from sensor to object space. [2] https://en.wikipedia.org/wiki/Exit_pupil

calc_entrance_pupil
calc_entrance_pupil(paraxial=False)

Calculate entrance pupil of the lens.

The entrance pupil is the optical image of the physical aperture stop, as seen through the optical elements in front of the stop. We sample backward rays from the aperture stop and trace them to the first surface, then find the intersection points of the reverse extension of the rays. The average of the intersection points defines the entrance pupil position and radius.

Parameters:

Name Type Description Default
paraxial bool

Ray sampling mode. If True, rays are emitted near the centre of the aperture stop (fast, paraxially stable). If False, rays are emitted from the stop edge in larger quantities (slower, accounts for aperture aberrations). Defaults to False.

False

Returns:

Name Type Description
tuple

(z_position, radius) of entrance pupil.

Note

[1] Use paraxial mode unless precise ray aiming is required. [2] This function only works for object at a far distance. For microscopes, this function usually returns a negative entrance pupil.

References

[1] Entrance pupil: how many rays can come from object space to sensor. [2] https://en.wikipedia.org/wiki/Entrance_pupil: "In an optical system, the entrance pupil is the optical image of the physical aperture stop, as 'seen' through the optical elements in front of the stop." [3] Zemax LLC, OpticStudio User Manual, Version 19.4, Document No. 2311, 2019.

compute_intersection_points_2d staticmethod
compute_intersection_points_2d(origins, directions)

Compute the intersection points of 2D lines.

Parameters:

Name Type Description Default
origins Tensor

Origins of the lines. Shape: [N, 2]

required
directions Tensor

Directions of the lines. Shape: [N, 2]

required

Returns:

Type Description

torch.Tensor: Intersection points. Shape: [N*(N-1)/2, 2]

refocus
refocus(foc_dist=float('inf'))

Refocus the lens to a depth distance by changing sensor position.

Parameters:

Name Type Description Default
foc_dist float

focal distance.

float('inf')
Note

In DSLR, phase detection autofocus (PDAF) is a popular and efficient method. But here we simplify the problem by calculating the in-focus position of green light.

set_fnum
set_fnum(fnum)

Set F-number and aperture radius using binary search.

Parameters:

Name Type Description Default
fnum float

target F-number.

required
set_target_fov_fnum
set_target_fov_fnum(rfov, fnum)

Set FoV, ImgH and F number, only use this function to assign design targets.

Parameters:

Name Type Description Default
rfov float

half diagonal-FoV in radian.

required
fnum float

F number.

required
set_fov
set_fov(rfov)

Set FoV. This function is used to assign design targets.

Parameters:

Name Type Description Default
rfov float

half diagonal-FoV in radian.

required
prune_surf
prune_surf(expand_factor=None)

Prune surfaces to allow all valid rays to go through.

Parameters:

Name Type Description Default
expand_factor float

height expansion factor. - For cellphone lens, we usually expand by 5% - For camera lens, we usually expand by 20%.

None
correct_shape
correct_shape(expand_factor=None)

Correct wrong lens shape during lens design optimization.

Applies correction rules to ensure valid lens geometry
  1. Move the first surface to z = 0.0
  2. Fix aperture distance if aperture is at the front
  3. Prune all surfaces to allow valid rays through

Parameters:

Name Type Description Default
expand_factor float

Height expansion factor for surface pruning. If None, auto-selects based on lens type. Defaults to None.

None

Returns:

Name Type Description
bool

True if any shape corrections were made, False otherwise.

match_materials
match_materials(mat_table='CDGM')

Match lens materials to a glass catalog.

Parameters:

Name Type Description Default
mat_table str

Glass catalog name. Common options include 'CDGM', 'SCHOTT', 'OHARA'. Defaults to 'CDGM'.

'CDGM'
analysis
analysis(save_name='./lens', depth=float('inf'), render=False, render_unwarp=False, lens_title=None, show=False)

Analyze the optical lens.

Parameters:

Name Type Description Default
save_name str

save name.

'./lens'
depth float

object depth distance.

float('inf')
render bool

whether render an image.

False
render_unwarp bool

whether unwarp the rendered image.

False
lens_title str

lens title

None
show bool

whether to show the rendered image.

False
get_optimizer_params
get_optimizer_params(lrs=[0.0001, 0.0001, 0.01, 0.0001], decay=0.01, optim_mat=False, optim_surf_range=None)

Get optimizer parameters for different lens surface.

Recommendation

For cellphone lens: [d, c, k, a], [1e-4, 1e-4, 1e-1, 1e-4] For camera lens: [d, c, 0, 0], [1e-3, 1e-4, 0, 0]

Parameters:

Name Type Description Default
lrs list

learning rate for different parameters.

[0.0001, 0.0001, 0.01, 0.0001]
decay float

decay rate for higher order a. Defaults to 0.01.

0.01
optim_mat bool

whether to optimize material. Defaults to False.

False
optim_surf_range list

surface indices to be optimized. Defaults to None.

None

Returns:

Name Type Description
list

optimizer parameters

get_optimizer
get_optimizer(lrs=[0.0001, 0.0001, 0.1, 0.0001], decay=0.01, optim_surf_range=None, optim_mat=False)

Get optimizers and schedulers for different lens parameters.

Parameters:

Name Type Description Default
lrs list

learning rate for different parameters [c, d, k, a]. Defaults to [1e-4, 1e-4, 0, 1e-4].

[0.0001, 0.0001, 0.1, 0.0001]
decay float

decay rate for higher order a. Defaults to 0.2.

0.01
optim_surf_range list

surface indices to be optimized. Defaults to None.

None
optim_mat bool

whether to optimize material. Defaults to False.

False

Returns:

Name Type Description
list

optimizer parameters

read_lens_json
read_lens_json(filename='./test.json')

Read the lens from a JSON file.

Loads lens configuration including surfaces, materials, and optical properties from the DeepLens native JSON format.

Parameters:

Name Type Description Default
filename str

Path to the JSON lens file. Defaults to './test.json'.

'./test.json'
Note

After loading, the lens is moved to self.device and post_computation is called to calculate derived properties.

write_lens_json
write_lens_json(filename='./test.json')

Write the lens to a JSON file.

Saves the complete lens configuration including all surfaces, materials, focal length, F-number, and sensor properties to the DeepLens JSON format.

Parameters:

Name Type Description Default
filename str

Path for the output JSON file. Defaults to './test.json'.

'./test.json'

HybridLens

Couples a GeoLens with a diffractive optical element (DOE). Uses a differentiable ray–wave pipeline: coherent ray tracing → DOE phase modulation → Angular Spectrum Method propagation to sensor.

import torch
from deeplens.optics import HybridLens

torch.set_default_dtype(torch.float64)   # required for wave optics
lens = HybridLens(filename='./datasets/lenses/hybrid/example.json', device='cuda')
lens.double()

# Access refractive and diffractive parts separately
print(lens.geolens.foclen)
print(type(lens.doe))   # Binary2 / Pixel2D / Fresnel / Zernike

Note

Operates in torch.float64 by default for numerical stability.

deeplens.optics.hybridlens.HybridLens

HybridLens(filename=None, device=None, dtype=torch.float64)

Bases: Lens

Hybrid refractive-diffractive lens using a differentiable ray–wave model.

Combines a :class:~deeplens.optics.geolens.GeoLens (refractive module) with a diffractive optical element (DOE) placed behind it. The pipeline is:

  1. Coherent ray tracing through the embedded GeoLens to obtain a complex wavefront at the DOE plane (including all geometric aberrations).
  2. DOE phase modulation applied to the wavefront.
  3. Angular Spectrum Method (ASM) propagation from the DOE to the sensor plane to produce the final intensity PSF.

This enables end-to-end gradient flow from image quality metrics back to both refractive surface parameters and the DOE phase profile.

Attributes:

Name Type Description
geolens GeoLens

Embedded refractive module.

doe

Diffractive optical element (one of Binary2, Pixel2D, Fresnel, Zernike, Grating).

Notes

Operates in torch.float64 by default for numerical stability of the wave-propagation step.

References

Xinge Yang et al., "End-to-End Hybrid Refractive-Diffractive Lens Design with Differentiable Ray-Wave Model," SIGGRAPH Asia 2024.

Initialize a hybrid refractive-diffractive lens.

Parameters:

Name Type Description Default
filename str

Path to the lens configuration JSON file. Defaults to None.

None
device str

Computation device ('cpu' or 'cuda'). Defaults to None.

None
dtype dtype

Data type for computations. Defaults to torch.float64.

float64
geolens instance-attribute
geolens = None
doe instance-attribute
doe = None
sensor_size instance-attribute
sensor_size = (8.0, 8.0)
sensor_res instance-attribute
sensor_res = (2000, 2000)
read_lens_json
read_lens_json(filename)

Read the lens configuration from a JSON file.

Loads a GeoLens and associated DOE from the specified file. Supported DOE types: binary2, pixel2d, fresnel, zernike, grating.

Parameters:

Name Type Description Default
filename str

Path to the JSON configuration file.

required
write_lens_json
write_lens_json(lens_path)

Write the lens configuration to a JSON file.

Saves the GeoLens and DOE configurations to a JSON file.

Parameters:

Name Type Description Default
lens_path str

Path for the output JSON file.

required
analysis
analysis(save_name='./test.png')

Perform lens analysis and save visualizations.

Draws the lens layout and DOE phase map.

Parameters:

Name Type Description Default
save_name str

Base path for saving analysis images. Defaults to './test.png'.

'./test.png'
double
double()

Convert lens to double precision (float64) for accurate phase calculations.

refocus
refocus(foc_dist)

Refocus the HybridLens to a given depth.

Adjusts the GeoLens focus distance. The DOE is not moved because it is installed with the geolens as described in the Siggraph Asia 2024 paper.

Parameters:

Name Type Description Default
foc_dist float

Target focus distance.

required
calc_scale
calc_scale(depth)

Calculate the scale factor for object-to-image mapping.

Parameters:

Name Type Description Default
depth float

Object depth distance.

required

Returns:

Name Type Description
float

Scale factor (object height / image height).

doe_field
doe_field(point, wvln=DEFAULT_WAVE, spp=SPP_COHERENT)

Compute the complex wave field at DOE plane using coherent ray tracing. This function re-implements geolens.pupil_field() by changing the computation position from pupil plane to the last surface (DOE). The wavefront stores information of all diffraction orders.

Parameters:

Name Type Description Default
point Tensor

Tensor of shape (3,) representing the point source position. Defaults to torch.tensor([0.0, 0.0, -10000.0]).

required
wvln float

Wavelength. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
spp int

Samples per pixel. Must be >= 1,000,000 for accurate simulation. Defaults to SPP_COHERENT.

SPP_COHERENT

Returns:

Name Type Description
wavefront

Tensor of shape [H, W] representing the complex wavefront.

psf_center

List containing the PSF center coordinates [x, y].

psf
psf(points=[0.0, 0.0, -10000.0], ks=PSF_KS, wvln=DEFAULT_WAVE, spp=SPP_COHERENT)

Single point monochromatic PSF using ray-wave model. The PSF contains all diffraction orders with correct diffraction efficiencies.

Steps

1, Calculate complex wavefield at DOE plane by coherent ray tracing. 2, Apply DOE phase modulation to the wavefield. 3, Propagate the wavefield to sensor plane, calculate intensity PSF, crop the valid region and normalize the intensity.

Parameters:

Name Type Description Default
points Tensor

[x, y, z] coordinates of the point source. Defaults to torch.Tensor([0,0,-10000]).

[0.0, 0.0, -10000.0]
ks int

size of the PSF patch. Defaults to PSF_KS.

PSF_KS
wvln float

wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
spp int

number of rays to sample. Defaults to SPP_COHERENT.

SPP_COHERENT

Returns:

Name Type Description
psf_out Tensor

PSF patch. Normalized to sum to 1. Shape [ks, ks]

draw_layout
draw_layout(save_name='./DOELens.png', depth=-10000.0, ax=None, fig=None)

Draw HybridLens layout with ray-tracing and wave-propagation visualization.

Shows the lens geometry with ray paths through the refractive elements and wave propagation arcs from the DOE to the sensor.

Parameters:

Name Type Description Default
save_name str

Path to save the figure. Defaults to './DOELens.png'.

'./DOELens.png'
depth float

Object depth for ray tracing. Defaults to -10000.0.

-10000.0
ax Axes

Existing axes to draw on. Defaults to None.

None
fig Figure

Existing figure to use. Defaults to None.

None

Returns:

Name Type Description
tuple

(ax, fig) if ax was provided, otherwise saves the figure.

get_optimizer
get_optimizer(doe_lr=0.0001, lens_lr=[0.0001, 0.0001, 0.01, 1e-05], lr_decay=0.01)

Get optimizer for lens and DOE parameters.

Parameters:

Name Type Description Default
doe_lr float

Learning rate for DOE parameters. Defaults to 1e-4.

0.0001
lens_lr list

Learning rates for lens parameters [d, c, k, a]. Defaults to [1e-4, 1e-4, 1e-2, 1e-5].

[0.0001, 0.0001, 0.01, 1e-05]
lr_decay float

Decay rate for higher-order coefficients. Defaults to 0.01.

0.01

Returns:

Type Description

torch.optim.Adam: Configured optimizer for all trainable parameters.

DiffractiveLens

Pure wave-optics lens where every element is a phase surface. Propagation uses scalar diffraction theory (ASM / Fresnel / Fraunhofer).

from deeplens.optics import DiffractiveLens

lens = DiffractiveLens(filename='./datasets/lenses/doe/doe_example.json', device='cuda')
# Or load a built-in example:
lens = DiffractiveLens.load_example1()

deeplens.optics.diffraclens.DiffractiveLens

DiffractiveLens(filename=None, device=None)

Bases: Lens

Paraxial diffractive lens in which each element is modelled as a phase surface.

Every optical element (converging lens, DOE, metasurface, …) is represented by a phase function applied to an incoming complex wavefront. Propagation between surfaces uses the Angular Spectrum Method (ASM). This model is simple and fast, but accurate only in the paraxial regime (it does not account for higher-order geometric aberrations).

Attributes:

Name Type Description
surfaces list

Ordered list of diffractive/phase surfaces.

d_sensor Tensor

Distance from the last surface to the sensor plane [mm].

Notes

Operates in torch.float64 by default for numerical stability of the wave-propagation step.

Initialize a diffractive lens.

Parameters:

Name Type Description Default
filename str

Path to the lens configuration JSON file. If provided, loads the lens configuration from file. Defaults to None.

None
device str

Computation device ('cpu' or 'cuda'). Defaults to 'cpu'.

None
surfaces instance-attribute
surfaces = []
sensor_size instance-attribute
sensor_size = (8.0, 8.0)
sensor_res instance-attribute
sensor_res = (2000, 2000)
load_example1 classmethod
load_example1()

Create an example diffractive lens with a single Fresnel DOE.

Returns:

Name Type Description
DiffractiveLens

A configured diffractive lens with a Fresnel surface at f=50mm, 4mm size, and 4000 resolution.

load_example2 classmethod
load_example2()

Create an example diffractive lens with a thin lens and binary DOE combination.

Returns:

Name Type Description
DiffractiveLens

A configured diffractive lens with a ThinLens (f=50mm) and a Binary2 DOE, both at 4mm size and 4000 resolution.

read_lens_json
read_lens_json(filename)

Load the lens configuration from a JSON file.

Reads lens parameters including sensor configuration and diffractive surfaces from the specified JSON file. If sensor_size or sensor_res are not provided, defaults of 8mm x 8mm and 2000x2000 pixels will be used.

Parameters:

Name Type Description Default
filename str

Path to the JSON configuration file.

required
write_lens_json
write_lens_json(filename)

Write the lens configuration to a JSON file.

Saves all lens parameters including sensor configuration and diffractive surface data to the specified file.

Parameters:

Name Type Description Default
filename str

Output path for the JSON file.

required
__call__
__call__(wave)

Propagate a wave through the lens system.

forward
forward(wave)

Propagate a wave through the diffractive lens system to the sensor.

Sequentially applies phase modulation from each diffractive surface, then propagates the wave to the sensor plane using wave optics.

Parameters:

Name Type Description Default
wave ComplexWave

Input wave field entering the lens system.

required

Returns:

Name Type Description
ComplexWave

Output wave field at the sensor plane.

render_mono
render_mono(img, wvln=DEFAULT_WAVE, ks=PSF_KS)

Simulate monochromatic lens blur by convolving an image with the point spread function.

Parameters:

Name Type Description Default
img Tensor

Input image. Shape: (B, 1, H, W)

required
wvln float

Wavelength. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
ks int

PSF kernel size. Defaults to PSF_KS.

PSF_KS

Returns:

Type Description

torch.Tensor: Rendered image after applying lens blur with shape (B, 1, H, W).

psf
psf(depth=float('inf'), wvln=DEFAULT_WAVE, ks=PSF_KS, upsample_factor=1)

Calculate monochromatic point PSF by wave propagation approach.

Parameters:

Name Type Description Default
depth float

Depth of the point source. Defaults to float('inf').

float('inf')
wvln float

Wavelength in micrometers. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
ks int

PSF kernel size. Defaults to PSF_KS.

PSF_KS
upsample_factor int

Upsampling factor to meet Nyquist sampling constraint. Defaults to 1.

1

Returns:

Name Type Description
psf_out tensor

PSF. shape [ks, ks]

Note

[1] Usually we only consider the on-axis PSF because paraxial approximation is implicitly applied for wave optical model. For the shifted phase issue, refer to "Modeling off-axis diffraction with the least-sampling angular spectrum method".

draw_layout
draw_layout(save_name='./doelens.png')

Draw the lens layout diagram.

Visualizes the DOE and sensor positions in a 2D layout.

Parameters:

Name Type Description Default
save_name str

Path to save the figure. Defaults to './doelens.png'.

'./doelens.png'
draw_psf
draw_psf(depth=DEPTH, ks=PSF_KS, save_name='./psf_doelens.png', log_scale=True, eps=0.0001)

Draw on-axis RGB PSF.

Computes and saves a visualization of the RGB PSF for a given depth.

Parameters:

Name Type Description Default
depth float

Depth of the point source. Defaults to DEPTH.

DEPTH
ks int

Size of the PSF kernel in pixels. Defaults to PSF_KS.

PSF_KS
save_name str

Path to save the PSF image. Defaults to './psf_doelens.png'.

'./psf_doelens.png'
log_scale bool

If True, display PSF in log scale. Defaults to True.

True
eps float

Small value for log scale to avoid log(0). Defaults to 1e-4.

0.0001
get_optimizer
get_optimizer(lr)

Get optimizer for the lens parameters.

Parameters:

Name Type Description Default
lr float

Learning rate.

required

Returns:

Name Type Description
Optimizer

Optimizer object for lens parameters.

ParaxialLens

Thin-lens / ABCD-matrix model for fast defocus (circle-of-confusion) simulation. Does not model higher-order aberrations.

from deeplens.optics import ParaxialLens

lens = ParaxialLens(
    foclen=50.0,             # focal length [mm]
    fnum=1.8,                # F-number
    sensor_size=(36.0, 24.0),
    sensor_res=(2000, 2000),
    device='cuda'
)
lens.refocus(foc_dist=-1000.0)
img_blurred = lens.render(img, depth=-2000.0)

deeplens.optics.paraxiallens.ParaxialLens

ParaxialLens(foclen, fnum, sensor_size=None, sensor_res=None, device='cpu')

Bases: Lens

Thin-lens / ABCD-matrix model for fast defocus simulation.

Models the circle of confusion (CoC) caused by defocus but not higher-order optical aberrations. Useful as a fast baseline renderer for depth-of-field effects, as commonly used in Blender and similar tools.

Attributes:

Name Type Description
foclen float

Focal length [mm].

fnum float

F-number.

sensor_size tuple

Physical sensor size (W, H) [mm].

sensor_res tuple

Pixel resolution (W, H).

pixel_size float

Pixel pitch [mm].

Initialize a paraxial lens.

Parameters:

Name Type Description Default
foclen float

Focal length in [mm].

required
fnum float

F-number.

required
sensor_size tuple

Physical sensor size as (W, H) in [mm]. Defaults to (8.0, 8.0).

None
sensor_res tuple

Sensor resolution as (W, H) in pixels. Defaults to (2000, 2000).

None
device str

Computation device. Defaults to "cpu".

'cpu'
foclen instance-attribute
foclen = foclen
fnum instance-attribute
fnum = fnum
sensor_size instance-attribute
sensor_size = sensor_size
sensor_res instance-attribute
sensor_res = sensor_res
pixel_size instance-attribute
pixel_size = sensor_size[0] / sensor_res[0]
d_far instance-attribute
d_far = -20000.0
d_close instance-attribute
d_close = -200.0
refocus
refocus(foc_dist)

Refocus the lens to the given focus distance.

psf
psf(points, ks=PSF_KS, psf_type='gaussian', **kwargs)

PSF is modeled as a 2D uniform circular disk with diameter CoC.

Parameters:

Name Type Description Default
points Tensor

Points of the object. Shape [N, 3] or [3].

required
ks int

Kernel size.

PSF_KS
psf_type str

PSF type. "gaussian" or "pillbox".

'gaussian'
**kwargs

Additional arguments for psf(). Currently not used.

{}

Returns:

Name Type Description
psf Tensor

PSF kernels. Shape [ks, ks] or [N, ks, ks].

coc
coc(depth)

Calculate circle of confusion (CoC) [mm].

Parameters:

Name Type Description Default
depth Tensor

Depth of the object. Shape [B].

required

Returns:

Name Type Description
coc Tensor

Circle of confusion. Shape [B].

Reference

[1] https://en.wikipedia.org/wiki/Circle_of_confusion

dof
dof(depth)

Calculate depth of field [mm].

Parameters:

Name Type Description Default
depth Tensor

Depth of the object. Shape [B].

required

Returns:

Name Type Description
dof Tensor

Depth of field. Shape [B].

Reference

[1] https://en.wikipedia.org/wiki/Depth_of_field

psf_rgb
psf_rgb(points, ks=PSF_KS, **kwargs)

Compute RGB PSF.

psf_map
psf_map(grid=(5, 5), ks=PSF_KS, depth=DEPTH, **kwargs)

Compute monochrome PSF map.

psf_dp
psf_dp(points, ks=PSF_KS)

Generate dual-pixel PSF for left and right sub-apertures.

This function generates separate PSFs for left and right sub-apertures of a dual pixel sensor, which enables depth estimation and improved autofocus capabilities.

Parameters:

Name Type Description Default
points Tensor

Input tensor with shape [N, 3], where columns are [x, y, z] coordinates.

required
ks int

Kernel size for PSF generation.

PSF_KS

Returns:

Name Type Description
tuple

(left_psf, right_psf) where each PSF tensor has shape [N, ks, ks].

psf_rgb_dp
psf_rgb_dp(points, ks=PSF_KS)

Compute RGB dual-pixel PSF.

psf_map_dp
psf_map_dp(grid=(5, 5), ks=PSF_KS, depth=DEPTH, **kwargs)

Compute dual-pixel PSF map.

render_rgbd
render_rgbd(img_obj, depth_map, method='psf_patch', **kwargs)

Occlusion-aware RGBD rendering for paraxial lens.

Uses back-to-front layered compositing to prevent color bleeding at depth discontinuities. Since paraxial lenses have no spatially varying aberrations, all methods (psf_patch, psf_map, psf_pixel) produce identical results; the method parameter is accepted for API compatibility but ignored.

Parameters:

Name Type Description Default
img_obj tensor

Object image. Shape [B, C, H, W].

required
depth_map tensor

Depth map [mm]. Shape [B, 1, H, W]. Values should be positive.

required
method str

Ignored (no spatial variation). Defaults to "psf_patch".

'psf_patch'
**kwargs

Additional keyword arguments: - psf_ks (int): PSF kernel size. Defaults to PSF_KS. - num_layers (int): Number of depth layers. Defaults to 16. - depth_min (float): Minimum depth. Defaults to depth_map.min(). - depth_max (float): Maximum depth. Defaults to depth_map.max().

{}

Returns:

Name Type Description
img_render tensor

Rendered image. Shape [B, C, H, W].

Reference

[1] "Dr.Bokeh: DiffeRentiable Occlusion-aware Bokeh Rendering", CVPR 2024.

render_rgbd_dp
render_rgbd_dp(rgb_img, depth)

Render RGBD image with dual-pixel PSF.

Parameters:

Name Type Description Default
rgb_img tensor

[B, 3, H, W]

required
depth tensor

[B, 1, H, W]

required

Returns:

Name Type Description
img_left tensor

[B, 3, H, W]

img_right tensor

[B, 3, H, W]

PSFNetLens

Neural surrogate wrapping a GeoLens with an MLP that predicts PSFs directly from (fov, depth, focus_distance). Provides ~100× speedup after a one-time training phase.

from deeplens import PSFNetLens

lens = PSFNetLens(
    lens_path='./datasets/lenses/camera/ef50mm_f1.8.json',
    in_chan=3, psf_chan=3, model_name='mlp_conv', kernel_size=64
)
lens.train_psfnet(iters=100000, spp=16384)   # one-time training
lens.load_net('./ckpts/psfnet/PSFNet_ef50mm.pth')

psf_rgb = lens.psf_rgb(points=torch.tensor([[0.0, 0.0, -10000.0]]), ks=64)

deeplens.optics.psfnetlens.PSFNetLens

PSFNetLens(lens_path, in_chan=3, psf_chan=3, model_name='mlp_conv', kernel_size=64)

Bases: Lens

Neural surrogate lens that predicts PSFs via a small MLP/MLPConv network.

Wraps a :class:~deeplens.optics.geolens.GeoLens with a neural network trained to predict RGB PSFs from (fov, depth, focus_distance) inputs. After training, PSF prediction is ~100× faster than ray tracing, making it suitable for real-time applications and large-scale optimisation.

Attributes:

Name Type Description
lens GeoLens

The underlying refractive lens (used for training data generation and for sensor metadata).

psfnet Module

Neural network for PSF prediction.

pixel_size float

Pixel pitch [mm] (copied from the embedded lens).

rfov float

Half-diagonal field of view [radians].

Notes

Use :meth:train_psfnet to train the surrogate from ray-traced PSF samples. Use :meth:load_net to load pre-trained weights.

Initialize a PSF network lens.

In the default settings, the PSF network takes (fov, depth, foc_dist) as input and outputs RGB PSF on y-axis at (fov, depth, foc_dist).

Parameters:

Name Type Description Default
lens_path str

Path to the lens file.

required
in_chan int

Number of input channels.

3
psf_chan int

Number of output channels.

3
model_name str

Name of the model.

'mlp_conv'
kernel_size int

Kernel size.

64
lens_path instance-attribute
lens_path = lens_path
lens instance-attribute
lens = GeoLens(filename=lens_path, device=device)
rfov instance-attribute
rfov = rfov
in_chan instance-attribute
in_chan = in_chan
psf_chan instance-attribute
psf_chan = psf_chan
kernel_size instance-attribute
kernel_size = kernel_size
pixel_size instance-attribute
pixel_size = pixel_size
psfnet instance-attribute
psfnet = init_net(in_chan=in_chan, psf_chan=psf_chan, kernel_size=kernel_size, model_name=model_name)
d_close instance-attribute
d_close = -200
d_far instance-attribute
d_far = -20000
foc_d_close instance-attribute
foc_d_close = -500
foc_d_far instance-attribute
foc_d_far = -20000
set_sensor_res
set_sensor_res(sensor_res)

Set sensor resolution for both PSFNetLens and the embedded GeoLens.

init_net
init_net(in_chan=2, psf_chan=3, kernel_size=64, model_name='mlpconv')

Initialize a PSF network.

PSF network

Input: [B, 3], (fov, depth, foc_dist). fov from [0, pi/2], depth from [-20000, -100], foc_dist from [-20000, -500] Output: psf kernel [B, 3, ks, ks]

Parameters:

Name Type Description Default
in_chan int

number of input channels

2
psf_chan int

number of output channels

3
kernel_size int

kernel size

64
model_name str

name of the network architecture

'mlpconv'

Returns:

Name Type Description
psfnet Module

network

load_net
load_net(net_path)

Load pretrained network.

Parameters:

Name Type Description Default
net_path str

path to load the network

required
save_psfnet
save_psfnet(psfnet_path)

Save the PSF network.

Parameters:

Name Type Description Default
psfnet_path str

path to save the PSF network

required
train_psfnet
train_psfnet(iters=100000, bs=128, lr=5e-05, evaluate_every=500, spp=16384, concentration_factor=2.0, result_dir='./results/psfnet')

Train the PSF surrogate network.

Parameters:

Name Type Description Default
iters int

number of training iterations

100000
bs int

batch size

128
lr float

learning rate

5e-05
evaluate_every int

evaluate every how many iterations

500
spp int

number of samples per pixel

16384
concentration_factor float

concentration factor for training data sampling

2.0
result_dir str

directory to save the results

'./results/psfnet'
sample_training_data
sample_training_data(num_points=512, concentration_factor=2.0)

Sample training data for PSF surrogate network.

Parameters:

Name Type Description Default
num_points int

number of training points

512
concentration_factor float

concentration factor for training data sampling

2.0

Returns:

Name Type Description
sample_input tensor

[B, 3] tensor, (fov, depth, foc_dist). - fov from [0, rfov] on 0y-axis, [radians] - depth from [d_far, d_close], [mm] - foc_dist from [foc_d_far, foc_d_close], [mm] - We use absolute fov and depth.

sample_psf tensor

[B, 3, ks, ks] tensor

eval
eval()

Set the network to evaluation mode.

points2input
points2input(points)

Convert points to input tensor.

Parameters:

Name Type Description Default
points tensor

[N, 3] tensor, [-1, 1] * [-1, 1] * [depth_min, depth_max]

required

Returns:

Name Type Description
input tensor

[N, 3] tensor, (fov, depth, foc_dist). - fov from [0, rfov] on y-axis, [radians] - depth/1000.0 from [d_far, d_close], [mm] - foc_dist/1000.0 from [foc_d_far, foc_d_close], [mm]

refocus
refocus(foc_dist)

Refocus the lens to the given focus distance.

psf_rgb
psf_rgb(points, ks=64)

Calculate RGB PSF using the PSF network.

Parameters:

Name Type Description Default
points tensor

[N, 3] tensor, [-1, 1] * [-1, 1] * [depth_min, depth_max]

required
foc_dist float

focus distance

required

Returns:

Name Type Description
psf tensor

[N, 3, ks, ks] tensor

psf_map_rgb
psf_map_rgb(grid=(11, 11), depth=DEPTH, ks=PSF_KS, **kwargs)

Compute monochrome PSF map.

Parameters:

Name Type Description Default
grid tuple

Grid size. Defaults to (11, 11), meaning 11x11 grid.

(11, 11)
wvln float

Wavelength. Defaults to DEFAULT_WAVE.

required
depth float

Depth of the object. Defaults to DEPTH.

DEPTH
ks int

Kernel size. Defaults to PSF_KS, meaning PSF_KS x PSF_KS kernel size.

PSF_KS

Returns:

Name Type Description
psf_map

Shape of [grid, grid, 3, ks, ks].

render_rgbd
render_rgbd(img, depth, foc_dist, ks=64, high_res=False)

Render image with aif image and depth map. Receive [N, C, H, W] image.

Parameters:

Name Type Description Default
img tensor

[1, C, H, W]

required
depth tensor

[1, H, W], depth map, unit in mm, range from [-20000, -200]

required
foc_dist tensor

[1], unit in mm, range from [-20000, -200]

required
ks int

kernel size

64
high_res bool

whether to use high resolution rendering

False

Returns:

Name Type Description
render tensor

[1, C, H, W]


GeoLens Mixins

GeoLens inherits from six mixin classes, each handling one aspect of its functionality.

GeoLensEval — Evaluation

Spot diagrams, MTF curves, vignetting maps, distortion grids.

deeplens.optics.geolens_pkg.eval.GeoLensEval

Mixin providing classical optical performance evaluation for GeoLens.

Provides spot diagrams, RMS error maps, MTF curves, distortion analysis, vignetting, and field curvature — results are accuracy-aligned with Zemax OpticStudio.

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

draw_spot_radial
draw_spot_radial(save_name='./lens_spot_radial.png', num_fov=5, depth=float('inf'), num_rays=SPP_PSF, wvln_list=WAVE_RGB, show=False)

Draw spot diagram of the lens at different field angles along meridional (y) direction.

Parameters:

Name Type Description Default
save_name string

filename to save. Defaults to "./lens_spot_radial.png".

'./lens_spot_radial.png'
num_fov int

field of view number. Defaults to 4.

5
depth float

depth of the point source. Defaults to float("inf").

float('inf')
num_rays int

number of rays to sample. Defaults to SPP_PSF.

SPP_PSF
wvln_list list

wavelength list to render.

WAVE_RGB
show bool

whether to show the plot. Defaults to False.

False
draw_spot_map
draw_spot_map(save_name='./lens_spot_map.png', num_grid=5, depth=DEPTH, num_rays=SPP_PSF, wvln_list=WAVE_RGB, show=False)

Draw spot diagram of the lens at different field angles.

Parameters:

Name Type Description Default
save_name string

filename to save. Defaults to "./lens_spot_map.png".

'./lens_spot_map.png'
num_grid int

number of grid points. Defaults to 5.

5
depth float

depth of the point source. Defaults to DEPTH.

DEPTH
num_rays int

number of rays to sample. Defaults to SPP_PSF.

SPP_PSF
wvln_list list

wavelength list to render. Defaults to WAVE_RGB.

WAVE_RGB
show bool

whether to show the plot. Defaults to False.

False
rms_map_rgb
rms_map_rgb(num_grid=32, depth=DEPTH)

Calculate the RMS spot error map across RGB wavelengths. Reference to the centroid of green rays.

Parameters:

Name Type Description Default
num_grid int

Number of grid points. Defaults to 64.

32
depth float

Depth of the point source. Defaults to DEPTH.

DEPTH

Returns:

Name Type Description
rms_map Tensor

RMS map for RGB channels. Shape [3, num_grid, num_grid].

rms_map
rms_map(num_grid=32, depth=DEPTH, wvln=DEFAULT_WAVE)

Calculate the RMS spot error map for a specific wavelength.

Currently this function is not used, but it can be used as the weight mask during optimization.

Parameters:

Name Type Description Default
num_grid int

Resolution of the grid used for sampling fields/points. Defaults to 64.

32
depth float

Depth of the point source. Defaults to DEPTH.

DEPTH
wvln float

Wavelength of the ray. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE

Returns:

Name Type Description
rms_map Tensor

RMS map for the specified wavelength. Shape [num_grid, num_grid].

calc_distortion_2D
calc_distortion_2D(rfov, wvln=DEFAULT_WAVE, plane='meridional', ray_aiming=True)

Calculate distortion at a specific field angle.

Parameters:

Name Type Description Default
rfov float

view angle (degree)

required
wvln float

wavelength

DEFAULT_WAVE
plane str

meridional or sagittal

'meridional'
ray_aiming bool

whether the chief ray through the center of the stop.

True

Returns:

Name Type Description
distortion float

distortion at the specific field angle

draw_distortion_radial
draw_distortion_radial(rfov, save_name=None, num_points=GEO_GRID, wvln=DEFAULT_WAVE, plane='meridional', ray_aiming=True, show=False)

Draw distortion. zemax format(default): ray_aiming = False.

Note: this function is provided by a community contributor.

Parameters:

Name Type Description Default
rfov

view angle (degrees)

required
save_name

Save filename. Defaults to None.

None
num_points

Number of points. Defaults to GEO_GRID.

GEO_GRID
plane

Meridional or sagittal. Defaults to meridional.

'meridional'
ray_aiming

Whether to use ray aiming. Defaults to False.

True
distortion_map
distortion_map(num_grid=16, depth=DEPTH, wvln=DEFAULT_WAVE)

Compute distortion map at a given depth.

Parameters:

Name Type Description Default
num_grid int

number of grid points.

16
depth float

depth of the point source.

DEPTH
wvln float

wavelength.

DEFAULT_WAVE

Returns:

Name Type Description
distortion_grid Tensor

distortion map. shape (grid_size, grid_size, 2)

distortion_center
distortion_center(points)

Calculate the distortion center for given normalized points.

Parameters:

Name Type Description Default
points

Normalized point source positions. Shape [N, 3] or [..., 3]. x, y in [-1, 1], z (depth) in [-Inf, 0].

required

Returns:

Name Type Description
distortion_center

Normalized distortion center positions. Shape [N, 2] or [..., 2]. x, y in [-1, 1].

draw_distortion
draw_distortion(save_name=None, num_grid=16, depth=DEPTH, wvln=DEFAULT_WAVE, show=False)

Draw distortion map.

Parameters:

Name Type Description Default
save_name str

filename to save. Defaults to None.

None
num_grid int

number of grid points. Defaults to 16.

16
depth float

depth of the point source. Defaults to DEPTH.

DEPTH
wvln float

wavelength. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
show bool

whether to show the plot. Defaults to False.

False
mtf
mtf(fov, wvln=DEFAULT_WAVE)

Calculate MTF at a specific field of view.

psf2mtf staticmethod
psf2mtf(psf, pixel_size)

Calculate MTF from PSF.

Parameters:

Name Type Description Default
psf tensor

2D PSF tensor (e.g., ks x ks). Assumes standard orientation where the array's y-axis corresponds to the tangential/meridional direction and the x-axis to the sagittal direction.

required
pixel_size float

Pixel size in mm.

required

Returns:

Name Type Description
freq ndarray

Frequency axis (cycles/mm).

tangential_mtf ndarray

Tangential MTF.

sagittal_mtf ndarray

Sagittal MTF.

Reference

[1] https://en.wikipedia.org/wiki/Optical_transfer_function [2] https://www.edmundoptics.com/knowledge-center/application-notes/optics/introduction-to-modulation-transfer-function/?srsltid=AfmBOoq09vVDVlh_uuwWnFoMTg18JVgh18lFSw8Ci4Sdlry-AmwGkfDd

draw_mtf
draw_mtf(save_name='./lens_mtf.png', relative_fov_list=[0.0, 0.7, 1.0], depth_list=[DEPTH], psf_ks=128, show=False)

Draw a grid of MTF curves. Each subplot in the grid corresponds to a specific (depth, FOV) combination. Each subplot displays MTF curves for R, G, B wavelengths.

Parameters:

Name Type Description Default
relative_fov_list list

List of relative field of view values. Defaults to [0.0, 0.7, 1.0].

[0.0, 0.7, 1.0]
depth_list list

List of depth values. Defaults to [DEPTH].

[DEPTH]
save_name str

Filename to save the plot. Defaults to "./mtf_grid.png".

'./lens_mtf.png'
psf_ks int

Kernel size for intermediate PSF calculation. Defaults to 256.

128
show bool

whether to show the plot. Defaults to False.

False
draw_field_curvature
draw_field_curvature(save_name=None, num_points=32, z_span=1.0, z_steps=1001, wvln_list=WAVE_RGB, spp=SPP_CALC, show=False)

Draw field curvature: best-focus defocus Δz (mm) vs field angle (deg), RGB overlaid.

  • Tangential (meridional) curves are solid lines (y-axis spread minimized).
vignetting
vignetting(depth=DEPTH, num_grid=64)

Compute vignetting.

draw_vignetting
draw_vignetting(filename=None, depth=DEPTH, resolution=512, show=False)

Draw vignetting.

wavefront_error
wavefront_error()

Compute wavefront error.

field_curvature
field_curvature()

Compute field curvature.

aberration_histogram
aberration_histogram()

Compute aberration histogram.

calc_chief_ray
calc_chief_ray(fov, plane='sagittal')

Compute chief ray for an incident angle.

If chief ray is only used to determine the ideal image height, we can warp this function into the image height calculation function.

Parameters:

Name Type Description Default
fov float

incident angle in degree.

required
plane str

"sagittal" or "meridional".

'sagittal'

Returns:

Name Type Description
chief_ray_o Tensor

origin of chief ray.

chief_ray_d Tensor

direction of chief ray.

Note

It is 2D ray tracing, for 3D chief ray, we can shrink the pupil, trace rays, calculate the centroid as the chief ray.

calc_chief_ray_infinite
calc_chief_ray_infinite(rfov, depth=0.0, wvln=DEFAULT_WAVE, plane='meridional', num_rays=SPP_CALC, ray_aiming=True)

Compute chief ray for an incident angle.

Parameters:

Name Type Description Default
rfov float

incident angle in degree.

required
depth float

depth of the object.

0.0
wvln float

wavelength of the light.

DEFAULT_WAVE
plane str

"sagittal" or "meridional".

'meridional'
num_rays int

number of rays.

SPP_CALC
ray_aiming bool

whether the chief ray through the center of the stop.

True

GeoLensOptim — Optimization

Loss functions (RMS spot, wavefront error), physical constraints, optimizer helpers.

# RMS-based optimisation loop
optimizer = lens.get_optimizer(lrs=[1e-3, 1e-4, 1e-1, 1e-4], decay=0.01)
for epoch in range(1000):
    optimizer.zero_grad()
    loss = lens.loss_rms(num_grid=9, depth=-10000.0, num_rays=2048)
    loss_reg, _ = lens.loss_reg()
    (loss + 0.05 * loss_reg).backward()
    optimizer.step()

deeplens.optics.geolens_pkg.optim.GeoLensOptim

Mixin providing differentiable optimisation for GeoLens.

Implements gradient-based lens design using PyTorch autograd:

  • Loss functions – RMS spot error, focus, surface regularity, gap constraints, material validity.
  • Constraint initialisation – edge-thickness and self-intersection guards.
  • Optimizer helpers – parameter groups with per-type learning rates and cosine annealing schedules.
  • High-level optimize() – curriculum-learning training loop.

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

References

Xinge Yang et al., "Curriculum learning for ab initio deep learned refractive optics," Nature Communications 2024.

init_constraints
init_constraints(constraint_params=None)

Initialize constraints for the lens design.

Parameters:

Name Type Description Default
constraint_params dict

Constraint parameters.

None
loss_reg
loss_reg(w_focus=10.0, w_ray_angle=2.0, w_intersec=1.0, w_gap=0.1, w_surf=1.0)

Regularization loss for lens design.

loss_infocus
loss_infocus(target=0.005)

Sample parallel rays and compute RMS loss on the sensor plane, minimize focus loss.

Parameters:

Name Type Description Default
target float

target of RMS loss. Defaults to 0.005 [mm].

0.005
loss_surface
loss_surface()

Penalize surface shape: 1. Penalize maximum sag 2. Penalize diameter to thickness ratio 3. Penalize thick_max to thick_min ratio 4. Penalize diameter to thickness ratio 5. Penalize maximum to minimum thickness ratio

loss_intersec
loss_intersec()

Loss function to avoid self-intersection.

This function penalizes when surfaces are too close to each other, which could cause self-intersection or manufacturing issues.

loss_gap
loss_gap()

Loss function to penalize too large air gap and thickness.

This function penalizes when air gaps or lens thicknesses are too large, which could make the lens system impractically large.

loss_ray_angle
loss_ray_angle()

Loss function to penalize large chief ray angle.

loss_mat
loss_mat()
loss_rms
loss_rms(num_grid=GEO_GRID, depth=DEPTH, num_rays=SPP_PSF, sample_more_off_axis=False)

Loss function to compute RGB spot error RMS.

Parameters:

Name Type Description Default
num_grid int

Number of grid points. Defaults to GEO_GRID.

GEO_GRID
depth float

Depth of the lens. Defaults to DEPTH.

DEPTH
num_rays int

Number of rays. Defaults to SPP_CALC.

SPP_PSF
sample_more_off_axis bool

Whether to sample more off-axis rays. Defaults to False.

False

Returns:

Name Type Description
avg_rms_error Tensor

RMS error averaged over wavelengths and grid points.

sample_ring_arm_rays
sample_ring_arm_rays(num_ring=8, num_arm=8, spp=2048, depth=DEPTH, wvln=DEFAULT_WAVE, scale_pupil=1.0, sample_more_off_axis=True)

Sample rays from object space using a ring-arm pattern.

This method distributes sampling points (origins of ray bundles) on a polar grid in the object plane, defined by field of view. This is useful for capturing lens performance across the full field. The points include the center and num_ring rings with num_arm points on each.

Parameters:

Name Type Description Default
num_ring int

Number of rings to sample in the field of view.

8
num_arm int

Number of arms (spokes) to sample for each ring.

8
spp int

Total number of rays to be sampled, distributed among field points.

2048
depth float

Depth of the object plane.

DEPTH
wvln float

Wavelength of the rays.

DEFAULT_WAVE
scale_pupil float

Scale factor for the pupil size.

1.0

Returns:

Name Type Description
Ray

A Ray object containing the sampled rays.

optimize
optimize(lrs=[0.001, 0.0001, 0.1, 0.0001], decay=0.01, iterations=5000, test_per_iter=100, centroid=False, optim_mat=False, shape_control=True, result_dir=None)

Optimize the lens by minimizing rms errors.

Debug hints

1, Slowly optimize with small learning rate 2, FOV and thickness should match well 3, Reasonable parameter range 4, Aspheric order higher is better but also more sensitive 5, More iterations with larger ray sampling

GeoLensIO — File I/O

Read/write JSON and Zemax .zmx lens files.

lens = GeoLens(filename='lens.json')          # load JSON
lens = GeoLens(filename='lens.zmx')           # load Zemax
lens.write_lens_json('optimized.json')        # save

deeplens.optics.geolens_pkg.io.GeoLensIO

Mixin providing file I/O for GeoLens.

Supports reading and writing lens prescriptions in three formats:

  • JSON (primary): human-readable, supports parenthesised optimisable parameters, e.g. "(d)": 5.0.
  • Zemax .zmx: industry-standard sequential lens file.
  • Code V .seq: Code V sequential format (read-only).

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

read_lens_zmx
read_lens_zmx(filename='./test.zmx')

Load the lens from .zmx file.

write_lens_zmx
write_lens_zmx(filename='./test.zmx')

Write the lens into .zmx file.

read_lens_seq
read_lens_seq(filename='./test.seq')

Load the lens from CODE V .seq file.

write_lens_seq
write_lens_seq(filename='./test.seq')

Write the lens into CODE V .seq file.

GeoLensTolerance — Tolerance Analysis

Monte-Carlo and sensitivity tolerance analysis.

deeplens.optics.geolens_pkg.tolerance.GeoLensTolerance

Mixin providing tolerance analysis for GeoLens.

Implements two complementary approaches:

  • Sensitivity analysis – first-order gradient-based estimation of how each manufacturing error affects optical performance.
  • Monte-Carlo analysis – statistical sampling of random manufacturing errors to predict yield and worst-case performance.

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

References

Jun Dai et al., "Tolerance-Aware Deep Optics," arXiv:2502.04719, 2025.

init_tolerance
init_tolerance(tolerance_params=None)

Initialize tolerance parameters for the lens.

sample_tolerance
sample_tolerance()

Sample a random manufacturing error for the lens.

zero_tolerance
zero_tolerance()

Clear manufacturing error for the lens.

tolerancing_sensitivity
tolerancing_sensitivity(tolerance_params=None)

Use sensitivity analysis (1st order gradient) to compute the tolerance score.

References

[1] Page 10 from: https://wp.optics.arizona.edu/optomech/wp-content/uploads/sites/53/2016/08/8-Tolerancing-1.pdf [2] Fast sensitivity control method with differentiable optics. Optics Express 2025. [3] Optical Design Tolerancing. CODE V.

tolerancing_monte_carlo
tolerancing_monte_carlo(trials=1000, tolerance_params=None)

Use Monte Carlo simulation to compute the tolerance.

Note: we can multiplex sampled rays to improve the speed.

Parameters:

Name Type Description Default
trials int

Number of Monte Carlo trials

1000
tolerance_params dict

Tolerance parameters

None

Returns:

Name Type Description
dict

Monte Carlo tolerance analysis results

References

[1] https://optics.ansys.com/hc/en-us/articles/43071088477587-How-to-analyze-your-tolerance-results [2] Optical Design Tolerancing. CODE V.

tolerancing_wavefront
tolerancing_wavefront(tolerance_params=None)

Use wavefront differential method to compute the tolerance.

Wavefront differential method is proposed in [1], while the detailed implementation remains unknown. I (Xinge Yang) assume a symbolic differentiation is used to compute the gradient/Jacobian of the wavefront error. With AutoDiff, we can easily calculate Jacobian with gradient backpropagation, therefore I leave the implementation of this method as future work.

Parameters:

Name Type Description Default
tolerance_params dict

Tolerance parameters

None

Returns:

Name Type Description
dict

Wavefront tolerance analysis results

References

[1] Optical Design Tolerancing. CODE V.

GeoLensVis — 2D Visualization

2D lens layout and ray path diagrams.

lens.draw_layout(filename='layout.png', depth=-10000.0)
lens.draw_spot_radial(save_name='spot.png', depth=-10000.0)
lens.draw_mtf(save_name='mtf.png', depth_list=[-10000.0])
lens.draw_psf_map(grid=(7, 7), ks=64, depth=-10000.0, save_name='psf_map.png')

deeplens.optics.geolens_pkg.vis.GeoLensVis

Mixin providing 2-D lens layout and ray visualisation for GeoLens.

Generates publication-quality cross-section plots showing lens surfaces and traced ray bundles in either the meridional or sagittal plane.

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

sample_parallel_2D
sample_parallel_2D(fov=0.0, num_rays=7, wvln=DEFAULT_WAVE, plane='meridional', entrance_pupil=True, depth=0.0)

Sample parallel rays (2D) in object space.

Used for (1) drawing lens setup, (2) 2D geometric optics calculation, for example, refocusing to infinity

Parameters:

Name Type Description Default
fov float

incident angle (in degree). Defaults to 0.0.

0.0
depth float

sampling depth. Defaults to 0.0.

0.0
num_rays int

ray number. Defaults to 7.

7
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
plane str

sampling plane. Defaults to "meridional" (y-z plane).

'meridional'
entrance_pupil bool

whether to use entrance pupil. Defaults to True.

True

Returns:

Name Type Description
ray Ray object

Ray object. Shape [num_rays, 3]

sample_point_source_2D
sample_point_source_2D(fov=0.0, depth=DEPTH, num_rays=7, wvln=DEFAULT_WAVE, entrance_pupil=True)

Sample point source rays (2D) in object space.

Used for (1) drawing lens setup.

Parameters:

Name Type Description Default
fov float

incident angle (in degree). Defaults to 0.0.

0.0
depth float

sampling depth. Defaults to DEPTH.

DEPTH
num_rays int

ray number. Defaults to 7.

7
wvln float

ray wvln. Defaults to DEFAULT_WAVE.

DEFAULT_WAVE
entrance_pupil bool

whether to use entrance pupil. Defaults to False.

True

Returns:

Name Type Description
ray Ray object

Ray object. Shape [num_rays, 3]

draw_layout
draw_layout(filename, depth=float('inf'), zmx_format=True, multi_plot=False, lens_title=None, show=False)

Plot 2D lens layout with ray tracing.

Parameters:

Name Type Description Default
filename

Output filename

required
depth

Depth for ray tracing

float('inf')
entrance_pupil

Whether to use entrance pupil

required
zmx_format

Whether to use ZMX format

True
multi_plot

Whether to create multiple plots

False
lens_title

Title for the lens plot

None
show

Whether to show the plot

False
draw_lens_2d
draw_lens_2d(ax=None, fig=None, color='k', linestyle='-', zmx_format=False, fix_bound=False)

Draw lens layout in a 2D plot.

draw_ray_2d
draw_ray_2d(ray_o_record, ax, fig, color='b')

Plot ray paths.

Parameters:

Name Type Description Default
ray_o_record list

list of intersection points.

required
ax Axes

matplotlib axes.

required
fig Figure

matplotlib figure.

required
draw_layout_3d
draw_layout_3d(filename=None, view_angle=30, show=False)

Draw 3D layout of the lens system.

Parameters:

Name Type Description Default
filename str

Path to save the figure. Defaults to None.

None
view_angle int

Viewing angle for the 3D plot

30
show bool

Whether to display the figure

False

Returns:

Type Description

fig, ax: Matplotlib figure and axis objects

create_barrier
create_barrier(filename, barrier_thickness=1.0, ring_height=0.5, ring_size=1.0)

Create a 3D barrier for the lens system.

Parameters:

Name Type Description Default
filename

Path to save the figure

required
barrier_thickness

Thickness of the barrier

1.0
ring_height

Height of the annular ring

0.5
ring_size

Size of the annular ring

1.0

GeoLensVis3D — 3D Visualization

3D mesh visualization via PyVista.

deeplens.optics.geolens_pkg.view_3d.GeoLensVis3D

Mixin providing 3-D mesh visualisation for GeoLens.

Creates lens surface, aperture, barrier, sensor, and ray-path meshes as polygon data and optionally renders them with PyVista. All geometry is expressed in millimetres and stored as :class:CrossPoly (vertex/face) objects that can be saved to .obj files for external renderers.

This class is not instantiated directly; it is mixed into :class:~deeplens.optics.geolens.GeoLens.

create_mesh
create_mesh(mesh_rings: int = 32, mesh_arms: int = 128, is_wrap: bool = False)

Create all lens/bridge/sensor/aperture meshes.

Parameters:

Name Type Description Default
lens GeoLens

The lens object.

required
mesh_rings int

The number of rings in the mesh.

32
mesh_arms int

The number of arms in the mesh.

128
is_wrap bool

Whether to wrap the lens bridge around the lens as cylinder.

False

Returns: surf_meshes (List[Surface]): Lens surfaces meshes. bridge_meshes (List[FaceMesh]): Lens bridges meshes. (NOT support wrap around for now) sensor_mesh (RectangleMesh): Sensor meshes. (only support rectangular sensor for now)

draw_lens_3d
draw_lens_3d(plotter=None, save_dir: Optional[str] = None, mesh_rings: int = 32, mesh_arms: int = 128, surface_color: List[float] = [0.06, 0.3, 0.6], draw_rays: bool = True, fovs: List[float] = [0.0], fov_phis: List[float] = [0.0], ray_rings: int = 6, ray_arms: int = 8, is_wrap: bool = False)

Draw lens 3D layout with rays using pyvista.

Note: PyVista is imported lazily only when this method is called.

Parameters:

Name Type Description Default
plotter

pv.Plotter. Optional pyvista Plotter instance. If None, a new one is created.

None
save_dir str

The directory to save the image.

None
mesh_rings int

The number of rings in the mesh.

32
mesh_arms int

The number of arms in the mesh.

128
surface_color List[float]

The color of the surfaces.

[0.06, 0.3, 0.6]
draw_rays bool

Whether to show the rays.

True
fovs List[float]

The FoV angles to be sampled, unit: degree.

[0.0]
fov_phis List[float]

The FoV azimuthal angles to be sampled, unit: degree.

[0.0]
ray_rings int

The number of pupil rings to be sampled.

6
ray_arms int

The number of pupil arms to be sampled.

8
is_wrap bool

Whether to wrap the lens bridge around the lens as cylinder.

False

Returns:

Name Type Description
plotter

pv.Plotter. The pyvista Plotter instance.

save_lens_obj
save_lens_obj(save_dir: str, mesh_rings: int = 64, mesh_arms: int = 128, save_rays: bool = False, fovs: List[float] = [0.0], fov_phis: List[float] = [0.0], ray_rings: int = 6, ray_arms: int = 8, is_wrap: bool = False, save_elements: bool = True)

Save lens geometry and rays as .obj files using pyvista.

Note: use #F2F7FFFF as the color for lens when rendering in Blender.

Parameters:

Name Type Description Default
lens GeoLens

The lens object.

required
save_dir str

The directory to save the image.

required
mesh_rings int

The number of rings in the mesh. (default: 128)

64
mesh_arms int

The number of arms in the mesh. (default: 256)

128
save_rays bool

Whether to save the rays.

False
fovs List[float]

The FoV angles to be sampled, unit: degree.

[0.0]
fov_phis List[float]

The FoV azimuthal angles to be sampled, unit: degree.

[0.0]
ray_rings int

The number of pupil rings to be sampled. (default: 6)

6
ray_arms int

The number of pupil arms to be sampled. (default: 8)

8
is_wrap bool

Whether to wrap the lens bridge around the lens as cylinder.

False
save_elements bool

Whether to save the elements.

True

Optical Elements

Base Classes

deeplens.optics.base.DeepObj

DeepObj(dtype=None)

Base class for all differentiable optical objects in DeepLens.

Provides device management, dtype conversion, and deep-copy support via automatic introspection over instance tensors and nested DeepObj sub-objects. All lens, surface, material, ray, and wave objects inherit from this class.

Attributes:

Name Type Description
dtype dtype

Current floating-point dtype of all owned tensors.

device dtype

Current compute device (set by :meth:to).

dtype instance-attribute
dtype = get_default_dtype() if dtype is None else dtype
__str__
__str__()

Called when using print() and str()

__call__
__call__(inp)

Call the forward function.

clone
clone()

Clone a DeepObj object.

to
to(device)

Move all tensors and nested objects to device.

Recursively walks over every instance attribute and moves tensors, nn.Module sub-objects, and nested DeepObj objects to the requested device.

Parameters:

Name Type Description Default
device

Target device, e.g. "cuda", "cpu", or a torch.device instance.

required

Returns:

Name Type Description
DeepObj

self (for chaining).

Example

lens = GeoLens(filename="lens.json") lens.to("cuda") # move all tensors to GPU

astype
astype(dtype)

Convert all floating-point tensors to dtype.

Also calls torch.set_default_dtype(dtype) so that subsequent tensor creation uses the same precision.

Parameters:

Name Type Description Default
dtype dtype

Target floating-point dtype. Must be one of torch.float16, torch.float32, or torch.float64. Pass None to be a no-op.

required

Returns:

Name Type Description
DeepObj

self (for chaining).

Raises:

Type Description
AssertionError

If dtype is not a recognised floating-point dtype.

Example

lens = GeoLens(filename="lens.json") lens.astype(torch.float64) # switch to double precision

deeplens.optics.geometric_surface.base.Surface

Surface(r, d, mat2, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: DeepObj

Base class for all geometric optical surfaces.

A surface sits at axial position d (mm) in the global coordinate system, has an aperture radius r (mm), and separates two optical media. Subclasses override :meth:_sag and :meth:_dfdxy to define their shape.

Ray–surface interaction is handled by three stages, implemented in :meth:ray_reaction:

  1. Coordinate transform – ray is brought into the local surface frame.
  2. Intersection – solved via Newton's method (:meth:newtons_method), using a non-differentiable iteration loop followed by a single differentiable Newton step to enable gradient flow.
  3. Refraction / reflection – vector Snell's law (:meth:refract) or specular reflection (:meth:reflect).

Attributes:

Name Type Description
d Tensor

Axial position of the surface vertex [mm].

r float

Aperture radius [mm].

mat2 Material

Optical material on the transmission side.

is_square bool

If True the aperture is square; otherwise circular.

tolerancing bool

When True, manufacturing error offsets are applied during ray tracing.

Initialize a generic optical surface.

Parameters:

Name Type Description Default
r float

Aperture radius [mm].

required
d float

Axial position of the surface vertex [mm].

required
mat2 str or Material

Material on the transmission side (e.g. "N-BK7", "air").

required
pos_xy list[float]

Lateral offset [x, y] [mm]. Defaults to [0.0, 0.0].

[0.0, 0.0]
vec_local list[float]

Local normal direction. Defaults to [0.0, 0.0, 1.0] (on-axis).

[0.0, 0.0, 1.0]
is_square bool

Use a square aperture. Defaults to False.

False
device str

Compute device. Defaults to "cpu".

'cpu'
vec_global instance-attribute
vec_global = tensor([0.0, 0.0, 1.0])
d instance-attribute
d = tensor(d)
pos_x instance-attribute
pos_x = tensor(pos_xy[0])
pos_y instance-attribute
pos_y = tensor(pos_xy[1])
vec_local instance-attribute
vec_local = normalize(tensor(vec_local), p=2, dim=-1)
mat2 instance-attribute
mat2 = Material(mat2)
r instance-attribute
r = float(r)
is_square instance-attribute
is_square = is_square
h instance-attribute
h = 2 * r
w instance-attribute
w = 2 * r
newton_maxiter instance-attribute
newton_maxiter = 10
newton_convergence instance-attribute
newton_convergence = 50.0 * 1e-06
newton_step_bound instance-attribute
newton_step_bound = r / 5
tolerancing instance-attribute
tolerancing = False
device instance-attribute
device = device if device is not None else device('cpu')
init_from_dict classmethod
init_from_dict(surf_dict)

Initialize surface from a dict.

ray_reaction
ray_reaction(ray, n1, n2, refraction=True)

Compute the output ray after intersection and refraction/reflection.

Transforms the ray to the local surface frame, solves the intersection via Newton's method, applies vector Snell's law (or specular reflection), then transforms back to global coordinates.

Parameters:

Name Type Description Default
ray Ray

Incident ray bundle.

required
n1 float

Refractive index of the incident medium.

required
n2 float

Refractive index of the transmission medium.

required
refraction bool

If True (default) refract the ray; if False reflect it.

True

Returns:

Name Type Description
Ray

Updated ray bundle after the surface interaction.

intersect
intersect(ray, n=1.0)

Solve ray-surface intersection in local coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray.

required
n float

refractive index. Defaults to 1.0.

1.0
newtons_method
newtons_method(ray)

Solve intersection by Newton's method in local coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray.

required

Returns:

Name Type Description
t tensor

intersection time.

valid tensor

valid mask.

refract
refract(ray, eta)

Calculate refracted ray according to Snell's law in local coordinate system.

Normal vector points from the surface toward the side where the light is coming from. d is already normalized if both n and ray.d are normalized.

Parameters:

Name Type Description Default
ray Ray

incident ray.

required
eta float

ratio of indices of refraction, eta = n_i / n_t

required

Returns:

Name Type Description
ray Ray

refracted ray.

References

[1] https://registry.khronos.org/OpenGL-Refpages/gl4/html/refract.xhtml [2] https://en.wikipedia.org/wiki/Snell%27s_law, "Vector form" section.

reflect
reflect(ray)

Calculate reflected ray in local coordinate system.

Normal vector points from the surface toward the side where the light is coming from.

Parameters:

Name Type Description Default
ray Ray

incident ray.

required

Returns:

Name Type Description
ray Ray

reflected ray.

References

[1] https://registry.khronos.org/OpenGL-Refpages/gl4/html/reflect.xhtml [2] https://en.wikipedia.org/wiki/Snell%27s_law, "Vector form" section.

normal_vec
normal_vec(ray)

Calculate surface normal vector at the intersection point in local coordinate system.

Normal vector points from the surface toward the side where the light is coming from.

Parameters:

Name Type Description Default
ray Ray

input ray.

required

Returns:

Name Type Description
n_vec tensor

surface normal vector.

to_local_coord
to_local_coord(ray)

Transform ray to local coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray in global coordinate system.

required

Returns:

Name Type Description
ray Ray

transformed ray in local coordinate system.

to_global_coord
to_global_coord(ray)

Transform ray to global coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray in local coordinate system.

required

Returns:

Name Type Description
ray Ray

transformed ray in global coordinate system.

_get_rotation_matrix
_get_rotation_matrix(vec_from, vec_to)

Calculate rotation matrix to rotate vec_from to vec_to.

Parameters:

Name Type Description Default
vec_from tensor

source direction vector [3]

required
vec_to tensor

target direction vector [3]

required

Returns:

Name Type Description
R tensor

rotation matrix [3, 3]

_apply_rotation
_apply_rotation(vectors, R)

Apply rotation matrix to vectors.

Parameters:

Name Type Description Default
vectors tensor

input vectors [..., 3]

required
R tensor

rotation matrix [3, 3]

required

Returns:

Name Type Description
rotated_vectors tensor

rotated vectors [..., 3]

sag
sag(x, y, valid=None)

Calculate sag (z) of the surface: z = f(x, y).

Valid term is used to avoid NaN when x, y exceed the data range, which happens in spherical and aspherical surfaces.

Calculating r = sqrt(x2, y2) may cause an NaN error during back-propagation. Because dr/dx = x / sqrt(x2 + y2), NaN will occur when x=y=0.

_sag
_sag(x, y)

Calculate sag (z) of the surface: z = f(x, y).

Parameters:

Name Type Description Default
x tensor

x coordinate

required
y tensor

y coordinate

required
valid tensor

valid mask

required
Return

z (tensor): z = sag(x, y)

dfdxyz
dfdxyz(x, y, valid=None)

Compute derivatives of surface function. Surface function: f(x, y, z): sag(x, y) - z = 0. This function is used in Newton's method and normal vector calculation.

There are several methods to compute derivatives of surfaces

[1] Analytical derivatives: The current implementation is based on this method. But the implementation only works for surfaces which can be written as z = sag(x, y). For implicit surfaces, we need to compute derivatives (df/dx, df/dy, df/dz). [2] Numerical derivatives: Use finite difference method to compute derivatives. This can be used for those very complex surfaces, for example, NURBS. But it may suffer from numerical instability when the surface is very steep. [3] Automatic differentiation: Use torch.autograd to compute derivatives. This can work for almost all the surfaces and is accurate, but it requires an extra backward pass to compute the derivatives of the surface function.

_dfdxy
_dfdxy(x, y)

Compute derivatives of sag to x and y. (dfdx, dfdy, dfdz) = (f'x, f'y, f'z).

Parameters:

Name Type Description Default
x tensor

x coordinate

required
y tensor

y coordinate

required
Return

dfdx (tensor): df / dx dfdy (tensor): df / dy

d2fdxyz2
d2fdxyz2(x, y, valid=None)

Compute second-order partial derivatives of the surface function f(x, y, z): sag(x, y) - z = 0. This function is currently only used for surfaces constraints.

_d2fdxy
_d2fdxy(x, y)

Compute second-order derivatives of sag to x and y. (d2fdx2, d2fdxdy, d2fdy2) = (f''xx, f''xy, f''yy).

Currently, we use finite difference method to compute the second-order derivatives. And the second-order derivatives are only used for surface constraints.

Parameters:

Name Type Description Default
x tensor

x coordinate

required
y tensor

y coordinate

required
Return

d2fdx2 (tensor): d2f / dx2 d2fdxdy (tensor): d2f / dxdy d2fdy2 (tensor): d2f / dy2

is_valid
is_valid(x, y)

Valid points within the data range and boundary of the surface.

is_within_boundary
is_within_boundary(x, y)

Valid points within the boundary of the surface.

is_within_data_range
is_within_data_range(x, y)

Valid points inside the data region of the sag function.

max_height
max_height()

Maximum valid height.

surface_with_offset
surface_with_offset(x, y, valid_check=True)

Calculate z coordinate of the surface at (x, y).

This function is used in lens setup plotting and lens self-intersection detection.

surface_sag
surface_sag(x, y)

Calculate sag of the surface at (x, y).

This function is currently not used.

get_optimizer_params
get_optimizer_params(lrs=[0.0001], optim_mat=False)

Get optimizer parameters for different parameters.

Parameters:

Name Type Description Default
lrs list

learning rates for different parameters.

[0.0001]
optim_mat bool

whether to optimize material. Defaults to False.

False
get_optimizer
get_optimizer(lrs=[0.0001], optim_mat=False)

Get optimizer for the surface.

update_r
update_r(r)

Update surface radius.

init_tolerance
init_tolerance(tolerance_params=None)

Initialize tolerance parameters for the surface.

Parameters:

Name Type Description Default
tolerance_params dict or None

Tolerance for surface parameters. Supported keys (all optional, default values shown):

.. code-block:: python

{
    "r_tole": 0.05,               # aperture radius [mm]
    "d_tole": 0.05,               # axial position [mm]
    "center_thickness_tole": 0.1, # centre thickness [mm]
    "decenter_tole": 0.1,         # lateral decentre [mm]
    "tilt_tole": 0.1,             # tilt [arcmin]
    "mat2_n_tole": 0.001,         # refractive index
    "mat2_V_tole": 0.01,          # Abbe number [%]
}
None
References

[1] https://www.edmundoptics.com/knowledge-center/application-notes/optics/understanding-optical-specifications/?srsltid=AfmBOorBa-0zaOcOhdQpUjmytthZc07oFlmPW_2AgaiNHHQwobcAzWII [2] https://wp.optics.arizona.edu/optomech/wp-content/uploads/sites/53/2016/08/8-Tolerancing-1.pdf [3] https://wp.optics.arizona.edu/jsasian/wp-content/uploads/sites/33/2016/03/L17_OPTI517_Lens-_Tolerancing.pdf

sample_tolerance
sample_tolerance()

Sample one example manufacturing error for the surface.

zero_tolerance
zero_tolerance()

Zero tolerance.

sensitivity_score
sensitivity_score()

Tolerance squared sum.

Reference

[1] Page 10 from: https://wp.optics.arizona.edu/optomech/wp-content/uploads/sites/53/2016/08/8-Tolerancing-1.pdf

draw_widget
draw_widget(ax, color='black', linestyle='solid')

Draw widget for the surface on the 2D plot.

create_mesh
create_mesh(n_rings=32, n_arms=128, color=[0.06, 0.3, 0.6])

Create triangulated surface mesh.

Parameters:

Name Type Description Default
n_rings int

Number of concentric rings for sampling.

32
n_arms int

Number of angular divisions.

128
color List[float]

The color of the mesh.

[0.06, 0.3, 0.6]

Returns:

Name Type Description
self

The surface with mesh data.

_create_vertices
_create_vertices(n_rings, n_arms)

Create vertices in radial pattern. Vertices will be used to plot the surface in PyVista.

_create_faces
_create_faces(n_rings, n_arms)

Create triangular faces. Faces will be used to plot the surface in PyVista.

_create_rim
_create_rim(n_rings, n_arms)

Create rim (outer edge) vertices. Rims will be used to bridge two surfaces.

get_polydata
get_polydata()

Get PyVista PolyData object from previously generated vertices and faces.

PolyData object will be used to draw the surface and export as .obj file.

surf_dict
surf_dict()
zmx_str
zmx_str(surf_idx, d_next)

Return Zemax surface string.

Geometric Surfaces

Spheric

Standard spherical surface. Most common refractive element.

\[z(\rho) = \frac{c\,\rho^2}{1 + \sqrt{1 - c^2\,\rho^2}}, \quad \rho^2 = x^2 + y^2\]
from deeplens.optics import Spheric
surface = Spheric(c=1/50.0, r=5.0, d=5.0, mat2="N-BK7", device='cuda')

deeplens.optics.geometric_surface.Spheric

Spheric(c, r, d, mat2, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: Surface

Spherical refractive surface parameterized by curvature.

The sag function is:

.. math::

z(x, y) = \frac{c \rho^2}{1 + \sqrt{1 - c^2 \rho^2}}, \quad
\rho^2 = x^2 + y^2

Attributes:

Name Type Description
c Tensor

Surface curvature 1/R [1/mm]. Differentiable with respect to gradient-based optimization.

Initialize a spherical surface.

Parameters:

Name Type Description Default
c float

Surface curvature 1/R [1/mm]. Use 0 for a flat surface (equivalent to Plane).

required
r float

Aperture radius [mm].

required
d float

Axial vertex position [mm].

required
mat2 str or Material

Material on the transmission side.

required
pos_xy list[float]

Lateral offset [x, y] [mm]. Defaults to [0.0, 0.0].

[0.0, 0.0]
vec_local list[float]

Local normal direction. Defaults to [0.0, 0.0, 1.0].

[0.0, 0.0, 1.0]
is_square bool

Square aperture flag. Defaults to False.

False
device str

Compute device. Defaults to "cpu".

'cpu'
c instance-attribute
c = tensor(c)
tolerancing instance-attribute
tolerancing = False
init_from_dict classmethod
init_from_dict(surf_dict)
_sag
_sag(x, y)

Compute surfaces sag z = r2 * c / (1 - sqrt(1 - r2 * c**2))

_dfdxy
_dfdxy(x, y)

Compute surface sag derivatives to x and y: dz / dx, dz / dy.

_d2fdxy
_d2fdxy(x, y)

Compute second-order derivatives of the surface sag z = sag(x, y).

Parameters:

Name Type Description Default
x tensor

x coordinate

required
y tensor

y coordinate

required

Returns:

Name Type Description
d2f_dx2 tensor

∂²f / ∂x²

d2f_dxdy tensor

∂²f / ∂x∂y

d2f_dy2 tensor

∂²f / ∂y²

intersect
intersect(ray, n=1.0)

Solve ray-surface intersection in local coordinate system using analytical method.

Sphere equation: (x)^2 + (y)^2 + (z - R)^2 = R^2, where R = 1/c Ray equation: p(t) = o + t*d Solve quadratic equation for intersection parameter t.

Parameters:

Name Type Description Default
ray Ray

input ray.

required
n float

refractive index. Defaults to 1.0.

1.0

Returns:

Name Type Description
ray Ray

ray with updated position and opl.

is_within_data_range
is_within_data_range(x, y)

Invalid when shape is non-defined.

max_height
max_height()

Maximum valid height.

init_tolerance
init_tolerance(tolerance_params=None)

Initialize tolerance parameters for the surface.

Parameters:

Name Type Description Default
tolerance_params dict

Tolerance for surface parameters.

None
sample_tolerance
sample_tolerance()

Randomly perturb surface parameters to simulate manufacturing errors.

zero_tolerance
zero_tolerance()

Zero tolerance.

sensitivity_score
sensitivity_score()

Tolerance squared sum.

get_optimizer_params
get_optimizer_params(lrs=[0.0001, 0.0001], optim_mat=False)

Activate gradient computation for c and d and return optimizer parameters.

surf_dict
surf_dict()

Return surface parameters.

zmx_str
zmx_str(surf_idx, d_next)

Return Zemax surface string.

Aspheric

Even-order aspheric surface for aberration correction.

\[z = \frac{c\rho^2}{1 + \sqrt{1-(1+k)c^2\rho^2}} + \sum_{i=1}^{n} a_i \rho^{2i}\]

Conic constant k: 0 = sphere, -1 = parabola, < -1 = hyperbola, (-1,0) = ellipse, > 0 = oblate ellipsoid.

from deeplens.optics import Aspheric
surface = Aspheric(r=50.0, d=5.0, k=0.0, ai=[0, 0, 1e-5, 0, -1e-7], device='cuda')

deeplens.optics.geometric_surface.Aspheric

Aspheric(r, d, c, k, ai, mat2, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: Surface

Even-order aspheric surface.

The sag function is:

.. math::

z(\rho) = \frac{c\,\rho^2}{1 + \sqrt{1-(1+k)c^2\rho^2}}
         + \sum_{i=1}^{n} a_{2i}\,\rho^{2i},
\quad \rho^2 = x^2 + y^2

All coefficients c, k, and ai are differentiable torch tensors so they can be optimised with gradient descent.

Attributes:

Name Type Description
c Tensor

Base curvature [1/mm].

k Tensor

Conic constant.

ai Tensor

Even-order aspheric coefficients [a2, a4, a6, ...].

Initialize an aspheric surface.

Parameters:

Name Type Description Default
r float

Aperture radius [mm].

required
d float

Axial vertex position [mm].

required
c float

Base curvature 1/R [1/mm].

required
k float

Conic constant (0 = sphere, -1 = paraboloid).

required
ai list[float] or None

Even-order aspheric coefficients [a2, a4, a6, ...]. Pass None or an empty list for a pure conic.

required
mat2 str or Material

Material on the transmission side.

required
pos_xy list[float]

Lateral offset [x, y] [mm]. Defaults to [0.0, 0.0].

[0.0, 0.0]
vec_local list[float]

Local normal direction. Defaults to [0.0, 0.0, 1.0].

[0.0, 0.0, 1.0]
is_square bool

Square aperture flag. Defaults to False.

False
device str

Compute device. Defaults to "cpu".

'cpu'
c instance-attribute
c = tensor(c)
k instance-attribute
k = tensor(k)
ai instance-attribute
ai = tensor(ai)
ai_degree instance-attribute
ai_degree = len(ai)
ai2 instance-attribute
ai2 = tensor(ai[0])
ai4 instance-attribute
ai4 = tensor(ai[1])
ai6 instance-attribute
ai6 = tensor(ai[2])
ai8 instance-attribute
ai8 = tensor(ai[3])
ai10 instance-attribute
ai10 = tensor(ai[4])
ai12 instance-attribute
ai12 = tensor(ai[5])
tolerancing instance-attribute
tolerancing = False
init_from_dict classmethod
init_from_dict(surf_dict)
_get_curvature_params
_get_curvature_params()

Get curvature parameters, accounting for tolerancing.

_sag
_sag(x, y)

Compute surface sag (height) z = sag(x, y).

The aspheric surface is defined as

z = r²c / (1 + sqrt(1 - (1+k)r²c²)) + Σ ai_{2i} * r^{2i}

where r² = x² + y², c is curvature, k is conic constant, and ai are the aspheric coefficients (ai2, ai4, ai6, ...).

_dfdxy
_dfdxy(x, y)

Compute first-order height derivatives df/dx and df/dy.

For the aspheric polynomial Σ ai_{2i} * r^{2i}, the derivative w.r.t. r² is Σ i * ai_{2i} * r^{2(i-1)}, i.e.: ai2 + 2ai4r² + 3ai6r⁴ + ...

is_within_data_range
is_within_data_range(x, y)

Invalid when shape is non-defined.

max_height
max_height()

Maximum valid height.

get_optimizer_params
get_optimizer_params(lrs=[0.0001, 0.0001, 0.01, 0.0001], decay=0.001, optim_mat=False)

Get optimizer parameters for different parameters.

Parameters:

Name Type Description Default
lrs list

learning rates for d, c, k, ai2, (ai4, ai6, ai8, ai10, ai12).

[0.0001, 0.0001, 0.01, 0.0001]
optim_mat bool

whether to optimize material. Defaults to False.

False
init_tolerance
init_tolerance(tolerance_params=None)

Perturb the surface with some tolerance.

Parameters:

Name Type Description Default
tolerance_params dict

Tolerance for surface parameters.

None
References

[1] https://www.edmundoptics.com/capabilities/precision-optics/capabilities/aspheric-lenses/ [2] https://www.edmundoptics.com/knowledge-center/application-notes/optics/all-about-aspheric-lenses/?srsltid=AfmBOoon8AUXVALojol2s5K20gQk7W1qUisc6cE4WzZp3ATFY5T1pK8q

sample_tolerance
sample_tolerance()

Randomly perturb surface parameters to simulate manufacturing errors.

zero_tolerance
zero_tolerance()

Zero tolerance.

sensitivity_score
sensitivity_score()

Tolerance squared sum.

surf_dict
surf_dict()

Return a dict of surface.

zmx_str
zmx_str(surf_idx, d_next)

Return Zemax surface string.

Plane

from deeplens.optics import Plane
surface = Plane(d=10.0, device='cuda')

deeplens.optics.geometric_surface.Plane

Plane(r, d, mat2, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: Surface

Plane surface.

Examples:

  • IR filter.
  • Lens cover glass.
  • DOE base.
The following surfaces inherit from Plane
  • Aperture.
  • Mirror.
  • ThinLens.
init_from_dict classmethod
init_from_dict(surf_dict)
intersect
intersect(ray, n=1.0)

Solve ray-surface intersection in local coordinate system and update ray data.

normal_vec
normal_vec(ray)

Calculate surface normal vector at intersection points in local coordinate system.

Normal vector points from the surface toward the side where the light is coming from.

_sag
_sag(x, y)
_dfdxy
_dfdxy(x, y)
_d2fdxy
_d2fdxy(x, y)
get_optimizer_params
get_optimizer_params(lrs=[0.0001], optim_mat=False)

Activate gradient computation for d and return optimizer parameters.

surf_dict
surf_dict()

Aperture

Controls F-number, vignetting, and depth of field.

from deeplens.optics import Aperture
surface = Aperture(r=5.0, d=0.0, device='cuda')

deeplens.optics.geometric_surface.Aperture

Aperture(r, d, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: Plane

Aperture surface.

tolerancing instance-attribute
tolerancing = False
init_from_dict classmethod
init_from_dict(surf_dict)
ray_reaction
ray_reaction(ray, n1=1.0, n2=1.0, refraction=False)

Compute output ray after intersection and refraction.

draw_widget
draw_widget(ax, color='orange', linestyle='solid')

Draw aperture wedge on the figure.

draw_widget3D
draw_widget3D(ax, color='black')

Draw the aperture as a circle in a 3D plot.

create_mesh
create_mesh(n_rings=32, n_arms=128, color=[0.0, 0.0, 0.0])

Create triangulated surface mesh.

Parameters:

Name Type Description Default
n_rings int

Number of concentric rings for sampling.

32
n_arms int

Number of angular divisions.

128
color List[float]

The color of the mesh.

[0.0, 0.0, 0.0]

Returns:

Name Type Description
self

The surface with mesh data.

_create_vertices
_create_vertices(n_rings, n_arms)

Generate vertices for two-ring aperture (inner and outer rings).

_create_faces
_create_faces(n_rings, n_arms)

Generate triangular faces connecting inner and outer rings.

_create_rim
_create_rim(n_rings, n_arms)

Create rim (outer edge) vertices for aperture.

get_optimizer_params
get_optimizer_params(lrs=[0.0001])

Activate gradient computation for d and return optimizer parameters.

surf_dict
surf_dict()

Dict of surface parameters.

zmx_str
zmx_str(surf_idx, d_next)

Zemax surface string.

Cubic

Cubic phase plate for extended depth of field (wavefront coding).

\[\phi(x, y) = \alpha (x^3 + y^3)\]
from deeplens.optics import Cubic
surface = Cubic(r=float('inf'), d=1.0, alpha=10.0, device='cuda')

deeplens.optics.geometric_surface.Cubic

Cubic(r, d, b, mat2, pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=False, device='cpu')

Bases: Surface

b instance-attribute
b = tensor(b)
b3 instance-attribute
b3 = tensor(b[0])
b_degree instance-attribute
b_degree = 1
b5 instance-attribute
b5 = tensor(b[1])
b7 instance-attribute
b7 = tensor(b[2])
rotate_angle instance-attribute
rotate_angle = 0.0
init_from_dict classmethod
init_from_dict(surf_dict)
_sag
_sag(x, y)

Compute surface height z(x, y).

_dfdxy
_dfdxy(x, y)

Compute surface height derivatives to x and y.

get_optimizer_params
get_optimizer_params(lrs=[0.0001], decay=0.1, optim_mat=False)

Return parameters for optimizer.

perturb
perturb(tolerance_params)

Perturb the surface

surf_dict
surf_dict()

Return surface parameters.

Mirror

deeplens.optics.geometric_surface.Mirror

Mirror(r, d, mat2='air', pos_xy=[0.0, 0.0], vec_local=[0.0, 0.0, 1.0], is_square=True, device='cpu')

Bases: Plane

Mirror surface.

init_from_dict classmethod
init_from_dict(surf_dict)
ray_reaction
ray_reaction(ray, n1=None, n2=None)

Compute output ray after intersection and reflection with the mirror surface.

surf_dict
surf_dict()

Return surface parameters.

Diffractive Surfaces

Fresnel

from deeplens.optics.diffractive_surface import Fresnel
surface = Fresnel(foclen=50.0, d=0.001, zone_num=100, wavelength=0.550, device='cuda')

deeplens.optics.diffractive_surface.Fresnel

Fresnel(d, f0=None, wvln0=0.55, res=(2000, 2000), mat='fused_silica', fab_ps=0.001, fab_step=16, device='cpu')

Bases: DiffractiveSurface

Initialize Fresnel DOE. A diffractive Fresnel lens shows inverse dispersion property compared to refractive lens.

Parameters:

Name Type Description Default
f0 float

Initial focal length. [mm]

None
d float

Distance of the DOE surface. [mm]

required
res tuple or int

Resolution of the DOE, [w, h]. [pixel]

(2000, 2000)
wvln0 float

Design wavelength. [um]

0.55
mat str

Material of the DOE.

'fused_silica'
fab_ps float

Fabrication pixel size. [mm]

0.001
fab_step int

Fabrication step.

16
device str

Device to run the DOE.

'cpu'
f0 instance-attribute
f0 = randn(1) * 1000000.0
init_from_dict classmethod
init_from_dict(doe_dict)

Initialize Fresnel DOE from a dict.

phase_func
phase_func()

Get the phase map at design wavelength.

get_optimizer_params
get_optimizer_params(lr=0.001)

Get parameters for optimization.

surf_dict
surf_dict()

Return a dict of surface.

Binary2

from deeplens.optics.diffractive_surface import Binary2
surface = Binary2(phase_pattern=torch.rand(512, 512) > 0.5, d=0.001, wavelength=0.550, device='cuda')

deeplens.optics.diffractive_surface.Binary2

Binary2(d, res=(2000, 2000), mat='fused_silica', wvln0=0.55, fab_ps=0.001, fab_step=16, device='cpu')

Bases: DiffractiveSurface

Initialize Binary DOE.

alpha2 instance-attribute
alpha2 = (rand(1) - 0.5) * 0.02
alpha4 instance-attribute
alpha4 = (rand(1) - 0.5) * 0.002
alpha6 instance-attribute
alpha6 = (rand(1) - 0.5) * 0.0002
alpha8 instance-attribute
alpha8 = (rand(1) - 0.5) * 2e-05
alpha10 instance-attribute
alpha10 = (rand(1) - 0.5) * 2e-06
init_from_dict classmethod
init_from_dict(doe_dict)

Initialize Binary DOE from a dict.

phase_func
phase_func()

Get the phase map at design wavelength.

get_optimizer_params
get_optimizer_params(lr=0.001)

Get parameters for optimization.

Parameters:

Name Type Description Default
lr float

Base learning rate for alpha2. Learning rates for higher-order parameters will be scaled progressively (10x, 100x, 1000x, 10000x).

0.001
surf_dict
surf_dict()

Return a dict of surface.

Pixel2D

High-resolution pixelated metasurface with a learnable height map.

from deeplens.optics.diffractive_surface import Pixel2D
surface = Pixel2D(
    height_map=torch.rand(1024, 1024) * 0.5,
    pixel_size=0.5, d=0.001, n_material=1.5, wavelength=0.550, device='cuda'
)

deeplens.optics.diffractive_surface.Pixel2D

Pixel2D(d, phase_map_path=None, res=(2000, 2000), mat='fused_silica', wvln0=0.55, fab_ps=0.001, fab_step=16, device='cpu')

Bases: DiffractiveSurface

Pixel2D DOE parameterization - direct phase map representation.

Initialize Pixel2D DOE, where each pixel is independent parameter.

Parameters:

Name Type Description Default
d float

Distance of the DOE surface. [mm]

required
size tuple or int

Size of the DOE, [w, h]. [mm]

required
res tuple or int

Resolution of the DOE, [w, h]. [pixel]

(2000, 2000)
mat str

Material of the DOE.

'fused_silica'
fab_ps float

Fabrication pixel size. [mm]

0.001
fab_step int

Fabrication step.

16
device str

Device to run the DOE.

'cpu'
phase_map instance-attribute
phase_map = randn(res, device=device) * 0.001
init_from_dict classmethod
init_from_dict(doe_dict)

Initialize Pixel2D DOE from a dict.

phase_func
phase_func()

Get the phase map at design wavelength.

get_optimizer_params
get_optimizer_params(lr=0.01)

Get parameters for optimization.

surf_dict
surf_dict(phase_map_path)

Return a dict of surface.

Zernike

Phase surface defined by Zernike polynomials. Common terms: indices 0–2 piston/tilt, 3 defocus, 4–5 astigmatism, 6–8 coma/trefoil, 9 spherical aberration.

from deeplens.optics.diffractive_surface import Zernike
surface = Zernike(
    coefficients=[0, 0, 1, 0.5, 0, 0], d=0.001,
    aperture_radius=10.0, wavelength=0.550, device='cuda'
)

deeplens.optics.diffractive_surface.Zernike

Zernike(d, z_coeff=None, zernike_order=37, res=(2000, 2000), mat='fused_silica', fab_ps=0.001, fab_step=16, wvln0=0.55, device='cpu')

Bases: DiffractiveSurface

DOE parameterized by Zernike polynomials.

Initialize Zernike DOE.

Parameters:

Name Type Description Default
d

DOE position

required
res

DOE resolution

(2000, 2000)
z_coeff

Zernike coefficients

None
zernike_order

Number of Zernike coefficients to use

37
fab_ps

Fabrication pixel size

0.001
fab_step

Fabrication step

16
device

Computation device

'cpu'
zernike_order instance-attribute
zernike_order = zernike_order
z_coeff instance-attribute
z_coeff = randn(zernike_order, device=device) * 0.001
init_from_dict classmethod
init_from_dict(doe_dict)

Initialize Zernike DOE from a dict.

phase_func
phase_func()

Get the phase map at design wavelength.

get_optimizer_params
get_optimizer_params(lr=0.01)

Get parameters for optimization.

surf_dict
surf_dict()

Return a dict of surface.

Grating

deeplens.optics.diffractive_surface.Grating

Grating(d, res=(2000, 2000), mat='fused_silica', wvln0=0.55, fab_ps=0.001, fab_step=16, theta=0.0, alpha=0.0, device='cpu')

Bases: DiffractiveSurface

Grating diffractive optical element.

A grating introduces a linear phase gradient defined by

phi(x, y) = alpha * (x * sin(theta) + y * cos(theta)) / norm_radii

where
  • theta: angle from y-axis to grating vector
  • alpha: slope of the grating (phase gradient strength)
  • norm_radii: normalization radius

Initialize Grating DOE.

Parameters:

Name Type Description Default
d float

Distance of the DOE surface. [mm]

required
res tuple or int

Resolution of the DOE, [w, h]. [pixel]

(2000, 2000)
mat str

Material of the DOE.

'fused_silica'
wvln0 float

Design wavelength. [um]

0.55
fab_ps float

Fabrication pixel size. [mm]

0.001
fab_step int

Fabrication step.

16
theta float

Angle from y-axis to grating vector. [rad]

0.0
alpha float

Slope of the grating (phase gradient strength).

0.0
device str

Device to run the DOE.

'cpu'
theta instance-attribute
theta = tensor(theta)
alpha instance-attribute
alpha = tensor(alpha)
norm_radii instance-attribute
norm_radii = w / 2
init_from_dict classmethod
init_from_dict(doe_dict)

Initialize Grating DOE from a dict.

Parameters:

Name Type Description Default
doe_dict dict

Dictionary containing DOE parameters.

required

Returns:

Name Type Description
Grating

Initialized Grating DOE object.

phase_func
phase_func()

Get the phase map at design wavelength.

The grating phase is a linear function of position

phi(x, y) = alpha * (x * sin(theta) + y * cos(theta)) / norm_radii

Returns:

Name Type Description
phase tensor

Phase map at design wavelength.

get_optimizer_params
get_optimizer_params(lr=0.001)

Get parameters for optimization.

Parameters:

Name Type Description Default
lr float

Learning rate for grating parameters.

0.001

Returns:

Name Type Description
list

List of parameter groups for optimizer.

surf_dict
surf_dict()

Return a dict of surface parameters.

Returns:

Name Type Description
dict

Dictionary containing surface parameters.

save_ckpt
save_ckpt(save_path='./grating_doe.pth')

Save grating DOE parameters.

Parameters:

Name Type Description Default
save_path str

Path to save the checkpoint.

'./grating_doe.pth'
load_ckpt
load_ckpt(load_path='./grating_doe.pth')

Load grating DOE parameters.

Parameters:

Name Type Description Default
load_path str

Path to load the checkpoint from.

'./grating_doe.pth'

Phase Surfaces

deeplens.optics.phase_surface.Phase

Phase(r, d, norm_radii=None, mat2='air', pos_xy=None, vec_local=None, is_square=True, device='cpu')

Bases: DeepObj

Base phase profile for diffractive surfaces (metasurface or DOE).

This is the base class that provides common functionality for all phase parameterizations. Specific parameterizations should inherit from this class.

Reference

[1] https://support.zemax.com/hc/en-us/articles/1500005489061-How-diffractive-surfaces-are-modeled-in-OpticStudio [2] https://optics.ansys.com/hc/en-us/articles/360042097313-Small-Scale-Metalens-Field-Propagation [3] https://optics.ansys.com/hc/en-us/articles/18254409091987-Large-Scale-Metalens-Ray-Propagation

vec_global instance-attribute
vec_global = tensor([0.0, 0.0, 1.0])
d instance-attribute
d = tensor(d)
pos_x instance-attribute
pos_x = tensor(pos_xy[0])
pos_y instance-attribute
pos_y = tensor(pos_xy[1])
vec_local instance-attribute
vec_local = normalize(tensor(vec_local), p=2, dim=-1)
mat2 instance-attribute
mat2 = Material(mat2)
r instance-attribute
r = float(r)
is_square instance-attribute
is_square = is_square
w instance-attribute
w = r * float(sqrt(2))
h instance-attribute
h = r * float(sqrt(2))
diffraction instance-attribute
diffraction = True
diffraction_order instance-attribute
diffraction_order = 1
norm_radii instance-attribute
norm_radii = r if norm_radii is None else norm_radii
device instance-attribute
device = device if device is not None else device('cpu')
phi
phi(x, y)

Reference phase map at design wavelength. Must be implemented by subclasses.

dphi_dxy
dphi_dxy(x, y)

Calculate phase derivatives. Must be implemented by subclasses.

init_param_model
init_param_model()

Initialize parameterization parameters. Must be implemented by subclasses.

get_optimizer_params
get_optimizer_params(lrs=[0.0001, 0.01], optim_mat=False)

Generate optimizer parameters. Must be implemented by subclasses.

save_ckpt
save_ckpt(save_path='./doe.pth')

Save DOE parameters. Must be implemented by subclasses.

load_ckpt
load_ckpt(load_path='./doe.pth')

Load DOE parameters. Must be implemented by subclasses.

surf_dict
surf_dict()

Return surface parameters. Must be implemented by subclasses.

activate_diffraction
activate_diffraction(diffraction_order=1)

Activate diffraction of DOE in ray tracing.

ray_reaction
ray_reaction(ray, n1=None, n2=None)

Ray reaction on DOE surface.

intersect
intersect(ray, n=1.0)

Solve ray-plane intersection in local coordinate system and update ray data.

diffract
diffract(ray)

Diffraction of DOE surface. 1, The phase φ in radians adds to the optical path length of the ray 2, The gradient of the phase profile (phase slope) change the direction of rays.

Reference

[1] https://support.zemax.com/hc/en-us/articles/1500005489061-How-diffractive-surfaces-are-modeled-in-OpticStudio [2] Light propagation with phase discontinuities: generalized laws of reflection and refraction. Science 2011.

refract
refract(ray, eta)

Calculate refracted ray according to Snell's law in local coordinate system.

Parameters:

Name Type Description Default
ray Ray

incident ray.

required
eta float

ratio of indices of refraction, eta = n_i / n_t

required

Returns:

Name Type Description
ray Ray

refracted ray.

normal_vec
normal_vec(ray)

Calculate surface normal vector at intersection points.

Normal vector points from the surface toward the side where the light is coming from.

to_local_coord
to_local_coord(ray)

Transform ray to local coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray in global coordinate system.

required

Returns:

Name Type Description
ray Ray

transformed ray in local coordinate system.

to_global_coord
to_global_coord(ray)

Transform ray to global coordinate system.

Parameters:

Name Type Description Default
ray Ray

input ray in local coordinate system.

required

Returns:

Name Type Description
ray Ray

transformed ray in global coordinate system.

_get_rotation_matrix
_get_rotation_matrix(vec_from, vec_to)

Calculate rotation matrix to rotate vec_from to vec_to.

_apply_rotation
_apply_rotation(vectors, R)

Apply rotation matrix to vectors.

surface_with_offset
surface_with_offset(*args, **kwargs)

Surface sag with offset, only used in layout drawing.

get_optimizer
get_optimizer(lrs)

Generate optimizer.

Parameters:

Name Type Description Default
lrs list or float

Learning rates for different parameters.

required
draw_phase_map
draw_phase_map(save_name='./DOE_phase_map.png')

Draw phase map. Range from [0, 2*pi].

draw_widget
draw_widget(ax, color='black', linestyle='-')

Draw DOE as a two-side surface.

Material

DeepLens includes the SCHOTT, CDGM, and PLASTIC glass catalogues.

from deeplens.optics import Material

glass = Material('N-BK7')
n = glass.n(wavelength=550)   # refractive index at 550 nm

# Custom glass via Sellmeier equation
custom = Material(name='MyGlass', catalog='CUSTOM',
                  sellmeier_coef=[1.040, 0.232, 1.010, 0.006, 0.020, 103.6])

Sellmeier equation:

\[n^2 = 1 + \frac{B_1\lambda^2}{\lambda^2 - C_1} + \frac{B_2\lambda^2}{\lambda^2 - C_2} + \frac{B_3\lambda^2}{\lambda^2 - C_3}\]
Name Type n (550 nm)
N-BK7 Crown glass 1.519
N-SF11 Flint glass 1.785
PMMA Plastic 1.492
Fused Silica Glass 1.460

deeplens.optics.material.Material

Material(name=None, device='cpu')

Bases: DeepObj

Optical material defined by its wavelength-dependent refractive index.

Materials are looked up by name in the bundled CDGM, SCHOTT, or MISC AGF catalogs, in a custom JSON catalog, or specified inline as "n/V" (Cauchy approximation from Abbe number V).

Supported dispersion models: "sellmeier", "cauchy", "schott", and "interp" (lookup table).

Attributes:

Name Type Description
name str

Lowercase material name.

dispersion str

Dispersion model used ("sellmeier", "cauchy", "schott", or "interp").

n float

Refractive index at the d-line (587 nm).

V float

Abbe number.

Initialize an optical material.

Parameters:

Name Type Description Default
name str or None

Material name (case-insensitive). Accepted forms:

  • Glass catalog name, e.g. "N-BK7", "H-K9L"
  • "air" or "vacuum" (n = 1, non-dispersive)
  • Inline Cauchy, e.g. "1.5168/64.17"
  • Custom name registered in materials_data.json

Defaults to None (treated as "vacuum").

None
device str

Compute device. Defaults to "cpu".

'cpu'

Raises:

Type Description
NotImplementedError

If name is not found in any catalog.

Example

mat = Material("N-BK7") n_green = mat.get_ri(0.587) # refractive index at 587 nm

name instance-attribute
name = 'vacuum' if name is None else lower()
device instance-attribute
device = device
get_name
get_name()
load_dispersion
load_dispersion()

Load material dispersion equation.

set_material_param_agf
set_material_param_agf(material_data, material_name)

Set the material parameters and dispersion equation from AGF file.

set_sellmeier_param
set_sellmeier_param(params=None)

Manually set sellmeier parameters k1, l1, k2, l2, k3, l3.

This function is used when we want to manually set the sellmeier parameters for a custom material.

refractive_index
refractive_index(wvln)

Compute the refractive index at given wvln.

ior
ior(wvln)

Compute the refractive index at given wvln.

nV_to_AB staticmethod
nV_to_AB(n, V)

Convert (n ,V) paramters to (A, B) parameters to find the material.

match_material
match_material(mat_table=None)

Find the closest material in the CDGM common glasses database.

get_optimizer_params
get_optimizer_params(lrs=[0.0001, 0.01])

Optimize the material parameters (n, V).

Optimizing refractive index is more important than optimizing Abbe number.

Parameters:

Name Type Description Default
lrs list

learning rates for n and V. Defaults to [1e-4, 1e-4].

[0.0001, 0.01]

Light

Ray

Holds ray origins o, directions d, wavelength, validity mask, energy, and optical path length (OPL for coherent tracing).

from deeplens.optics import Ray

ray = Ray(
    o=torch.zeros(N, 3),   # origins [mm]
    d=torch.zeros(N, 3),   # unit direction vectors
    wavelength=0.550,       # wavelength [μm]
    device='cuda'
)
# Trace through a surface
ray_out = surface.ray_reaction(ray, n1=1.0, n2=1.5, wavelength=0.550)

deeplens.optics.light.Ray

Ray(o, d, wvln=DEFAULT_WAVE, coherent=False, device='cpu')

Bases: DeepObj

Batched ray bundle for optical simulation.

Stores ray origins, directions, wavelength, validity mask, energy, obliquity, and (in coherent mode) optical path length. All tensor attributes share the same batch shape (*batch_size, num_rays).

Attributes:

Name Type Description
o Tensor

Ray origins, shape (*batch, num_rays, 3) [mm].

d Tensor

Unit ray directions, shape (*batch, num_rays, 3).

wvln Tensor

Wavelength scalar [µm].

is_valid Tensor

Binary validity mask, shape (*batch, num_rays).

en Tensor

Energy weight, shape (*batch, num_rays, 1).

obliq Tensor

Obliquity factor, shape (*batch, num_rays, 1).

opl Tensor

Optical path length (coherent mode only), shape (*batch, num_rays, 1) [mm].

coherent bool

Whether OPL tracking is enabled.

Initialize a ray object.

Parameters:

Name Type Description Default
o Tensor

Ray origin, shape (..., num_rays, 3) [mm].

required
d Tensor

Ray direction, shape (..., num_rays, 3).

required
wvln float

Ray wavelength [µm].

DEFAULT_WAVE
coherent bool

Enable optical path length tracking for coherent tracing. Defaults to False.

False
device str

Compute device. Defaults to "cpu".

'cpu'
o instance-attribute
o = to(device)
d instance-attribute
d = normalize(d, p=2, dim=-1)
shape instance-attribute
shape = shape[:(-1)]
wvln instance-attribute
wvln = tensor(wvln, device=device)
is_valid instance-attribute
is_valid = ones(shape, device=device)
en instance-attribute
en = ones((*(shape), 1), device=device)
obliq instance-attribute
obliq = ones((*(shape), 1), device=device)
coherent instance-attribute
coherent = coherent
opl instance-attribute
opl = zeros((*(shape), 1), device=device)
device instance-attribute
device = device
prop_to
prop_to(z, n=1.0)

Ray propagates to a given depth plane.

Parameters:

Name Type Description Default
z float

depth.

required
n float

refractive index. Defaults to 1.

1.0
centroid
centroid()

Calculate the centroid of the ray, shape (..., num_rays, 3)

Returns:

Type Description

torch.Tensor: Centroid of the ray, shape (..., 3)

rms_error
rms_error(center_ref=None)

Calculate the RMS error of the ray.

Parameters:

Name Type Description Default
center_ref Tensor

Reference center of the ray, shape (..., 3). If None, use the centroid of the ray as reference.

None

Returns:

Type Description

torch.Tensor: average RMS error of the ray

flip_xy
flip_xy()

Flip the x and y coordinates of the ray.

This function is used when calculating point spread function and wavefront distribution.

clone
clone(device=None)

Clone the ray.

Can spercify which device we want to clone. Sometimes we want to store all rays in CPU, and when using it, we move it to GPU.

squeeze
squeeze(dim=None)

Squeeze the ray.

Parameters:

Name Type Description Default
dim int

dimension to squeeze. Defaults to None.

None
unsqueeze
unsqueeze(dim=None)

Unsqueeze the ray.

Parameters:

Name Type Description Default
dim int

dimension to unsqueeze. Defaults to None.

None

ComplexWave

Complex field with ASM / Fresnel / Fraunhofer propagation via torch.fft.

deeplens.optics.light.ComplexWave

ComplexWave(u=None, wvln=0.55, z=0.0, phy_size=(4.0, 4.0), res=(2000, 2000))

Bases: DeepObj

Complex scalar wave field for diffraction simulation.

Represents a monochromatic, coherent complex amplitude on a uniform rectangular grid. Propagation methods (ASM, Fresnel, Fraunhofer) are implemented as member functions and use torch.fft for efficiency.

Attributes:

Name Type Description
u Tensor

Complex amplitude, shape [1, 1, H, W].

wvln float

Wavelength [µm].

k float

Wave number 2π / (λ × 10⁻³) [mm⁻¹].

phy_size tuple

Physical aperture size (W, H) [mm].

ps float

Pixel pitch [mm] (must be square).

res tuple

Grid resolution (H, W) in pixels.

z float

Current axial position [mm].

Initialize a complex wave field.

Parameters:

Name Type Description Default
u Tensor or None

Initial complex amplitude. Accepted shapes: [H, W], [1, H, W], or [1, 1, H, W]. If None a zero field is created with the given res.

None
wvln float

Wavelength [µm]. Defaults to 0.55.

0.55
z float

Initial axial position [mm]. Defaults to 0.0.

0.0
phy_size tuple

Physical aperture (W, H) [mm]. Defaults to (4.0, 4.0).

(4.0, 4.0)
res tuple

Grid resolution (H, W) [pixels]. Only used when u is None. Defaults to (2000, 2000).

(2000, 2000)

Raises:

Type Description
AssertionError

If the pixel pitch is not square or the wavelength is outside the range (0.1, 10) µm.

u instance-attribute
u = u if is_tensor(u) else from_numpy(u)
res instance-attribute
res = shape[(-2):]
wvln instance-attribute
wvln = wvln
k instance-attribute
k = 2 * pi / (wvln * 0.001)
phy_size instance-attribute
phy_size = phy_size
ps instance-attribute
ps = phy_size[0] / res[0]
z instance-attribute
z = full_like(x, z)
point_wave classmethod
point_wave(point=(0, 0, -1000.0), wvln=0.55, z=0.0, phy_size=(4.0, 4.0), res=(2000, 2000), valid_r=None)

Create a spherical wave field on x0y plane originating from a point source.

Parameters:

Name Type Description Default
point tuple

Point source position in object space. [mm]. Defaults to (0, 0, -1000.0).

(0, 0, -1000.0)
wvln float

Wavelength. [um]. Defaults to 0.55.

0.55
z float

Field z position. [mm]. Defaults to 0.0.

0.0
phy_size tuple

Valid plane on x0y plane. [mm]. Defaults to (2, 2).

(4.0, 4.0)
res tuple

Valid plane resoltution. Defaults to (1000, 1000).

(2000, 2000)
valid_r float

Valid circle radius. [mm]. Defaults to None.

None

Returns:

Name Type Description
field ComplexWave

Complex field on x0y plane.

plane_wave classmethod
plane_wave(wvln=0.55, z=0.0, phy_size=(4.0, 4.0), res=(2000, 2000), valid_r=None)

Create a planar wave field on x0y plane.

Parameters:

Name Type Description Default
wvln float

Wavelength. [um].

0.55
z float

Field z position. [mm].

0.0
phy_size tuple

Physical size of the field. [mm].

(4.0, 4.0)
res tuple

Resolution.

(2000, 2000)
valid_r float

Valid circle radius. [mm].

None

Returns:

Name Type Description
field ComplexWave

Complex field.

image_wave classmethod
image_wave(img, wvln=0.55, z=0.0, phy_size=(4.0, 4.0))

Initialize a complex wave field from an image.

Parameters:

Name Type Description Default
img Tensor

Input image with shape [H, W] or [B, C, H, W]. Data range is [0, 1].

required
wvln float

Wavelength. [um].

0.55
z float

Field z position. [mm].

0.0
phy_size tuple

Physical size of the field. [mm].

(4.0, 4.0)

Returns:

Name Type Description
field ComplexWave

Complex field.

prop
prop(prop_dist, n=1.0)

Propagate the field by distance z. Can only propagate planar wave.

Reference

[1] Modeling and propagation of near-field diffraction patterns: A more complete approach. Table 1. [2] https://github.com/kaanaksit/odak/blob/master/odak/wave/classical.py [3] https://spie.org/samples/PM103.pdf [4] "Non-approximated Rayleigh Sommerfeld diffraction integral: advantages and disadvantages in the propagation of complex wave fields"

Parameters:

Name Type Description Default
prop_dist float

propagation distance, unit [mm].

required
n float

refractive index.

1.0

Returns:

Name Type Description
self

propagated complex wave field.

prop_to
prop_to(z, n=1)

Propagate the field to plane z.

Parameters:

Name Type Description Default
z float

destination plane z coordinate.

required
gen_xy_grid
gen_xy_grid()

Generate the x and y grid.

gen_freq_grid
gen_freq_grid()

Generate the frequency grid.

load
load(filepath)
load_npz
load_npz(filepath)

Load data from npz file.

save
save(filepath='./wavefield.npz')

Save the complex wave field to a npz file.

save_npz
save_npz(filepath='./wavefield.npz')

Save the complex wave field to a npz file.

save_image
save_image(save_name=None, data='irr')
show
show(save_name=None, data='irr')

Save the field as an image.

pad
pad(Hpad, Wpad)

Pad the input field by (Hpad, Hpad, Wpad, Wpad). This step will also expand physical size of the field.

Parameters:

Name Type Description Default
Hpad int

Number of pixels to pad on the top and bottom.

required
Wpad int

Number of pixels to pad on the left and right.

required

Returns:

Name Type Description
self

Padded complex wave field.

flip
flip()

Flip the field horizontally and vertically.

AngularSpectrumMethod

from deeplens.optics import AngularSpectrumMethod

asm = AngularSpectrumMethod(device='cuda')
field_out = asm.forward(field_in, distance=10.0, wavelength=0.550, pixel_size=0.01)

deeplens.optics.light.AngularSpectrumMethod

AngularSpectrumMethod(u, z, wvln, ps, n=1.0, padding=True)

Angular spectrum method.

Parameters:

Name Type Description Default
u tesor

complex field, shape [H, W] or [B, 1, H, W]

required
z float

propagation distance in [mm]

required
wvln float

wavelength in [um]

required
ps float

pixel size in [mm]

required
n float

refractive index

1.0
padding bool

padding or not

True

Returns:

Name Type Description
u

complex field, shape [H, W] or [B, 1, H, W]

Reference

[1] https://github.com/kaanaksit/odak/blob/master/odak/wave/classical.py#L293 [2] https://blog.csdn.net/zhenpixiaoyang/article/details/111569495


Image Simulation

Monte-Carlo PSF Integration

Bins ray hits into PSF grids via index_put_ with accumulate=True. Coherent mode uses OPL for complex amplitude accumulation.

deeplens.optics.imgsim.forward_integral

forward_integral(ray, ps, ks, pointc=None)

Differentiable Monte-Carlo integral over a ray bundle onto a pixel grid.

Bins ray hit positions into a ks × ks grid centred on pointc (or the ray centroid if pointc is None). In coherent mode the complex amplitude is accumulated instead of intensity, allowing PSF and wavefront computation.

The implementation uses index_put_ with accumulate=True for differentiability. A loop over the N field points is used because index_put_ cannot independently accumulate to separate batch slices; this is acceptable because N is typically small (1–10) while spp is large.

Parameters:

Name Type Description Default
ray Ray

Traced ray bundle with origin ray.o of shape [N, spp, 3] (or [spp, 3] for a single field point).

required
ps float

Pixel size [mm].

required
ks int

Output grid size in pixels (square).

required
pointc Tensor or None

Reference centre for each field point, shape [N, 2]. If None, the valid-ray centroid is used.

None

Returns:

Type Description

torch.Tensor: Accumulated field, shape [N, ks, ks]. Dtype is

complex if ray.coherent is True, otherwise real (float).

PSF Convolution

deeplens.optics.imgsim.conv_psf

conv_psf(img, psf)

Convolve an image batch with a single spatially-uniform PSF.

Applies a per-channel 2-D convolution using reflect boundary padding so that the output has the same spatial dimensions as the input. The PSF is internally flipped to convert the cross-correlation implemented by F.conv2d into a true convolution.

Parameters:

Name Type Description Default
img Tensor

Input image batch, shape [B, C, H, W].

required
psf Tensor

PSF kernel, shape [C, ks, ks]. ks may be odd or even.

required

Returns:

Type Description

torch.Tensor: Rendered image, shape [B, C, H, W].

Example

psf = lens.psf_rgb(points=torch.tensor([0.0, 0.0, -10000.0])) img_blur = conv_psf(img, psf)

deeplens.optics.imgsim.conv_psf_map

conv_psf_map(img, psf_map)

Convolve an image batch with a spatially-varying PSF map.

Divides the image into grid_h × grid_w non-overlapping patches and convolves each patch with its corresponding PSF kernel. The results are assembled back into a full-resolution output via a weighted blending step.

Parameters:

Name Type Description Default
img Tensor

Input image batch, shape [B, C, H, W].

required
psf_map Tensor

PSF map, shape [grid_h, grid_w, C, ks, ks].

required

Returns:

Type Description

torch.Tensor: Rendered image, shape [B, C, H, W].

deeplens.optics.imgsim.conv_psf_depth_interp

conv_psf_depth_interp(img, depth, psf_kernels, psf_depths, interp_mode='depth')

Depth-interpolated PSF convolution for a spatially-uniform but depth-varying blur.

Pre-convolves the image with PSFs at each reference depth, then blends the results using per-pixel linear interpolation weights derived from depth. This approximates defocus blur for a single field position across a depth range without computing a separate PSF per pixel.

Parameters:

Name Type Description Default
img Tensor

Image batch, shape [B, C, H, W], values in [0, 1].

required
depth Tensor

Depth map, shape [B, 1, H, W], values in (-∞, 0) mm (negative convention).

required
psf_kernels Tensor

PSF stack at reference depths, shape [num_depth, C, ks, ks].

required
psf_depths Tensor

Depth of each PSF layer, shape [num_depth], values in (-∞, 0) mm. Must be monotone.

required
interp_mode str

Interpolation space. "depth" interpolates linearly in depth; "disparity" interpolates linearly in 1/depth. Defaults to "depth".

'depth'

Returns:

Type Description

torch.Tensor: Blurred image, shape [B, C, H, W].

Raises:

Type Description
AssertionError

If depth or psf_depths contain non-negative values, or if interp_mode is not "depth" or "disparity".

deeplens.optics.imgsim.conv_psf_map_depth_interp

conv_psf_map_depth_interp(img, depth, psf_map, psf_depths, interp_mode='depth')

Convolve an image with a PSF map. Within each image patch, do interpolation with a depth map.

Parameters:

Name Type Description Default
img

(B, 3, H, W), [0, 1]

required
depth

(B, 1, H, W), (-inf, 0)

required
psf_map

(grid_h, grid_w, num_depth, 3, ks, ks)

required
psf_depths

(num_depth). (-inf, 0). Used to interpolate psf_map.

required
interp_mode

"depth" or "disparity". If "disparity", weights are calculated based on disparity (1/depth).

'depth'

Returns:

Name Type Description
img_render

(B, 3, H, W), [0, 1]

deeplens.optics.imgsim.conv_psf_pixel

conv_psf_pixel(img, psf)

Convolve an image batch with pixel-wise PSF.

Use the different PSF kernel for different pixels (folding approach). Application example: Blurs image with dynamic Gaussian blur.

Parameters:

Name Type Description Default
img Tensor

The image to be blurred (B, C, H, W).

required
psf Tensor

Per pixel local PSFs (H, W, C, ks, ks). ks can be odd or even.

required

Returns:

Name Type Description
img_render Tensor

Rendered image (B, C, H, W).