"""
Material property definitions for PADRE simulations.
Defines physical parameters for semiconductor and insulator materials.
"""
from typing import Optional, Union, List
from .base import PadreCommand
[docs]
class Alloy(PadreCommand):
"""
Define an alloy material from predefined materials.
The alloy can then be used with MATERIAL lines to create
new material systems with interpolated properties.
Parameters
----------
name : str
Name of the alloy to create
material1 : str
First material name
x1 : float
Compositional fraction for material1 (0-1)
material2 : str
Second material name
x2 : float
Compositional fraction for material2
material3 : str, optional
Third material name
x3 : float, optional
Compositional fraction for material3
material4 : str, optional
Fourth material name
x4 : float, optional
Compositional fraction for material4
Example
-------
>>> # SiGe alloy
>>> alloy = Alloy(name="sige",
... material1="silicon", x1=0,
... material2="germanium", x2=1)
"""
command_name = "ALLOY"
[docs]
def __init__(
self,
name: str,
material1: str,
x1: float,
material2: str,
x2: float,
material3: Optional[str] = None,
x3: Optional[float] = None,
material4: Optional[str] = None,
x4: Optional[float] = None,
):
super().__init__()
self.name = name
self.material1 = material1
self.x1 = x1
self.material2 = material2
self.x2 = x2
self.material3 = material3
self.x3 = x3
self.material4 = material4
self.x4 = x4
[docs]
def to_padre(self) -> str:
params = {
"NAME": self.name,
"M1ALLOY": self.material1,
"X1ALLOY": self.x1,
"M2ALLOY": self.material2,
"X2ALLOY": self.x2,
}
if self.material3 and self.x3 is not None:
params["M3ALLOY"] = self.material3
params["X3ALLOY"] = self.x3
if self.material4 and self.x4 is not None:
params["M4ALLOY"] = self.material4
params["X4ALLOY"] = self.x4
return self._build_command(params)
[docs]
class Material(PadreCommand):
"""
Define material properties for a region.
Many parameters have defaults for standard materials (silicon, gaas, etc.).
Parameters
----------
name : str
Material name (new or predefined)
default : str, optional
Copy parameters from this material
alloy : str, optional
Alloy name to interpolate from
composition : float, optional
Compositional fraction for alloy (0-1)
Band structure:
eg300 : float
Energy gap at 300K (eV)
eg_alpha : float
Eg temperature coefficient alpha
eg_beta : float
Eg temperature coefficient beta
affinity : float
Electron affinity (eV)
ec_off : float
Conduction band offset (eV)
Constants:
permittivity : float
Dielectric permittivity (F/cm)
nc300 : float
Conduction band density at 300K (/cm^3)
nv300 : float
Valence band density at 300K (/cm^3)
mun : float
Electron mobility at 300K (cm^2/V-s)
mup : float
Hole mobility at 300K (cm^2/V-s)
vsatn : float
Electron saturation velocity at 300K (cm/s)
vsatp : float
Hole saturation velocity at 300K (cm/s)
Lifetimes:
taun0 : float or list
Electron lifetime(s) (s)
taup0 : float or list
Hole lifetime(s) (s)
ntaun : float
Electron lifetime concentration parameter (/cm^3)
ntaup : float
Hole lifetime concentration parameter (/cm^3)
Auger:
augn : float
Electron Auger coefficient (cm^6/s)
augp : float
Hole Auger coefficient (cm^6/s)
Models:
in_model : str
Ionized impurity scattering model
en_model : str
Velocity saturation model (electrons)
ep_model : str
Velocity saturation model (holes)
gn_model : str
Gate-field mobility model (electrons)
gp_model : str
Gate-field mobility model (holes)
bgnn_model : str
Band-gap narrowing model (electrons)
bgnp_model : str
Band-gap narrowing model (holes)
n_type, p_type : bool
Set separate values for n-type/p-type material
Example
-------
>>> # Define silicon with custom lifetimes
>>> mat = Material(name="silicon", taun0=1e-6, taup0=1e-6)
>>>
>>> # SiGe alloy material
>>> mat = Material(name="sige30", alloy="sige", composition=0.3,
... eg300=0.830)
"""
command_name = "MATERIAL"
[docs]
def __init__(
self,
name: str,
default: Optional[str] = None,
alloy: Optional[str] = None,
composition: Optional[float] = None,
# Type
n_type: bool = False,
p_type: bool = False,
no_charge: bool = False,
# Band structure
eg300: Optional[float] = None,
eg_alpha: Optional[float] = None,
eg_beta: Optional[float] = None,
affinity: Optional[float] = None,
decdev: Optional[float] = None,
decdeg: Optional[float] = None,
ec_off: Optional[float] = None,
refoff: Optional[str] = None,
# Constants
permittivity: Optional[float] = None,
qf: Optional[float] = None,
nc300: Optional[float] = None,
nv300: Optional[float] = None,
gcb: Optional[float] = None,
gvb: Optional[float] = None,
edb: Optional[float] = None,
eab: Optional[float] = None,
arichn: Optional[float] = None,
arichp: Optional[float] = None,
# Mobility
mun: Optional[float] = None,
mup: Optional[float] = None,
vsatn: Optional[float] = None,
vsatp: Optional[float] = None,
tauwn: Optional[float] = None,
tauwp: Optional[float] = None,
# Lifetimes
taun0: Optional[Union[float, List[float]]] = None,
taup0: Optional[Union[float, List[float]]] = None,
taur0: Optional[float] = None,
ntaun: Optional[float] = None,
ntaup: Optional[float] = None,
ntaur: Optional[float] = None,
b0dir: Optional[float] = None,
# Auger
augn: Optional[float] = None,
augp: Optional[float] = None,
# Traps
trap_type: Optional[str] = None,
etrap: Optional[Union[float, List[float]]] = None,
ntrap: Optional[Union[float, List[float]]] = None,
# Generation
gen_con: Optional[float] = None,
# Models
in_model: Optional[str] = None,
ip_model: Optional[str] = None,
en_model: Optional[str] = None,
ep_model: Optional[str] = None,
gn_model: Optional[str] = None,
gp_model: Optional[str] = None,
cn_model: Optional[str] = None,
cp_model: Optional[str] = None,
dn_model: Optional[str] = None,
dp_model: Optional[str] = None,
wn_model: Optional[str] = None,
wp_model: Optional[str] = None,
bgnn_model: Optional[str] = None,
bgnp_model: Optional[str] = None,
# Model coefficients
ln_mu: Optional[List[float]] = None,
lp_mu: Optional[List[float]] = None,
iin_mu: Optional[List[float]] = None,
iip_mu: Optional[List[float]] = None,
en_mu: Optional[List[float]] = None,
ep_mu: Optional[List[float]] = None,
gn_mu: Optional[List[float]] = None,
gp_mu: Optional[List[float]] = None,
# Impact ionization
en_ion: Optional[List[float]] = None,
ep_ion: Optional[List[float]] = None,
an_ion: Optional[List[float]] = None,
ap_ion: Optional[List[float]] = None,
bn_ion: Optional[List[float]] = None,
bp_ion: Optional[List[float]] = None,
# BGN coefficients
n_bgn: Optional[List[float]] = None,
p_bgn: Optional[List[float]] = None,
):
super().__init__()
self.name = name
self.default = default
self.alloy = alloy
self.composition = composition
self.n_type = n_type
self.p_type = p_type
self.no_charge = no_charge
# Band structure
self.eg300 = eg300
self.eg_alpha = eg_alpha
self.eg_beta = eg_beta
self.affinity = affinity
self.decdev = decdev
self.decdeg = decdeg
self.ec_off = ec_off
self.refoff = refoff
# Constants
self.permittivity = permittivity
self.qf = qf
self.nc300 = nc300
self.nv300 = nv300
self.gcb = gcb
self.gvb = gvb
self.edb = edb
self.eab = eab
self.arichn = arichn
self.arichp = arichp
# Mobility
self.mun = mun
self.mup = mup
self.vsatn = vsatn
self.vsatp = vsatp
self.tauwn = tauwn
self.tauwp = tauwp
# Lifetimes
self.taun0 = taun0
self.taup0 = taup0
self.taur0 = taur0
self.ntaun = ntaun
self.ntaup = ntaup
self.ntaur = ntaur
self.b0dir = b0dir
# Auger
self.augn = augn
self.augp = augp
# Traps
self.trap_type = trap_type
self.etrap = etrap
self.ntrap = ntrap
# Generation
self.gen_con = gen_con
# Models
self.in_model = in_model
self.ip_model = ip_model
self.en_model = en_model
self.ep_model = ep_model
self.gn_model = gn_model
self.gp_model = gp_model
self.cn_model = cn_model
self.cp_model = cp_model
self.dn_model = dn_model
self.dp_model = dp_model
self.wn_model = wn_model
self.wp_model = wp_model
self.bgnn_model = bgnn_model
self.bgnp_model = bgnp_model
# Model coefficients
self.ln_mu = ln_mu
self.lp_mu = lp_mu
self.iin_mu = iin_mu
self.iip_mu = iip_mu
self.en_mu = en_mu
self.ep_mu = ep_mu
self.gn_mu = gn_mu
self.gp_mu = gp_mu
# Impact ionization
self.en_ion = en_ion
self.ep_ion = ep_ion
self.an_ion = an_ion
self.ap_ion = ap_ion
self.bn_ion = bn_ion
self.bp_ion = bp_ion
# BGN
self.n_bgn = n_bgn
self.p_bgn = p_bgn
def _format_vector(self, value: Union[float, List[float]]) -> str:
"""Format a scalar or vector value."""
if isinstance(value, (list, tuple)):
return ",".join(str(v) for v in value)
return str(value)
[docs]
def to_padre(self) -> str:
params = {"NAME": self.name}
flags = []
if self.default:
params["DEF"] = self.default
if self.alloy:
params["ALLOY"] = self.alloy
if self.composition is not None:
params["COMP"] = self.composition
if self.n_type:
flags.append("N.TYPE")
if self.p_type:
flags.append("P.TYPE")
if self.no_charge:
flags.append("NO.CHARGE")
# Band structure
if self.eg300 is not None:
params["EG300"] = self.eg300
if self.eg_alpha is not None:
params["EGALPHA"] = self.eg_alpha
if self.eg_beta is not None:
params["EGBETA"] = self.eg_beta
if self.affinity is not None:
params["AFFINITY"] = self.affinity
if self.decdev is not None:
params["DECDEV"] = self.decdev
if self.decdeg is not None:
params["DECDEG"] = self.decdeg
if self.ec_off is not None:
params["EC.OFF"] = self.ec_off
if self.refoff:
params["REFOFF"] = self.refoff
# Constants
if self.permittivity is not None:
params["PERMI"] = self.permittivity
if self.qf is not None:
params["QF"] = self.qf
if self.nc300 is not None:
params["NC300"] = self.nc300
if self.nv300 is not None:
params["NV300"] = self.nv300
if self.gcb is not None:
params["GCB"] = self.gcb
if self.gvb is not None:
params["GVB"] = self.gvb
if self.edb is not None:
params["EDB"] = self.edb
if self.eab is not None:
params["EAB"] = self.eab
if self.arichn is not None:
params["ARICHN"] = self.arichn
if self.arichp is not None:
params["ARICHP"] = self.arichp
# Mobility
if self.mun is not None:
params["MUN"] = self.mun
if self.mup is not None:
params["MUP"] = self.mup
if self.vsatn is not None:
params["VSATN"] = self.vsatn
if self.vsatp is not None:
params["VSATP"] = self.vsatp
if self.tauwn is not None:
params["TAUWN"] = self.tauwn
if self.tauwp is not None:
params["TAUWP"] = self.tauwp
# Lifetimes
if self.taun0 is not None:
params["TAUN0"] = self._format_vector(self.taun0)
if self.taup0 is not None:
params["TAUP0"] = self._format_vector(self.taup0)
if self.taur0 is not None:
params["TAUR0"] = self.taur0
if self.ntaun is not None:
params["NTAUN"] = self.ntaun
if self.ntaup is not None:
params["NTAUP"] = self.ntaup
if self.ntaur is not None:
params["NTAUR"] = self.ntaur
if self.b0dir is not None:
params["B0DIR"] = self.b0dir
# Auger
if self.augn is not None:
params["AUGN"] = self.augn
if self.augp is not None:
params["AUGP"] = self.augp
# Traps
if self.trap_type:
params["TRAP.TYP"] = self.trap_type
if self.etrap is not None:
params["ETRAP"] = self._format_vector(self.etrap)
if self.ntrap is not None:
params["NTRAP"] = self._format_vector(self.ntrap)
# Generation
if self.gen_con is not None:
params["GEN.CON"] = self.gen_con
# Models
if self.in_model:
params["IN.MOD"] = self.in_model
if self.ip_model:
params["IP.MOD"] = self.ip_model
if self.en_model:
params["EN.MOD"] = self.en_model
if self.ep_model:
params["EP.MOD"] = self.ep_model
if self.gn_model:
params["GN.MOD"] = self.gn_model
if self.gp_model:
params["GP.MOD"] = self.gp_model
if self.cn_model:
params["CN.MOD"] = self.cn_model
if self.cp_model:
params["CP.MOD"] = self.cp_model
if self.dn_model:
params["DN.MOD"] = self.dn_model
if self.dp_model:
params["DP.MOD"] = self.dp_model
if self.wn_model:
params["WN.MOD"] = self.wn_model
if self.wp_model:
params["WP.MOD"] = self.wp_model
if self.bgnn_model:
params["BGNN.MOD"] = self.bgnn_model
if self.bgnp_model:
params["BGNP.MOD"] = self.bgnp_model
# Model coefficients
if self.ln_mu:
params["LN.MU"] = self._format_vector(self.ln_mu)
if self.lp_mu:
params["LP.MU"] = self._format_vector(self.lp_mu)
if self.iin_mu:
params["IIN.MU"] = self._format_vector(self.iin_mu)
if self.iip_mu:
params["IIP.MU"] = self._format_vector(self.iip_mu)
if self.en_mu:
params["EN.MU"] = self._format_vector(self.en_mu)
if self.ep_mu:
params["EP.MU"] = self._format_vector(self.ep_mu)
if self.gn_mu:
params["GN.MU"] = self._format_vector(self.gn_mu)
if self.gp_mu:
params["GP.MU"] = self._format_vector(self.gp_mu)
# Impact ionization
if self.en_ion:
params["EN.ION"] = self._format_vector(self.en_ion)
if self.ep_ion:
params["EP.ION"] = self._format_vector(self.ep_ion)
if self.an_ion:
params["AN.ION"] = self._format_vector(self.an_ion)
if self.ap_ion:
params["AP.ION"] = self._format_vector(self.ap_ion)
if self.bn_ion:
params["BN.ION"] = self._format_vector(self.bn_ion)
if self.bp_ion:
params["BP.ION"] = self._format_vector(self.bp_ion)
# BGN
if self.n_bgn:
params["N.BGN"] = self._format_vector(self.n_bgn)
if self.p_bgn:
params["P.BGN"] = self._format_vector(self.p_bgn)
return self._build_command(params, flags)
[docs]
@classmethod
def silicon(cls, name: str = "silicon", **kwargs) -> "Material":
"""Create silicon material with optional customizations."""
return cls(name=name, default="silicon", **kwargs)
[docs]
@classmethod
def gaas(cls, name: str = "gaas", **kwargs) -> "Material":
"""Create GaAs material with optional customizations."""
return cls(name=name, default="gaas", **kwargs)