Skip to content

Commit 611ac8a

Browse files
mode solver pec frame
1 parent f1bc896 commit 611ac8a

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

tidy3d/components/simulation.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from .data.unstructured.tetrahedral import TetrahedralGridDataset
4545
from .data.unstructured.triangular import TriangularGridDataset
4646
from .data.utils import CustomSpatialDataType
47-
from .geometry.base import Box, Geometry
47+
from .geometry.base import Box, Geometry, ClipOperation
4848
from .geometry.mesh import TriangleMesh
4949
from .geometry.utils import flatten_groups, traverse_geometries
5050
from .geometry.utils_2d import get_bounds, get_thickened_geom, snap_coordinate_to_grid, subdivide
@@ -62,6 +62,7 @@
6262
Medium2D,
6363
MediumType,
6464
MediumType3D,
65+
PECMedium,
6566
)
6667
from .monitor import (
6768
AbstractFieldProjectionMonitor,
@@ -174,6 +175,10 @@
174175
# additional (safety) time step reduction factor for fixed angle simulations
175176
FIXED_ANGLE_DT_SAFETY_FACTOR = 0.9
176177

178+
# length and thickness of optional PEC frames around mode sources (in cells)
179+
MODE_PEC_FRAME_LENGTH = 2
180+
MODE_PEC_FRAME_THICKNESS = 1e-3
181+
177182

178183
def validate_boundaries_for_zero_dims():
179184
"""Error if absorbing boundaries, bloch boundaries, unmatching pec/pmc, or symmetry is used along a zero dimension."""
@@ -5209,3 +5214,50 @@ def from_scene(cls, scene: Scene, **kwargs) -> Simulation:
52095214
)
52105215

52115216
_boundaries_for_zero_dims = validate_boundaries_for_zero_dims()
5217+
5218+
def _make_pec_frame(self, mode_source) -> Structure:
5219+
"""Make a pec frame around a mode source."""
5220+
5221+
coords = self.grid.boundaries.to_list
5222+
axis = mode_source.injection_axis
5223+
direction = mode_source.direction
5224+
5225+
span_inds = np.array(self.grid.discretize_inds(mode_source))
5226+
if direction == "+":
5227+
span_inds[axis][1] += MODE_PEC_FRAME_LENGTH - 1
5228+
else:
5229+
span_inds[axis][0] -= MODE_PEC_FRAME_LENGTH - 1
5230+
bounds_outer = [[(1 - MODE_PEC_FRAME_THICKNESS) * c[beg] + MODE_PEC_FRAME_THICKNESS * c[max(0, beg - 1)], (1 - MODE_PEC_FRAME_THICKNESS) * c[end] + MODE_PEC_FRAME_THICKNESS * c[min(len(c) - 1, end + 1)]] for c, (beg, end) in zip(coords, span_inds)]
5231+
bounds_inner = [[(1 - MODE_PEC_FRAME_THICKNESS) * c[beg] + MODE_PEC_FRAME_THICKNESS * c[beg + 1], (1 - MODE_PEC_FRAME_THICKNESS) * c[end] + MODE_PEC_FRAME_THICKNESS * c[end - 1]] for c, (beg, end) in zip(coords, span_inds)]
5232+
bounds_inner[axis] = [-inf, inf]
5233+
structure = Structure(
5234+
geometry=ClipOperation(
5235+
geometry_a=Box.from_bounds(*np.transpose(bounds_outer)),
5236+
geometry_b=Box.from_bounds(*np.transpose(bounds_inner)),
5237+
operation="difference",
5238+
),
5239+
medium=PECMedium(),
5240+
)
5241+
return structure
5242+
5243+
@cached_property
5244+
def with_mode_source_pec_frames(self) -> Simulation:
5245+
"""Return an instance with added pec frames around mode sources."""
5246+
5247+
pec_frames = [self._make_pec_frame(src) for src in self.sources if isinstance(src, ModeSource) and src.pec_frame]
5248+
5249+
if len(pec_frames) == 0:
5250+
return self
5251+
5252+
return self.updated_copy(grid_spec=GridSpec.from_grid(self.grid), structures=list(self.structures) + pec_frames)
5253+
5254+
def _validate_with_mode_source_pec_frames(self):
5255+
"""Validate that after adding pec frames simulation setup is still valid."""
5256+
5257+
try:
5258+
_ = self.with_mode_source_pec_frames
5259+
except Exception:
5260+
log.error(
5261+
"Simulation fails after requested mode source PEC frames are added. "
5262+
"Please inspec '.with_mode_source_pec_frames'."
5263+
)

tidy3d/components/source/field.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,12 @@ class ModeSource(DirectionalSource, PlanarSource, BroadbandSource):
437437
le=99,
438438
)
439439

440+
pec_frame: bool = pydantic.Field(
441+
False,
442+
title="PEC Frame.",
443+
description="Add a thin pec frame around the source during FDTD run.",
444+
)
445+
440446
@cached_property
441447
def angle_theta(self):
442448
"""Polar angle of propagation."""

0 commit comments

Comments
 (0)