Skip to content

feat: add validation for grid spacing in AutoGrid #2453

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 1 commit 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The method `Geometry.reflected` can be used to create a reflected copy of any geometry off a plane. As for other transformations, for efficiency, `reflected` `PolySlab` directly returns an updated `PolySlab` object rather than a `Transformed` object, except when the normal of the plane of reflection has a non-zero component along the slab axis, in which case `Transformed` is still returned.
- Validation check for unit error in grid spacing.
- Validation that when symmetry is imposed along a given axis, the boundary conditions on each side of the axis are identical.
- Validation check for unit error in grid spacing for `AutoGrid`.

### Changed
- Supplying autograd-traced values to geometric fields (`center`, `size`) of simulations, monitors, and sources now logs a warning and falls back to the static value instead of erroring.
Expand Down
38 changes: 38 additions & 0 deletions tests/test_components/test_grid_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,3 +541,41 @@ def test_uniform_grid_dl_validation(dl, expect_exception):
grid_spec=td.GridSpec.uniform(dl=dl),
run_time=1e-12,
)


@pytest.mark.parametrize(
("freq0", "expect_error"),
[
(3e21, True), # dl<1e-6 → fail
(1e14, False), # dl>1e-7 → pass
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1e-6 for both

],
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you just make the simulation size 1e7 smaller wouldn't that avoid the long runtime of the test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it reduces the runtime. Thanks!

def test_autogrid_min_spacing(freq0, expect_error):
"""
Test that Simulation.post_init catches too‐fine spacing produced by AutoGrid
(i.e. min grid spacing < 1e-7 µm).
"""
L = 10.0
buffer = 1.0
source = td.PointDipole(
center=(-L / 2 + buffer, 0, 0),
source_time=td.GaussianPulse(freq0=freq0, fwidth=freq0 / 10.0),
polarization="Ez",
)

kwargs = dict(
size=(L, L, L),
sources=[source],
grid_spec=td.GridSpec(
grid_x=td.AutoGrid(min_steps_per_wvl=10),
grid_y=td.AutoGrid(min_steps_per_wvl=10),
grid_z=td.AutoGrid(min_steps_per_wvl=10),
),
run_time=1e-11,
)

if expect_error:
with pytest.raises(SetupError):
_ = td.Simulation(**kwargs)
else:
_ = td.Simulation(**kwargs)
26 changes: 26 additions & 0 deletions tidy3d/components/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,29 @@ def boundaries_for_zero_dims(cls, val, values):
return boundaries_for_zero_dims


def _validate_min_grid_spacing(grid, threshold=1e-7, msg_prefix=""):
"""
Ensure that the smallest grid spacing in any direction of the simulation grid
is not below `threshold` (µm).
"""
# grab the 1D cell‐boundary arrays
xs, ys, zs = grid.boundaries.x, grid.boundaries.y, grid.boundaries.z
dx = np.diff(xs)
dy = np.diff(ys)
dz = np.diff(zs)
# ignore zero‐length dims
min_dx = dx[dx > 0].min() if np.any(dx > 0) else np.inf
min_dy = dy[dy > 0].min() if np.any(dy > 0) else np.inf
min_dz = dz[dz > 0].min() if np.any(dz > 0) else np.inf
overall = min(min_dx, min_dy, min_dz)
if (overall < threshold) and not np.isclose(overall, threshold, rtol=1e-6):
raise SetupError(
f"{msg_prefix} grid spacing is {overall:.2e} µm. "
"Please check your units! For more info on Tidy3D units, see: "
"https://docs.flexcompute.com/projects/tidy3d/en/latest/faq/docs/faq/What-are-the-units-used-in-the-simulation.html"
)


class AbstractYeeGridSimulation(AbstractSimulation, ABC):
"""
Abstract class for a simulation involving electromagnetic fields defined on a Yee grid.
Expand Down Expand Up @@ -3596,6 +3619,9 @@ def _post_init_validators(self) -> None:
self._validate_custom_source_time()
self._validate_mode_object_bends()
self._warn_mode_object_pml()
_validate_min_grid_spacing(
self.grid, threshold=1e-7, msg_prefix=f"'{self.__class__.__name__}'"
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do 1e-6, even that sounds too large, but to be consistent with the uniform grid validator. Or maybe we should increase the threshold for both? I don't know if I missed anything in the other discussion but wouldn't even 1e-5 be more than reasonable (hard to imagine any simulation that needs to go even below 1e-4). @yaugenst ?


def _warn_mode_object_pml(self) -> None:
"""Warn if any mode objects have large pml."""
Expand Down