Skip to content

Commit b54df57

Browse files
committed
adding support for coaxial lumped ports and elements
extending impedance calculator for custom paths and fixing one bug modified convention for vertices in custom path integral
1 parent b3d2f82 commit b54df57

28 files changed

+1650
-430
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
- Support for complex and self-intersecting polyslabs in adjoint module via `JaxComplexPolySlab`.
2929
- Support for `.gz` files in `Simulation` version updater.
3030
- Warning if a nonuniform custom medium is intersecting `PlaneWave`, `GaussianBeam`, `AstigmaticGaussianBeam`, `FieldProjectionCartesianMonitor`, `FieldProjectionAngleMonitor`, `FieldProjectionKSpaceMonitor`, and `DiffractionMonitor`.
31+
- Added a `CoaxialLumpedPort` and `CoaxialLumpedResistor` for coaxial type transmission lines and excitations.
3132

3233
### Changed
3334
- `tidy3d convert` from `.lsf` files to tidy3d scripts has moved to another repository at `https://github.com/hirako22/Lumerical-to-Tidy3D-Converter`.

docs/api/lumped_elements.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ Passive elements
1010
:template: module.rst
1111

1212
tidy3d.LumpedResistor
13+
tidy3d.CoaxialLumpedResistor

docs/api/plugins/microwave.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ Microwave
1010
tidy3d.plugins.microwave.AxisAlignedPathIntegral
1111
tidy3d.plugins.microwave.VoltageIntegralAxisAligned
1212
tidy3d.plugins.microwave.CurrentIntegralAxisAligned
13+
tidy3d.plugins.microwave.CustomPathIntegral2D
14+
tidy3d.plugins.microwave.CustomVoltageIntegral2D
15+
tidy3d.plugins.microwave.CustomCurrentIntegral2D
1316
tidy3d.plugins.microwave.ImpedanceCalculator

docs/api/plugins/smatrix.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Scattering Matrix Calculator
1212
tidy3d.plugins.smatrix.ModalPortDataArray
1313
tidy3d.plugins.smatrix.TerminalComponentModeler
1414
tidy3d.plugins.smatrix.LumpedPort
15-
tidy3d.plugins.smatrix.LumpedPortDataArray
15+
tidy3d.plugins.smatrix.LumpedPortDataArray
16+
tidy3d.plugins.smatrix.CoaxialLumpedPort

tests/test_components/test_medium.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,10 +754,16 @@ def test_lumped_resistor():
754754
voltage_axis=0,
755755
name="R",
756756
)
757-
_ = resistor.sheet_conductance
757+
_ = resistor._sheet_conductance
758758
normal_axis = resistor.normal_axis
759759
assert normal_axis == 1
760760

761+
# Check conversion to geometry
762+
_ = resistor.to_structure
763+
764+
# Check conversion to mesh overrides
765+
_ = resistor.to_mesh_overrides()
766+
761767
# error if voltage axis is not in plane with the resistor
762768
with pytest.raises(pydantic.ValidationError):
763769
_ = td.LumpedResistor(
@@ -785,3 +791,45 @@ def test_lumped_resistor():
785791
voltage_axis=2,
786792
name="R",
787793
)
794+
795+
796+
def test_coaxial_lumped_resistor():
797+
resistor = td.CoaxialLumpedResistor(
798+
resistance=50.0,
799+
center=[0, 0, 0],
800+
outer_diameter=3,
801+
inner_diameter=1,
802+
normal_axis=1,
803+
name="R",
804+
)
805+
806+
_ = resistor._sheet_conductance
807+
normal_axis = resistor.normal_axis
808+
assert normal_axis == 1
809+
810+
# Check conversion to geometry
811+
_ = resistor.to_structure
812+
813+
# Check conversion to mesh overrides
814+
_ = resistor.to_mesh_overrides()
815+
816+
# error if inner diameter is larger
817+
with pytest.raises(pydantic.ValidationError):
818+
_ = td.CoaxialLumpedResistor(
819+
resistance=50.0,
820+
center=[0, 0, 0],
821+
outer_diameter=3,
822+
inner_diameter=4,
823+
normal_axis=1,
824+
name="R",
825+
)
826+
827+
with pytest.raises(pydantic.ValidationError):
828+
_ = td.CoaxialLumpedResistor(
829+
resistance=50.0,
830+
center=[0, 0, np.inf],
831+
outer_diameter=3,
832+
inner_diameter=1,
833+
normal_axis=1,
834+
name="R",
835+
)

