Skip to content

Commit 7753b89

Browse files
committed
fix(adjoint): crash in adjoint simulation creation for simulations with multiple sources
and `normalize_index` set
1 parent 3cba218 commit 7753b89

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Fixed
1919
- Stricter validation for `bend_radius` in mode simulations, preventing the bend center from coinciding with the simulation boundary.
20+
- Prevent autograd adjoint simulations from reusing out-of-range `normalize_index` values by defaulting their normalization to the first adjoint source when needed.
2021

2122

2223
## [v2.10.0rc1] - 2025-09-11

tests/test_components/autograd/test_autograd.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,58 @@ def test_broadband_adjoint_src_width():
14271427
)
14281428

14291429

1430+
def test_autograd_multi_source_normalize_index(use_emulated_run):
1431+
"""Gradient run with multi-source normalization does not raise and returns finite grads."""
1432+
1433+
freq0 = 2e14
1434+
fwidth = 5e13
1435+
1436+
source_time = td.GaussianPulse(freq0=freq0, fwidth=fwidth)
1437+
source0 = td.UniformCurrentSource(
1438+
size=(0, 0, 0),
1439+
center=(0.0, -0.2, 0.0),
1440+
polarization="Hx",
1441+
source_time=source_time,
1442+
)
1443+
source1 = source0.updated_copy(center=(0.0, 0.2, 0.0))
1444+
1445+
monitor = td.FieldMonitor(
1446+
size=(0, 0, 0),
1447+
center=(0.0, 0.0, 0.0),
1448+
freqs=[freq0],
1449+
fields=["Ex"],
1450+
name="field",
1451+
)
1452+
1453+
base_sim = td.Simulation(
1454+
size=(1.0, 1.0, 1.0),
1455+
run_time=8 / fwidth,
1456+
grid_spec=td.GridSpec.uniform(dl=0.1),
1457+
sources=[source0, source1],
1458+
monitors=[monitor],
1459+
normalize_index=1,
1460+
)
1461+
1462+
def objective(params):
1463+
eps = 2.0 + params[0]
1464+
structure = td.Structure(
1465+
geometry=td.Box(size=(0.5, 0.5, 0.5), center=(0.0, 0.0, 0.0)),
1466+
medium=td.Medium(permittivity=eps),
1467+
)
1468+
1469+
sim = base_sim.updated_copy(structures=[structure])
1470+
data = run(sim, task_name="normalize_index_clamp", verbose=False)
1471+
field = data["field"].Ex.sel(f=freq0).values
1472+
return anp.real(field).sum()
1473+
1474+
params = anp.array([0.1])
1475+
val, grad = ag.value_and_grad(objective)(params)
1476+
1477+
assert anp.isfinite(val)
1478+
assert grad.shape == params.shape
1479+
assert anp.all(anp.isfinite(grad))
1480+
1481+
14301482
@pytest.mark.parametrize("colocate", [True, False])
14311483
@pytest.mark.parametrize("objtype", ["flux", "intensity"])
14321484
def test_interp_objectives(use_emulated_run, colocate, objtype):

tidy3d/components/data/sim_data.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,8 +1098,12 @@ def _make_adjoint_sims(
10981098
"post_norm": adjoint_source_info.post_norm,
10991099
}
11001100

1101-
if not adjoint_source_info.normalize_sim:
1102-
sim_adj_update_dict["normalize_index"] = None
1101+
if adjoint_source_info.normalize_sim:
1102+
normalize_index_adj = 0
1103+
else:
1104+
normalize_index_adj = None
1105+
1106+
sim_adj_update_dict["normalize_index"] = normalize_index_adj
11031107

11041108
if sim_original.sources and grid_spec_original.wavelength is None:
11051109
sim_adj_update_dict["grid_spec"] = grid_spec_adj

0 commit comments

Comments
 (0)