Skip to content

Commit b0a92fd

Browse files
committed
fix bug in autograd differentiation cylinder.center
1 parent 76ab553 commit b0a92fd

File tree

3 files changed

+53
-28
lines changed

3 files changed

+53
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515
- Regression in local field projection leading to incorrect results for `far_field_approx=True`.
16+
- Bug when differentiating with respect to `Cylinder.center`.
17+
1618

1719
## [2.7.6] - 2024-10-30
1820

tests/test_components/test_autograd.py

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,10 @@ def make_structures(params: anp.ndarray) -> dict[str, td.Structure]:
395395
custom_pole_res = td.Structure(geometry=box, medium=custom_med_pole_res)
396396

397397
radius = 0.4 * (1 + anp.abs(vector @ params))
398-
cyl_center_y = 0 # vector @ params
399-
cyl_center_z = 0 # -vector @ params
398+
cyl_center_y = vector @ params
399+
cyl_center_z = -vector @ params
400400
cylinder_geo = td.Cylinder(
401-
radius=radii,
401+
radius=anp.mean(radii) * 0.5,
402402
center=(0, cyl_center_y, cyl_center_z),
403403
axis=0,
404404
length=LX / 2 if IS_3D else td.inf,
@@ -770,43 +770,67 @@ def objective(*args):
770770
def test_autograd_polyslab_cylinder(use_emulated_run, monitor_key):
771771
"""Test an objective function through tidy3d autograd."""
772772

773-
fn_dict_polyslab = get_functions("polyslab", monitor_key)
774-
make_sim_polyslab = fn_dict_polyslab["sim"]
773+
t = 1.0
774+
axis = 0
775775

776-
fn_dict_cylinder = get_functions("cylinder", monitor_key)
777-
make_sim_cylinder = fn_dict_cylinder["sim"]
776+
num_pts = 89
778777

779-
postprocess = fn_dict_cylinder["postprocess"]
778+
monitor, postprocess = make_monitors()[monitor_key]
779+
780+
def make_cylinder(radius, x0, y0):
781+
return td.Cylinder(
782+
center=td.Cylinder.unpop_axis(0.0, (x0, y0), axis=axis),
783+
radius=radius,
784+
length=t,
785+
axis=axis,
786+
) # .to_polyslab(num_pts)
787+
788+
def make_polyslab(radius, x0, y0):
789+
phis = anp.linspace(0, 2 * np.pi, num_pts + 1)[:-1]
790+
791+
xs = radius * anp.cos(phis) + x0
792+
ys = radius * anp.sin(phis) + y0
793+
794+
vertices = anp.stack((xs, ys), axis=-1)
795+
796+
return td.PolySlab(
797+
vertices=vertices,
798+
axis=axis,
799+
slab_bounds=(-t / 2, t / 2),
800+
)
780801

781-
def objective_polyslab(*args):
802+
def make_sim(params, geo_maker):
803+
geo = geo_maker(*params)
804+
structure = td.Structure(geometry=geo, medium=td.Medium(permittivity=2))
805+
806+
return SIM_BASE.updated_copy(structures=[structure], monitors=[monitor])
807+
808+
p0 = [1.0, 0.0, 0.0]
809+
810+
def objective_polyslab(params):
782811
"""Objective function."""
783-
sim = make_sim_polyslab(*args)
812+
sim = make_sim(params, geo_maker=make_polyslab)
784813
if PLOT_SIM:
785814
plot_sim(sim, plot_eps=True)
786815
data = run(sim, task_name="autograd_test", verbose=False)
787-
value = postprocess(data)
788-
return value
816+
return anp.sum(anp.abs(data[monitor.name].amps)).item()
789817

790-
val_polyslab, grad_polyslab = ag.value_and_grad(objective_polyslab)(params0)
818+
val_polyslab, grad_polyslab = ag.value_and_grad(objective_polyslab)(p0)
791819
print(val_polyslab, grad_polyslab)
792820
assert anp.all(grad_polyslab != 0.0), "some gradients are 0"
793821

794-
def objective_cylinder(*args):
822+
def objective_cylinder(params):
795823
"""Objective function."""
796-
sim = make_sim_cylinder(*args)
824+
sim = make_sim(params, geo_maker=make_cylinder)
797825
if PLOT_SIM:
798826
plot_sim(sim, plot_eps=True)
799827
data = run(sim, task_name="autograd_test", verbose=False)
800-
value = postprocess(data)
801-
return value
828+
return anp.sum(anp.abs(data[monitor.name].amps)).item()
802829

803-
val_cylinder, grad_cylinder = ag.value_and_grad(objective_cylinder)(params0)
830+
val_cylinder, grad_cylinder = ag.value_and_grad(objective_cylinder)(p0)
804831
print(val_cylinder, grad_cylinder)
805832
assert anp.all(grad_cylinder != 0.0), "some gradients are 0"
806833

807-
# just make sure they're somewhat close (use different discretizations)
808-
assert np.allclose(grad_cylinder, grad_polyslab, rtol=0.3)
809-
810834

811835
@pytest.mark.parametrize("structure_key, monitor_key", args)
812836
def test_autograd_server(use_emulated_run, structure_key, monitor_key):

tidy3d/components/geometry/primitives.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,13 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM
301301
vjps_vertices_xs, vjps_vertices_ys = vjps_polyslab[("vertices",)].T
302302

303303
# transform polyslab vertices derivatives into Cylinder parameter derivatives
304+
xs_, ys_ = self._points_unit_circle(num_pts_circumference=num_pts_circumference)
305+
vjp_xs = np.sum(xs_ * vjps_vertices_xs)
306+
vjp_ys = np.sum(ys_ * vjps_vertices_ys)
307+
304308
vjps = {}
305309
for path in derivative_info.paths:
306310
if path == ("radius",):
307-
xs_, ys_ = self._points_unit_circle(num_pts_circumference=num_pts_circumference)
308-
309-
vjp_xs = np.sum(xs_ * vjps_vertices_xs)
310-
vjp_ys = np.sum(ys_ * vjps_vertices_ys)
311-
312311
vjps[path] = vjp_xs + vjp_ys
313312

314313
elif "center" in path:
@@ -322,9 +321,9 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM
322321

323322
_, (index_x, index_y) = self.pop_axis((0, 1, 2), axis=self.axis)
324323
if center_index == index_x:
325-
vjps[path] = np.sum(vjp_xs)
324+
vjps[path] = np.sum(vjps_vertices_xs)
326325
elif center_index == index_y:
327-
vjps[path] = np.sum(vjp_ys)
326+
vjps[path] = np.sum(vjps_vertices_ys)
328327
else:
329328
raise ValueError(
330329
"Something unexpected happened. Was asked to differentiate "

0 commit comments

Comments
 (0)