Skip to content

Commit 7d2c9a2

Browse files
dbochkov-flexcomputemomchil-flex
authored andcommitted
functionality to select simulation subsection
1 parent 11da0ec commit 7d2c9a2

File tree

14 files changed

+991
-94
lines changed

14 files changed

+991
-94
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Integration of the `documentation` alongside the main codebase repository.
1313
- Integration of the `tidy3d-notebooks` repository.
1414
- `tidy3d develop` CLI and development guide on the main documentation.
15+
- Added a convenience method `Simulation.subsection()` to a create a new simulation based on a subregion of another one.
1516

1617
### Changed
1718
- `poetry` based installation. Removal of `setup.py` and `requirements.txt`.
1819
- Upgrade to sphinx 6 for the documentation build, and change of theme.
20+
- Remote mode solver web api automatically reduces the associated `Simulation` object to the mode solver plane before uploading it to server.
1921

2022
### Fixed
2123

tests/test_components/test_custom.py

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def test_n_cfl():
351351
assert med.n_cfl >= 2
352352

353353

354-
def verify_custom_medium_methods(mat):
354+
def verify_custom_medium_methods(mat, reduced_fields=[]):
355355
"""Verify that the methods in custom medium is producing expected results."""
356356
freq = 1.0
357357
assert isinstance(mat, AbstractCustomMedium)
@@ -362,6 +362,41 @@ def verify_custom_medium_methods(mat):
362362
for i in range(3):
363363
assert np.allclose(eps_grid[i].shape, [len(f) for f in coord_interp.to_list])
364364

365+
# check reducing data
366+
subsection = td.Box(size=(0.3, 0.4, 0.35), center=(0.4, 0.4, 0.4))
367+
368+
mat_reduced = mat.sel_inside(subsection.bounds)
369+
370+
for field in reduced_fields:
371+
original = getattr(mat, field)
372+
reduced = getattr(mat_reduced, field)
373+
374+
if original is None:
375+
assert reduced is None
376+
continue
377+
378+
# data fields in medium classes could be SpatialArrays or 2d tuples of spatial arrays
379+
# lets convert everything into 2d tuples of spatial arrays for uniform handling
380+
if isinstance(original, td.SpatialDataArray):
381+
original = [
382+
[
383+
original,
384+
],
385+
]
386+
reduced = [
387+
[
388+
reduced,
389+
],
390+
]
391+
392+
for or_set, re_set in zip(original, reduced):
393+
assert len(or_set) == len(re_set)
394+
395+
for ind in range(len(or_set)):
396+
diff = (or_set[ind] - re_set[ind]).abs
397+
assert diff.does_cover(subsection.bounds)
398+
assert np.allclose(diff, 0)
399+
365400
# construct sim
366401
struct = td.Structure(
367402
geometry=td.Box(size=(0.5, 0.5, 0.5)),
@@ -375,6 +410,8 @@ def verify_custom_medium_methods(mat):
375410
structures=(struct,),
376411
)
377412
_ = sim.grid
413+
sim_reduced = sim.subsection(subsection, remove_outside_custom_mediums=False)
414+
sim_reduced = sim.subsection(subsection, remove_outside_custom_mediums=True)
378415

379416
# bkg
380417
sim = td.Simulation(
@@ -384,6 +421,8 @@ def verify_custom_medium_methods(mat):
384421
medium=mat,
385422
)
386423
_ = sim.grid
424+
sim_reduced = sim.subsection(subsection, remove_outside_custom_mediums=False)
425+
sim_reduced = sim.subsection(subsection, remove_outside_custom_mediums=True)
387426

388427

389428
def test_anisotropic_custom_medium():
@@ -438,7 +477,7 @@ def test_custom_isotropic_medium():
438477
with pytest.raises(pydantic.ValidationError):
439478
mat = CustomMedium(permittivity=permittivity, conductivity=sigmatmp)
440479
mat = CustomMedium(permittivity=permittivity, conductivity=sigmatmp, allow_gain=True)
441-
verify_custom_medium_methods(mat)
480+
verify_custom_medium_methods(mat, ["permittivity", "conductivity"])
442481

443482
# inconsistent coords
444483
with pytest.raises(pydantic.ValidationError):
@@ -448,15 +487,15 @@ def test_custom_isotropic_medium():
448487
mat = CustomMedium(permittivity=permittivity, conductivity=sigmatmp)
449488

450489
mat = CustomMedium(permittivity=permittivity, conductivity=conductivity)
451-
verify_custom_medium_methods(mat)
490+
verify_custom_medium_methods(mat, ["permittivity", "conductivity"])
452491

