Skip to content

Electric field monitor for Charge #2566

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
145 changes: 131 additions & 14 deletions tests/test_components/test_heat_charge.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,19 +254,22 @@ def monitors():

mesh_mnt = td.VolumeMeshMonitor(size=(1.6, 2, 3), name="mesh_test")

electric_field_mnt = td.SteadyElectricFieldMonitor(size=(1.6, 2, 3), name="electric_field_test")

return [
temp_mnt1,
temp_mnt2,
temp_mnt3,
temp_mnt4,
volt_mnt1,
volt_mnt2,
volt_mnt3,
volt_mnt4,
capacitance_mnt1,
free_carrier_mnt1,
energy_band_mnt1,
mesh_mnt,
temp_mnt1, # 0
temp_mnt2, # 1
temp_mnt3, # 2
temp_mnt4, # 3
volt_mnt1, # 4
volt_mnt2, # 5
volt_mnt3, # 6
volt_mnt4, # 7
capacitance_mnt1, # 8
free_carrier_mnt1, # 9
energy_band_mnt1, # 10
mesh_mnt, # 11
electric_field_mnt, # 12
]


Expand Down Expand Up @@ -519,7 +522,10 @@ def temperature_monitor_data(monitors):
@pytest.fixture(scope="module")
def voltage_monitor_data(monitors):
"""Creates different voltage monitor data."""
_, _, _, _, volt_mnt1, volt_mnt2, volt_mnt3, volt_mnt4, _, _, _, _ = monitors
volt_mnt1 = monitors[4]
volt_mnt2 = monitors[5]
volt_mnt3 = monitors[6]
volt_mnt4 = monitors[7]

# SpatialDataArray
nx, ny, nz = 9, 6, 5
Expand Down Expand Up @@ -679,6 +685,76 @@ def energy_band_monitor_data(monitors):
return (eb_data1,)


@pytest.fixture(scope="module")
def electric_field_monitor_data(monitors):
"""Creates different electric field monitor data."""
monitor = monitors[12]

# TetrahedralGridDataset
tet_grid_points = td.PointDataArray(
[[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]],
dims=("index", "axis"),
)

tet_grid_cells = td.CellDataArray(
[[0, 1, 2, 4], [1, 2, 3, 4]],
dims=("cell_index", "vertex_index"),
)

tet_grid_values = td.PointDataArray(
[[0.0, 1.0, 0.0], [1.0, 1.0, 1.0], [3.0, 5.0, 1.0], [4.0, 5.0, 3.0], [5.0, 2.0, 1.0]],
dims=(
"index",
"axis",
),
name="T",
)

tet_grid = td.TetrahedralGridDataset(
points=tet_grid_points,
cells=tet_grid_cells,
values=tet_grid_values,
)

mnt_data1 = td.SteadyElectricFieldData(monitor=monitor, E=tet_grid)

# TriangularGridDataset
tri_grid_points = td.PointDataArray(
[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],
dims=("index", "axis"),
)

tri_grid_cells = td.CellDataArray(
[[0, 1, 2], [1, 2, 3]],
dims=("cell_index", "vertex_index"),
)

tri_grid_values = td.IndexedFieldVoltageDataArray(
[
[[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]],
[[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]],
[[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]],
[[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]],
],
coords={"index": np.arange(4), "axis": np.arange(3), "voltage": [-1, 1]},
name="T",
)

tri_grid = td.TriangularGridDataset(
normal_axis=1,
normal_pos=0,
points=tri_grid_points,
cells=tri_grid_cells,
values=tri_grid_values,
)

mnt_data2 = td.SteadyElectricFieldData(monitor=monitor, E=tri_grid)

mnt_data3 = td.SteadyElectricFieldData(monitor=monitor, E=None)

return (mnt_data1, mnt_data2, mnt_data3)