tests/test_components/test_simulation.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,15 @@ def test_plot_boundaries():
691691
plt.close()
692692

693693

694+
def test_plot_with_lumped_elements():
695+
load = td.LumpedResistor(
696+
center=(0, 0, 0), size=(1, 2, 0), name="resistor", voltage_axis=0, resistance=50
697+
)
698+
sim_test = SIM_FULL.updated_copy(lumped_elements=[load])
699+
sim_test.plot(z=0)
700+
plt.close()
701+
702+
694703
def test_wvl_mat_grid():
695704
td.Simulation.wvl_mat_min.fget(SIM_FULL)
696705

@@ -2398,7 +2407,6 @@ def test_to_gds(tmp_path):
23982407
def test_sim_subsection(unstructured, nz):
23992408
region = td.Box(size=(0.3, 0.5, 0.7), center=(0.1, 0.05, 0.02))
24002409
region_xy = td.Box(size=(0.3, 0.5, 0), center=(0.1, 0.05, 0.02))
2401-
_ = td.Box(size=(0, 0.5, 0.7), center=(0.1, 0.05, 0.02))
24022410

24032411
sim_red = SIM_FULL.subsection(region=region)
24042412
assert sim_red.structures != SIM_FULL.structures
@@ -2809,19 +2817,38 @@ def test_suggested_mesh_overrides():
28092817
lumped_elements=[resistor],
28102818
)
28112819

