simudo.physics package¶
Submodules¶
simudo.physics.electro_optical_process module¶
- class simudo.physics.electro_optical_process.AbsorptionAndRadiativeRecombinationEOPMixin[source]¶
Bases:
object- enable_radiative_recombination = True¶
- get_generation_user(band)[source]¶
Call
get_generation_optical()andget_radiative_recombination()and add together their results accordingly.Only include the radiative recombination process if
enable_radiative_recombinationis true.
- class simudo.physics.electro_optical_process.BeerLambert(**kwargs)[source]¶
Bases:
AbsorptionAndRadiativeRecombinationEOPMixin,TwoBandEOPMixin,ElectroOpticalProcessBeer-Lambert absorption with energy-dependent, per-region alpha(E).
Alpha is registered via
add_callable_rule()with key<name>/alpha_function, where<name>is the instance name of this EOP. MultipleBeerLambertinstances can share the same optical fields (overlapping absorption is physically correct).Radiative recombination is disabled in v1 (
enable_radiative_recombination = False).Generation is pre-accumulated into a
dolfin.Functionbefore each Newton iteration so that Newton assembly sees a single function rather than an N-term UFL sum over optical fields, where N is the number of optical fields.Example usage:
spatial.add_callable_rule( 'opt_cv/alpha_function', R.absorber, make_alpha_from_table(energies_eV, alphas)) pdd.easy_add_electro_optical_process( BeerLambert, dst_band=CB, src_band=VB, name='opt_cv')
- dst_band_is_trap = False¶
- enable_radiative_recombination = True¶
- get_alpha(photon_energy)[source]¶
This method is called to get Beer-Lambert absorption coefficient alpha at a particular photon energy. Must return a UFL quantity on the PDD mesh, or
None.User class must implement this.
- get_generation_optical(band)[source]¶
Compute carrier generation due to optical absorption, using absorption coefficient given by
get_alpha_by_optical_field()and quantum yield given byget_quantum_yield().
- get_refractive_index()[source]¶
Return the spatially-varying refractive index from the spatial registry.
Raises a clear error (instead of the low-level “no value rules for key” AssertionError) if
refractive_indexhas not been set anywhere, since the Shockley-van Roosbroeck radiative-recombination integral cannot run without it.
- gui_hint = "Beer-Lambert absorption with tabulated or analytic alpha(E). Register alpha per region with spatial.add_callable_rule('<name>/alpha_function', region, func). Overlapping absorption across multiple instances is supported."¶
- name = 'beer_lambert'¶
- pre_first_iteration_hook(solver)¶
- pre_iteration_hook(solver)¶
- required_spatial_callables: dict = {'alpha_function': {'arg_units': 'eV', 'description': 'optical absorption coefficient α(E)', 'return_units': '1/cm'}}¶
- required_spatial_params: dict = {}¶
- src_band_is_trap = False¶
- svr_E_max = None¶
- svr_E_min = None¶
- svr_integration_bins = 100¶
- svr_solid_angle = 12.566370614359172¶
- svr_static_alpha = True¶
- class simudo.physics.electro_optical_process.ElectroOpticalProcess(**kwargs)[source]¶
Bases:
SetattrInitMixinThis class exists to represent both electro-optical process and purely electronic (dark) processes, such as nonradiative recombination.
- Variables:
pdd (PoissonDriftDiffusion) – Instance of
PoissonDriftDiffusion.pre_iteration_hook (callable) – Implement this method in order to run code before each PDD Newton iteration. Useful for processes that need procedural code (cannot be expressed as UFL form).
pre_first_iteration_hook (callable) – This method is called before the first PDD Newton iteration.
post_iteration_hook (callable) – This method is called after each PDD Newton iteration.
- check_band_types()[source]¶
Warn if a band is not of the type this process is derived for.
Bands whose
is_trap_bandisNoneare left alone: the class never declared one, so there is nothing to check against.
- dst_band_is_trap = None¶
- get_alpha(photon_energy)[source]¶
This method is called to get Beer-Lambert absorption coefficient alpha at a particular photon energy. Must return a UFL quantity on the PDD mesh, or
None.User class must implement this.
- get_alpha_by_optical_field(optical_field)[source]¶
Exists as a separate method to make anisotropy possible.
By default just calls
self.get_alpha.
- get_band_generation_sign(band)[source]¶
As the generation process intensifies (e.g., light intensity increases), does
bandlose or gain more carriers?The default implementation always returns
None. User classes are expected to override this method.Note: If you are implementing a two-band process, you almost certainly want to inherit from
TwoBandEOPMixin.- Returns:
sign – If the band participates in the process, returns
+1or-1if it gains or loses carriers, respectively. Otherwise, returnNone.- Return type:
object
- get_generation_optical(band)[source]¶
Compute carrier generation due to optical absorption, using absorption coefficient given by
get_alpha_by_optical_field()and quantum yield given byget_quantum_yield().
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- get_optical_generation(photon_energy)[source]¶
Override for luminescent coupling. By default returns zero.
- get_optical_generation_by_optical_field(optical_field)[source]¶
Exists as a separate method to make anisotropy possible.
By default just calls
self.get_optical_generation, and multiplies bysolid_angle.
- get_photon_flux_on_pdd_mesh(optical_field)[source]¶
Returns optical photon flux, adapted onto PDD mesh. Use this accessor instead of reaching inside
optical.OpticalFieldyourself.- Parameters:
optical_field (
optical.OpticalField) – Optical field whose photon flux (clipped to be nonnegative) to get.
- get_quantum_yield_by_optical_field(optical_field)[source]¶
Exists as a separate method to make anisotropy possible.
By default just calls
self.get_quantum_yield.
- logger¶
- property mesh_util¶
- post_iteration_hook = None¶
- pre_first_iteration_hook = None¶
- pre_iteration_hook = None¶
- required_spatial_callables: dict = {}¶
- required_spatial_params: dict = {}¶
- src_band_is_trap = None¶
- property unit_registry¶
- class simudo.physics.electro_optical_process.IBBeerLambert(**kwargs)[source]¶
Bases:
TrapEOPMixin,BeerLambertBeer-Lambert absorption / radiative recombination for a transition involving an intermediate band (IB), where alpha is state-dependent:
α(E, x) = σ(E, x) · u_active(x) = σ(E, x) · N_IB(x) · f_IB(x)
where σ(E, x) is the optical cross-section (cm²), registered via
add_callable_rule()with key<name>/sigma_function, and f_IB = u_IB / N_IB.Which states are active depends on the direction of the transition (live UFL):
- u_active = IB.u when IB and the regular band carry
the same carrier sign (eg, IB and CB both electron-like): the occupied IB states are the ones a photon can excite out of
- u_active = IB.number_of_states - IB.u otherwise (eg, IB electron-like and
VB hole-like): the empty IB states are the ones that can receive a carrier
Both generation and radiative recombination are Picard-frozen: σΦ and u_active are each projected into a
dolfin.Functionand treated as constant by UFL, so the Jacobian sees no contribution from these terms. That is a fixed-point rather than a Newton linearisation — convergence is linear rather than quadratic — but it is robust across the full intensity range, whereas a live-UFL formulation gives a negative diagonal entry ∂G/∂(u_IB) = −σΦ that destabilises Newton once σΦ grows large enough to overwhelm the stabilising terms.trap_bandidentifies the intermediate band;dst_band/src_bandfollow the usual BeerLambert convention (higher-energy band = dst_band).Example usage:
spatial.add_callable_rule( 'opt_ib_cv/sigma_function', R.absorber, make_sigma_top_hat(0.7*U('eV'), 1.1*U('eV'), 1e-15*U('cm^2'))) pdd.easy_add_electro_optical_process( IBBeerLambert, dst_band=CB, src_band=IB, trap_band=IB, name='opt_ib_cv')
- enable_radiative_recombination = True¶
- get_alpha(photon_energy)[source]¶
This method is called to get Beer-Lambert absorption coefficient alpha at a particular photon energy. Must return a UFL quantity on the PDD mesh, or
None.User class must implement this.
- get_generation_optical(band)[source]¶
Picard-frozen generation: _u_active_function · _SigmaPhi_function.
Both _SigmaPhi = Σ_k σ(E_k)·Φ_k and u_active are projected once before the first Newton iteration and held frozen during the solve. The Jacobian therefore sees zero contribution from this term (Picard / fixed-point linearisation), which prevents the negative diagonal entry ∂G/∂(u_IB) = -_SigmaPhi from destabilising Newton when _SigmaPhi grows large enough to overwhelm the NR/relaxation stabilising contributions. Convergence is slower (linear rather than quadratic) but robust across the full intensity range.
- get_radiative_recombination()[source]¶
SVR recombination, Picard-frozen: _u_active_function · _B0norm · expm1(ΔqFL/kT).
u_active is frozen (Picard) to remove the destabilising ∂u_active/∂u_IB Jacobian contribution. UFL still differentiates through expm1(x), giving the full QFL-split Jacobian for the radiative term.
- gui_hint = "Beer-Lambert absorption / radiative recombination for a transition involving a sharp IB, with a state-dependent alpha = sigma(E) * N_IB * f_IB that tracks the band's occupancy. Lower E band and Higher E band are the two bands of the transition, one of which is the IB; Trap band = the IB. Requires an optical cross-section '<name>/sigma_function' per region: a top hat set below, a tabulated sigma(E) in the project file, or a callable provided by the material."¶
- name = 'beer_lambert_ib'¶
- pre_first_iteration_hook(solver)¶
Project Σ σ·Φ and Σ σ·φ_bb into frozen Functions before each Newton step.
- pre_iteration_hook = None¶
- required_spatial_callables: dict = {'sigma_function': {'arg_units': 'eV', 'description': 'IB optical cross-section σ(E)', 'return_units': 'cm^2'}}¶
- required_spatial_params: dict = {}¶
- svr_static_alpha = False¶
- class simudo.physics.electro_optical_process.NonOverlappingTopHatBeerLambert(**kwargs)[source]¶
Bases:
AbsorptionAndRadiativeRecombinationEOPMixin,RadiativeEOPMixin,TwoBandEOPMixin,ElectroOpticalProcessAbsorption or radiative recombination between src_band and dst_band. For absorption, src_band=VB and dst_band=CB, and vice versa for recombination.
Includes radiative recombination by default.
- dst_band_is_trap = False¶
- gui_hint = 'Photon absorption / radiative recombination between two standard bands (e.g. VB → CB). Lower E band = valence-like band (e.g. VB); Higher E band = conduction-like band (e.g. CB). Requires spatial parameter ‘alpha’ per region.'¶
- name = 'beer_lambert'¶
- required_spatial_params: dict = {'alpha': '1/cm'}¶
- src_band_is_trap = False¶
- class simudo.physics.electro_optical_process.NonOverlappingTopHatBeerLambertIB(**kwargs)[source]¶
Bases:
AbsorptionAndRadiativeRecombinationEOPMixin,RadiativeEOPMixin,TrapEOPMixin,TwoBandEOPMixin,ElectroOpticalProcessAbsorption between intermediate band and regular band.
Includes radiative recombination by default.
Based on [Strandberg2011].
- get_alpha(photon_energy)[source]¶
This method is called to get Beer-Lambert absorption coefficient alpha at a particular photon energy. Must return a UFL quantity on the PDD mesh, or
None.User class must implement this.
- gui_hint = "Photon absorption / radiative recombination between a standard band and a sharp IB. Lower E band and Higher E band are the regular bands on each side (e.g. VB and CB); Trap band = the IB. Requires spatial parameter 'sigma_opt' per region."¶
- name = 'beer_lambert_IB'¶
- required_spatial_params: dict = {'sigma_opt': 'cm^2'}¶
- class simudo.physics.electro_optical_process.NonRadiativeTrap(**kwargs)[source]¶
Bases:
DarkEOPMixin,TrapEOPMixin,TwoBandEOPMixin,ElectroOpticalProcessShockley Read trapping process. Typically, trap_band = IB. If you do not have an explicit
Bandobject for the trap concentration, useSRHRecombinationinstead.See doc/ib.lyx.
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- gui_hint = "Non-radiative trapping between a standard band (SB) and a sharp IB. Use when you have an explicit Band object for the IB (use SRHRecombination otherwise). Trap band = IB. One of lower or higher E band must also be the IB. Requires spatial parameter 'sigma_th' per region; thermal velocity comes from the band (CB/vth, VB/vth), usually from the material. To implement a full recombination, you need two NonRadiativeTrap processes (eg, for CB-IB and IB-VB) "¶
- name = 'nonradiative'¶
- required_spatial_params: dict = {'sigma_th': 'cm^2'}¶
- class simudo.physics.electro_optical_process.RadiativeEOPMixin[source]¶
Bases:
objectCalculates properties involved in radiative processes, such as trapping or recombination.
Only works in non-degenerate condition
exp((E_photon_min - mu_fi)/kT) >> 1. See [Strandberg2011], page 3, under Eq. 6.
- class simudo.physics.electro_optical_process.SRHRecombination(**kwargs)[source]¶
Bases:
DarkEOPMixin,TrapEnergyLevelMixin,TwoBandEOPMixin,ElectroOpticalProcessSRH recombination. The destination band is the one losing carriers through recombination.
Typically, dst_band=CB and src_band=VB.
Uses TrapEnergyLevelMixin (not TrapEOPMixin) — SRH has no explicit trap band object; the trap energy level and lifetime tau come from spatial parameters. The GUI therefore does not show a “Trap band” selector for this class.
- dst_band_is_trap = False¶
- get_degeneracy_factor(band)[source]¶
Degeneracy factor
gamma = u / u_nondegeneratefor band.Returns
1for a nondegenerate band.Guarded against underflow: the Boltzmann density underflows to exactly zero in double precision once
(E_F - E_C)/kTfalls below roughly -745, which is reachable for a wide-gap band under reverse bias. Gamma tends to 1 in that limit – Fermi-Dirac and Boltzmann statistics coincide when carriers are sparse – so fall back to 1 rather than dividing by zero.
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- gui_hint = "Shockley-Read-Hall recombination through midgap traps with no explicit trap band. Lower E band = valence-like band (e.g. VB); Higher E band = conduction-like band (e.g. CB). Trap band should be left as (none) — SRH uses per-band lifetime parameters instead. Requires spatial parameters '{dst_band}/tau' and '{src_band}/tau' per region."¶
- name = 'SRH'¶
- required_spatial_params: dict = {'energy_level': 'eV', '{dst_band}/tau': 's', '{src_band}/tau': 's'}¶
- src_band_is_trap = False¶
- trap_band = None¶
- class simudo.physics.electro_optical_process.ShockleyReadBand2BandTrap(**kwargs)[source]¶
Bases:
TwoBandEOPMixin,DarkEOPMixin,ElectroOpticalProcessShockley-Read-like trapping process between the receiving (R) and sending (D) bands. Similar to
NonRadiativeTrap(which is Shockley-Read trapping from a band to trap states with a single energy).If the signs of both bands are the same, s_D = s_R, then the rate is
U = [1 - exp(s_D (w_D - w_R)/kT)] u_D/tau
w_k is the qfl of band k u_D is the carrier concentration in band D where we approximate that the number of receiving states is independent of w_R Derivation assumes that the receiving band (R) is essentially entirely empty, so only the population of the sending band (D) enters the rate.
The energy-averaged (usually phenomenological) capture time tau must be defined. Convention: only the value of tau in the dst_band will be used. If the instance of this EOP has
nameSR_B2B and the D bandnameis DB tau is found from spatial[“SR_B2B/DB/tau”]If s_D = -s_R, then the rate is
U = [1 - exp(s_D (w_D - w_R)/kT)] u_D u_R <c>
<c> is the average capture rate [volume^-1 time^-1] for the process. If the instance of this EOP has
nameSR_B2B and the D bandnameis DB <c> is found from spatial[“SR_B2B/DB/capture_rate”](In the previous case, 1/tau = <c> u_pR where u_pR is the concentration of carriers of opposite sign in band R)
Following the standard sign convention, dst_band = D, src_band = R
- dst_band_is_trap = False¶
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- gui_hint = "Shockley-Read-like interband transfer between two standard bands (no explicit or implicit trap band). Lower E band = lower-energy band Higher E band = higher-energy band Requires '{dst_band}/tau' (for same-sign bands) or '{dst_band}/capture_rate' (for opposite-sign bands)."¶
- name = 'SR_B2B'¶
- required_spatial_params: dict = {'{dst_band}/capture_rate': 'cm^3/s', '{dst_band}/tau': 's'}¶
- src_band_is_trap = False¶
- class simudo.physics.electro_optical_process.ShockleyReadTrap2Trap(**kwargs)[source]¶
Bases:
TwoBandEOPMixin,DarkEOPMixin,ElectroOpticalProcessShockley-Read-like trapping process between the receiving (R) and sending (D) bands where both are trap (ie, sharp) bands. Similar to
NonRadiativeTrap(which is Shockley-Read trapping from a dispersing band to trap states with a single energy).Regardless of the signs of the band, the net transfer rate from D to R is
U = [1 - exp( -(w_D - w_R)/kT)] f_D (1-f_R) n_R N_D c
- where
c is the capture coefficient [vol/time] for the trapping process N_D is the number of states [1/vol] in the D band N_R is the number of states [1/vol] in the R band
If the instance of this EOP has
nameSR_T2T and the D bandnameis DB c is found from spatial[“SR_T2T/DB/capture_rate”]Following the standard sign convention, dst_band = D, src_band = R
- dst_band_is_trap = True¶
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- gui_hint = "Shockley-Read-like inter-trap transfer between two sharp IB states. Both Lower E band and Higher E band must be sharp (IB-type) bands. Lower E band = source / receiving (R) band; Higher E band = destination / sending (D) band. Requires '{dst_band}/capture_rate' per region."¶
- name = 'SR_T2T'¶
- required_spatial_params: dict = {'{dst_band}/capture_rate': 'cm^3/s'}¶
- src_band_is_trap = True¶
- class simudo.physics.electro_optical_process.StaticGeneration(**kwargs)[source]¶
Bases:
TwoBandEOPMixin,ElectroOpticalProcessStatic generation process. Typically, dst_band=CB and src_band=VB. Uses a generation rate that does not change during the simulation.
Generation rate is defined in pdd.spatial[‘name/generation’], where the default name is static.
- get_generation_user(band)[source]¶
This method is called to get the generation contribution to band
band. Must return a UFL quantity on the PDD mesh.User class may override this. By default, this method just calls
get_generation_optical().Sign convention: The returned value is positive or negative if the band gains or loses carriers respectively.
This method will be called for every band in the system. You are strongly encouraged to use
get_band_generation_sign()to determine whether the process causes a gain or a loss of carriers in bandband, and whether the band participates in the process at all.
- gui_hint = 'Not usable in the GUI. Consider using BeerLambert or IBBeerLambert. If using Python, you can apply arbitrary static absorption profiles using UniformGenerationAdaptiveStepper'¶
- name = 'static'¶
- class simudo.physics.electro_optical_process.TrapEOPMixin[source]¶
Bases:
TrapEnergyLevelMixinCalculates properties involved in trapping between a trap band and dispersing band, such as u1, tau, etc.
Requires an explicit trap_band Band object.
GUI cross-reference: any class that directly inherits this mixin will have the “Trap band” selector shown for it in code/gui/panels/processes.py. (SRHRecombination inherits TrapEnergyLevelMixin instead — it does not use an explicit trap band and should NOT show the trap band selector.)
- Variables:
- check_band_types()[source]¶
These processes need one trap band and one dispersing band, and
reg_bandidentifies the dispersing one by elimination. Anything leaving it undefined raises rather than warns: the process cannot be assembled at all.
- classmethod easy_add_two_traps_to_pdd(pdd, name_prefix, top_band, bottom_band, trap_band, **kwargs)[source]¶
- reg_band¶
- class simudo.physics.electro_optical_process.TrapEnergyLevelMixin[source]¶
Bases:
objectMinimal mixin providing trap energy level and SRH u1 statistics.
Shared by TrapEOPMixin (explicit trap band) and SRHRecombination (implicit trap from spatial parameters, no Band object).
- get_trap_energy_level():
Returns the trap energy level, either from the explicit trap_band (if set) or from the spatial parameter
<name>/energy_level.
- get_u1(band):
Quasi-Fermi level equilibrium carrier concentration in
bandevaluated at the trap energy level. Used in the SRH denominator.
- class simudo.physics.electro_optical_process.TwoBandEOPMixin[source]¶
Bases:
objectConvenience mixin representing a generation process across two bands.
Sign convention: As the generation process intensifies, the destination band gains more carriers. The source band may gain or lose carriers depending on its carrier type.
- Variables:
- get_band_generation_sign(band)[source]¶
Provides a non-trivial implementation of
ElectroOpticalProcess.get_band_generation_sign()in the case of two active bands.See
TwoBandEOPMixinfor the sign convention.
simudo.physics.heterojunction module¶
- class simudo.physics.heterojunction.ThermionicHeterojunction(band: Band, boundary: FacetRegion, interface_quadrature_degree: int = 20, HJBC_enhancement: Constant = _Nothing.NOTHING, use_alternative_BC: bool = True, use_nondegen: bool = False)[source]¶
Bases:
objectThermionic emission heterojunction BC valid with parabolic bands. Treats both nondegenerate (Boltzmann) and degenerate bands
- Parameters:
band (
Band) – Semiconductor band on which the BC is applied. Only MixedQflBand is currently supported.boundary (
FacetRegion) – Boundary on which to implement heterojunction boundary condition.
Notes
See V. Palankovski (2004), eq. 3.72 and K. Yang, J. R. East, G. I. Haddad, Solid State Electronics v.36 (3) p.321-330 (1993) K. Horio, H. Yanai, IEEE Trans. Elec. Devices v.37(4) p.1093-1098 (1990)
For degenerate conditions, see Sentaurus sdevice manual
For a conduction band BC, band.spatial must have attribute “CB/vth” in the barrier region. Similarly for other bands.
Unlimited carrier flow from low to barrier region can be resolved, but due to precision issues, cannot resolve Delta_w producing carrier flows from barrier to low region with Delta_w larger than
|ln(1e-16)| * kTin double precisionDX 20260813: make use_alternative_BC = True the default. Alternative BC is using the exponential of delta_w, or lambda, instead of delta_w as the HJBC requirement.
- HJBC_enhancement: Constant¶
- property N_eff¶
- boundary: FacetRegion¶
- property emission_velocity¶
Richardson emission velocity,
.The material files export
<band>/vthas the mean speed
, which is the average
an SRH capture coefficient needs. Thermionic emission is a flux
across the interface, so it needs the one-directional flux average
instead – only the carriers moving toward the barrier, weighted by
how fast they cross:
The factor is exactly 4, since
. Equivalently
with
.Applying the conversion here, rather than exporting a second velocity from every material file, keeps one
vthper band and puts the choice of average next to the physics that fixes it.
- interface_quadrature_degree: int¶
- use_alternative_BC: bool¶
- use_nondegen: bool¶
- property vth¶
simudo.physics.material module¶
- class simudo.physics.material.BadSimpleSiliconMaterial(**kwargs)[source]¶
Bases:
SimpleSiliconMaterialJust an example of how to use inheritance to selectively modify properties of the superclass
- get_dict()[source]¶
Construct dictionary of material parameters.
- Returns:
Dictionary where keys are
add_rule()keys, and values are the values (expressions).- Return type:
dict
- name = 'badSi'¶
- class simudo.physics.material.Material(**kwargs)[source]¶
Bases:
SetattrInitMixinBase material class.
- Parameters:
problem_data (
problem_data.ProblemData, optional) – ProblemData instance (used to pull, for example, the temperature variable).unit_registry (
pint.UnitRegistry, optional) – Unit registry.
- Variables:
name (str, optional) – Material name.
required_spatial_params (list of str) – Spatial rule keys that must be registered in
spatialbeforeget_dict()can evaluate correctly (e.g.['MoleFractionX']for alloy materials). The GUI uses this list to prompt the user to set these values per layer. Subclasses should override as needed.
- dict¶
- get_dict()[source]¶
Construct dictionary of material parameters.
- Returns:
Dictionary where keys are
add_rule()keys, and values are the values (expressions).- Return type:
dict
- name = None¶
- property pdd¶
- required_spatial_params: list = []¶
- property temperature¶
- property unit_registry¶
- class simudo.physics.material.SimpleSiliconMaterial(**kwargs)[source]¶
Bases:
MaterialVery simple silicon material. No temperature dependences.
- get_dict()[source]¶
Construct dictionary of material parameters.
- Returns:
Dictionary where keys are
add_rule()keys, and values are the values (expressions).- Return type:
dict
- name = 'Si'¶
simudo.physics.optical module¶
- class simudo.physics.optical.AbsorptionRangesHelper(**kwargs)[source]¶
Bases:
SetattrInitMixin- Parameters:
problem_data – Problem_data object.
inf_upper_bound – Upper bound on absorption to use instead of literal ‘inf’. By default 100 eV.
energy_unit – By default, eV.
- property bands¶
- property energy_unit¶
- get_transition_bounds()[source]¶
Returns dictionary of (lower, upper) bounds for energy transitions. See
get_transition_lower_bounds()for more.
- get_transition_lower_bounds()[source]¶
Returns a dictionary of minimum transition lower bounds. The keys in the dictionary are frozensets
{source_band_key, destination_band_key}.
- property inf_upper_bound¶
- property unit_registry¶
- class simudo.physics.optical.Optical(**kwargs)[source]¶
Bases:
DefaultProblemDataChildMixin,GetToSaveMixin,SetattrInitMixinContains optical part of the problem. Note that unlike PDD, the optical fields are solved independent (self-consistently), so we do not have a big mixed space made up of all the photon flux fields.
- Parameters:
problem_data – See
problem_data.mesh_data (optional) – See
mesh_data.
- Variables:
problem_data (
ProblemData) – Parent problem.mesh_data (
MeshData) – Mesh data. Taken fromproblem_dataif not specified.fields (
NameDict) – Dictionary ofOpticalFieldobjects.spatial (
spatial.Spatial) – Object managing boundary conditions and spatial quantities.Phi_scale (
dolfin.Constant) – This controls the scaling factor applied to light photon flux boundary conditions. This is particularly useful when doing a light ramp-up.
- Phi_pddproj_space¶
- Phi_scale¶
- fields¶
- get_to_save()[source]¶
Get dict of functions needed to restore a solution from file, or to save in a backtracking/adaptive solver.
The default implementation returns an empty NameDict.
- Returns:
NameDict of
SaveItem.- Return type:
- initialize_from(other_optical)[source]¶
Copy solved optical state (
Phi_scaleand each field’s solved photon flux) from other_optical into this instance.Unlike
initialize_from(), which only carries over PDD (Poisson + band) state, this must be called separately sinceOpticalis a sibling ofpddonProblemData, not one of its children. Skipping this leaves the copied-in carrier state (fully illuminated, viapdd.initialize_from) inconsistent with a not-yet-solved (effectively zero) photon flux, which reliably fails to converge on the first solve.
- spatial¶
- class simudo.physics.optical.OpticalField(**kwargs)[source]¶
Bases:
SetattrInitMixinA single optical field subproblem. This represents a scalar photon flux at a single wavelength and direction of propagation.
- Parameters:
optical (
Optical) – Parent object.key (str) – Name of optical field. Must be unique.
photon_energy (
pint.Quantity) – Photon energy. Magnitude must be floating point constant.direction (
numpy.ndarray) – Direction of propagation. Must be a normalized vector.solid_angle (float) – Solid angle spanned by this optical field. The sum of all solid angles at a given wavelength must sum up to
.
- Variables:
Phi (
pint.Quantitywrappingdolfin.Function) – Photon flux field. This function is on the optical mesh.alpha (
pint.Quantitywrapping expression) – Absorption/extinction coefficient. This quantity is on the optical mesh (and may be a result of a projection/interpolation from the PDD mesh).g (
pint.Quantitywrapping expression) – Additional generation (excluding-alpha*Phi). This quantity is on the optical mesh (and may be a result of a projection/interpolation from the PDD mesh).Phi_pddproj (
pint.Quantityofdolfin.Function) – Projected/interpolated version ofPhion the PDD mesh. To update the projection, callupdate_output().Phi_pddproj_clipped (
pint.Quantitywrapping expression) – Clipped version ofPhi_pddprojthat is always nonnegative.
Notes
TODO: write down radiative transfer equation
- Phi_pddproj¶
- property Phi_pddproj_clipped¶
- alpha¶
- property function_subspace_registry¶
- g¶
- get_alpha_pdd_expr()[source]¶
This represents the extinction coefficient on the PDD mesh, as extracted from the
poisson_drift_diffusion.ElectroOpticalProcessinstances inelectro_optical_processes.
- get_g_pdd_expr()[source]¶
This represents the optical generation on the PDD mesh (excluding the loss through the extinction coefficient), as extracted from the
poisson_drift_diffusion.ElectroOpticalProcessinstances inelectro_optical_processes.
- property mesh_util¶
- mixed_function_helper¶
- property mixed_function_solution_object¶
- property name¶
- property pdd¶
- property spatial¶
- property unit_registry¶
- update_output()[source]¶
Update output quantities (e.g. by projecting onto PDD mesh).
This updates
Phi_pddproj.
- property vacuum_wavelength¶
Computes vacuum wavelength based on
photon_energy. Can also be used to initialize that property, with the conversion being done automatically.
- class simudo.physics.optical.OpticalFieldMSORTE(**kwargs)[source]¶
Bases:
OpticalFieldMSORTE,InitializeFromByAttributesMixin,WithSubfunctionsMixin,OpticalField,GetToSaveMixin- get_to_save()[source]¶
Get dict of functions needed to restore a solution from file, or to save in a backtracking/adaptive solver.
The default implementation returns an empty NameDict.
- Returns:
NameDict of
SaveItem.- Return type:
- initialize_from_attributes = ('Phi',)¶
simudo.physics.poisson_drift_diffusion module¶
- class simudo.physics.poisson_drift_diffusion.Band(**kwargs)[source]¶
Bases:
Band,WithSubfunctionsMixin,GetToSaveMixin,TypicalFromPDDMixin,SetattrInitMixin- Represents a band where its carriers are at thermal equilibrium
with each other (such that a quasifermi level is well defined).
- Variables:
name (str) – Name of this band. Must be unique among
PoissonDriftDiffusion.bandsas it is used as a key in thatNameDict. By default simply an alias forkey, so you do not need to set it.key (str) – Unique key used to prefix subfunctions.
pdd (PoissonDriftDiffusion) – Parent object.
u – Carrier density in this band.
qfl – Quasi-Fermi level, aka imref, of carriers in this band.
j – Current density through this band.
sign – Sign of the charge carriers;
-1for electrons, and+1for holes.mobility – Band mobility. By default taken from
.spatial.subdomain – Region name on which the band exists.
- property g¶
- is_degenerate_band = False¶
- is_trap_band = None¶
- property name¶
- property phiqfl¶
- subfunctions_info = ()¶
- class simudo.physics.poisson_drift_diffusion.IntermediateBand(**kwargs)[source]¶
Bases:
DegeneracyMixin,IntermediateBand,BandThis represents an intermediate band with an energetically sharp density of states, where all
number_of_states(
) states are concentrated at an energy level
energy_level(
).The number of carriers obeys Fermi-Dirac statistics. The defining relationship is therefore

