Skip to content

Commit

Permalink
Fixed 2d projection monitor intersection error
Browse files Browse the repository at this point in the history
  • Loading branch information
QimingFlex committed Sep 12, 2024
1 parent 6f86b80 commit 3e2f044
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Gradient inaccuracies in `PolySlab.vertices`, `Medium.conductivity`, and `DiffractionData` s-polarization.
- Adjoint field monitors no longer store H fields, which aren't needed for gradient calculation.
- `MeshOverrideStructures` in a `Simulation.GridSpec` are properly handled to remove any derivative tracers.
- Error when field projection monitor intersecting structures outside of the simulation domain in 2D simulations.

## [2.7.1] - 2024-07-10

Expand Down
32 changes: 32 additions & 0 deletions tests/test_components/test_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2977,3 +2977,35 @@ def test_validate_sources_monitors_in_bounds():
grid_spec=td.GridSpec(wavelength=1.0),
monitors=[mode_monitor],
)


def test_2d_projection_monitor_out_sim_domain():
# set up a structure interset with far field monitor outside the computational domain
cylinder = td.Structure(
geometry=td.Cylinder(axis=2, radius=0.5, length=2), medium=td.PECMedium()
)

num_phi = 100
theta = np.pi / 2
phis = np.linspace(0, np.pi, num_phi)
monitor_far = td.FieldProjectionAngleMonitor(
size=[2, 2, 0.5],
freqs=[1e12],
name="far_field",
theta=theta,
phi=phis,
)

sim2d = td.Simulation(
size=(4, 4, 0),
run_time=1e-12,
grid_spec=td.GridSpec.uniform(dl=0.025),
sources=[],
structures=[cylinder],
monitors=[monitor_far],
boundary_spec=td.BoundarySpec(
x=td.Boundary.pml(),
y=td.Boundary.pml(),
z=td.Boundary.periodic(),
),
)
33 changes: 32 additions & 1 deletion tidy3d/components/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@
# height of the PML plotting boxes along any dimensions where sim.size[dim] == 0
PML_HEIGHT_FOR_0_DIMS = inf

# fraction of structure size to monitor along 0 dim in 2D simulations
FRACTION = 0.9


class AbstractYeeGridSimulation(AbstractSimulation, ABC):
"""
Expand Down Expand Up @@ -2741,6 +2744,15 @@ def _projection_monitors_homogeneous(cls, val, values):
if val is None:
return val

sim_size = values.get("size")

# Validation and return zero-dim index of 2D simulations
zero_dim_ind = None
is_2d_simulation = False
if sim_size.count(0.0) == 1:
zero_dim_ind = sim_size.index(0.0)
is_2d_simulation = True

# list of structures including background as a Box()
structure_bg = Structure(
geometry=Box(
Expand All @@ -2756,7 +2768,26 @@ def _projection_monitors_homogeneous(cls, val, values):
with log as consolidated_logger:
for monitor_ind, monitor in enumerate(val):
if isinstance(monitor, (AbstractFieldProjectionMonitor, DiffractionMonitor)):
mediums = Scene.intersecting_media(monitor, total_structures)
if is_2d_simulation:
exclude_surfaces_2d = {
0: ["x-", "x+"],
1: ["y-", "y+"],
2: ["z-", "z+"],
}.get(zero_dim_ind)
monitor_dict = monitor.dict()
# Append exclude surfaces for 2D simulation to existing ones
existing_exclude_surfaces = monitor_dict.get("exclude_surfaces") or []
updated_exclude_surfaces = list(
set(existing_exclude_surfaces + exclude_surfaces_2d)
)
monitor_dict["exclude_surfaces"] = updated_exclude_surfaces
surfaces = monitor.surfaces_with_exclusion(**monitor_dict)
mediums = set()
for surface in surfaces:
_mediums = Scene.intersecting_media(surface, total_structures)
mediums.update(_mediums)
else:
mediums = Scene.intersecting_media(monitor, total_structures)
# make sure there is no more than one medium in the returned list
if len(mediums) > 1:
raise SetupError(
Expand Down

0 comments on commit 3e2f044

Please sign in to comment.