2812-
suggested_mesh_overrides = sim.suggest_mesh_overrides()
2813-
assert len(suggested_mesh_overrides) == 2
2814-
grid_spec = sim.grid_spec.copy(
2815-
update={
2816-
"override_structures": list(sim.grid_spec.override_structures)
2817-
+ suggested_mesh_overrides,
2818-
}
2820+
def update_sim_with_suggested_overrides(sim):
2821+
suggested_mesh_overrides = sim.suggest_mesh_overrides()
2822+
assert len(suggested_mesh_overrides) == 2
2823+
grid_spec = sim.grid_spec.copy(
2824+
update={
2825+
"override_structures": list(sim.grid_spec.override_structures)
2826+
+ suggested_mesh_overrides,
2827+
}
2828+
)
2829+
2830+
return sim.updated_copy(
2831+
grid_spec=grid_spec,
2832+
)
2833+
2834+
_ = update_sim_with_suggested_overrides(sim)
2835+
2836+
coax_resistor = td.CoaxialLumpedResistor(
2837+
resistance=50.0,
2838+
center=[0, 0, 0],
2839+
outer_diameter=2,
2840+
inner_diameter=0.5,
2841+
normal_axis=0,
2842+
name="R",
28192843
)
28202844

2821-
_ = sim.updated_copy(
2822-
grid_spec=grid_spec,
2845+
sim = sim.updated_copy(
2846+
lumped_elements=[coax_resistor],
2847+
grid_spec=td.GridSpec.uniform(dl=0.1),
28232848
)
28242849

2850+
_ = update_sim_with_suggested_overrides(sim)
2851+
28252852

28262853
def test_run_time_spec():
28272854
run_time_spec = td.RunTimeSpec(quality_factor=3.0)

tests/test_plugins/terminal_component_modeler_def.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import tidy3d as td
44
from tidy3d.plugins.smatrix import (
55
LumpedPort,
6+
CoaxialLumpedPort,
67
TerminalComponentModeler,
78
)
89

@@ -24,6 +25,10 @@
2425
freq_start = 1e8
2526
freq_stop = 10e9
2627

28+
# Coaxial dimensions
29+
Rinner = 0.2768 * 1e-3
30+
Router = 1.0 * 1e-3
31+
2732

2833
def make_simulation(planar_pec: bool, length: float = None, auto_grid: bool = True):
2934
if length:
@@ -156,3 +161,124 @@ def make_component_modeler(
156161
)
157162

158163
return modeler
164+
165+
166+
def make_coaxial_simulation(length: float = None, auto_grid: bool = True):
167+
if length:
168+
coax_length = length
169+
else:
170+
coax_length = default_strip_length
171+
172+
# wavelength / frequency
173+
freq0 = (freq_start + freq_stop) / 2
174+
fwidth = freq_stop - freq_start
175+
wavelength0 = td.C_0 / freq0
176+
run_time = 60 / fwidth
177+
178+
# Spatial grid specification
179+
if auto_grid:
180+
grid_spec = td.GridSpec.auto(min_steps_per_wvl=10, wavelength=td.C_0 / freq_stop)
181+
else:
182+
grid_spec = td.GridSpec.uniform(wavelength0 / 11)
183+
184+
# Make structures
185+
inner_conductor = td.Cylinder(
186+
center=(0, 0, 0),
187+
radius=Rinner,
188+
length=length,
189+
axis=2,
190+
)
191+
192+
outer_1 = td.Cylinder(
193+
center=(0, 0, 0),
194+
radius=Router,
195+
length=length,
196+
axis=2,
197+
)
198+
199+
outer_2 = td.Cylinder(
200+
center=(0, 0, 0),
201+
radius=Router * 1.1,
202+
length=length,
203+
axis=2,
204+
)
205+
206+
outer_shell_clip = td.ClipOperation(
207+
operation="difference", geometry_a=outer_2, geometry_b=outer_1
208+
)
209+
210+
inner = td.Structure(
211+
geometry=inner_conductor,
212+
medium=pec,
213+
)
214+
215+
outer_shell = td.Structure(
216+
geometry=outer_shell_clip,
217+
medium=pec,
218+
)
219+
220+
structures_list = [inner, outer_shell]
221+
222+
# Make simulation
223+
center_sim = [0, 0, 0]
224+
size_sim = [
225+
2 * Router,
226+
2 * Router,
227+
coax_length + 0.5 * wavelength0,
228+
]
229+
230+
sim = td.Simulation(
231+
center=center_sim,
232+
size=size_sim,
233+
grid_spec=grid_spec,
234+
structures=structures_list,
235+
sources=[],
236+
monitors=[],
237+
run_time=run_time,
238+
boundary_spec=td.BoundarySpec.all_sides(boundary=td.PML()),
239+
shutoff=1e-4,
240+
)
241+
242+
return sim
243+
244+
245+
def make_coaxial_component_modeler(
246+
reference_impedance: complex = 50,
247+
length: float = None,
248+
port_refinement: bool = True,
249+
auto_grid: bool = True,
250+
**kwargs,
251+
):
252+
if length:
253+
coax_length = length
254+
else:
255+
coax_length = default_strip_length
256+
257+
sim = make_coaxial_simulation(length=coax_length, auto_grid=auto_grid)
258+
259+
center_src1 = [0, 0, -coax_length / 2]
260+
261+
port_cells = None
262+
if port_refinement:
263+
port_cells = 21
264+
265+
port_1 = CoaxialLumpedPort(
266+
center=center_src1,
267+
outer_diameter=2 * Router,
268+
inner_diameter=2 * Rinner,
269+
normal_axis=2,
270+
direction="+",
271+
name="coax_port_1",
272+
num_grid_cells=port_cells,
273+
impedance=reference_impedance,
274+
)
275+
center_src2 = [0, 0, coax_length / 2]
276+
port_2 = port_1.updated_copy(name="coax_port_2", center=center_src2, direction="-")
277+
ports = [port_1, port_2]
278+
freqs = np.linspace(freq_start, freq_stop, 100)
279+
280+
modeler = TerminalComponentModeler(
281+
simulation=sim, ports=ports, freqs=freqs, remove_dc_component=False, verbose=True, **kwargs
282+
)
283+
284+
return modeler

tests/test_plugins/test_microwave.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from tidy3d.plugins.microwave import (
1414
VoltageIntegralAxisAligned,
1515
CurrentIntegralAxisAligned,
16+
CustomVoltageIntegral2D,
17+
CustomCurrentIntegral2D,
1618
ImpedanceCalculator,
1719
)
1820

@@ -379,3 +381,60 @@ def test_coupled_microstrip_model():
379381
assert np.isclose(Z_odd, 39, rtol=0.01)
380382
assert np.isclose(eps_even, 3.42, rtol=0.01)
381383
assert np.isclose(eps_odd, 2.80, rtol=0.01)
384+
385+
386+
def test_frequency_monitor_custom_voltage_integral():
387+
length = 0.5
388+
size = [0, 0, 0]
389+
size[1] = length
390+
# Make line
391+
vertices = [(0, 0), (0, 0.2), (0, 0.4)]
392+
voltage_integral = CustomVoltageIntegral2D(axis=2, position=0, vertices=vertices)
393+
voltage_integral.compute_voltage(SIM_Z_DATA["field"])
394+
395+
396+
def test_vertices_validator_custom_current_integral():
397+
length = 0.5
398+
size = [0, 0, 0]
399+
size[1] = length
400+
# Make wrong box
401+
vertices = [(0.2, -0.2, 0.5), (0.2, 0.2), (-0.2, 0.2), (-0.2, -0.2), (0.2, -0.2)]
402+
403+
with pytest.raises(pydantic.ValidationError):
404+
_ = CustomCurrentIntegral2D(axis=2, position=0, vertices=vertices)
405+
406+
# Make wrong box shape
407+
vertices = [(0.2, 0.2, -0.2, -0.2, 0.2), (-0.2, 0.2, 0.2, -0.2, 0.2)]
408+
with pytest.raises(pydantic.ValidationError):
409+
_ = CustomCurrentIntegral2D(axis=2, position=0, vertices=vertices)
410+
411+
412+
def test_fields_missing_custom_current_integral():
413+
length = 0.5
414+
size = [0, 0, 0]
415+
size[1] = length
416+
# Make box
417+
vertices = [(0.2, -0.2), (0.2, 0.2), (-0.2, 0.2), (-0.2, -0.2), (0.2, -0.2)]
418+
current_integral = CustomCurrentIntegral2D(axis=2, position=0, vertices=vertices)
419+
with pytest.raises(DataError):
420+
current_integral.compute_current(SIM_Z_DATA["ExHx"])
421+
422+
423+
def test_time_monitor_custom_current_integral():
424+
length = 0.5
425+
size = [0, 0, 0]
426+
size[1] = length
427+
# Make box
428+
vertices = [(0.2, -0.2), (0.2, 0.2), (-0.2, 0.2), (-0.2, -0.2), (0.2, -0.2)]
429+
current_integral = CustomCurrentIntegral2D(axis=2, position=0, vertices=vertices)
430+
current_integral.compute_current(SIM_Z_DATA["field_time"])
431+
432+
433+
def test_mode_solver_custom_current_integral():
434+
length = 0.5
435+
size = [0, 0, 0]
436+
size[1] = length
437+
# Make box
438+
vertices = [(0.2, -0.2), (0.2, 0.2), (-0.2, 0.2), (-0.2, -0.2), (0.2, -0.2)]
439+
current_integral = CustomCurrentIntegral2D(axis=2, position=0, vertices=vertices)
440+
current_integral.compute_current(SIM_Z_DATA["mode"])

0 commit comments

Comments
 (0)