Skip to content

Commit e902f77

Browse files
marc-flexmomchil-flex
authored andcommitted
Adding monitor validations for Conduction simulations
1 parent f392a26 commit e902f77

File tree

3 files changed

+210
-4
lines changed

3 files changed

+210
-4
lines changed

tests/test_components/test_heat.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,14 @@ def place_box(center_offset):
453453
)
454454
],
455455
grid_spec=td.UniformUnstructuredGrid(dl=0.1),
456+
monitors=[
457+
td.TemperatureMonitor(
458+
center=(0, 0, 0),
459+
size=(td.inf, td.inf, td.inf),
460+
name="test_monitor",
461+
unstructured=True,
462+
)
463+
],
456464
)
457465

458466
# create all permutations of squares being shifted 1, -1, or zero in all three directions
@@ -494,6 +502,14 @@ def test_sim_structure_extent(box_size, log_level):
494502
placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300)
495503
)
496504
],
505+
monitors=[
506+
td.TemperatureMonitor(
507+
center=(0, 0, 0),
508+
size=(td.inf, td.inf, td.inf),
509+
name="test_monitor",
510+
unstructured=True,
511+
)
512+
],
497513
grid_spec=td.UniformUnstructuredGrid(dl=0.1),
498514
)
499515

@@ -549,6 +565,14 @@ def test_relative_min_dl_warning():
549565
placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300)
550566
)
551567
],
568+
monitors=[
569+
td.TemperatureMonitor(
570+
center=(0, 0, 0),
571+
size=(td.inf, td.inf, td.inf),
572+
name="test_monitor",
573+
unstructured=True,
574+
)
575+
],
552576
)
553577

554578
with AssertLogLevel("WARNING"):
@@ -567,6 +591,14 @@ def test_relative_min_dl_warning():
567591
placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300)
568592
)
569593
],
594+
monitors=[
595+
td.TemperatureMonitor(
596+
center=(0, 0, 0),
597+
size=(td.inf, td.inf, td.inf),
598+
name="test_monitor",
599+
unstructured=True,
600+
)
601+
],
570602
)
571603

572604
with AssertLogLevel("WARNING"):
@@ -585,6 +617,14 @@ def test_relative_min_dl_warning():
585617
placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300)
586618
)
587619
],
620+
monitors=[
621+
td.TemperatureMonitor(
622+
center=(0, 0, 0),
623+
size=(td.inf, td.inf, td.inf),
624+
name="test_monitor",
625+
unstructured=True,
626+
)
627+
],
588628
)
589629

590630

tests/test_components/test_heat_charge.py

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,32 @@ def mediums():
133133
name="insulator_medium",
134134
)
135135

136+
semiconductor_medium = td.MultiPhysicsMedium(
137+
optical=td.Medium(
138+
permittivity=5,
139+
conductivity=0.01,
140+
heat_spec=td.SolidSpec(
141+
capacity=2,
142+
conductivity=3,
143+
),
144+
),
145+
charge=td.SemiconductorMedium(
146+
N_c=1e10,
147+
N_v=1e10,
148+
E_g=1,
149+
mobility_n=td.ConstantMobilityModel(mu=1500),
150+
mobility_p=td.ConstantMobilityModel(mu=1500),
151+
),
152+
name="solid_medium",
153+
)
154+
136155
return {
137156
"fluid_medium": fluid_medium,
138157
"solid_medium": solid_medium,
139158
"solid_no_heat": solid_no_heat,
140159
"solid_no_elect": solid_no_elect,
141160
"insulator_medium": insulator_medium,
161+
"semiconductor_medium": semiconductor_medium,
142162
}
143163

144164

@@ -177,12 +197,19 @@ def structures(mediums):
177197
name="insulator_structure",
178198
)
179199

200+
semiconductor_structure = td.Structure(
201+
geometry=box,
202+
medium=mediums["semiconductor_medium"],
203+
name="semiconductor_structure",
204+
)
205+
180206
return {
181207
"fluid_structure": fluid_structure,
182208
"solid_structure": solid_structure,
183209
"solid_struct_no_heat": solid_struct_no_heat,
184210
"solid_struct_no_elect": solid_struct_no_elect,
185211
"insulator_structure": insulator_structure,
212+
"semiconductor_structure": semiconductor_structure,
186213
}
187214

188215

