Skip to content

Commit 51161f9

Browse files
feat: custom source time in modeler
1 parent 8945224 commit 51161f9

File tree

7 files changed

+103
-3
lines changed

7 files changed

+103
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
- Added voltage integral specification classes: `AxisAlignedVoltageIntegralSpec` and `Custom2DVoltageIntegralSpec`.
2323
- Added current integral specification classes: `AxisAlignedCurrentIntegralSpec`, `CompositeCurrentIntegralSpec`, and `Custom2DCurrentIntegralSpec`.
2424
- `sort_spec` in `ModeSpec` allows for fine-grained filtering and sorting of modes. This also deprecates `filter_pol`. The equivalent usage for example to `filter_pol="te"` is `sort_spec=ModeSortSpec(filter_key="TE_polarization", filter_reference=0.5)`. `ModeSpec.track_freq` has also been deprecated and moved to `ModeSortSpec.track_freq`.
25+
- Added `custom_source_time` parameter to `ComponentModeler` classes (`ModalComponentModeler` and `TerminalComponentModeler`), allowing specification of custom source time dependence.
2526

2627
### Changed
2728
- Improved performance of antenna metrics calculation by utilizing cached wave amplitude calculations instead of recomputing wave amplitudes for each port excitation in the `TerminalComponentModelerData`.

