Skip to content

Commit dd03867

Browse files
Mihouclaude
andcommitted
revert: hold the aperture edge check out of the release
Reverts merge 927a506, which carried 2755b3a (code-update/ aperture-edge-validity-20261014): rejecting rays that enter an asphere through its rim, and sizing prune_surf apertures only from sensor-reaching rays. The check is physically right and changes no evaluated metric of an existing lens, but it changes AutoLens trajectories: with lost edge rays out of the RMS loss, vignetting becomes free. In the short ex2 gate, full-field throughput fell on 3 of 4 seeds (v2.5.6 -> dev: s1 0.81 -> 0.78, s2 0.69 -> 0.77, s3 0.99 -> 0.42, s7 0.77 -> 0.48). Held out of this release until the owner decides to re-land it. To re-land it, revert this commit (re-merging the branch would be a no-op, since its commits are already in history). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 70c7363 commit dd03867

3 files changed

Lines changed: 6 additions & 205 deletions

File tree

‎deeplens/geolens_pkg/ops.py‎

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ def prune_surf(self, mounting_margin=None):
4040
"""Prune surface radii so all valid rays pass through, then enforce manufacturability.
4141
4242
Traces 16 meridional fields from 0 to the full FoV to find the maximum
43-
sensor-reaching ray height [mm] on each surface, expands it by a mounting
44-
margin, then caps the proposed radii to satisfy an edge-sag limit and
45-
edge-clearance (air-gap / edge-thickness) constraints with neighbouring surfaces.
43+
ray height [mm] on each surface, expands it by a mounting margin, then
44+
caps the proposed radii to satisfy an edge-sag limit and edge-clearance
45+
(air-gap / edge-thickness) constraints with neighbouring surfaces.
4646
Aperture surfaces are not resized. The capped radii are committed via
47-
each surface's `update_r`. With no sensor-reaching ray height, the saved
48-
radius is used without a mounting margin; geometry caps still apply.
47+
each surface's `update_r`.
4948
5049
Args:
5150
mounting_margin (float or None, optional): Absolute mounting margin
@@ -76,11 +75,8 @@ def prune_surf(self, mounting_margin=None):
7675

7776
# Ray record, shape [num_rays, num_surfaces + 2, 3]
7877
ray_o_record = torch.stack(ray_o_record, dim=-2)
79-
ray_o_record = ray_o_record.reshape(-1, ray_o_record.shape[-2], 3)
80-
# A ray lost later must not inflate an earlier surface's aperture.
81-
reaches_sensor = torch.isfinite(ray_o_record[:, -1, :]).all(-1)
82-
ray_o_record = torch.where(reaches_sensor[:, None, None], ray_o_record, 0.0)
8378
ray_o_record = torch.nan_to_num(ray_o_record, nan=0.0, posinf=0.0, neginf=0.0)
79+
ray_o_record = ray_o_record.reshape(-1, ray_o_record.shape[-2], 3)
8480

8581
# Compute the maximum ray height for each surface
8682
ray_r_record = (ray_o_record[..., :2] ** 2).sum(-1).sqrt()
@@ -95,9 +91,7 @@ def prune_surf(self, mounting_margin=None):
9591
if surf_r_max[i] > 0:
9692
base = float(surf_r_max[i].item())
9793
else:
98-
# No ray evidence: repeated pruning must not add another margin.
99-
proposed_r[i] = float(saved_radii[i])
100-
continue
94+
base = float(self.surfaces[i].r)
10195

10296
# Expand the ray-traced radius by a mounting margin
10397
if mounting_margin is None:

‎deeplens/geometric_surface/aspheric.py‎

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -178,68 +178,6 @@ def _get_curvature_params(self):
178178
"""
179179
return self.c, self.k
180180

181-
def newtons_method(self, ray):
182-
"""Find an intersection, rejecting rays entering behind the aperture rim."""
183-
t, valid = super().newtons_method(ray)
184-
return t, valid & ~self._enters_through_edge(ray)
185-
186-
@torch.no_grad()
187-
def _enters_through_edge(self, ray):
188-
"""Identify rays entering the aperture or conic domain behind the face.
189-
190-
The entry point is pulled radially inside the boundary before evaluating
191-
sag, so a grazing ray is not sampled past its intersection. Rays starting
192-
inside the valid region retain the usual Newton validity checks.
193-
194-
Args:
195-
ray (Ray): Input ray bundle in local surface coordinates.
196-
197-
Returns:
198-
mask (torch.Tensor): Boolean edge-entry mask, shape [...].
199-
"""
200-
o, d = ray.o, ray.d
201-
c, k = self._get_curvature_params()
202-
aperture_sq = (self.w**2 + self.h**2) / 4 if self.is_square else self.r**2
203-
conic_power = (1 + k) * c**2
204-
domain_sq = torch.where(
205-
conic_power > 0,
206-
1 / torch.where(conic_power > 0, conic_power, 1.0),
207-
torch.full_like(conic_power, float("inf")),
208-
)
209-
radius_sq = domain_sq.clamp(max=aperture_sq).to(o)
210-
a = d[..., :2].square().sum(-1)
211-
b = (o[..., :2] * d[..., :2]).sum(-1)
212-
outside = o[..., :2].square().sum(-1) - radius_sq
213-
disc = b.square() - a * outside
214-
axial = a == 0
215-
denominator = torch.where(axial, 1.0, a)
216-
root = disc.clamp(min=0).sqrt()
217-
t_in = torch.where(axial, -float("inf"), (-b - root) / denominator)
218-
t_out = torch.where(axial, float("inf"), (-b + root) / denominator)
219-
reaches = torch.where(axial, outside <= 0, disc > 0)
220-
starts_inside = outside <= 0
221-
222-
if self.is_square:
223-
# Square apertures use half-side lengths, not a circular substitute.
224-
half_size = o.new_tensor([self.w / 2, self.h / 2])
225-
parallel = d[..., :2] == 0
226-
safe_d = torch.where(parallel, 1.0, d[..., :2])
227-
t1 = (-half_size - o[..., :2]) / safe_d
228-
t2 = (half_size - o[..., :2]) / safe_d
229-
near = torch.where(parallel, -float("inf"), torch.minimum(t1, t2))
230-
far = torch.where(parallel, float("inf"), torch.maximum(t1, t2))
231-
t_in = torch.maximum(t_in, near.amax(-1))
232-
t_out = torch.minimum(t_out, far.amin(-1))
233-
inside_square = o[..., :2].abs() <= half_size
234-
reaches = reaches & (~parallel | inside_square).all(-1)
235-
starts_inside = starts_inside & inside_square.all(-1)
236-
237-
enters = reaches & ~starts_inside & (t_in > 0) & (t_out > t_in)
238-
entry = o + d * torch.where(enters, t_in, 0.0).unsqueeze(-1)
239-
xy = torch.where(enters.unsqueeze(-1), entry[..., :2], 0.0) * (1 - 1e-6)
240-
behind = (self._sag(xy[..., 0], xy[..., 1]) - entry[..., 2]) * d[..., 2] < 0
241-
return enters & behind
242-
243181
def paraxial_power(self, n1, n2, wvln=None):
244182
"""Return the paraxial optical power of this surface [1/mm].
245183

‎test/test_aperture_validity.py‎

Lines changed: 0 additions & 131 deletions
This file was deleted.

0 commit comments

Comments
 (0)