Skip to content

Commit e445dd0

Browse files
committed
wip
1 parent 324b721 commit e445dd0

File tree

4 files changed

+229
-35
lines changed

4 files changed

+229
-35
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
"""Storing data associated with microwave quantities"""
2+
3+
from __future__ import annotations
4+
5+
from tidy3d.components.data.data_array import (
6+
DataArray,
7+
FreqDataArray,
8+
FreqModeDataArray,
9+
TimeDataArray,
10+
)
11+
from tidy3d.constants import AMP, OHM, VOLT
12+
13+
14+
class VoltageArray(DataArray):
15+
# Always set __slots__ = () to avoid xarray warnings
16+
__slots__ = ()
17+
_data_attrs = {"units": VOLT, "long_name": "voltage"}
18+
19+
20+
class CurrentArray(DataArray):
21+
# Always set __slots__ = () to avoid xarray warnings
22+
__slots__ = ()
23+
_data_attrs = {"units": AMP, "long_name": "current"}
24+
25+
26+
class ImpedanceArray(DataArray):
27+
# Always set __slots__ = () to avoid xarray warnings
28+
__slots__ = ()
29+
_data_attrs = {"units": OHM, "long_name": "impedance"}
30+
31+
32+
# Voltage arrays
33+
class VoltageFreqDataArray(FreqDataArray):
34+
"""Voltage data array in frequency domain.
35+
36+
Example
37+
-------
38+
>>> import numpy as np
39+
>>> f = [2e9, 3e9, 4e9]
40+
>>> coords = dict(f=f)
41+
>>> data = np.random.random(3) + 1j * np.random.random(3)
42+
>>> vfd = VoltageFreqDataArray(data, coords=coords)
43+
"""
44+
45+
__slots__ = ()
46+
47+
48+
class VoltageTimeDataArray(VoltageArray, TimeDataArray):
49+
"""Voltage data array in time domain.
50+
51+
Example
52+
-------
53+
>>> import numpy as np
54+
>>> t = [0, 1e-9, 2e-9, 3e-9]
55+
>>> coords = dict(t=t)
56+
>>> data = np.sin(2 * np.pi * 1e9 * np.array(t))
57+
>>> vtd = VoltageTimeDataArray(data, coords=coords)
58+
"""
59+
60+
__slots__ = ()
61+
62+
63+
class VoltageFreqModeDataArray(VoltageArray, FreqModeDataArray):
64+
"""Voltage data array in frequency-mode domain.
65+
66+
Example
67+
-------
68+
>>> import numpy as np
69+
>>> f = [2e9, 3e9]
70+
>>> mode_index = [0, 1]
71+
>>> coords = dict(f=f, mode_index=mode_index)
72+
>>> data = np.random.random((2, 2)) + 1j * np.random.random((2, 2))
73+
>>> vfmd = VoltageFreqModeDataArray(data, coords=coords)
74+
"""
75+
76+
__slots__ = ()
77+
78+
79+
# Current arrays
80+
class CurrentFreqDataArray(CurrentArray, FreqDataArray):
81+
"""Current data array in frequency domain.
82+
83+
Example
84+
-------
85+
>>> import numpy as np
86+
>>> f = [2e9, 3e9, 4e9]
87+
>>> coords = dict(f=f)
88+
>>> data = np.random.random(3) + 1j * np.random.random(3)
89+
>>> cfd = CurrentFreqDataArray(data, coords=coords)
90+
"""
91+
92+
__slots__ = ()
93+
94+
95+
class CurrentTimeDataArray(CurrentArray, TimeDataArray):
96+
"""Current data array in time domain.
97+
98+
Example
99+
-------
100+
>>> import numpy as np
101+
>>> t = [0, 1e-9, 2e-9, 3e-9]
102+
>>> coords = dict(t=t)
103+
>>> data = np.cos(2 * np.pi * 1e9 * np.array(t))
104+
>>> ctd = CurrentTimeDataArray(data, coords=coords)
105+
"""
106+
107+
__slots__ = ()
108+
109+
110+
class CurrentFreqModeDataArray(CurrentArray, FreqModeDataArray):
111+
"""Current data array in frequency-mode domain.
112+
113+
Example
114+
-------
115+
>>> import numpy as np
116+
>>> f = [2e9, 3e9]
117+
>>> mode_index = [0, 1]
118+
>>> coords = dict(f=f, mode_index=mode_index)
119+
>>> data = np.random.random((2, 2)) + 1j * np.random.random((2, 2))
120+
>>> cfmd = CurrentFreqModeDataArray(data, coords=coords)
121+
"""
122+
123+
__slots__ = ()
124+
125+
126+
# Impedance arrays
127+
class ImpedanceFreqDataArray(ImpedanceArray, FreqDataArray):
128+
"""Impedance data array in frequency domain.
129+
130+
Example
131+
-------
132+
>>> import numpy as np
133+
>>> f = [2e9, 3e9, 4e9]
134+
>>> coords = dict(f=f)
135+
>>> data = 50.0 + 1j * np.random.random(3)
136+
>>> zfd = ImpedanceFreqDataArray(data, coords=coords)
137+
"""
138+
139+
__slots__ = ()
140+
141+
142+
class ImpedanceTimeDataArray(ImpedanceArray, TimeDataArray):
143+
"""Impedance data array in time domain.
144+
145+
Example
146+
-------
147+
>>> import numpy as np
148+
>>> t = [0, 1e-9, 2e-9, 3e-9]
149+
>>> coords = dict(t=t)
150+
>>> data = 50.0 * np.ones_like(t)
151+
>>> ztd = ImpedanceTimeDataArray(data, coords=coords)
152+
"""
153+
154+
__slots__ = ()
155+
156+
157+
class ImpedanceFreqModeDataArray(ImpedanceArray, FreqModeDataArray):
158+
"""Impedance data array in frequency-mode domain.
159+
160+
Example
161+
-------
162+
>>> import numpy as np
163+
>>> f = [2e9, 3e9]
164+
>>> mode_index = [0, 1]
165+
>>> coords = dict(f=f, mode_index=mode_index)
166+
>>> data = 50.0 + 10.0 * np.random.random((2, 2))
167+
>>> zfmd = ImpedanceFreqModeDataArray(data, coords=coords)
168+
"""
169+
170+
__slots__ = ()