@pytest.fixture(scope="module")
def simulation_data(
heat_simulation,
Expand Down Expand Up @@ -853,11 +929,52 @@ def test_monitor_crosses_medium(mediums, structures, heat_simulation, conduction


def test_heat_charge_mnt_data(
temperature_monitor_data, voltage_monitor_data, capacitance_monitor_data
temperature_monitor_data, voltage_monitor_data, electric_field_monitor_data
):
"""Tests whether different heat-charge monitor data can be created."""
assert len(temperature_monitor_data) == 4, "Expected 4 temperature monitor data entries."
assert len(voltage_monitor_data) == 4, "Expected 4 voltage monitor data entries."
assert len(electric_field_monitor_data) == 3, "Expected 3 electric field monitor data entries."

for mnt_data in electric_field_monitor_data:
assert "E" in mnt_data.field_components.keys()

symm_data = mnt_data.symmetry_expanded_copy
assert symm_data.E == mnt_data.E

names = mnt_data.field_name("abs^2")
assert names == "E²"
names = mnt_data.field_name()
assert names == "E"

# make sure an error is raised if we don't use a field data array
# TriangularGridDataset
tri_grid_points = td.PointDataArray(
[[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],
dims=("index", "axis"),
)

tri_grid_cells = td.CellDataArray(
[[0, 1, 2], [1, 2, 3]],
dims=("cell_index", "vertex_index"),
)

tri_grid_values = td.IndexedDataArray(
[1.0, 2.0, 3.0, 4.0],
dims=("index",),
name="T",
)

tri_grid = td.TriangularGridDataset(
normal_axis=1,
normal_pos=0,
points=tri_grid_points,
cells=tri_grid_cells,
values=tri_grid_values,
)

with pytest.raises(pd.ValidationError):
_ = mnt_data.updated_copy(E=tri_grid)


def test_grid_spec_validation(grid_specs):
Expand Down
6 changes: 6 additions & 0 deletions tidy3d/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
)
from tidy3d.components.tcad.data.types import (
SteadyCapacitanceData,
SteadyElectricFieldData,
SteadyEnergyBandData,
SteadyFreeCarrierData,
SteadyPotentialData,
Expand All @@ -53,6 +54,7 @@
from tidy3d.components.tcad.mesher import VolumeMesher
from tidy3d.components.tcad.monitors.charge import (
SteadyCapacitanceMonitor,
SteadyElectricFieldMonitor,
SteadyEnergyBandMonitor,
SteadyFreeCarrierMonitor,
SteadyPotentialMonitor,
Expand Down Expand Up @@ -136,6 +138,7 @@
FluxTimeDataArray,
HeatDataArray,
IndexedDataArray,
IndexedFieldVoltageDataArray,
IndexedTimeDataArray,
IndexedVoltageDataArray,
ModeAmpsDataArray,
Expand Down Expand Up @@ -565,6 +568,7 @@ def set_logging_level(level: str) -> None:
"HuraySurfaceRoughness",
"IndexPerturbation",
"IndexedDataArray",
"IndexedFieldVoltageDataArray",
"IndexedTimeDataArray",
"IndexedVoltageDataArray",
"InsulatingBC",
Expand Down Expand Up @@ -653,6 +657,8 @@ def set_logging_level(level: str) -> None:
"Staircasing",
"SteadyCapacitanceData",
"SteadyCapacitanceMonitor",
"SteadyElectricFieldData",
"SteadyElectricFieldMonitor",
"SteadyEnergyBandData",
"SteadyEnergyBandMonitor",
"SteadyFreeCarrierData",
Expand Down
35 changes: 32 additions & 3 deletions tidy3d/components/data/data_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1175,9 +1175,9 @@ class SteadyVoltageDataArray(DataArray):


class PointDataArray(DataArray):
"""A two-dimensional array that stores coordinates of a collection of points.
"""A two-dimensional array that stores coordinates/field components for a collection of points.
Dimension ``index`` denotes the index of a point in the collection, and dimension ``axis``
denotes the point's coordinate along that axis.
denotes the field component (or point coordinate) in that direction.

Example
-------
Expand All @@ -1188,6 +1188,14 @@ class PointDataArray(DataArray):
>>> point3 = point_array.sel(index=3)
>>> # get x coordinates of all points
>>> x_coords = point_array.sel(axis=0)
>>>
>>> field_da = PointDataArray(
... np.random.random((120, 3)), coords=dict(index=np.arange(120), axis=np.arange(3)),
... )
>>> # get field of point number 90
>>> field_point90 = field_da.sel(index=90)
>>> # get z component of all points
>>> z_field = field_da.sel(axis=2)
"""

__slots__ = ()
Expand Down Expand Up @@ -1265,6 +1273,20 @@ class IndexedTimeDataArray(DataArray):
_dims = ("index", "t")


class IndexedFieldVoltageDataArray(DataArray):
"""Stores indexed values of vector fields for different voltages. It is typically used
in conjuction with a ``PointDataArray`` to store point-associated vector data.
Example
-------
>>> indexed_array = IndexedFieldVoltageDataArray(
... (1+1j) * np.random.random((4,3,2)), coords=dict(index=np.arange(4), axis=np.arange(3), voltage=[-1, 1])
... )
"""

__slots__ = ()
_dims = ("index", "axis", "voltage")


class SpatialVoltageDataArray(AbstractSpatialDataArray):
"""Spatial distribution with voltage mapping.

Expand Down Expand Up @@ -1319,11 +1341,18 @@ class PerturbationCoefficientDataArray(DataArray):
PointDataArray,
CellDataArray,
IndexedDataArray,
IndexedFieldVoltageDataArray,
IndexedVoltageDataArray,
SpatialVoltageDataArray,
PerturbationCoefficientDataArray,
IndexedTimeDataArray,
]
DATA_ARRAY_MAP = {data_array.__name__: data_array for data_array in DATA_ARRAY_TYPES}

IndexedDataArrayTypes = Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray]
IndexedDataArrayTypes = Union[
IndexedDataArray,
IndexedVoltageDataArray,
IndexedTimeDataArray,
IndexedFieldVoltageDataArray,
PointDataArray,
]
14 changes: 14 additions & 0 deletions tidy3d/components/data/unstructured/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,20 @@ def to_vtu(self, fname: str):
writer.SetInputData(self._vtk_obj)
writer.Write()

@classmethod
@requires_vtk
def _cell_to_point_data(
cls,
vtk_obj,
):
"""Get point data values from a VTK object."""

cellDataToPointData = vtk["mod"].vtkCellDataToPointData()
cellDataToPointData.SetInputData(vtk_obj)
cellDataToPointData.Update()

return cellDataToPointData.GetOutput()

@classmethod
@requires_vtk
def _get_values_from_vtk(
Expand Down
Loading