From 27b62433461ddce571dc3d6f9282563081e8aaae Mon Sep 17 00:00:00 2001 From: Marc de Cea Date: Sat, 9 May 2026 17:26:42 -0700 Subject: [PATCH 1/6] add target_neff parameter to mode solver --- gplugins/tidy3d/modes.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gplugins/tidy3d/modes.py b/gplugins/tidy3d/modes.py index 63b1fc87..30809f3c 100644 --- a/gplugins/tidy3d/modes.py +++ b/gplugins/tidy3d/modes.py @@ -92,6 +92,8 @@ class Waveguide(BaseModel, extra="forbid", arbitrary_types_allowed=True): surface_k: absorption coefficient added to the core material index on the top-surface layer. bend_radius: radius to simulate circular bend. + target_neff: target effective index for the mode solver. Defaults + to the real part of the core refractive index if not specified. num_modes: number of modes to compute. group_index_step: if set to `True`, indicates that the group index must also be calculated. If set to a positive float @@ -147,6 +149,7 @@ class Waveguide(BaseModel, extra="forbid", arbitrary_types_allowed=True): surface_thickness: float = 0.0 surface_k: float = 0.0 bend_radius: float | None = None + target_neff: float | None = None num_modes: int = 2 group_index_step: bool | float = False precision: Precision = "double" @@ -222,9 +225,11 @@ def waveguide(self): else None ) + target_neff = self.target_neff if self.target_neff is not None else n_core.real + mode_spec = td.ModeSpec( num_modes=self.num_modes, - target_neff=n_core.real, + target_neff=target_neff, bend_radius=self.bend_radius, bend_axis=1, num_pml=(12, 12) if self.bend_radius else (0, 0), @@ -554,9 +559,11 @@ def waveguide(self): else None ) + target_neff = self.target_neff if self.target_neff is not None else n_core.real + mode_spec = td.ModeSpec( num_modes=self.num_modes, - target_neff=n_core.real, + target_neff=target_neff, bend_radius=self.bend_radius, bend_axis=1, num_pml=(12, 12) if self.bend_radius else (0, 0), From 3928144ca310a734b7974c332857a9a8063143b5 Mon Sep 17 00:00:00 2001 From: Marc de Cea Date: Sun, 10 May 2026 15:51:29 -0700 Subject: [PATCH 2/6] implement shared method and docstring for target_neff --- gplugins/tidy3d/modes.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gplugins/tidy3d/modes.py b/gplugins/tidy3d/modes.py index 30809f3c..e69fa3ab 100644 --- a/gplugins/tidy3d/modes.py +++ b/gplugins/tidy3d/modes.py @@ -181,6 +181,10 @@ def filepath(self) -> pathlib.Path | None: h = hashlib.md5(named_args_string.encode()).hexdigest()[:16] return cache_path / f"{self.__class__.__name__}_{h}.npz" + def _resolve_target_neff(self, n_core: complex) -> float: + """Return target_neff if set, otherwise fall back to n_core.real.""" + return self.target_neff if self.target_neff is not None else n_core.real + @property def waveguide(self): """Tidy3D waveguide used by this instance.""" @@ -225,7 +229,7 @@ def waveguide(self): else None ) - target_neff = self.target_neff if self.target_neff is not None else n_core.real + target_neff = self._resolve_target_neff(n_core) mode_spec = td.ModeSpec( num_modes=self.num_modes, @@ -559,7 +563,7 @@ def waveguide(self): else None ) - target_neff = self.target_neff if self.target_neff is not None else n_core.real + target_neff = self._resolve_target_neff(n_core) mode_spec = td.ModeSpec( num_modes=self.num_modes, From ed6a276a60ec7e6ab15882d7b58eed4d1980af8e Mon Sep 17 00:00:00 2001 From: Marc de Cea Date: Sun, 10 May 2026 15:51:48 -0700 Subject: [PATCH 3/6] Use lossless SiO2 by default --- gplugins/tidy3d/materials.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gplugins/tidy3d/materials.py b/gplugins/tidy3d/materials.py index 435b3602..c9f05159 100644 --- a/gplugins/tidy3d/materials.py +++ b/gplugins/tidy3d/materials.py @@ -9,7 +9,7 @@ material_name_to_tidy3d = { "si": td.material_library["cSi"]["Li1993_293K"], - "sio2": td.material_library["SiO2"]["Horiba"], + "sio2": td.material_library["SiO2"]["Palik_Lossless"], "sin": td.material_library["Si3N4"]["Luke2015PMLStable"], } From 503aeacecb1b797e17995da8e35ed7fb3ba7a65f Mon Sep 17 00:00:00 2001 From: Marc de Cea Date: Wed, 13 May 2026 15:09:21 -0700 Subject: [PATCH 4/6] Adjust neff of test --- gplugins/tidy3d/tests/test_modes_coupler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gplugins/tidy3d/tests/test_modes_coupler.py b/gplugins/tidy3d/tests/test_modes_coupler.py index 674b6fdb..f945c50f 100644 --- a/gplugins/tidy3d/tests/test_modes_coupler.py +++ b/gplugins/tidy3d/tests/test_modes_coupler.py @@ -18,7 +18,7 @@ def test_neff() -> None: clad_material="sio2", ) n_eff = wg.n_eff[0].real - n_eff_ref = 2.5743837634515767 + n_eff_ref = 2.6076116125083564 assert np.isclose(n_eff, n_eff_ref, rtol=0.01), n_eff From f80388a014e1984e4579ff2c230edc8d91aaa5b4 Mon Sep 17 00:00:00 2001 From: Marc de Cea Date: Wed, 13 May 2026 16:44:59 -0700 Subject: [PATCH 5/6] Add track_modes to sweep_bend_mismatch --- gplugins/tidy3d/modes.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/gplugins/tidy3d/modes.py b/gplugins/tidy3d/modes.py index e69fa3ab..ba52c9cf 100644 --- a/gplugins/tidy3d/modes.py +++ b/gplugins/tidy3d/modes.py @@ -511,6 +511,8 @@ class WaveguideCoupler(Waveguide): index must also be calculated. If set to a positive float it defines the fractional frequency step used for the numerical differentiation of the effective index. + target_neff: target effective index for the mode solver. Defaults + to the real part of the core refractive index if not specified. precision: computation precision. grid_resolution: wavelength resolution of the computation grid. max_grid_scaling: grid scaling factor in cladding regions. @@ -874,7 +876,10 @@ def sweep_mode_area(waveguide: Waveguide, **sweep_kwargs) -> np.ndarray: def sweep_bend_mismatch( - waveguide: Waveguide, bend_radii: tuple[float, ...] + waveguide: Waveguide, + bend_radii: tuple[float, ...], + track_modes: bool = False, + modes_to_track: Sequence[int] = (0, ), ) -> np.ndarray: """Overlap integral squared for the bend mode mismatch loss. @@ -884,7 +889,24 @@ def sweep_bend_mismatch( Args: waveguide: base waveguide geometry. bend_radii: radii values to sweep. + track_modes: if True, for each radius select the bend mode with + the best overlap for each tracked straight mode. + modes_to_track: straight mode indices to track. Required when + track_modes is True. """ + if track_modes: + if len(modes_to_track) == 0: + raise ValueError("modes_to_track must be provided when track_modes is True") + if waveguide.num_modes < max(modes_to_track) + 1: + raise ValueError( + f"num_modes ({waveguide.num_modes}) must be >= " + f"{max(modes_to_track) + 1} to track modes {modes_to_track}" + ) + if waveguide.num_modes < 2: + raise ValueError( + "Track modes requires num_modes >= 2" + ) + kwargs = dict(waveguide) kwargs.pop("bend_radius") straight = Waveguide(**kwargs) @@ -893,9 +915,16 @@ def sweep_bend_mismatch( for radius in tqdm(bend_radii): bend = Waveguide(bend_radius=radius, **kwargs) overlap = bend.overlap(straight) - results.append( - np.diagonal(overlap) ** 2 if straight.num_modes > 1 else overlap**2 - ) + + if track_modes: + best = [ + np.max(np.abs(overlap[:, m]) ** 2) for m in modes_to_track + ] + results.append(best) + else: + results.append( + np.diagonal(overlap) ** 2 if straight.num_modes > 1 else overlap**2 + ) return np.abs(results) ** 2 From 9f7fa52bb2490d8ccc770fdba091d9b3ac5f8c95 Mon Sep 17 00:00:00 2001 From: Joaquin Matres <4514346+joamatab@users.noreply.github.com> Date: Sun, 17 May 2026 10:29:31 -0700 Subject: [PATCH 6/6] fix pre-commit formatting in modes.py --- gplugins/tidy3d/modes.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/gplugins/tidy3d/modes.py b/gplugins/tidy3d/modes.py index ba52c9cf..8ebd42a5 100644 --- a/gplugins/tidy3d/modes.py +++ b/gplugins/tidy3d/modes.py @@ -879,7 +879,7 @@ def sweep_bend_mismatch( waveguide: Waveguide, bend_radii: tuple[float, ...], track_modes: bool = False, - modes_to_track: Sequence[int] = (0, ), + modes_to_track: Sequence[int] = (0,), ) -> np.ndarray: """Overlap integral squared for the bend mode mismatch loss. @@ -903,9 +903,7 @@ def sweep_bend_mismatch( f"{max(modes_to_track) + 1} to track modes {modes_to_track}" ) if waveguide.num_modes < 2: - raise ValueError( - "Track modes requires num_modes >= 2" - ) + raise ValueError("Track modes requires num_modes >= 2") kwargs = dict(waveguide) kwargs.pop("bend_radius") @@ -917,9 +915,7 @@ def sweep_bend_mismatch( overlap = bend.overlap(straight) if track_modes: - best = [ - np.max(np.abs(overlap[:, m]) ** 2) for m in modes_to_track - ] + best = [np.max(np.abs(overlap[:, m]) ** 2) for m in modes_to_track] results.append(best) else: results.append(