Skip to content

ABC boundary #2424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 271 additions & 0 deletions tests/test_components/test_boundaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,274 @@ def test_boundaryspec_classmethods():
assert all(
isinstance(boundary, PML) for boundary_dim in boundaries for boundary in boundary_dim
)


def test_abc_boundary():
# check basic instance
_ = td.ABCBoundary()

# check enforced perm (and conductivity)
_ = td.ABCBoundary(permittivity=2)
_ = td.ABCBoundary(permittivity=2, conductivity=0.1)

with pytest.raises(pydantic.ValidationError):
_ = td.ABCBoundary(permittivity=0)

with pytest.raises(pydantic.ValidationError):
_ = td.ABCBoundary(permittivity=2, conductivity=-0.1)

with pytest.raises(pydantic.ValidationError):
_ = td.ABCBoundary(permittivity=None, conductivity=-0.1)

# test mode abc
wvl_um = 1
freq0 = td.C_0 / wvl_um
mode_abc = td.ModeABCBoundary(
plane=td.Box(size=(1, 1, 0)),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=1,
frequency=freq0,
)

with pytest.raises(pydantic.ValidationError):
_ = td.ModeABCBoundary(
plane=td.Box(size=(1, 1, 0)),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=1,
frequency=-1,
)

with pytest.raises(pydantic.ValidationError):
_ = td.ModeABCBoundary(
plane=td.Box(size=(1, 1, 0)),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=-1,
frequency=freq0,
)

with pytest.raises(pydantic.ValidationError):
_ = td.ModeABCBoundary(
plane=td.Box(size=(1, 1, 1)),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=0,
frequency=freq0,
)

# from mode source
mode_source = td.ModeSource(
size=(1, 1, 0),
source_time=td.GaussianPulse(freq0=freq0, fwidth=0.2 * freq0),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=1,
direction="+",
)
mode_abc_from_source = td.ModeABCBoundary.from_source(mode_source)
assert mode_abc == mode_abc_from_source

# from mode monitor
mode_monitor = td.ModeMonitor(
size=(1, 1, 0), mode_spec=td.ModeSpec(num_modes=2), freqs=[freq0], name="mnt"
)
mode_abc_from_monitor = td.ModeABCBoundary.from_monitor(
mode_monitor, mode_index=1, frequency=freq0
)
assert mode_abc == mode_abc_from_monitor

# in Boundary
_ = td.Boundary(
minus=td.ABCBoundary(permittivity=3), plus=td.ModeABCBoundary(plane=td.Box(size=(1, 1, 0)))
)
_ = td.Boundary.abc(permittivity=3, conductivity=1e-5)
abc_boundary = td.Boundary.mode_abc(
plane=td.Box(size=(1, 1, 0)),
mode_spec=td.ModeSpec(num_modes=2),
mode_index=1,
frequency=freq0,
)
abc_boundary_from_source = td.Boundary.mode_abc_from_source(mode_source)
abc_boundary_from_monitor = td.Boundary.mode_abc_from_monitor(
mode_monitor, mode_index=1, frequency=freq0
)
assert abc_boundary == abc_boundary_from_source
assert abc_boundary == abc_boundary_from_monitor

with pytest.raises(pydantic.ValidationError):
_ = td.Boundary(minus=td.Periodic(), plus=td.ABCBoundary())

with pytest.raises(pydantic.ValidationError):
_ = td.Boundary(minus=td.Periodic(), plus=td.ModeABCBoundary(plane=td.Box(size=(1, 1, 0))))

# in Simulation
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)

# validate ABC medium is not anisotorpic
with pytest.raises(pydantic.ValidationError):
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
medium=td.AnisotropicMedium(xx=td.Medium(), yy=td.Medium(), zz=td.Medium()),
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)

# validate homogeneous medium when permittivity=None, that is, automatic detection
box_crossing_boundary = td.Structure(
geometry=td.Box(size=(0.3, 0.2, td.inf)),
medium=td.Medium(permittivity=2),
)
# ok if ABC boundary is not crossed
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
structures=[box_crossing_boundary],
run_time=1e-20,
boundary_spec=td.BoundarySpec(
x=td.Boundary.abc(),
y=td.Boundary.abc(),
z=td.Boundary.pml(),
),
)
# or if we override manually
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
structures=[box_crossing_boundary],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary(permittivity=2)),
)
# not ok if ABC boudary is crossed
with pytest.raises(pydantic.ValidationError):
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
structures=[box_crossing_boundary],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)
# edge case when a structure exactly coincides with simulation domain
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
structures=[box_crossing_boundary.updated_copy(geometry=td.Box(size=(1, 1, 1)))],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)

# warning for possibly non-uniform custom medium
with AssertLogLevel(
"WARNING", contains_str="Nonuniform custom medium detected on an 'ABCBoundary'"
):
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
medium=td.CustomMedium(
permittivity=td.SpatialDataArray([[[2, 3]]], coords=dict(x=[0], y=[0], z=[0, 1]))
),
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)

# disallow ABC boundaries in zero dimensions
with pytest.raises(pydantic.ValidationError):
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 0],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
structures=[box_crossing_boundary],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ABCBoundary()),
)

# need to define frequence for ModeABCBoundary
# manually
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(
td.ModeABCBoundary(plane=td.Box(size=(1, 1, 0)), frequency=freq0)
),
)
# or at least one source
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[mode_source],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(td.ModeABCBoundary(plane=td.Box(size=(1, 1, 0)))),
)
# multiple sources with different central freqs is still ok, but show warning
with AssertLogLevel(
"WARNING", contains_str="The central frequency of the first source will be used"
):
_ = td.Simulation(
center=[0, 0, 0],
size=[1, 1, 1],
grid_spec=td.GridSpec.auto(
min_steps_per_wvl=10,
wavelength=wvl_um,
),
sources=[
mode_source,
mode_source.updated_copy(
source_time=td.GaussianPulse(freq0=2 * freq0, fwidth=0.2 * freq0)
),
],
run_time=1e-20,
boundary_spec=td.BoundarySpec.all_sides(
td.ModeABCBoundary(plane=td.Box(size=(1, 1, 0)))
),
)
4 changes: 4 additions & 0 deletions tidy3d/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
# boundary
from .components.boundary import (
PML,
ABCBoundary,
Absorber,
AbsorberParams,
BlochBoundary,
Expand All @@ -106,6 +107,7 @@
DefaultAbsorberParameters,
DefaultPMLParameters,
DefaultStablePMLParameters,
ModeABCBoundary,
PECBoundary,
Periodic,
PMCBoundary,
Expand Down Expand Up @@ -534,6 +536,8 @@ def set_logging_level(level: str) -> None:
"Periodic",
"PECBoundary",
"PMCBoundary",
"ABCBoundary",
"ModeABCBoundary",
"PML",
"StablePML",
"Absorber",
Expand Down
Loading