diff --git a/tests/test_components/test_heat_charge.py b/tests/test_components/test_heat_charge.py index 832915c129..08c70b1677 100644 --- a/tests/test_components/test_heat_charge.py +++ b/tests/test_components/test_heat_charge.py @@ -11,6 +11,8 @@ from tidy3d.components.tcad.types import ( AugerRecombination, CaugheyThomasMobility, + ConstantEffectiveDOS, + ConstantEnergyBandGap, SlotboomBandGapNarrowing, ) from tidy3d.exceptions import DataError @@ -39,9 +41,9 @@ class CHARGE_SIMULATION: permittivity=11.7, N_d=0, N_a=0, - N_c=2.86e19, - N_v=3.1e19, - E_g=1.11, + N_c=ConstantEffectiveDOS(N=2.86e19), + N_v=ConstantEffectiveDOS(N=3.1e19), + E_g=ConstantEnergyBandGap(eg=1.11), mobility_n=CaugheyThomasMobility( mu_min=52.2, mu=1471.0, diff --git a/tidy3d/__init__.py b/tidy3d/__init__.py index 2fa84b7d75..f17602edcf 100644 --- a/tidy3d/__init__.py +++ b/tidy3d/__init__.py @@ -68,12 +68,19 @@ AugerRecombination, CaugheyThomasMobility, ConstantMobilityModel, + ConstantEffectiveDOS, + ConstantEnergyBandGap, + QuadraticEnergyBandGap, + VarshniEnergyBandGap, ConvectionBC, CurrentBC, + DualValleyEffectiveDOS, HeatFluxBC, HeatFromElectricSource, HeatSource, InsulatingBC, + IsotropicEffectiveDOS, + MultiValleyEffectiveDOS, RadiativeRecombination, ShockleyReedHallRecombination, SlotboomBandGapNarrowing, @@ -451,6 +458,10 @@ def set_logging_level(level: str) -> None: "CoaxialLumpedResistor", "ConstantDoping", "ConstantMobilityModel", + "ConstantEffectiveDOS", + "IsotropicEffectiveDOS", + "MultiValleyEffectiveDOS", + "DualValleyEffectiveDOS", "ContinuousWave", "ContinuousWaveTimeModulation", "ContourPathAveraging", @@ -716,4 +727,7 @@ def set_logging_level(level: str) -> None: "set_logging_console", "set_logging_file", "wavelengths", + "ConstantEnergyBandGap", + "QuadraticEnergyBandGap", + "VarshniEnergyBandGap", ] diff --git a/tidy3d/components/material/tcad/charge.py b/tidy3d/components/material/tcad/charge.py index 707e0ebd64..d784b2b9de 100644 --- a/tidy3d/components/material/tcad/charge.py +++ b/tidy3d/components/material/tcad/charge.py @@ -9,6 +9,8 @@ from tidy3d.components.tcad.doping import DopingBoxType from tidy3d.components.tcad.types import ( BandGapNarrowingModelType, + EffectiveDOSModelType, + EnergyBandGapModelType, MobilityModelType, RecombinationModelType, ) @@ -254,21 +256,21 @@ class SemiconductorMedium(AbstractChargeMedium): """ - N_c: pd.PositiveFloat = pd.Field( + N_c: EffectiveDOSModelType = pd.Field( ..., title="Effective density of electron states", description=r"$N_c$ Effective density of states in the conduction band.", units="cm^(-3)", ) - N_v: pd.PositiveFloat = pd.Field( + N_v: EffectiveDOSModelType = pd.Field( ..., title="Effective density of hole states", description=r"$N_v$ Effective density of states in the valence band.", units="cm^(-3)", ) - E_g: pd.PositiveFloat = pd.Field( + E_g: EnergyBandGapModelType = pd.Field( ..., title="Band-gap energy", description="Band-gap energy", diff --git a/tidy3d/components/tcad/bandgap_energy.py b/tidy3d/components/tcad/bandgap_energy.py new file mode 100644 index 0000000000..da9fe3c5c3 --- /dev/null +++ b/tidy3d/components/tcad/bandgap_energy.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import pydantic.v1 as pd + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.constants import ELECTRON_VOLT + + +class ConstantEnergyBandGap(Tidy3dBaseModel): + """Constant Energy band gap""" + + eg: pd.PositiveFloat = pd.Field( + title="Band Gap", + description="Energy band gap", + units=ELECTRON_VOLT, + ) + + +class QuadraticEnergyBandGap(Tidy3dBaseModel): + """ + Models the temperature dependence of the energy band gap (Eg) using a + quadratic approximation. + + Notes + ----- + The model uses the following formula: + + .. math:: + + E_g(T) = E_g(300) + \\alpha T + \\beta T^2 + + Example + ------- + >>> model = QuadraticEnergyBandGap( + ... eg_300=1.12, + ... alpha=-4.73e-4, + ... beta=-2.0e-7, + ... ) + """ + + eg_300: pd.PositiveFloat = pd.Field( + ..., + title="Band Gap at 300 K", + description="Energy band gap at a reference temperature of 300 K.", + units=ELECTRON_VOLT, + ) + + alpha: float = pd.Field( + ..., + title="Linear Temperature Coefficient (alpha)", + description="Linear coefficient for the temperature dependence of the band gap.", + units="eV/K", + ) + + beta: float = pd.Field( + ..., + title="Quadratic Temperature Coefficient (beta)", + description="Quadratic coefficient for the temperature dependence of the band gap.", + units="eV/K²", + ) + + +class VarshniEnergyBandGap(Tidy3dBaseModel): + """ + Models the temperature dependence of the energy band gap (Eg) + using the Varshni formula. + + Notes + ----- + The model implements the following formula: + + .. math:: + + E_g(T) = E_g(0) - \\frac{\\alpha T^2}{T + \\beta}$ + + Example + ------- + >>> # Parameters for Silicon (Si) + >>> si_model = VarshniBandGap( + ... eg_0=1.17, + ... alpha=4.73e-4, + ... beta=636.0, + ... ) + + References + ------- + + Varshni, Y. P. (1967). Temperature dependence of the energy gap in semiconductors. Physica, 34(1), 149-154. + + """ + + eg_0: pd.PositiveFloat = pd.Field( + ..., + title="Band Gap at 0 K", + description="Energy band gap at absolute zero (0 Kelvin).", + units=ELECTRON_VOLT, + ) + + alpha: pd.PositiveFloat = pd.Field( + ..., + title="Varshni Alpha Coefficient", + description="Empirical Varshni coefficient (α).", + units="eV/K", + ) + + beta: pd.PositiveFloat = pd.Field( + ..., + title="Varshni Beta Coefficient", + description="Empirical Varshni coefficient (β), related to the Debye temperature.", + units="K", + ) diff --git a/tidy3d/components/tcad/effective_DOS.py b/tidy3d/components/tcad/effective_DOS.py new file mode 100644 index 0000000000..6a7fea3903 --- /dev/null +++ b/tidy3d/components/tcad/effective_DOS.py @@ -0,0 +1,158 @@ +from abc import ABC, abstractmethod + +import numpy as np +import pydantic.v1 as pd + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.constants import C_0, HBAR, K_B + +from ...exceptions import DataError + +# constants definition +m_e_C_square = 0.51099895069e6 # (electron mass * C_0^2) in eV +m_e_eV = m_e_C_square / C_0 / C_0 # equivalent electron mass in eV +um_3_to_cm_3 = 1e12 # conversion factor from micron^(-3) to cm^(-3) + +DOS_aux_const = 2.0 * np.power((m_e_eV * K_B) / (2 * np.pi * HBAR * HBAR), 1.5) * um_3_to_cm_3 + + +class EffectiveDOS(Tidy3dBaseModel, ABC): + """Abstract class for the effective density of states""" + + @abstractmethod + def calc_eff_dos(self, T: float): + """Abstract method to calculate the effective density of states.""" + pass + + @abstractmethod + def calc_eff_dos_derivative(self, T: float): + """Abstract method to calculate the temperature derivative of the effective density of states.""" + pass + + def get_effective_DOS(self, T: float): + if T <= 0: + raise DataError( + f"Incorrect temperature value ({T}) for the effectve density of states calculation." + ) + + return self.calc_eff_dos(T) + + def get_effective_DOS_derivative(self, T: float): + if T <= 0: + raise DataError( + f"Incorrect temperature value ({T}) for the effectve density of states calculation." + ) + + return self.calc_eff_dos_derivative(T) + + +class ConstantEffectiveDOS(EffectiveDOS): + """Constant effective density of states model.""" + + N: pd.PositiveFloat = pd.Field( + ..., title="Effective DOS", description="Effective density of states", units="cm^(-3)" + ) + + def calc_eff_dos(self, T: float): + return self.N + + def calc_eff_dos_derivative(self, T: float): + return 0.0 + + +class IsotropicEffectiveDOS(EffectiveDOS): + """Effective density of states model that assumes single valley and isotropic effective mass. + The model assumes the standard equation for the 3D semiconductor with parabolic energy dispersion: + + .. math:: + + \\begin{equation} + \\mathbf{N_eff} = 2 * (\\frac{m_eff * m_e * k_B T}{2 \\pi \\hbar^2})^(3/2) + \\end{equation} + """ + + m_eff: pd.PositiveFloat = pd.Field( + ..., + title="Effective mass", + description="Effective mass of the carriers", + units="Electron mass", + ) + + def calc_eff_dos(self, T: float): + return np.power(self.m_eff * T, 1.5) * DOS_aux_const + + def calc_eff_dos_derivative(self, T: float): + return self.calc_eff_dos(T) * 1.5 / T + + +class MultiValleyEffectiveDOS(EffectiveDOS): + """Effective density of states model that assumes multiple equivalent valleys and anisotropic effective mass. + The model assumes the standard equation for the 3D semiconductor with parabolic energy dispersion: + + .. math:: + + \\begin{equation} + \\mathbf{N_eff} = 2 * N_valley * (m_{eff_long} * m_{eff_trans} * m_{eff_trans})^(1/2) *(\\frac{m_e * k_B * T}{2 \\pi * \\hbar^2})^(3/2) + \\end{equation} + """ + + m_eff_long: pd.PositiveFloat = pd.Field( + ..., + title="Longitudinal effective mass", + description="Effective mass of the carriers in the longitudinal direction", + units="Electron mass", + ) + + m_eff_trans: pd.PositiveFloat = pd.Field( + ..., + title="Longitudinal effective mass", + description="Effective mass of the carriers in the transverse direction", + units="Electron mass", + ) + + N_valley: pd.PositiveFloat = pd.Field( + ..., title="Number of valleys", description="Number of effective valleys" + ) + + def calc_eff_dos(self, T: float): + return ( + self.N_valley + * np.power(self.m_eff_long * self.m_eff_trans * self.m_eff_trans, 0.5) + * np.power(T, 1.5) + * DOS_aux_const + ) + + def calc_eff_dos_derivative(self, T: float): + return self.calc_eff_dos(T) * 1.5 / T + + +class DualValleyEffectiveDOS(EffectiveDOS): + """Effective density of states model that assumes combibation of light holes and heavy holes with isotropic effective masses. + The model assumes the standard equation for the 3D semiconductor with parabolic energy dispersion: + + .. math:: + + \\begin{equation} + \\mathbf{N_eff} = 2 * ( {\\frac{m_{eff_lh} * m_e * k_B * T}{2 \\pi \\hbar^2})^(3/2) + (\\frac{m_{eff_hh} * m_e * k_B * T}{2 \\pi \\hbar^2})^(3/2) ) + \\end{equation} + """ + + m_eff_lh: pd.PositiveFloat = pd.Field( + ..., + title="Light hole effective mass", + description="Effective mass of the light holes", + units="Electron mass", + ) + + m_eff_hh: pd.PositiveFloat = pd.Field( + ..., + title="Heavy hole effective mass", + description="Effective mass of the heavy holes", + units="Electron mass", + ) + + def calc_eff_dos(self, T: float): + return (np.power(self.m_eff_lh * T, 1.5) + np.power(self.m_eff_hh * T, 1.5)) * DOS_aux_const + + def calc_eff_dos_derivative(self, T: float): + return self.calc_eff_dos(T) * 1.5 / T diff --git a/tidy3d/components/tcad/types.py b/tidy3d/components/tcad/types.py index dec3f44f62..060bfaf8fe 100644 --- a/tidy3d/components/tcad/types.py +++ b/tidy3d/components/tcad/types.py @@ -5,6 +5,17 @@ from tidy3d.components.tcad.bandgap import SlotboomBandGapNarrowing from tidy3d.components.tcad.boundary.charge import CurrentBC, InsulatingBC, VoltageBC from tidy3d.components.tcad.boundary.heat import ConvectionBC, HeatFluxBC, TemperatureBC +from tidy3d.components.tcad.effective_DOS import ( + ConstantEffectiveDOS, + DualValleyEffectiveDOS, + IsotropicEffectiveDOS, + MultiValleyEffectiveDOS, +) +from tidy3d.components.tcad.bandgap_energy import ( + ConstantEnergyBandGap, + QuadraticEnergyBandGap, + VarshniEnergyBandGap, +) from tidy3d.components.tcad.generation_recombination import ( AugerRecombination, RadiativeRecombination, @@ -23,6 +34,10 @@ from tidy3d.components.tcad.source.heat import HeatSource, UniformHeatSource from tidy3d.components.types import Union +EffectiveDOSModelType = Union[ + ConstantEffectiveDOS, IsotropicEffectiveDOS, MultiValleyEffectiveDOS, DualValleyEffectiveDOS +] +EnergyBandGapModelType = Union[ConstantEnergyBandGap, QuadraticEnergyBandGap, VarshniEnergyBandGap] MobilityModelType = Union[CaugheyThomasMobility, ConstantMobilityModel] RecombinationModelType = Union[ AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination diff --git a/tidy3d/material_library/material_library.py b/tidy3d/material_library/material_library.py index 480f98ee8d..ebf0fc54a4 100644 --- a/tidy3d/material_library/material_library.py +++ b/tidy3d/material_library/material_library.py @@ -14,10 +14,12 @@ from tidy3d.components.tcad.types import ( AugerRecombination, CaugheyThomasMobility, + ConstantEffectiveDOS, RadiativeRecombination, ShockleyReedHallRecombination, SlotboomBandGapNarrowing, ) +from tidy3d.components.tcad.bandgap_energy import ConstantEnergyBandGap from tidy3d.components.types import Axis from tidy3d.exceptions import SetupError from tidy3d.log import log @@ -2063,9 +2065,9 @@ def medium(self, optical_axis: Axis): optical=cSi_Green2008.medium, charge=SemiconductorMedium( permittivity=11.7, - N_c=2.86e19, - N_v=3.1e19, - E_g=1.11, + N_c=ConstantEffectiveDOS(N=2.86e19), + N_v=ConstantEffectiveDOS(N=3.1e19), + E_g=ConstantEnergyBandGap(eg=1.11), mobility_n=CaugheyThomasMobility( mu_min=52.2, mu=1471.0,