Skip to content

Commit 036dd87

Browse files
committed
Warn/error if too many structures are of the same medium
1 parent 708668e commit 036dd87

File tree

3 files changed

+88
-6
lines changed

3 files changed

+88
-6
lines changed

tests/test_components/test_simulation.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,19 +2146,19 @@ def test_tfsf_structures_grid():
21462146

21472147

21482148
@pytest.mark.parametrize(
2149-
"size, num_struct, log_level", [(1, 1, None), (50, 1, "WARNING"), (1, 11000, "WARNING")]
2149+
"size, num_struct, log_level", [(1, 1, None), (50, 1, "WARNING"), (1, 11, "WARNING")]
21502150
)
2151-
def test_warn_large_epsilon(size, num_struct, log_level):
2151+
def test_warn_large_epsilon(monkeypatch, size, num_struct, log_level):
21522152
"""Make sure we get a warning if the epsilon grid is too large."""
21532153

2154+
monkeypatch.setattr(simulation, "NUM_STRUCTURES_WARN_EPSILON", 10)
21542155
structures = [
21552156
td.Structure(
21562157
geometry=td.Box(center=(0, 0, 0), size=(0.1, 0.1, 0.1)),
2157-
medium=td.Medium(permittivity=1.0),
2158+
medium=td.Medium(permittivity=eps),
21582159
)
2159-
for _ in range(num_struct)
2160+
for eps in np.linspace(1, 2, num_struct)
21602161
]
2161-
21622162
sim = td.Simulation(
21632163
size=(size, size, size),
21642164
grid_spec=td.GridSpec.uniform(dl=0.1),
@@ -3715,3 +3715,44 @@ def test_messages_contain_object_names():
37153715
monitor = td.FieldMonitor(name=name, center=(-1.0, 0, 0), size=(0.5, 0, 1), freqs=[100e14])
37163716
with pytest.raises(pydantic.ValidationError, match=name) as e:
37173717
_ = sim.updated_copy(monitors=[monitor])
3718+
3719+
3720+
def test_structures_per_medium(monkeypatch):
3721+
"""Test if structures that share the same medium warn or error appropriately."""
3722+
import tidy3d.components.scene as scene
3723+
3724+
# Set low thresholds to keep the test fast; ensure len(structures) > MAX to avoid early return
3725+
monkeypatch.setattr(scene, "WARN_STRUCTURES_PER_MEDIUM", 2)
3726+
monkeypatch.setattr(scene, "MAX_STRUCTURES_PER_MEDIUM", 4)
3727+
3728+
shared_med = td.Medium(permittivity=2.0)
3729+
# 3 share the same medium -> triggers warning (> WARN), but <= MAX per-medium
3730+
same_medium_structs = [
3731+
td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=shared_med) for _ in range(3)
3732+
]
3733+
# Add two with different mediums so total structures > MAX but error should not be triggered
3734+
other_structs = [
3735+
td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.Medium(permittivity=3.0)),
3736+
td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.Medium(permittivity=4.0)),
3737+
]
3738+
structs = same_medium_structs + other_structs # total = 5 > MAX = 4
3739+
3740+
with AssertLogLevel("WARNING", contains_str="use the same medium"):
3741+
_ = td.Simulation(
3742+
size=(10, 10, 10),
3743+
run_time=1e-12,
3744+
grid_spec=td.GridSpec.uniform(dl=0.02),
3745+
structures=structs,
3746+
)
3747+
3748+
# Now test error
3749+
monkeypatch.setattr(scene, "MAX_STRUCTURES_PER_MEDIUM", 3, raising=False)
3750+
structs = [td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=shared_med) for _ in range(4)]
3751+
3752+
with pytest.raises(pydantic.ValidationError, match="use the same medium"):
3753+
_ = td.Simulation(
3754+
size=(10, 10, 10),
3755+
run_time=1e-12,
3756+
grid_spec=td.GridSpec.uniform(dl=0.02),
3757+
structures=structs,
3758+
)

tidy3d/components/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def _special_characters_not_in_name(cls, values):
212212
"operation of Tidy3D as it is not used internally. "
213213
"Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. "
214214
"For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. "
215-
"Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects "
215+
"Also note that Tidy3D will raise a ``TypeError`` if ``attrs`` contain objects "
216216
"that can not be serialized. One can check if ``attrs`` are serializable "
217217
"by calling ``obj.json()``.",
218218
)

tidy3d/components/scene.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@
7979
# maximum geometry count in a single structure
8080
MAX_GEOMETRY_COUNT = 100
8181

82+
# warn and error out if the same medium is present in too many structures
83+
WARN_STRUCTURES_PER_MEDIUM = 200
84+
MAX_STRUCTURES_PER_MEDIUM = 1_000
85+
8286

8387
class Scene(Tidy3dBaseModel):
8488
"""Contains generic information about the geometry and medium properties common to all types of
@@ -176,6 +180,43 @@ def _validate_num_geometries(cls, val):
176180

177181
return val
178182

183+
@pd.validator("structures", always=True)
184+
def _validate_structures_per_medium(cls, val):
185+
"""Error if too many structures share the same medium; suggest using GeometryGroup."""
186+
if val is None:
187+
return val
188+
189+
# if total structures are <= warn limit, the constraint cannot be violated.
190+
if len(val) <= WARN_STRUCTURES_PER_MEDIUM:
191+
return val
192+
193+
# Count structures per medium
194+
counts = {}
195+
get = counts.get
196+
for structure in val:
197+
key = structure.medium
198+
new_count = get(key, 0) + 1
199+
# Exit early to avoid slow counting if many structures present
200+
if new_count > MAX_STRUCTURES_PER_MEDIUM:
201+
raise SetupError(
202+
f"More than {MAX_STRUCTURES_PER_MEDIUM} structures use the same medium. "
203+
"For performance, use a 'GeometryGroup' or boolean operations to combine "
204+
"geometries that share a medium."
205+
)
206+
counts[key] = new_count
207+
208+
# Now check if we should warn
209+
for count in counts.values():
210+
if count > WARN_STRUCTURES_PER_MEDIUM:
211+
log.warning(
212+
f"More than {WARN_STRUCTURES_PER_MEDIUM} structures use the same medium. "
213+
"For performance, use a 'GeometryGroup' or boolean operations to combine "
214+
"geometries that share a medium."
215+
)
216+
break
217+
218+
return val
219+
179220
""" Accounting """
180221

181222
@cached_property

0 commit comments

Comments
 (0)