Skip to content

Commit 2d869d4

Browse files
unstructured grid datasets
1 parent fe7e4e7 commit 2d869d4

File tree

22 files changed

+2155
-148
lines changed

22 files changed

+2155
-148
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
### Added
2121
- Added support for two-photon absorption via `TwoPhotonAbsorption` class. Added `KerrNonlinearity` that implements Kerr effect without third-harmonic generation.
2222
- Can create `PoleResidue` from LO-TO form via `PoleResidue.from_lo_to`.
23+
- Added `TriangularGridDataset` and `TehrahedralGridDataset` for storing and manipulating unstructured data.
2324
- Support for an anisotropic medium containing PEC components.
2425
- `SimulationData.mnt_data_from_file()` method to load only a single monitor data object from a simulation data `.hdf5` file.
2526
- `_hash_self` to base model, uses `hashlib` to hash a Tidy3D component the same way every session.

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ include requirements/gdspy.txt
88
include requirements/gdstk.txt
99
include requirements/dev.txt
1010
include requirements/trimesh.txt
11+
include requirements/vtk.txt
1112
include tidy3d/web/cacert.pem

requirements/dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
-r gdspy.txt
66
-r jax.txt
77
-r trimesh.txt
8+
-r vtk.txt
89

910
# required for development
1011
pre-commit