where
sisBand.sign,wisBand.qfl,qis the elementary charge,kTisPoissonDriftDiffusion.kT,
is Poisson.phi, and
.
Note that state degeneracy is handled through
DegeneracyMixin.- Variables:
number_of_states – Number of states in the intermediate band. The carrier concentration in this band can never be higher than this number. By default taken from
spatial.energy_level – Band energy level. By default inherited from
DegeneracyMixin.energy_level.use_constant_mobility (bool) – Use spatial variable
"${band_name}/mobility0"as a constant mobility in the IB, neglecting the influence of filling fraction on the mobility. (default: False)
- is_degenerate_band = True¶
- is_trap_band = True¶
- use_constant_mobility = False¶
- class simudo.physics.poisson_drift_diffusion.MixedDensityNondegenerateBand(**kwargs)[source]¶
Bases:
InitializeFromByAttributesMixin,MixedDensityBandMixin,NondegenerateBand
- class simudo.physics.poisson_drift_diffusion.MixedPoisson(**kwargs)[source]¶
Bases:
InitializeFromByAttributesMixin,MixedMethodPoissonMixin,Poisson
- class simudo.physics.poisson_drift_diffusion.MixedQflBandMixin[source]¶
Bases:
MixedQflBandMixed method for the drift-diffusion and continuity equations using quasi-fermi level and current density as the dynamical variables.
- initialize_from_attributes = ('qfl', 'j')¶
- mixedqfl_base_w¶
- mixedqfl_debug_fill_from_boundary = True¶
- mixedqfl_debug_fill_thresholds = (0.0, 0.0)¶
- mixedqfl_debug_fill_with_zero_except_bc = False¶
- mixedqfl_debug_quad_degree_g = 8¶
- mixedqfl_debug_quad_degree_super = 20¶
- mixedqfl_debug_use_bchack = False¶
- mixedqfl_drift_diffusion_heterojunction_bc_term¶
- mixedqfl_drift_diffusion_heterojunction_facet_region¶
- property mixedqfl_drift_diffusion_jump_dS¶
- mixedqfl_surface_recombination_term¶
- class simudo.physics.poisson_drift_diffusion.MixedQflIntermediateBand(**kwargs)[source]¶
Bases:
InitializeFromByAttributesMixin,MixedQflBandMixin,IntermediateBand
- class simudo.physics.poisson_drift_diffusion.MixedQflNondegenerateBand(**kwargs)[source]¶
Bases:
InitializeFromByAttributesMixin,MixedQflBandMixin,NondegenerateBand
- class simudo.physics.poisson_drift_diffusion.NondegenerateBand(**kwargs)[source]¶
Bases:
NondegenerateBand,BandThis represents a nondegenerate band obeying Boltzmann statistics (instead of Fermi-Dirac as it would be for a proper degenerate band), with an effective density of states
effective_density_of_states(
) at an energy
level energy_level(
).The defining relationship is
![u = N_0 \exp\Big[s\cdot\big(E_0 - (w + q\phi)\big) / kT\Big]](../_images/math/877c551cd60ce1e7c890e09c50ee4f06cc9a2552.png)
where
sisBand.sign,wisBand.qfl,qis the elementary charge,kTisPoissonDriftDiffusion.kT,
is Poisson.phi.
- Variables:
- property effective_energy_level¶
In a nondegenerate band, by default the
energy_levelis assumed to include degeneracy effects, so this just returns that attribute.
- is_trap_band = False¶
- class simudo.physics.poisson_drift_diffusion.Poisson(**kwargs)[source]¶
Bases:
Poisson,WithSubfunctionsMixin,GetToSaveMixin,SetattrInitMixin,TypicalFromPDDMixinBase class for Poisson part of the problem. You should instead look at one of the subclasses, such as
MixedPoisson.- Variables:
key (str) – Unique key used to prefix subfunctions.
pdd (PoissonDriftDiffusion) – Parent object.
phi (pint.Quantity) – Electrostatic potential.
E (pint.Quantity) – Electric field.
rho (pint.Quantity) – Charge density.
thermal_equilibrium_phi (pint.Quantity) – Electrostatic potential at thermal equilibrium (i.e. when all qfls are equal to zero).
- property at_thermal_equilibrium¶
- get_to_save()[source]¶
Get dict of functions needed to restore a solution from file, or to save in a backtracking/adaptive solver.
The default implementation returns an empty NameDict.
- key = 'poisson'¶
- property permittivity¶
- thermal_equilibrium_phi¶
- class simudo.physics.poisson_drift_diffusion.PoissonDriftDiffusion(**kwargs)[source]¶
Bases:
DefaultProblemDataChildMixin,GetToSaveMixin,SetattrInitMixin- Parameters:
problem_data – See
problem_data.mesh_data (optional) – See
mesh_data.
- Variables:
problem_data (
ProblemData) – Parent problem.mesh_data (
MeshData) – Mesh data. Taken fromproblem_dataif not specified.bands (
NameDict) – Dictionary of band objects.poisson (
Poisson) – Poisson part of the problem.electro_optical_processes (
NameDict) – Dictionary ofElectroOpticalProcessinstances, including dark generation/recombination mechanisms like SRH.mesh_util (
MeshUtil) – PDE utilities, many of which are (needlessly) mesh-specific.mixed_function_helper (MixedFunctionHelper) – Mixed function and related registry.
- add_band(cls, kwargs)[source]¶
Instantiate and add band. You probably want to use
easy_add_band()instead.
- bands¶
- easy_add_band(name, band_type=None, sign='auto', subdomain=None)[source]¶
Shortcut for instantiating and adding a band.
- Parameters:
name (str) – Name of the band.
band_type (str or class or None) –
Can be a string, or a band class (inheriting from
Band). If it is a string, it serves as an alias as defined below:”nondegenerate”, “boltzmann” ->
MixedQflNondegenerateBand”degenerate”, “parabolic”, “fermi” ->
MixedQflDegenerateBand”intermediate”, “sharp” ->
MixedQflIntermediateBand
If None, the type will be deduced from the band name:
”CB”, “VB” -> “nondegenerate”
”IB” -> “intermediate”
sign (+1, -1, None, or "auto") –
The sign of the charge carrier for this band (negative for electrons, positive for holes).
If “auto”, the sign will be deduced from the name of the band.
If None, the sign keyword argument will not be passed to be band object constructor.
subdomain (
topology.CellRegion) – Subset of the domain where the band exists.
- Returns:
band – Band object.
- Return type:
- electro_optical_processes¶
- get_subspace_descriptors_for_solution_space()[source]¶
Used by
self.mixed_function_helperto build the mixed function space.
- get_to_save()[source]¶
Get dict of functions needed to restore a solution from file, or to save in a backtracking/adaptive solver.
The default implementation returns an empty NameDict.
- property kT¶
Shortcut for
, where
is the
Boltzmann constant, and
is the temperature
(temperature).
- mixed_function_helper¶
- property mixed_function_space¶
- poisson¶
- spatial¶
simudo.physics.problem_data module¶
- class simudo.physics.problem_data.ProblemData(**kwargs)[source]¶
Bases:
SetattrInitMixin- Parameters:
goal (str) – Represents the goal of this problem. Must be
"local charge neutrality","thermal equilibrium", or"full"(representing full coupled solution).unit_registry (
pint.UnitRegistry) – Unit registry to use.mesh_data (
MeshData) – Mesh data to use by default inPoissonDriftDiffusionandOptical.
- Variables:
pdd (
PoissonDriftDiffusion) – Poisson and electronic transport.optical (
Optical) – Optics.
- function_space_cache¶
- function_subspace_registry¶
- property goal_abbreviated¶
return abbreviated goal, for logging tag purposes
- optical¶
- pdd¶
simudo.physics.problem_data_child module¶
simudo.physics.steppers module¶
- class simudo.physics.steppers.NonequilibriumCoupledStepper(**kwargs)[source]¶
Bases:
AdaptiveStepperAdaptively solve a coupled poisson-drift diffusion-optical problem.
Extends
AdaptiveStepperwith PDD-specific logic. The linear solve at each Newton step usesNewtonSolver(or a subclass set viasolver_class). The optical problem can be solved self-consistently with the drift-diffusion problem.Concrete subclasses for common use cases:
VoltageStepper— ramp contact bias.OpticalIntensityAdaptiveStepper— ramp optical intensity.OpticalIntensityLogDampStepper— same with log-damped updates.
- Parameters:
solution (
ProblemData) – Solution on which to operate. This solution object will be progressively re-solved at each of the target parameter values.selfconsistent_optics (bool) – If True, the optical problem will be re-solved at every Newton iteration, allowing for problems where optical absorption and carrier concentrations are interdependent.
output_writer (
OutputWriter) – Ifoutput_writeris a string, it is used as a filename to be passed to the defaultOutputWriterobject. Ifoutput_writeris an object inherited fromOutputWriter, this object will be used instead. If None, then no output is written. Output will be written after each target_value is solved.
- solver_class¶
alias of
NewtonSolver
- solver_parameters = None¶
- to_save_objects¶
- class simudo.physics.steppers.OpticalIntensityAdaptiveStepper(**kwargs)[source]¶
Bases:
NonequilibriumCoupledConstantStepperAdaptively increase the optical intensity by increasing
optical.Optical.Phi_scale.- constants¶
- parameter_name = 'I'¶
- parameter_target_values¶
- parameter_unit¶
- run_optics = True¶
- step_size = 1e-30¶
- update_parameter_failure_factor = 0.2¶
- update_parameter_success_factor = 3¶
- class simudo.physics.steppers.OpticalIntensityLogDampStepper(**kwargs)[source]¶
Bases:
OpticalIntensityAdaptiveStepperOptical itensity stepper with log damping parameter updates
- solver_class¶
alias of
NewtonSolverLogDamping
- class simudo.physics.steppers.UniformGenerationAdaptiveStepper(**kwargs)[source]¶
Bases:
NonequilibriumCoupledConstantStepperAdaptively ramp a prescribed generation rate, without solving optics.
Ramps
pdd.uniform_generation_scale– a dimensionlessdolfin.Constant– from its initial value up to1.0. No optical problem is solved (selfconsistent_opticsis False), which makes this much cheaper thanOpticalIntensityAdaptiveStepperwhen the generation profile is known in advance and only its magnitude needs to be brought up from zero.Two things the user must do, neither of which happens automatically:
Set
pdd.uniform_generation_scalebefore constructing the stepper. It does not exist otherwise, and its absence raisesAttributeErrorwhenconstantsis first evaluated.Build the generation spatial rule out of the same
dolfin.Constantobject. The stepper only assigns to that Constant; if the generation rule does not reference it, ramping the parameter has no effect on the solution.
Example
generation_scale = dolfin.Constant(0) pdd.uniform_generation_scale = generation_scale * U.dimensionless # profile1 may be any fixed spatial profile; generation_scale is the # same Constant object assigned above, and is what gets ramped. spatial.add_rule("static_cv/generation", R.domain, profile1 * generation_scale) pdd.easy_add_electro_optical_process( StaticGeneration, name='static_cv', dst_band=CB, src_band=VB) stepper = UniformGenerationAdaptiveStepper(solution=full_problem, ...) stepper.do_loop()
The spatial key prefix must match the process
name:StaticGenerationreads<name>/generation, soname='static_cv'pairs with the rule"static_cv/generation"above.uniformin the class and attribute names is historical. The profile need not be uniform – it need only be fixed in shape while its magnitude is ramped.- constants¶
- parameter_name = 'G'¶
- parameter_target_values¶
- parameter_unit¶
- selfconsistent_optics = False¶
- step_size = 1e-10¶
- update_parameter_failure_factor = 0.5¶
- update_parameter_success_factor = 3¶
- class simudo.physics.steppers.VoltageStepper(**kwargs)[source]¶
Bases:
NonequilibriumCoupledConstantStepperStarting from an existing solution, which may be at thermal equilibrium or with previously applied bias of illumination, ramp the bias at one or more contacts.
- parameter_name = 'V'¶
- run_optics = False¶
- step_size = 0.1¶
- update_parameter_failure_factor = 0.5¶
- update_parameter_success_factor = 1.5¶