@@ -336,7 +363,12 @@ def voltage_capacitance_simulation(mediums, structures, boundary_conditions, mon
336363
bc_insulating = td.InsulatingBC()
337364
pl7 = td.HeatChargeBoundarySpec(
338365
condition=bc_insulating,
339-
placement=td.StructureBoundary(structure="solid_structure"),
366+
placement=td.StructureBoundary(structure="semiconductor_structure"),
367+
)
368+
369+
# we need two voltage BCs for Charge simulations
370+
pl8 = pl7.updated_copy(
371+
condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),
340372
)
341373

342374
# Let’s pick a couple of monitors. We'll definitely include the CapacitanceMonitor
@@ -349,10 +381,10 @@ def voltage_capacitance_simulation(mediums, structures, boundary_conditions, mon
349381
# Build a new HeatChargeSimulation
350382
voltage_cap_sim = td.HeatChargeSimulation(
351383
medium=mediums["insulator_medium"],
352-
structures=[structures["insulator_structure"], structures["solid_structure"]],
384+
structures=[structures["insulator_structure"], structures["semiconductor_structure"]],
353385
center=(0, 0, 0),
354386
size=(2, 2, 2),
355-
boundary_spec=[pl6, pl7],
387+
boundary_spec=[pl6, pl7, pl8],
356388
grid_spec=grid_specs["uniform"],
357389
sources=[],
358390
monitors=chosen_monitors,
@@ -1123,6 +1155,13 @@ def place_box(center_offset):
11231155
)
11241156
],
11251157
grid_spec=td.UniformUnstructuredGrid(dl=0.1),
1158+
monitors=[
1159+
td.SteadyPotentialMonitor(
1160+
center=[0, 0, 0],
1161+
size=(td.inf, td.inf, td.inf),
1162+
name="test_monitor",
1163+
)
1164+
],
11261165
)
11271166

11281167
# Create all permutations of squares being shifted 1, -1, or zero in all three directions
@@ -1165,6 +1204,11 @@ def test_sim_structure_extent(box_size, log_level):
11651204
)
11661205
],
11671206
grid_spec=td.UniformUnstructuredGrid(dl=0.1),
1207+
monitors=[
1208+
td.SteadyPotentialMonitor(
1209+
center=(0, 0, 0), size=(td.inf, td.inf, td.inf), name="test_monitor"
1210+
)
1211+
],
11681212
)
11691213

11701214

@@ -1705,3 +1749,75 @@ def test_unsteady_heat_analysis(heat_simulation):
17051749
unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=100000),
17061750
)
17071751
_ = unsteady_sim.updated_copy(analysis_spec=mew_spex)
1752+
1753+
1754+
def test_heat_conduction_simulations():
1755+
"""Test that heat-conduction simulations have necessary components."""
1756+
1757+
# let's create some mediums
1758+
solid_medium = td.MultiPhysicsMedium(
1759+
heat=td.SolidSpec(conductivity=1),
1760+
charge=td.ChargeConductorMedium(conductivity=1),
1761+
name="solid_medium",
1762+
)
1763+
air = td.MultiPhysicsMedium(heat=td.FluidSpec(), charge=td.ChargeInsulatorMedium(), name="air")
1764+
1765+
struct1 = td.Structure(
1766+
geometry=td.Box(center=(0, 0, 0), size=(1, 1, 1)),
1767+
medium=solid_medium,
1768+
name="struct1",
1769+
)
1770+
1771+
# thermal BC
1772+
thermal_bc = td.HeatChargeBoundarySpec(
1773+
condition=td.TemperatureBC(temperature=300),
1774+
placement=td.StructureBoundary(structure="struct1"),
1775+
)
1776+
1777+
# electric BCs
1778+
electric_bc = td.HeatChargeBoundarySpec(
1779+
condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[1])),
1780+
placement=td.StructureBoundary(structure="struct1"),
1781+
)
1782+
1783+
# thermal monitors
1784+
temp_monitor = td.TemperatureMonitor(
1785+
center=(0, 0, 0), size=(1, 1, 1), name="temp_monitor", unstructured=True
1786+
)
1787+
# electric monitors
1788+
voltage_monitor = td.SteadyPotentialMonitor(
1789+
center=(0, 0, 0), size=(1, 1, 1), name="voltage_monitor", unstructured=True
1790+
)
1791+
1792+
sim = td.HeatChargeSimulation(
1793+
medium=air,
1794+
structures=[struct1],
1795+
center=(0, 0, 0),
1796+
size=(3, 3, 3),
1797+
boundary_spec=[thermal_bc, electric_bc],
1798+
grid_spec=td.UniformUnstructuredGrid(dl=0.1),
1799+
sources=[],
1800+
monitors=[temp_monitor, voltage_monitor],
1801+
)
1802+
1803+
with pytest.raises(pd.ValidationError):
1804+
# no thermal monitors
1805+
_ = sim.updated_copy(monitors=[voltage_monitor])
1806+
1807+
with pytest.raises(pd.ValidationError):
1808+
# voltage array in electric BC
1809+
_ = sim.updated_copy(
1810+
boundary_spec=[
1811+
thermal_bc,
1812+
electric_bc.updated_copy(
1813+
condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[1, 2]))
1814+
),
1815+
]
1816+
)
1817+
1818+
# this doesn't raise error
1819+
coupling_sim = sim.updated_copy(sources=[td.HeatFromElectricSource()])
1820+
1821+
with pytest.raises(pd.ValidationError):
1822+
# This should error since the conduction simulation doesn't have a monitor
1823+
_ = sim.updated_copy(monitors=[temp_monitor])

