Skip to content

Commit 3ab9256

Browse files
committed
revert overly strict validation of 'freqs'
1 parent 6faed26 commit 3ab9256

File tree

5 files changed

+34
-29
lines changed

5 files changed

+34
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
- Calculation of voltage and current in the `WavePort`, when one type of path integral is supplied and the transmission line mode is lossy.
2828
- Polygon vertices cleanup in `ClipOperation.intersections_plane`.
2929
- Removed sources from `sim_inf_structure` simulation object in `postprocess_adj` to avoid source and background medium validation errors.
30+
- Revert overly restrictive validation of `freqs` in the `ComponentModeler` and `TerminalComponentModeler`.
3031

3132
## [2.9.0] - 2025-08-04
3233

tests/test_plugins/smatrix/test_terminal_component_modeler.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,18 +235,16 @@ def test_validate_no_sources(tmp_path):
235235

236236

237237
def test_validate_freqs():
238-
"""Ensure the 'freqs' array is strictly increasing and length of at least 2."""
238+
"""Ensure the 'freqs' array does not contain negative values nor duplicate entries."""
239239
modeler = make_component_modeler(planar_pec=False)
240-
freqs = np.array([1.0])
241-
with pytest.raises(pd.ValidationError):
242-
_ = modeler.updated_copy(freqs=freqs)
243-
freqs = np.array([-1.0, 5])
244-
with pytest.raises(pd.ValidationError):
245-
_ = modeler.updated_copy(freqs=freqs)
246-
freqs = np.array([1, 2, 1.9])
240+
# It should be possible to provide a single frequency point
241+
freqs = np.array([1.0e6])
242+
modeler = modeler.updated_copy(freqs=freqs)
243+
_ = modeler._source_time
244+
# Negative frequencies are not allowed
245+
freqs = np.array([-1.0, 5]) * 1e9
247246
with pytest.raises(pd.ValidationError):
248247
_ = modeler.updated_copy(freqs=freqs)
249-
250248
# Test case with non-unique value
251249
f_min, f_max = (0.5e9, 1.5e9)
252250
f0 = (f_min + f_max) / 2

tidy3d/components/validators.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,19 @@ def freqs_not_empty(cls, val):
465465
return freqs_not_empty
466466

467467

468+
def validate_freqs_unique():
469+
"""Validate that the array of frequencies does not have duplicate entries."""
470+
471+
@pydantic.validator("freqs", always=True, allow_reuse=True)
472+
def freqs_unique(cls, val):
473+
"""Raise validation error if ``freqs`` has duplicate entries."""
474+
if len(set(val)) != len(val):
475+
raise ValidationError(f"'{cls.__name__}.freqs' must not contain duplicate entries.")
476+
return val
477+
478+
return freqs_unique
479+
480+
468481
def _warn_unsupported_traced_argument(name: str):
469482
@pydantic.validator(name, always=True, allow_reuse=True)
470483
def _warn_traced_arg(cls, val, values):

tidy3d/plugins/smatrix/component_modelers/base.py

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
from tidy3d.components.data.sim_data import SimulationData
1515
from tidy3d.components.simulation import Simulation
1616
from tidy3d.components.types import Complex, FreqArray
17-
from tidy3d.components.validators import assert_unique_names
17+
from tidy3d.components.validators import (
18+
assert_unique_names,
19+
validate_freqs_min,
20+
validate_freqs_not_empty,
21+
validate_freqs_unique,
22+
)
1823
from tidy3d.config import config
1924
from tidy3d.constants import HERTZ
2025
from tidy3d.exceptions import SetupError, Tidy3dKeyError
@@ -150,24 +155,9 @@ def _sim_has_no_sources(cls, val):
150155
raise SetupError(f"'{cls.__name__}.simulation' must not have any sources.")
151156
return val
152157

153-
@pd.validator("freqs", always=True)
154-
def _validate_freqs(cls, val):
155-
"""The array of frequencies must be sorted, unique and non-negative."""
156-
if len(val) < 2:
157-
raise SetupError(f"You must supply at least 2 entries for '{cls.__name__}.freqs'.")
158-
np_val = np.array(val)
159-
if not np.all(np_val >= 0):
160-
raise SetupError(f"'{cls.__name__}.freqs' must be an array of non-negative numbers.")
161-
# Ensure freqs is sorted
162-
diff = np.diff(np_val)
163-
if not np.all(diff > 0):
164-
violations = np.where(diff <= 0)[0] + 1
165-
raise SetupError(
166-
f"'{cls.__name__}.freqs' must be strictly increasing (unique values sorted "
167-
"in ascending order). "
168-
f"The entries at the following indices violated this requirement: {violations}."
169-
)
170-
return val
158+
_freqs_not_empty = validate_freqs_not_empty()
159+
_freqs_lower_bound = validate_freqs_min()
160+
_freqs_unique = validate_freqs_unique()
171161

172162
@pd.validator("ports", always=True)
173163
def _warn_rf_license(cls, val):

tidy3d/plugins/smatrix/component_modelers/terminal.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from tidy3d.plugins.smatrix.ports.wave import WavePort
2929
from tidy3d.web.api.container import BatchData
3030

31-
from .base import AbstractComponentModeler, TerminalPortType
31+
from .base import FWIDTH_FRAC, AbstractComponentModeler, TerminalPortType
3232

3333
NetworkIndex = str # the 'i' in S_ij
3434
NetworkElement = tuple[NetworkIndex, NetworkIndex] # the 'ij' in S_ij
@@ -272,6 +272,9 @@ def _add_source_to_sim(self, source_index: NetworkIndex) -> tuple[str, Simulatio
272272
@cached_property
273273
def _source_time(self):
274274
"""Helper to create a time domain pulse for the frequency range of interest."""
275+
if len(self.freqs) == 1:
276+
freq0 = self.freqs[0]
277+
return GaussianPulse(freq0=self.freqs[0], fwidth=freq0 * FWIDTH_FRAC)
275278
return GaussianPulse.from_frequency_range(
276279
fmin=min(self.freqs), fmax=max(self.freqs), remove_dc_component=self.remove_dc_component
277280
)

0 commit comments

Comments
 (0)