requirements/vtk.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# vtk
2+
3+
vtk
4+

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def read_requirements(req_file: str):
3333
gdstk_required = read_requirements("requirements/gdstk.txt")
3434
gdspy_required = read_requirements("requirements/gdspy.txt")
3535
trimesh_required = read_requirements("requirements/trimesh.txt")
36+
vtk_required = read_requirements("requirements/vtk.txt")
3637
core_required = read_requirements("requirements/core.txt")
3738
core_required += basic_required + web_required
3839
dev_required = read_requirements("requirements/dev.txt")
@@ -72,6 +73,7 @@ def create_config_folder():
7273
"gdspy": gdspy_required,
7374
"gdstk": gdstk_required,
7475
"trimesh": trimesh_required,
76+
"vtk": vtk_required,
7577
},
7678
entry_points={
7779
"console_scripts": [

test_local.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ ruff check tidy3d
66

77
pytest -rA tests/
88

9+
# test no vtk available (must be done separately from other tests to reload tidy3d from scratch)
10+
pytest -rA tests/test_data/_test_datasets_no_vtk.py
11+
912
pytest --doctest-modules tidy3d/components

tests/sims/simulation_2_5_0rc3.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,14 +1011,14 @@
10111011
},
10121012
"transform": [
10131013
[
1014-
0.9659258262890684,
1015-
-0.2588190451025208,
1014+
0.9659258262890683,
1015+
-0.25881904510252074,
10161016
0.0,
10171017
0.0
10181018
],
10191019
[
1020-
0.2588190451025208,
1021-
0.9659258262890684,
1020+
0.25881904510252074,
1021+
0.9659258262890683,
10221022
0.0,
10231023
0.0
10241024
],
@@ -1506,7 +1506,7 @@
15061506
1,
15071507
1
15081508
],
1509-
"colocate": 1,
1509+
"colocate": true,
15101510
"freqs": [
15111511
200000000000000.0,
15121512
250000000000000.0
@@ -1538,7 +1538,7 @@
15381538
1,
15391539
1
15401540
],
1541-
"colocate": 1,
1541+
"colocate": true,
15421542
"start": 0.0,
15431543
"stop": null,
15441544
"interval": 1,
@@ -1687,7 +1687,7 @@
16871687
1,
16881688
1
16891689
],
1690-
"colocate": 1,
1690+
"colocate": true,
16911691
"freqs": [
16921692
250000000000000.0,
16931693
300000000000000.0
@@ -1832,7 +1832,7 @@
18321832
1,
18331833
1
18341834
],
1835-
"colocate": 1,
1835+
"colocate": true,
18361836
"freqs": [
18371837
250000000000000.0,
18381838
300000000000000.0
@@ -1884,7 +1884,7 @@
18841884
1,
18851885
1
18861886
],
1887-
"colocate": 1,
1887+
"colocate": true,
18881888
"freqs": [
18891889
250000000000000.0,
18901890
300000000000000.0
@@ -1933,7 +1933,7 @@
19331933
1,
19341934
1
19351935
],
1936-
"colocate": 1,
1936+
"colocate": true,
19371937
"freqs": [
19381938
250000000000000.0,
19391939
300000000000000.0

tests/test_components/test_heat.py

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from tidy3d import HeatSimulationData
2626
from tidy3d import TemperatureMonitor
2727
from tidy3d import TemperatureData
28+
from tidy3d.exceptions import DataError
2829

2930
from ..utils import STL_GEO, assert_log_level, log_capture
3031

@@ -103,12 +104,17 @@ def test_heat_bcs():
103104
_ = ConvectionBC(ambient_temperature=400, transfer_coeff=-0.2)
104105

105106

106-
def make_heat_mnt():
107-
return TemperatureMonitor(size=(1, 2, 3), name="test")
107+
def make_heat_mnts():
108+
temp_mnt1 = TemperatureMonitor(size=(1, 2, 3), name="test")
109+
temp_mnt2 = TemperatureMonitor(size=(1, 2, 3), name="tet", unstructured=True)
110+
temp_mnt3 = TemperatureMonitor(size=(1, 0, 3), name="tri", unstructured=True, conformal=True)
111+
temp_mnt4 = TemperatureMonitor(size=(1, 0, 3), name="empty", unstructured=True, conformal=False)
112+
113+
return (temp_mnt1, temp_mnt2, temp_mnt3, temp_mnt4)
108114

109115

110116
def test_heat_mnt():
111-
temp_mnt = make_heat_mnt()
117+
temp_mnt, _, _, _ = make_heat_mnts()
112118

113119
with pytest.raises(pd.ValidationError):
114120
_ = temp_mnt.updated_copy(name=None)
@@ -118,21 +124,75 @@ def test_heat_mnt():
118124

119125

120126
def make_heat_mnt_data():
121-
temp_mnt = make_heat_mnt()
127+
temp_mnt1, temp_mnt2, temp_mnt3, temp_mnt4 = make_heat_mnts()
122128

123129
nx, ny, nz = 9, 6, 5
124-
x = np.linspace(-1, 1, nx)
125-
y = np.linspace(-2, 2, ny)
126-
z = np.linspace(-3, 3, nz)
130+
x = np.linspace(0, 1, nx)
131+
y = np.linspace(0, 2, ny)
132+
z = np.linspace(0, 3, nz)
127133
T = np.random.default_rng().uniform(300, 350, (nx, ny, nz))
128134
coords = dict(x=x, y=y, z=z)
129135
temperature_field = td.SpatialDataArray(T, coords=coords)
130136

131-
return TemperatureData(monitor=temp_mnt, temperature=temperature_field)
137+
mnt_data1 = TemperatureData(monitor=temp_mnt1, temperature=temperature_field)
138+
139+
tet_grid_points = td.PointDataArray(
140+
[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
141+
dims=("index", "axis"),
142+
)
143+
144+
tet_grid_cells = td.CellDataArray(
145+
[[0, 1, 2, 4], [1, 2, 3, 4]],
146+
dims=("cell_index", "vertex_index"),
147+
)
148+
149+
tet_grid_values = td.IndexedDataArray(
150+
[1.0, 2.0, 3.0, 4.0, 5.0],
151+
dims=("index"),
152+
name="T",
153+
)
154+
155+
tet_grid = td.TetrahedralGridDataset(
156+
points=tet_grid_points,
157+
cells=tet_grid_cells,
158+
values=tet_grid_values,
159+
)
160+
161+
mnt_data2 = TemperatureData(monitor=temp_mnt2, temperature=tet_grid)
162+
163+
tri_grid_points = td.PointDataArray(
164+
[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],
165+
dims=("index", "axis"),
166+
)
167+
168+
tri_grid_cells = td.CellDataArray(
169+
[[0, 1, 2], [1, 2, 3]],
170+
dims=("cell_index", "vertex_index"),
171+
)
172+
173+
tri_grid_values = td.IndexedDataArray(
174+
[1.0, 2.0, 3.0, 4.0],
175+
dims=("index"),
176+
name="T",
177+
)
178+
179+
tri_grid = td.TriangularGridDataset(
180+
normal_axis=1,
181+
normal_pos=0,
182+
points=tri_grid_points,
183+
cells=tri_grid_cells,
184+
values=tri_grid_values,
185+
)
186+
187+
mnt_data3 = TemperatureData(monitor=temp_mnt3, temperature=tri_grid)
188+
189+
mnt_data4 = TemperatureData(monitor=temp_mnt4, temperature=None)
190+
191+
return (mnt_data1, mnt_data2, mnt_data3, mnt_data4)
132192

133193

134194
def test_heat_mnt_data():
135-
_ = make_heat_mnt_data
195+
_ = make_heat_mnt_data()
136196

137197

138198
def make_uniform_grid_spec():
@@ -192,7 +252,7 @@ def make_heat_sim():
192252

193253
grid_spec = make_uniform_grid_spec()
194254

195-
temp_mnt = make_heat_mnt()
255+
temp_mnts = make_heat_mnts()
196256

197257
heat_sim = HeatSimulation(
198258
medium=fluid_medium,
@@ -202,7 +262,7 @@ def make_heat_sim():
202262
boundary_spec=[pl1, pl2, pl3, pl4, pl5],
203263
grid_spec=grid_spec,
204264
sources=[heat_source],
205-
monitors=[temp_mnt],
265+
monitors=temp_mnts,
206266
)
207267

208268
return heat_sim
@@ -253,7 +313,7 @@ def test_heat_sim():
253313
with pytest.raises(pd.ValidationError):
254314
_ = heat_sim.updated_copy(center=(0, 0, 0), size=(1, 0, 0))
255315

256-
temp_mnt = make_heat_mnt()
316+
temp_mnt = heat_sim.monitors[0]
257317

258318
with pytest.raises(pd.ValidationError):
259319
heat_sim.updated_copy(monitors=[temp_mnt, temp_mnt])
@@ -337,7 +397,7 @@ def make_heat_sim_data():
337397

338398
heat_sim_data = HeatSimulationData(
339399
simulation=heat_sim,
340-
data=[temp_data],
400+
data=temp_data,
341401
)
342402

343403
return heat_sim_data
@@ -346,15 +406,23 @@ def make_heat_sim_data():
346406
def test_sim_data():
347407
heat_sim_data = make_heat_sim_data()
348408
_ = heat_sim_data.plot_field("test", z=0)
409+
_ = heat_sim_data.plot_field("tri")
410+
_ = heat_sim_data.plot_field("tet", y=0.5)
349411
plt.close()
350412

413+
with pytest.raises(DataError):
414+
_ = heat_sim_data.plot_field("empty")
415+
416+
with pytest.raises(DataError):
417+
_ = heat_sim_data.plot_field("test")
418+
351419
with pytest.raises(KeyError):
352420
_ = heat_sim_data.plot_field("test3", x=0)
353421

354422
with pytest.raises(pd.ValidationError):
355423
_ = heat_sim_data.updated_copy(data=[heat_sim_data.data[0]] * 2)
356424

357-
temp_mnt = make_heat_mnt()
425+
temp_mnt = TemperatureMonitor(size=(1, 2, 3), name="test")
358426
temp_mnt = temp_mnt.updated_copy(name="test2")
359427

360428
sim = heat_sim_data.simulation.updated_copy(monitors=[temp_mnt])
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Tests tidy3d/components/data/dataset.py"""
2+
import pytest
3+
import builtins
4+
from .test_datasets import test_triangular_dataset as _test_triangular_dataset
5+
from .test_datasets import test_tetrahedral_dataset as _test_tetrahedral_dataset
6+
7+
8+
@pytest.fixture
9+
def hide_vtk(monkeypatch, request):
10+
import_orig = builtins.__import__
11+
12+
def mocked_import(name, *args, **kwargs):
13+
if name in ["vtk", "vtkmodules.vtkCommonCore"]:
14+
raise ImportError()
15+
return import_orig(name, *args, **kwargs)
16+
17+
monkeypatch.setattr(builtins, "__import__", mocked_import)
18+
19+
20+
@pytest.mark.usefixtures("hide_vtk")
21+
def test_triangular_dataset_no_vtk(tmp_path):
22+
_test_triangular_dataset(tmp_path, "test_name")
23+
24+
# double check that vtk was not imported
25+
from tidy3d.components.types import vtk
26+
27+
assert vtk is None
28+
29+
30+
@pytest.mark.usefixtures("hide_vtk")
31+
def test_tetrahedral_dataset_no_vtk(tmp_path):
32+
_test_tetrahedral_dataset(tmp_path, "test_name")
33+
34+
# double check that vtk was not imported
35+
from tidy3d.components.types import vtk
36+
37+
assert vtk is None

tests/test_data/test_data_arrays.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Tests tidy3d/components/data/data_array.py"""
2+
import pytest
23
import numpy as np
34
from typing import Tuple, List
45

56
import tidy3d as td
7+
from tidy3d.exceptions import DataError
68

79
np.random.seed(4)
810

@@ -277,3 +279,52 @@ def test_charge_data_array():
277279
n = [0, 1e-12, 2e-12]
278280
p = [0, 3e-12, 4e-12]
279281
_ = td.ChargeDataArray((1 + 1j) * np.random.random((3, 3)), coords=dict(n=n, p=p))
282+
283+
284+
def test_point_data_array():
285+
_ = td.PointDataArray(
286+
np.random.rand(2, 3),
287+
coords=dict(index=np.arange(2), axis=np.arange(3)),
288+
)
289+
290+
291+
def test_cell_data_array():
292+
_ = td.CellDataArray(
293+
[[0, 1, 2], [1, 2, 3]],
294+
coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),
295+
)
296+
297+
298+
def test_indexed_data_array():
299+
_ = td.IndexedDataArray(
300+
np.random.rand(10),
301+
coords=dict(index=np.arange(10)),
302+
)
303+
304+
305+
def test_spatial_data_array():
306+
arr = td.SpatialDataArray(
307+
[[[0, 1], [2, 3]], [[4, 5], [6, 7]]],
308+
coords=dict(x=[0, 1], y=[1, 2], z=[2, 3]),
309+
)
310+
311+
reflected = arr.reflect(axis=0, center=-0.5)
312+
313+
reflected_expected = td.SpatialDataArray(
314+
[[[4, 5], [6, 7]], [[0, 1], [2, 3]], [[0, 1], [2, 3]], [[4, 5], [6, 7]]],
315+
coords=dict(x=[-2, -1, 0, 1], y=[1, 2], z=[2, 3]),
316+
)
317+
318+
assert reflected == reflected_expected
319+
320+
reflected = arr.reflect(axis=1, center=1)
321+
322+
reflected_expected = td.SpatialDataArray(
323+
[[[2, 3], [0, 1], [2, 3]], [[6, 7], [4, 5], [6, 7]]],
324+
coords=dict(x=[0, 1], y=[0, 1, 2], z=[2, 3]),
325+
)
326+
327+
assert reflected == reflected_expected
328+
329+
with pytest.raises(DataError):
330+
reflected = arr.reflect(axis=2, center=2.5)

0 commit comments

Comments
 (0)