453492
mat = CustomMedium(permittivity=permittivity)
454-
verify_custom_medium_methods(mat)
493+
verify_custom_medium_methods(mat, ["permittivity", "conductivity"])
455494

456495

457-
def verify_custom_dispersive_medium_methods(mat):
496+
def verify_custom_dispersive_medium_methods(mat, reduced_fields=[]):
458497
"""Verify that the methods in custom dispersive medium is producing expected results."""
459-
verify_custom_medium_methods(mat)
498+
verify_custom_medium_methods(mat, reduced_fields)
460499
freq = 1.0
461500
for i in range(3):
462501
assert mat.eps_dataarray_freq(freq)[i].shape == (Nx, Ny, Nz)
@@ -515,7 +554,7 @@ def test_custom_pole_residue():
515554

516555
eps_inf = td.SpatialDataArray(np.random.random((Nx, Ny, Nz)) + 1, coords=dict(x=X, y=Y, z=Z))
517556
mat = CustomPoleResidue(eps_inf=eps_inf, poles=((a, c),))
518-
verify_custom_dispersive_medium_methods(mat)
557+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "poles"])
519558
assert mat.n_cfl > 1
520559

521560
# to custom non-dispersive medium
@@ -529,12 +568,12 @@ def test_custom_pole_residue():
529568
mat_medium = mat.to_medium()
530569
mat = CustomPoleResidue(eps_inf=eps_inf, poles=((a, c - 0.1),), allow_gain=True)
531570
mat_medium = mat.to_medium()
532-
verify_custom_medium_methods(mat_medium)
571+
verify_custom_medium_methods(mat_medium, ["permittivity", "conductivity"])
533572
assert mat_medium.n_cfl > 1
534573

535574
# custom medium to pole residue
536575
mat = CustomPoleResidue.from_medium(mat_medium)
537-
verify_custom_dispersive_medium_methods(mat)
576+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "poles"])
538577
assert mat.n_cfl > 1
539578

540579

@@ -578,14 +617,14 @@ def test_custom_sellmeier():
578617
mat = CustomSellmeier(coeffs=((b1, c2), (btmp, c2)))
579618

580619
mat = CustomSellmeier(coeffs=((b1, c1), (b2, c2)))
581-
verify_custom_dispersive_medium_methods(mat)
620+
verify_custom_dispersive_medium_methods(mat, ["coeffs"])
582621
assert mat.n_cfl == 1
583622

584623
# from dispersion
585624
n = td.SpatialDataArray(2 + np.random.random((Nx, Ny, Nz)), coords=dict(x=X, y=Y, z=Z))
586625
dn_dwvl = td.SpatialDataArray(-np.random.random((Nx, Ny, Nz)), coords=dict(x=X, y=Y, z=Z))
587626
mat = CustomSellmeier.from_dispersion(n=n, dn_dwvl=dn_dwvl, freq=2, interp_method="linear")
588-
verify_custom_dispersive_medium_methods(mat)
627+
verify_custom_dispersive_medium_methods(mat, ["coeffs"])
589628
assert mat.n_cfl == 1
590629

591630

@@ -638,13 +677,13 @@ def test_custom_lorentz():
638677
mat = CustomLorentz(
639678
eps_inf=eps_inf, coeffs=((de1, f1, delta1), (detmp, f2, delta2)), allow_gain=True
640679
)
641-
verify_custom_dispersive_medium_methods(mat)
680+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "coeffs"])
642681
assert mat.n_cfl > 1
643682

644683
mat = CustomLorentz(
645684
eps_inf=eps_inf, coeffs=((de1, f1, delta1), (de2, f2, delta2)), subpixel=True
646685
)
647-
verify_custom_dispersive_medium_methods(mat)
686+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "coeffs"])
648687
assert mat.n_cfl > 1
649688
assert mat.pole_residue.subpixel
650689

@@ -681,7 +720,7 @@ def test_custom_drude():
681720
mat = CustomDrude(eps_inf=eps_inf, coeffs=((f1, delta1), (ftmp, delta2)))
682721

683722
mat = CustomDrude(eps_inf=eps_inf, coeffs=((f1, delta1), (f2, delta2)))
684-
verify_custom_dispersive_medium_methods(mat)
723+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "coeffs"])
685724
assert mat.n_cfl > 1
686725

687726

@@ -728,11 +767,11 @@ def test_custom_debye():
728767
)
729768
mat = CustomDebye(eps_inf=eps_inf, coeffs=((eps1, tau1), (epstmp, tau2)))
730769
mat = CustomDebye(eps_inf=eps_inf, coeffs=((eps1, tau1), (epstmp, tau2)), allow_gain=True)
731-
verify_custom_dispersive_medium_methods(mat)
770+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "coeffs"])
732771
assert mat.n_cfl > 1
733772

