# Defines specifications for subpixel averaging
from __future__ import annotations
from typing import Union
import pydantic.v1 as pd
from .base import Tidy3dBaseModel, cached_property
from .types import TYPE_TAG_STR
# Default Courant number reduction rate in PEC conformal's scheme
DEFAULT_COURANT_REDUCTION_PEC_CONFORMAL = 0.3
class AbstractSubpixelAveragingMethod(Tidy3dBaseModel):
"""Base class defining how to handle material assignment on structure interfaces."""
@cached_property
def courant_ratio(self) -> float:
"""The scaling ratio applied to Courant number so that the courant number
in the simulation is ``sim.courant * courant_ratio``.
"""
return 1.0
[docs]
class Staircasing(AbstractSubpixelAveragingMethod):
"""Apply staircasing scheme to material assignment of Yee grids on structure boundaries.
Note
----
For PEC interface, the algorithm is based on:
A. Taflove and S. C. Hagness, "Computational electromagnetics: the
finite-difference time-domain method", Chapter 10.3 (2005).
"""
[docs]
class PolarizedAveraging(AbstractSubpixelAveragingMethod):
"""Apply a polarized subpixel averaging method to dielectric boundaries.
Note
----
The algorithm is based on:
A. Mohammadi, H. Nadgaran and M. Agio, "Contour-path effective
permittivities for the two-dimensional finite-difference
time-domain method", Optics express, 13(25), 10367-10381 (2005).
"""
DielectricSubpixelType = Union[Staircasing, PolarizedAveraging]
[docs]
class VolumetricAveraging(AbstractSubpixelAveragingMethod):
"""Apply volumetric averaging scheme to material properties of Yee grids on structure boundaries.
The material property is averaged in the volume surrounding the Yee grid.
"""
staircase_normal_component: bool = pd.Field(
True,
title="Staircasing for field components substantially normal to interface",
description="Volumetric averaging works accurately if the electric field component "
"is substantially tangential to the interface. If ``True``, apply volumetric averaging only "
"if the field component is largely tangential to the interface; if ``False``, apply volumetric "
"averaging regardless of how field component orients with the interface.",
)
MetalSubpixelType = Union[Staircasing, VolumetricAveraging]
[docs]
class HeuristicPECStaircasing(AbstractSubpixelAveragingMethod):
"""Apply a variant of staircasing scheme to PEC boundaries: the electric field grid is set to PEC
if the field is substantially parallel to the interface.
"""
PECSubpixelType = Union[Staircasing, HeuristicPECStaircasing, PECConformal]
[docs]
class SubpixelSpec(Tidy3dBaseModel):
"""Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``."""
dielectric: DielectricSubpixelType = pd.Field(
PolarizedAveraging(),
title="Subpixel averaging method on dielectric material interfaces",
description="Subpixel averaging method applied to dielectric material interfaces.",
discriminator=TYPE_TAG_STR,
)
metal: MetalSubpixelType = pd.Field(
Staircasing(),
title="Subpixel averaging method on metallic material interfaces",
description="Subpixel averaging method applied to metallic structure interfaces. "
"A material is considered as metallic if its real part of relative permittivity "
"is less than 1 at the central frequency.",
discriminator=TYPE_TAG_STR,
)
pec: PECSubpixelType = pd.Field(
PECConformal(),
title="Subpixel averaging method on PEC interfaces",
description="Subpixel averaging method applied to PEC structure interfaces.",
discriminator=TYPE_TAG_STR,
)
[docs]
@classmethod
def staircasing(cls) -> SubpixelSpec:
"""Apply staircasing on all material boundaries."""
return cls(dielectric=Staircasing(), metal=Staircasing(), pec=Staircasing())
[docs]
def courant_ratio(self, contain_pec_structures: bool) -> float:
"""The scaling ratio applied to Courant number so that the courant number
in the simulation is ``sim.courant * courant_ratio``. So far only PEC subpixel averaging
scheme requires deduction of Courant number.
"""
if contain_pec_structures:
return self.pec.courant_ratio
return 1.0