tidy3d/plugins/microwave/custom_path_integrals.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
AbstractAxesRH,
2121
AxisAlignedPathIntegral,
2222
CurrentIntegralAxisAligned,
23+
CurrentIntegralResultTypes,
2324
IntegralResultTypes,
2425
MonitorDataTypes,
2526
VoltageIntegralAxisAligned,
27+
VoltageIntegralResultTypes,
2628
)
2729
from .viz import (
2830
ARROW_CURRENT,
@@ -243,7 +245,7 @@ class CustomVoltageIntegral2D(CustomPathIntegral2D):
243245
244246
.. TODO Improve by including extrapolate_to_endpoints field, non-trivial extension."""
245247

246-
def compute_voltage(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
248+
def compute_voltage(self, em_field: MonitorDataTypes) -> VoltageIntegralResultTypes:
247249
"""Compute voltage along path defined by a line.
248250
249251
Parameters
@@ -253,12 +255,12 @@ def compute_voltage(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
253255
254256
Returns
255257
-------
256-
:class:`.IntegralResultTypes`
258+
:class:`.VoltageIntegralResultTypes`
257259
Result of voltage computation over remaining dimensions (frequency, time, mode indices).
258260
"""
259261
AxisAlignedPathIntegral._check_monitor_data_supported(em_field=em_field)
260262
voltage = -1.0 * self.compute_integral(field="E", em_field=em_field)
261-
voltage = VoltageIntegralAxisAligned._set_data_array_attributes(voltage)
263+
voltage = VoltageIntegralAxisAligned._make_result_data_array(voltage)
262264
return voltage
263265

264266
@add_ax_if_none
@@ -316,7 +318,7 @@ class CustomCurrentIntegral2D(CustomPathIntegral2D):
316318
To compute the current flowing in the positive ``axis`` direction, the vertices should be
317319
ordered in a counterclockwise direction."""
318320

319-
def compute_current(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
321+
def compute_current(self, em_field: MonitorDataTypes) -> CurrentIntegralResultTypes:
320322
"""Compute current flowing in a custom loop.
321323
322324
Parameters
@@ -326,12 +328,12 @@ def compute_current(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
326328
327329
Returns
328330
-------
329-
:class:`.IntegralResultTypes`
331+
:class:`.CurrentIntegralResultTypes`
330332
Result of current computation over remaining dimensions (frequency, time, mode indices).
331333
"""
332334
AxisAlignedPathIntegral._check_monitor_data_supported(em_field=em_field)
333335
current = self.compute_integral(field="H", em_field=em_field)
334-
current = CurrentIntegralAxisAligned._set_data_array_attributes(current)
336+
current = CurrentIntegralAxisAligned._make_result_data_array(current)
335337
return current
336338

337339
@add_ax_if_none

tidy3d/plugins/microwave/impedance_calculator.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,28 @@
88
import pydantic.v1 as pd
99

1010
from tidy3d.components.base import Tidy3dBaseModel
11-
from tidy3d.components.data.data_array import FreqDataArray, FreqModeDataArray, TimeDataArray
11+
from tidy3d.components.data.data_array import DataArray
1212
from tidy3d.components.data.monitor_data import FieldTimeData
13+
from tidy3d.components.microwave.data.data_array import (
14+
ImpedanceFreqDataArray,
15+
ImpedanceFreqModeDataArray,
16+
ImpedanceTimeDataArray,
17+
)
1318
from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor
14-
from tidy3d.constants import OHM
1519
from tidy3d.exceptions import ValidationError
1620
from tidy3d.log import log
1721

1822
from .custom_path_integrals import CustomCurrentIntegral2D, CustomVoltageIntegral2D
1923
from .path_integrals import (
2024
AxisAlignedPathIntegral,
2125
CurrentIntegralAxisAligned,
22-
IntegralResultTypes,
2326
MonitorDataTypes,
2427
VoltageIntegralAxisAligned,
2528
)
2629

30+
ImpedanceResultTypes = Union[
31+
ImpedanceFreqDataArray, ImpedanceFreqModeDataArray, ImpedanceTimeDataArray
32+
]
2733
VoltageIntegralTypes = Union[VoltageIntegralAxisAligned, CustomVoltageIntegral2D]
2834
CurrentIntegralTypes = Union[CurrentIntegralAxisAligned, CustomCurrentIntegral2D]
2935

@@ -43,7 +49,7 @@ class ImpedanceCalculator(Tidy3dBaseModel):
4349
description="Definition of contour integral for computing current.",
4450
)
4551

46-
def compute_impedance(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
52+
def compute_impedance(self, em_field: MonitorDataTypes) -> ImpedanceResultTypes:
4753
"""Compute impedance for the supplied ``em_field`` using ``voltage_integral`` and
4854
``current_integral``. If only a single integral has been defined, impedance is
4955
computed using the total flux in ``em_field``.
@@ -56,7 +62,7 @@ def compute_impedance(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
5662
5763
Returns
5864
-------
59-
:class:`.IntegralResultTypes`
65+
:class:`.ImpedanceResultTypes`
6066
Result of impedance computation over remaining dimensions (frequency, time, mode indices).
6167
"""
6268
AxisAlignedPathIntegral._check_monitor_data_supported(em_field=em_field)
@@ -98,7 +104,7 @@ def compute_impedance(self, em_field: MonitorDataTypes) -> IntegralResultTypes:
98104
impedance = np.real(voltage) / np.real(current)
99105
else:
100106
impedance = voltage / current
101-
impedance = ImpedanceCalculator._set_data_array_attributes(impedance)
107+
impedance = ImpedanceCalculator._make_result_data_array(impedance)
102108
return impedance
103109

104110
@pd.validator("current_integral", always=True)
@@ -112,17 +118,13 @@ def check_voltage_or_current(cls, val, values):
112118
return val
113119

114120
@staticmethod
115-
def _set_data_array_attributes(data_array: IntegralResultTypes) -> IntegralResultTypes:
116-
"""Helper to set additional metadata for ``IntegralResultTypes``."""
117-
# Determine type based on coords present
118-
if "mode_index" in data_array.coords:
119-
data_array = FreqModeDataArray(data_array)
120-
elif "f" in data_array.coords:
121-
data_array = FreqDataArray(data_array)
122-
else:
123-
data_array = TimeDataArray(data_array)
124-
data_array.name = "Z0"
125-
return data_array.assign_attrs(units=OHM, long_name="characteristic impedance")
121+
def _make_result_data_array(result: DataArray) -> ImpedanceResultTypes:
122+
"""Helper for creating the proper result type."""
123+
if "t" in result.coords:
124+
return ImpedanceTimeDataArray(data=result.data, coords=result.coords)
125+
if "f" in result.coords and "mode_index" in result.coords:
126+
return ImpedanceFreqModeDataArray(data=result.data, coords=result.coords)
127+
return ImpedanceFreqDataArray(data=result.data, coords=result.coords)
126128

127129
@pd.root_validator(pre=False)
128130
def _warn_rf_license(cls, values):

0 commit comments

Comments
 (0)