734773
mat = CustomDebye(eps_inf=eps_inf, coeffs=((eps1, tau1), (eps2, tau2)))
735-
verify_custom_dispersive_medium_methods(mat)
774+
verify_custom_dispersive_medium_methods(mat, ["eps_inf", "coeffs"])
736775
assert mat.n_cfl > 1
737776

738777

tests/test_components/test_simulation.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,3 +2248,76 @@ def test_to_gds(tmp_path):
22482248
assert np.allclose(areas[(2, 1)], 0.5)
22492249
assert np.allclose(areas[(1, 0)], 0.25 * np.pi * 1.4**2, atol=1e-2)
22502250
assert np.allclose(areas[(0, 0)], 0.25 * np.pi * 1.4**2, atol=1e-2)
2251+
2252+
2253+
def test_sim_subsection():
2254+
region = td.Box(size=(0.3, 0.5, 0.7), center=(0.1, 0.05, 0.02))
2255+
2256+
sim_red = SIM_FULL.subsection(region=region)
2257+
assert sim_red.structures != SIM_FULL.structures
2258+
sim_red = SIM_FULL.subsection(
2259+
region=region,
2260+
symmetry=(1, 0, -1),
2261+
monitors=[
2262+
mnt
2263+
for mnt in SIM_FULL.monitors
2264+
if not isinstance(mnt, (td.ModeMonitor, td.ModeSolverMonitor))
2265+
],
2266+
)
2267+
assert sim_red.symmetry == (1, 0, -1)
2268+
sim_red = SIM_FULL.subsection(
2269+
region=region, boundary_spec=td.BoundarySpec.all_sides(td.Periodic())
2270+
)
2271+
sim_red = SIM_FULL.subsection(region=region, sources=[], grid_spec=td.GridSpec.uniform(dl=20))
2272+
assert len(sim_red.sources) == 0
2273+
sim_red = SIM_FULL.subsection(region=region, monitors=[])
2274+
assert len(sim_red.monitors) == 0
2275+
sim_red = SIM_FULL.subsection(region=region, remove_outside_structures=False)
2276+
assert sim_red.structures == SIM_FULL.structures
2277+
sim_red = SIM_FULL.subsection(region=region, remove_outside_custom_mediums=True)
2278+
2279+
fine_custom_medium = td.CustomMedium(
2280+
permittivity=td.SpatialDataArray(
2281+
1 + np.random.random((11, 12, 13)),
2282+
coords=dict(
2283+
x=np.linspace(-0.51, 0.52, 11),
2284+
y=np.linspace(-1.02, 1.04, 12),
2285+
z=np.linspace(-1.51, 1.51, 13),
2286+
),
2287+
)
2288+
)
2289+
2290+
sim = SIM_FULL.updated_copy(
2291+
structures=[
2292+
td.Structure(
2293+
geometry=td.Box(size=(1, 2, 3)),
2294+
medium=fine_custom_medium,
2295+
)
2296+
],
2297+
medium=fine_custom_medium,
2298+
)
2299+
sim_red = sim.subsection(region=region, remove_outside_custom_mediums=True)
2300+
2301+
# check automatic symmetry expansion
2302+
sim_sym = SIM_FULL.updated_copy(
2303+
symmetry=(-1, 0, 1),
2304+
sources=[src for src in SIM_FULL.sources if not isinstance(src, td.TFSF)],
2305+
)
2306+
sim_red = sim_sym.subsection(region=region)
2307+
assert np.allclose(sim_red.center, (0, 0.05, 0.0))
2308+
2309+
# check grid is preserved when requested
2310+
sim_red = SIM_FULL.subsection(
2311+
region=region, grid_spec="identical", boundary_spec=td.BoundarySpec.all_sides(td.Periodic())
2312+
)
2313+
grids_1d = SIM_FULL.grid.boundaries
2314+
grids_1d_red = sim_red.grid.boundaries
2315+
tol = 1e-8
2316+
for full_grid, red_grid in zip(
2317+
[grids_1d.x, grids_1d.y, grids_1d.z], [grids_1d_red.x, grids_1d_red.y, grids_1d_red.z]
2318+
):
2319+
# find index into full grid at which reduced grid is starting
2320+
start = red_grid[0]
2321+
ind = np.argmax(np.logical_and(full_grid >= start - tol, full_grid <= start + tol))
2322+
# compare
2323+
assert np.allclose(red_grid, full_grid[ind : ind + len(red_grid)])

0 commit comments

Comments
 (0)