From daf7c5d85448d280b533c2aa9ddcf5455243db43 Mon Sep 17 00:00:00 2001 From: Casey Wojcik Date: Fri, 6 Oct 2023 12:56:35 +0100 Subject: [PATCH] Added PECMedium to IsotropicUniformMediumType, and added PEC2D --- tests/sims/simulation_2_5_0rc1.json | 94 +++++++++++++++++++++++++++++ tests/utils.py | 8 +++ tidy3d/__init__.py | 4 +- tidy3d/components/grid/mesher.py | 4 +- tidy3d/components/medium.py | 24 +++++++- tidy3d/components/simulation.py | 10 +-- 6 files changed, 135 insertions(+), 9 deletions(-) diff --git a/tests/sims/simulation_2_5_0rc1.json b/tests/sims/simulation_2_5_0rc1.json index c5875ea936..6e7a58789d 100644 --- a/tests/sims/simulation_2_5_0rc1.json +++ b/tests/sims/simulation_2_5_0rc1.json @@ -302,6 +302,100 @@ } } }, + { + "geometry": { + "type": "Box", + "center": [ + -1.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 0.0, + 1.0 + ] + }, + "name": null, + "type": "Structure", + "medium": { + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "Medium2D", + "ss": { + "name": "PEC", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "PECMedium" + }, + "tt": { + "name": "PEC", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "PECMedium" + } + } + }, + { + "geometry": { + "type": "Box", + "center": [ + -1.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "type": "Structure", + "medium": { + "name": null, + "frequency_range": null, + "allow_gain": null, + "nonlinear_spec": null, + "heat_spec": null, + "type": "AnisotropicMedium", + "xx": { + "name": "PEC", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "PECMedium" + }, + "yy": { + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "zz": { + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + } + } + }, { "geometry": { "type": "GeometryGroup", diff --git a/tests/utils.py b/tests/utils.py index 496aba5e57..7841e4dec6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -139,6 +139,14 @@ geometry=td.Box(size=(1, 0, 1), center=(-1, 0, 0)), medium=td.Medium2D.from_medium(td.Medium(conductivity=0.45), thickness=0.01), ), + td.Structure( + geometry=td.Box(size=(1, 0, 1), center=(-1, 0, 0)), + medium=td.PEC2D, + ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), + medium=td.AnisotropicMedium(xx=td.PEC, yy=td.Medium(), zz=td.Medium()), + ), td.Structure( geometry=td.GeometryGroup(geometries=[td.Box(size=(1, 1, 1), center=(-1, 0, 0))]), medium=td.PEC, diff --git a/tidy3d/__init__.py b/tidy3d/__init__.py index 974a357fec..a1c4d76fdd 100644 --- a/tidy3d/__init__.py +++ b/tidy3d/__init__.py @@ -11,7 +11,8 @@ from .components.geometry.polyslab import PolySlab # medium -from .components.medium import Medium, PoleResidue, AnisotropicMedium, PEC, PECMedium, Medium2D +from .components.medium import Medium, PoleResidue, AnisotropicMedium, PEC, PECMedium +from .components.medium import Medium2D, PEC2D from .components.medium import Sellmeier, Debye, Drude, Lorentz from .components.medium import CustomMedium, CustomPoleResidue from .components.medium import CustomSellmeier, FullyAnisotropicMedium @@ -159,6 +160,7 @@ def set_logging_level(level: str) -> None: "PEC", "PECMedium", "Medium2D", + "PEC2D", "Sellmeier", "Debye", "Drude", diff --git a/tidy3d/components/grid/mesher.py b/tidy3d/components/grid/mesher.py index 0814056838..d847c28592 100644 --- a/tidy3d/components/grid/mesher.py +++ b/tidy3d/components/grid/mesher.py @@ -16,7 +16,7 @@ from ..base import Tidy3dBaseModel from ..types import Axis, ArrayFloat1D from ..structure import Structure, MeshOverrideStructure, StructureType -from ..medium import PECMedium, Medium2D +from ..medium import Medium2D from ...exceptions import SetupError, ValidationError from ...constants import C_0, fp_eps @@ -373,7 +373,7 @@ def structure_steps( min_steps = [] for structure in structures: if isinstance(structure, Structure): - if isinstance(structure.medium, (PECMedium, Medium2D)): + if structure.medium.is_pec or isinstance(structure.medium, Medium2D): index = 1.0 else: n, k = structure.medium.eps_complex_to_nk( diff --git a/tidy3d/components/medium.py b/tidy3d/components/medium.py index ac0c8c4da1..d5e6e52d3e 100644 --- a/tidy3d/components/medium.py +++ b/tidy3d/components/medium.py @@ -452,6 +452,11 @@ def sigma_model(self, freq: float) -> complex: sigma = (eps_inf - eps_complex) * 1j * omega * EPSILON_0 return sigma + @cached_property + def is_pec(self): + """Whether the medium is a PEC.""" + return False + class AbstractCustomMedium(AbstractMedium, ABC): """A spatially varying medium.""" @@ -621,6 +626,11 @@ def n_cfl(self): """ return 1.0 + @cached_property + def is_pec(self): + """Whether the medium is a PEC.""" + return True + # PEC builtin instance PEC = PECMedium(name="PEC") @@ -2667,7 +2677,7 @@ def eps_dataarray_freq( return (eps, eps, eps) -IsotropicUniformMediumType = Union[Medium, PoleResidue, Sellmeier, Lorentz, Debye, Drude] +IsotropicUniformMediumType = Union[Medium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium] IsotropicCustomMediumType = Union[ CustomPoleResidue, CustomSellmeier, @@ -2808,6 +2818,11 @@ def elements(self) -> Dict[str, IsotropicUniformMediumType]: """The diagonal elements of the medium as a dictionary.""" return dict(xx=self.xx, yy=self.yy, zz=self.zz) + @cached_property + def is_pec(self): + """Whether the medium is a PEC.""" + return any(isinstance(med, PECMedium) for med in self.components.values()) + class FullyAnisotropicMedium(AbstractMedium): """Fully anisotropic medium including all 9 components of the permittivity and conductivity @@ -3856,6 +3871,13 @@ def n_cfl(self): """ return 1.0 + @cached_property + def is_pec(self): + """Whether the medium is a PEC.""" + return any(isinstance(med, PECMedium) for med in self.elements.values()) + + +PEC2D = Medium2D(ss=PEC, tt=PEC) # types of mediums that can be used in Simulation and Structures diff --git a/tidy3d/components/simulation.py b/tidy3d/components/simulation.py index 186bc7bbe6..ace7420dc1 100644 --- a/tidy3d/components/simulation.py +++ b/tidy3d/components/simulation.py @@ -22,7 +22,7 @@ from .types import Ax, Shapely, FreqBound, Axis, annotate_type, Symmetry, TYPE_TAG_STR, InterpMethod from .grid.grid import Coords1D, Grid, Coords from .grid.grid_spec import GridSpec, UniformGrid, AutoGrid -from .medium import Medium, MediumType, AbstractMedium, PECMedium +from .medium import Medium, MediumType, AbstractMedium from .medium import AbstractCustomMedium, Medium2D, MediumType3D from .medium import AnisotropicMedium, FullyAnisotropicMedium, AbstractPerturbationMedium from .boundary import BoundarySpec, BlochBoundary, PECBoundary, PMCBoundary, Periodic @@ -809,7 +809,7 @@ def _warn_grid_size_too_small(cls, val, values): for medium_index, medium in enumerate(mediums): # min wavelength in PEC is meaningless and we'll get divide by inf errors - if isinstance(medium, PECMedium): + if medium.is_pec: continue # min wavelength in Medium2D is meaningless if isinstance(medium, Medium2D): @@ -1589,7 +1589,7 @@ def _get_structure_plot_params(self, mat_index: int, medium: Medium) -> PlotPara if mat_index == 0 or medium == self.medium: # background medium plot_params = plot_params.copy(update={"facecolor": "white", "edgecolor": "white"}) - elif isinstance(medium, PECMedium): + elif medium.is_pec: # perfect electrical conductor plot_params = plot_params.copy( update={"facecolor": "gold", "edgecolor": "k", "linewidth": 1} @@ -1722,7 +1722,7 @@ def eps_bounds(self, freq: float = None) -> Tuple[float, float]: """Compute range of (real) permittivity present in the simulation at frequency "freq".""" medium_list = [self.medium] + list(self.mediums) - medium_list = [medium for medium in medium_list if not isinstance(medium, PECMedium)] + medium_list = [medium for medium in medium_list if not medium.is_pec] # regular medium eps_list = [ medium.eps_model(freq).real @@ -1829,7 +1829,7 @@ def _get_structure_eps_plot_params( if alpha is not None: plot_params = plot_params.copy(update={"alpha": alpha}) - if isinstance(medium, PECMedium): + if medium.is_pec: # perfect electrical conductor plot_params = plot_params.copy( update={"facecolor": "gold", "edgecolor": "k", "linewidth": 1}