tidy3d/components/tcad/simulation/heat_charge.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,55 @@ def check_coupling_source_can_be_applied(cls, values):
787787

788788
return values
789789

790+
@pd.root_validator(skip_on_failure=True)
791+
def check_heat_sim(cls, values):
792+
"""Make sure that heat simulations have at least one monitor defined."""
793+
794+
simulation_types = cls._check_simulation_types(values=values)
795+
796+
if TCADAnalysisTypes.HEAT in simulation_types:
797+
monitors = values.get("monitors")
798+
if not any(isinstance(mnt, TemperatureMonitor) for mnt in monitors):
799+
raise SetupError(
800+
"Heat simulations require the definition of, at least, one "
801+
"'TemperatureMonitor' but none have been defined."
802+
)
803+
804+
return values
805+
806+
@pd.root_validator(skip_on_failure=True)
807+
def check_conduction_sim(cls, values):
808+
"""Make sure that conduction simulations have at least one monitor defined."""
809+
810+
simulation_types = cls._check_simulation_types(values=values)
811+
sources = values.get("sources")
812+
813+
if TCADAnalysisTypes.CONDUCTION in simulation_types:
814+
monitors = values.get("monitors")
815+
if not any(isinstance(mnt, SteadyPotentialMonitor) for mnt in monitors):
816+
if any(isinstance(s, HeatFromElectricSource) for s in sources):
817+
log.warning(
818+
"A Conduction simulation has been defined but no "
819+
"SteadyPotentialMonitor has been defined. "
820+
)
821+
else:
822+
raise SetupError(
823+
"Conduction simulations require the definition of, at least, one "
824+
"'SteadyPotentialMonitor' but none have been defined."
825+
)
826+
827+
# now make sure we only have one voltage per VoltageBC
828+
for bc in values.get("boundary_spec", []):
829+
if isinstance(bc.condition, VoltageBC):
830+
if isinstance(bc.condition.source, DCVoltageSource):
831+
if len(bc.condition.source.voltage) > 1:
832+
raise SetupError(
833+
"A Conduction simulation has been defined but a VoltageBC with an array of voltages "
834+
"has been defined. This is not supported in Conduction simulations."
835+
)
836+
837+
return values
838+
790839
@pd.root_validator(skip_on_failure=True)
791840
def estimate_charge_mesh_size(cls, values):
792841
"""Make an estimate of the mesh size and raise a warning if too big.
@@ -1641,7 +1690,7 @@ def from_scene(cls, scene: Scene, **kwargs) -> HeatChargeSimulation:
16411690
16421691
Example
16431692
-------
1644-
>>> from tidy3d import Scene, Medium, Box, Structure, UniformUnstructuredGrid
1693+
>>> from tidy3d import Scene, Medium, Box, Structure, UniformUnstructuredGrid, TemperatureMonitor
16451694
>>> box = Structure(
16461695
... geometry=Box(center=(0, 0, 0), size=(1, 2, 3)),
16471696
... medium=Medium(permittivity=5),
@@ -1667,6 +1716,7 @@ def from_scene(cls, scene: Scene, **kwargs) -> HeatChargeSimulation:
16671716
... condition=TemperatureBC(temperature=500),
16681717
... )
16691718
... ],
1719+
... monitors=[TemperatureMonitor(name="temp_monitor", center=(0, 0, 0), size=(1, 1, 1))],
16701720
... )
16711721
"""
16721722

0 commit comments

Comments
 (0)