171 lines
6.5 KiB
Python
171 lines
6.5 KiB
Python
# Copyright 2013 DEVSIM LLC
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
from devsim import contact_equation, element_from_edge_model, equation, get_dimension
|
|
|
|
from devsim.python_packages.model_create import (
|
|
CreateElementModel2d,
|
|
CreateElementModelDerivative2d,
|
|
)
|
|
|
|
|
|
def CreateElementElectronContinuityEquation(device, region, current_model):
|
|
"""
|
|
Uses element current model for equation
|
|
"""
|
|
equation(
|
|
device=device,
|
|
region=region,
|
|
name="ElectronContinuityEquation",
|
|
variable_name="Electrons",
|
|
time_node_model="NCharge",
|
|
node_model="ElectronGeneration",
|
|
element_model=current_model,
|
|
variable_update="positive",
|
|
)
|
|
|
|
|
|
# TODO: expand for circuit
|
|
def CreateElementContactElectronContinuityEquation(device, contact, current_model):
|
|
"""
|
|
Uses element current model for equation
|
|
"""
|
|
contact_electrons_name = "{0}nodeelectrons".format(contact)
|
|
contact_equation(
|
|
device=device,
|
|
contact=contact,
|
|
name="ElectronContinuityEquation",
|
|
node_model=contact_electrons_name,
|
|
element_current_model=current_model,
|
|
)
|
|
|
|
|
|
#### this version is from the direction of current flow
|
|
#### TODO: version from interface normal distance
|
|
def CreateNormalElectricFieldFromInterfaceNormal(device, region, interface):
|
|
### assume the interface normal already exists
|
|
#### Get the electric field on the element
|
|
element_from_edge_model(edge_model="ElectricField", device=device, region=region)
|
|
element_from_edge_model(
|
|
edge_model="ElectricField", device=device, region=region, derivative="Potential"
|
|
)
|
|
|
|
#### Get the normal e field to current flow /// need to figure out sign importance for electron/hole
|
|
Enormal = "{0}_normal_x * ElectricField_x + {0}_normal_y * ElectricField_y".format(
|
|
interface
|
|
)
|
|
CreateElementModel2d(device, region, "Enormal", Enormal)
|
|
CreateElementModelDerivative2d(device, region, "Enormal", Enormal, "Potential")
|
|
|
|
|
|
###### make this on a per carrier basis function
|
|
###### assume that low field model already exists, but not projected
|
|
def CreateNormalElectricFieldFromCurrentFlow(device, region, low_curr):
|
|
dimension = get_dimension(device=device)
|
|
if dimension != 2:
|
|
raise ValueError("Supported in 2d only")
|
|
|
|
element_from_edge_model(edge_model=low_curr, device=device, region=region)
|
|
element_from_edge_model(
|
|
edge_model=low_curr, device=device, region=region, derivative="Potential"
|
|
)
|
|
element_from_edge_model(
|
|
edge_model=low_curr, device=device, region=region, derivative="Electrons"
|
|
)
|
|
element_from_edge_model(
|
|
edge_model=low_curr, device=device, region=region, derivative="Holes"
|
|
)
|
|
|
|
#### Get the current magnitude on the element
|
|
#### do we need the derivative, since this is only scaling the direction?
|
|
#### Worry about small denominator 1e-300 is about the limit
|
|
J_lf_mag = "pow({0}_x^2 + {0}_y^2 + 1e-300, 0.5)".format(low_curr)
|
|
CreateElementModel2d(
|
|
device, region, "{0}_mag".format(low_curr), "{0}".format(J_lf_mag)
|
|
)
|
|
for j in ("Electrons", "Holes", "Potential"):
|
|
for i in ("@en0", "@en1", "@en2"):
|
|
ex = "({0}_x * {0}_x:{1}{2} + {0}_y * {0}_y:{1}{2})/{0}_mag".format(
|
|
low_curr, j, i
|
|
)
|
|
CreateElementModel2d(
|
|
device, region, "{0}_mag:{1}{2}".format(low_curr, j, i), ex
|
|
)
|
|
|
|
### This calculates the normalized current in each direction
|
|
for i in ("x", "y"):
|
|
J_norm = "{0}_{1} / {0}_mag".format(low_curr, i)
|
|
CreateElementModel2d(device, region, "{0}_norm_{1}".format(low_curr, i), J_norm)
|
|
CreateElementModelDerivative2d(
|
|
device,
|
|
region,
|
|
"{0}_norm_{1}".format(low_curr, i),
|
|
J_norm,
|
|
"Electrons",
|
|
"Holes",
|
|
"Potential",
|
|
)
|
|
|
|
#### Get the electric field on the element
|
|
element_from_edge_model(edge_model="ElectricField", device=device, region=region)
|
|
element_from_edge_model(
|
|
edge_model="ElectricField", device=device, region=region, derivative="Potential"
|
|
)
|
|
|
|
#### Get the parallel e field to current flow
|
|
Eparallel_J = "{0}_norm_x * ElectricField_x + {0}_norm_y * ElectricField_y".format(
|
|
low_curr
|
|
)
|
|
CreateElementModel2d(device, region, "Eparallel_{0}".format(low_curr), Eparallel_J)
|
|
CreateElementModelDerivative2d(
|
|
device, region, "Eparallel_{0}".format(low_curr), Eparallel_J, "Potential"
|
|
)
|
|
|
|
# magnitude e field
|
|
ElectricField_mag = "pow(ElectricField_x^2 + ElectricField_y^2 + 1e-300, 0.5)"
|
|
CreateElementModel2d(device, region, "ElectricField_mag", ElectricField_mag)
|
|
# the , turns this into an actual tuple
|
|
for j in ("Potential",):
|
|
for i in ("@en0", "@en1", "@en2"):
|
|
ex = "(ElectricField_x * ElectricField_x:{0}{1} + ElectricField_y * ElectricField_y:{0}{1})/ElectricField_mag".format(
|
|
j, i
|
|
)
|
|
CreateElementModel2d(
|
|
device, region, "ElectricField_mag:{0}{1}".format(j, i), ex
|
|
)
|
|
|
|
#### Get the normal e field to current flow
|
|
Enormal_J = "pow(max(ElectricField_mag^2 - Eparallel_{0}^2,1e-300), 0.5)".format(
|
|
low_curr
|
|
)
|
|
CreateElementModel2d(device, region, "Enormal_{0}".format(low_curr), Enormal_J)
|
|
|
|
# CreateElementModelDerivative2d $device $region Enormal_{low_curr} {Enormal_J} Electrons Holes Potential
|
|
for j in ("Electrons", "Holes", "Potential"):
|
|
for i in ("@en0", "@en1", "@en2"):
|
|
ex = "(ElectricField_mag * ElectricField_mag:{0}{1} - Eparallel_{2} * Eparallel_{2}:{0}{1})/Enormal_{2}".format(
|
|
j, i, low_curr
|
|
)
|
|
CreateElementModel2d(
|
|
device, region, "Enormal_{0}:{1}{2}".format(low_curr, j, i), ex
|
|
)
|
|
|
|
|
|
def CreateElementElectronCurrent2d(device, region, name, mobility_model):
|
|
Jn = "ElectronCharge*{0}*EdgeInverseLength*V_t*kahan3(Electrons@en1*Bern01, Electrons@en1*vdiff, -Electrons@en0*Bern01)".format(
|
|
mobility_model
|
|
)
|
|
CreateElementModel2d(device, region, name, Jn)
|
|
for i in ("Electrons", "Holes", "Potential"):
|
|
CreateElementModelDerivative2d(device, region, name, Jn, i)
|
|
|
|
|
|
def CreateElementHoleCurrent2d(device, region, name, mobility_model):
|
|
Jp = "-ElectronCharge*{0}*EdgeInverseLength*V_t*kahan3(Holes@en1*Bern01, -Holes@en0*Bern01, -Holes@en0*vdiff)".format(
|
|
mobility_model
|
|
)
|
|
CreateElementModel2d(device, region, name, Jp)
|
|
for i in ("Electrons", "Holes", "Potential"):
|
|
CreateElementModelDerivative2d(device, region, name, Jp, i)
|