schemas/TerminalComponentModeler.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18180,6 +18180,19 @@
1818018180
"default": {},
1818118181
"type": "object"
1818218182
},
18183+
"custom_source_time": {
18184+
"anyOf": [
18185+
{
18186+
"$ref": "#/definitions/ContinuousWave"
18187+
},
18188+
{
18189+
"$ref": "#/definitions/CustomSourceTime"
18190+
},
18191+
{
18192+
"$ref": "#/definitions/GaussianPulse"
18193+
}
18194+
]
18195+
},
1818318196
"element_mappings": {
1818418197
"default": [],
1818518198
"items": {

tests/test_plugins/smatrix/test_component_modeler.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from tidy3d.plugins.smatrix import ModalComponentModeler, ModalComponentModelerData, Port
1313
from tidy3d.web.api.container import Batch
1414

15-
from ...utils import run_emulated
15+
from ...utils import AssertLogStr, run_emulated
1616

1717
# Waveguide height
1818
wg_height = 0.22
@@ -445,3 +445,37 @@ def test_get_task_name():
445445
# Test with invalid format
446446
with pytest.raises(ValueError):
447447
ModalComponentModeler.get_task_name(port=port, format="invalid")
448+
449+
450+
def test_custom_source_time(monkeypatch):
451+
"""Test that custom_source_time is properly used in the component modeler."""
452+
modeler = make_component_modeler()
453+
freqs = modeler.freqs
454+
custom_source = td.GaussianPulse.from_frequency_range(fmin=min(freqs), fmax=max(freqs))
455+
456+
# Create modeler with custom source time
457+
with AssertLogStr(
458+
log_level_expected="WARNING", excludes_str="Custom source time does not cover all"
459+
):
460+
modeler = make_component_modeler(custom_source_time=custom_source)
461+
462+
# Run the modeler and verify it works with custom source time
463+
modeler_data = run_component_modeler(monkeypatch, modeler=modeler)
464+
465+
# Verify that simulations were created and run successfully
466+
s_matrix = modeler_data.smatrix()
467+
assert s_matrix is not None
468+
469+
# Verify that the simulations in sim_dict use the custom source time
470+
for sim in modeler.sim_dict.values():
471+
# Each simulation should have sources with the custom source time
472+
assert len(sim.sources) > 0
473+
for source in sim.sources:
474+
assert source.source_time.freq0 == custom_source.freq0
475+
assert source.source_time.fwidth == custom_source.fwidth
476+
477+
with AssertLogStr(
478+
log_level_expected="WARNING", contains_str="Custom source time does not cover all"
479+
):
480+
custom_source = td.GaussianPulse(freq0=td.C_0, fwidth=1e12)
481+
modeler = make_component_modeler(custom_source_time=custom_source)

tests/test_plugins/smatrix/test_terminal_component_modeler.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,3 +1778,29 @@ def test_wave_port_extrusion_differential_stripline():
17781778
# make sure that the error is triggered even when ports are reshuffled
17791779
with pytest.raises(SetupError):
17801780
sim = tcm.base_sim
1781+
1782+
1783+
def test_custom_source_time(monkeypatch, tmp_path):
1784+
"""Test that custom_source_time is properly used in the terminal component modeler."""
1785+
# Create a custom source time
1786+
custom_source = td.GaussianPulse(freq0=2e9, fwidth=1e8)
1787+
1788+
# Create modeler with custom source time
1789+
modeler = make_component_modeler(
1790+
planar_pec=True, port_refinement=False, custom_source_time=custom_source
1791+
)
1792+
1793+
# Run the modeler and verify it works with custom source time
1794+
modeler_data = run_component_modeler(monkeypatch, modeler=modeler)
1795+
1796+
# Verify that simulations were created and run successfully
1797+
s_matrix = modeler_data.smatrix()
1798+
assert s_matrix is not None
1799+
1800+
# Verify that the simulations in sim_dict use the custom source time
1801+
for sim in modeler.sim_dict.values():
1802+
# Each simulation should have sources with the custom source time
1803+
assert len(sim.sources) > 0
1804+
for source in sim.sources:
1805+
assert source.source_time.freq0 == custom_source.freq0
1806+
assert source.source_time.fwidth == custom_source.fwidth

tidy3d/plugins/smatrix/component_modelers/base.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import pydantic.v1 as pd
99

1010
from tidy3d.components.autograd.constants import MAX_NUM_ADJOINT_PER_FWD
11-
from tidy3d.components.base import Tidy3dBaseModel, cached_property
11+
from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing
1212
from tidy3d.components.geometry.utils import _shift_value_signed
1313
from tidy3d.components.simulation import Simulation
14+
from tidy3d.components.source.time import SourceTimeType
1415
from tidy3d.components.types import Complex, FreqArray
1516
from tidy3d.components.validators import (
1617
assert_unique_names,
@@ -94,6 +95,12 @@ class AbstractComponentModeler(ABC, Tidy3dBaseModel):
9495
"matrix element. If all elements of a given column of the scattering matrix are defined "
9596
"by ``element_mappings``, the simulation corresponding to this column is skipped automatically.",
9697
)
98+
custom_source_time: Optional[SourceTimeType] = pd.Field(
99+
None,
100+
title="Custom Source Time",
101+
description="If provided, this will be used as specification of the source time-dependence in simulations. "
102+
"Otherwise, a default source time will be constructed.",
103+
)
97104

98105
@pd.validator("simulation", always=True)
99106
def _sim_has_no_sources(cls, val):
@@ -130,6 +137,21 @@ def _validate_element_mappings(cls, element_mappings, values):
130137
_freqs_lower_bound = validate_freqs_min()
131138
_freqs_unique = validate_freqs_unique()
132139

140+
@pd.validator("custom_source_time", always=True)
141+
@skip_if_fields_missing(["freqs"])
142+
def _freqs_in_custom_source_time(cls, val, values):
143+
"""Make sure freqs is in the range of the custom source time."""
144+
if val is None:
145+
return val
146+
freq_range = val._frequency_range_sigma_cached
147+
freqs = values["freqs"]
148+
149+
if freq_range[0] > min(freqs) or max(freqs) > freq_range[1]:
150+
log.warning(
151+
"Custom source time does not cover all 'freqs'.",
152+
)
153+
return val
154+
133155
@staticmethod
134156
def get_task_name(
135157
port: Port, mode_index: Optional[int] = None, format: Optional[TaskNameFormat] = "RF"

tidy3d/plugins/smatrix/component_modelers/modal.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ def to_source(
191191
return ModeSource(
192192
center=port.center,
193193
size=port.size,
194-
source_time=GaussianPulse(freq0=freq0, fwidth=fwidth),
194+
source_time=self.custom_source_time
195+
if self.custom_source_time is not None
196+
else GaussianPulse(freq0=freq0, fwidth=fwidth),
195197
mode_spec=port.mode_spec,
196198
mode_index=mode_index,
197199
direction=port.direction,

tidy3d/plugins/smatrix/component_modelers/terminal.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ def _add_source_to_sim(self, source_index: NetworkIndex) -> tuple[str, Simulatio
413413
@cached_property
414414
def _source_time(self):
415415
"""Helper to create a time domain pulse for the frequency range of interest."""
416+
if self.custom_source_time is not None:
417+
return self.custom_source_time
416418
if len(self.freqs) == 1:
417419
freq0 = self.freqs[0]
418420
return GaussianPulse(freq0=self.freqs[0], fwidth=freq0 * FWIDTH_FRAC)

0 commit comments

Comments
 (0)