Source code for sesame.observables

# Copyright 2017 University of Maryland.
#
# This file is part of Sesame. It is subject to the license terms in the file
# LICENSE.rst found in the top-level directory of this distribution.

from numpy import exp
import numpy as np


[docs]def get_n(sys, efn, v, sites): """ Compute the electron density on the given sites. Parameters ---------- sys: Builder The discretized system. efn: numpy array of floats Values of the electron quasi-Fermi level. v: numpy array of floats Values of the electrostatic potential. sites: list of integers The sites where the electron density should be computed. Returns ------- n: numpy array """ n = sys.Nc[sites] * exp(+sys.bl[sites] + efn[sites] + v[sites]) return n
[docs]def get_p(sys, efp, v, sites): """ Compute the hole density on the given sites. Parameters ---------- sys: Builder The discretized system. efp: numpy array of floats Values of the hole quasi-Fermi level. v: numpy array of floats Values of the electrostatic potential. sites: list of integers The sites where the hole density should be computed. Returns ------- p: numpy array """ bl = sys.bl[sites] Eg = sys.Eg[sites] Nv = sys.Nv[sites] p = Nv * exp(-Eg - bl - efp[sites] - v[sites]) return p
def get_bulk_rr(sys, n, p): # Compute the bulk recombination of the entire system for SRH, radiative and # Auger mechanisms ni2 = sys.ni ** 2 _np = n * p r = (_np - ni2) / (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) \ + (sys.Cn * n + sys.Cp * p) * (_np - ni2) \ + sys.B * (_np - ni2) return r def get_bulk_rr_derivs(sys, n, p): ni2 = sys.ni ** 2 _np = n * p defn = (_np * (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) - (_np - ni2) * n * sys.tau_h) \ / (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) ** 2 \ + sys.Cn * n * (2 * _np - ni2) + sys.Cp * _np * p \ + sys.B * _np defp = -(_np * (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) - (_np - ni2) * p * sys.tau_e) \ / (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) ** 2 \ + sys.Cn * n * _np + sys.Cp * p * (2 * _np - ni2) \ + sys.B * _np dv = (_np - ni2) * (sys.tau_e * p - sys.tau_h * n) \ / (sys.tau_h * (n + sys.n1) + sys.tau_e * (p + sys.p1)) ** 2 \ + sys.Cn * n * (_np - ni2) - sys.Cp * p * (_np - ni2) return defn, defp, dv
[docs]def get_jn(sys, efn, v, sites_i, sites_ip1, dl): """ Compute the electron current between sites ``site_i`` and ``sites_ip1``. Parameters ---------- sys: Builder The discretized system. efn: numpy array of floats Values of the electron quasi-Fermi level for the entire system (as given by the drift diffusion Poisson solver). v: numpy array of floats Values of the electrostatic potential for the entire system (as given by the drift diffusion Poisson solver). sites_i: list of integers Indices of the sites the current is coming from. sites_ip1: list of integers Indices of the sites the current is going to. dl: numpy arrays of floats Lattice distances between sites ``sites_i`` and sites ``sites_ip1``. Returns ------- jn: numpy array of floats """ # tol1 controls the minimum value of dv. all values less than tol1 are set equal to tol1 tol1 = 1e-12 # tol2 controls threshold for taylor series expansion of jp in terms of dv0: series expansion is used if dv0<tol2 tol2 = 1e-5 # tol3 controls threshold for taylor series expansion of jp in terms of defp: series expansion is used if defp<tol3 tol3 = 1e-9 # this description of tol variables applies for the jp function, and jn and jp derivative functions vp0 = v[sites_i] + sys.bl[sites_i] + np.log(sys.Nc[sites_i]) dv = vp0 - (v[sites_ip1] + sys.bl[sites_ip1] + np.log(sys.Nc[sites_ip1])) dv0 = dv dv = dv + (np.abs(dv) < tol1) * tol1 efnp0 = efn[sites_i] efnp1 = efn[sites_ip1] defn = efnp1 - efnp0 mu = sys.mu_e[sites_i] jn = ( mu * exp(efnp1)*(1 - exp(efnp0-efnp1)) / dl * dv / (-exp(-vp0) * (1 - exp(dv))) * (np.abs(dv0) >= tol2) + \ -1 * mu * exp(efnp1)*(1 - exp(efnp0-efnp1)) / dl / (-exp(-vp0) * (1 + .5 * dv0 + 1/6.*(dv0)**2)) * (np.abs(dv0) < tol2)) * (np.abs(defn)>=tol3) + \ ( mu * exp(efnp1)*(-(efnp0 - efnp1)) / dl * dv / (-exp(-vp0) * (1 - exp(dv))) * (np.abs(dv0) >= tol2) + \ -1 * mu * exp(efnp1)*(-(efnp0 - efnp1)) / dl / (-exp(-vp0) * (1 + .5 * dv0 + 1 / 6. * (dv0) ** 2)) * (np.abs(dv0) < tol2)) * (np.abs(defn) < tol3) return jn
[docs]def get_jp(sys, efp, v, sites_i, sites_ip1, dl): """ Compute the hole current between sites ``site_i`` and ``sites_ip1``. Parameters ---------- sys: Builder The discretized system. efp: numpy array of floats Values of the hole quasi-Fermi level for the entire system (as given by the drift diffusion Poisson solver). v: numpy array of floats Values of the electrostatic potential for the entire system (as given by the drift diffusion Poisson solver). sites_i: list of integers Indices of the sites the current is coming from. sites_ip1: list of integers Indices of the sites the current is going to. dl: numpy arrays of floats Lattice distances between sites ``sites_i`` and sites ``sites_ip1``. Returns ------- jp: numpy array of floats """ tol1 = 1e-12 tol2 = 1e-5 tol3 = 1e-9 vp0 = v[sites_i] + sys.bl[sites_i] + sys.Eg[sites_i] - np.log(sys.Nv[sites_i]) dv = vp0 - (v[sites_ip1] + sys.bl[sites_ip1] + sys.Eg[sites_ip1] - np.log(sys.Nv[sites_ip1])) dv0 = dv dv = dv + (np.abs(dv) < tol1) * tol1 efpp0 = -efp[sites_i] efpp1 = -efp[sites_ip1] defp = efpp1 - efpp0 mu = sys.mu_h[sites_i] jp = (mu * exp(efpp1) * (1 - exp(efpp0-efpp1)) / dl * dv / (-exp(vp0) * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ mu * exp(efpp1) * (1 - exp(efpp0-efpp1)) / dl * 1 / (-exp(vp0) * (1 - .5*(dv0) + 1/6.*(dv0)**2.)) * (np.abs(dv0) < tol2)) * (np.abs(defp) >= tol3) + \ (mu * exp(efpp1) * ( -(efpp0 - efpp1)) / dl * dv / (-exp(vp0) * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ mu * exp(efpp1) * ( -(efpp0 - efpp1)) / dl * 1 / (-exp(vp0) * (1 - .5 * (dv0) + 1 / 6. * (dv0) ** 2.)) * (np.abs(dv0) < tol2)) * (np.abs(defp) < tol3) return jp
def get_jn_derivs(sys, efn, v, sites_i, sites_ip1, dl): tol1 = 1e-12 tol2 = 1e-5 tol3 = 1e-9 vp0 = v[sites_i] + sys.bl[sites_i] + np.log(sys.Nc[sites_i]) vp1 = v[sites_ip1] + sys.bl[sites_ip1] + np.log(sys.Nc[sites_ip1]) dv = vp0 - vp1 dv0 = dv dv = dv + (np.abs(dv) < tol1) * tol1 efnp0 = efn[sites_i] efnp1 = efn[sites_ip1] defn = efnp1 - efnp0 mu = sys.mu_e[sites_i] ev0 = exp(-vp0) ep1 = exp(efnp1) ep0 = exp(efnp0) defn_i = (1. / dl * exp(efnp0 + vp0) * (dv) / (1 - exp(dv)) * (np.abs(dv0) >= tol2) + \ -1. / dl * exp(efnp0 + vp0) / (1 + .5*dv0 + 1/6.*dv0**2) * (np.abs(dv0) < tol2)) * (np.abs(defn) >= tol3) + \ (1. * exp(efnp1) / dl * exp(vp0) * (dv) / (1 - exp(dv)) * (np.abs(dv0) >= tol2) + \ -1. * exp(efnp1) / dl * exp(vp0) / (1 + .5 * dv0 + 1 / 6. * dv0 ** 2) * (np.abs(dv0) < tol2)) * (np.abs(defn) < tol3) defn_ip1 = (-1. / dl * exp(efnp1 + vp0) * (dv) / (1 - exp(dv)) * (np.abs(dv0) >= tol2) + \ 1. / dl * exp(efnp1 + vp0) / (1 + .5*dv0 + 1/6.*dv0**2) * (np.abs(dv0) < tol2)) * (np.abs(defn) >= tol3) + \ (-1. * exp(efnp1) *(1-(efnp0 - efnp1))/ dl * exp(vp0) * (dv) / (1 - exp(dv)) * (np.abs(dv0) >= tol2) + \ 1. * exp(efnp1) *(1-(efnp0 - efnp1))/ dl * exp(vp0) / (1 + .5 * dv0 + 1 / 6. * dv0 ** 2) * (np.abs(dv0) < tol2)) * (np.abs(defn) < tol3) dv_i = (-exp(efnp1)*(1 - exp(efnp0-efnp1)) / dl * ev0 * (1 + dv - exp(dv)) / (ev0 ** 2 * (exp(dv) - 1) ** 2) * (np.abs(dv0) >= tol2) + \ -6*exp(vp0) * exp(efnp1)*(1 - exp(efnp0-efnp1)) / dl * (3 + vp0 + vp0**2 - 2*vp0*vp1 + vp1*(-1 + vp1)) \ / (6 + vp0**2 + vp0*(3 - 2*vp1) + vp1*(-3 + vp1))**2 * (np.abs(dv0) < tol2)) * (np.abs(defn)>=tol3) + \ (-exp(efnp1) * ( -(efnp0 - efnp1)) / dl * ev0 * (1 + dv - exp(dv)) / (ev0 ** 2 * (exp(dv) - 1) ** 2) * (np.abs(dv0) >= tol2) + \ -6 * exp(vp0) * exp(efnp1) * (-(efnp0 - efnp1)) / dl * (3 + vp0 + vp0 ** 2 - 2 * vp0 * vp1 + vp1 * (-1 + vp1)) \ / (6 + vp0 ** 2 + vp0 * (3 - 2 * vp1) + vp1 * (-3 + vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defn) < tol3) dv_ip1 = (-1. / dl * exp(efnp1)*(1 - exp(efnp0-efnp1)) * exp(-vp1) * (1 - dv - exp(-dv)) / (exp(-2 * vp1) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ -6 * exp(vp0) * exp(efnp1)*(1 - exp(efnp0-efnp1)) / dl * (3 + 2*vp0 - 2*vp1)\ / (6 + vp0**2 + vp0*(3 - 2*vp1) + vp1*(-3 + vp1))**2 * (np.abs(dv0) < tol2)) * (np.abs(defn) >= tol3) + \ (-1. / dl * exp(efnp1) * (-(efnp0 - efnp1)) * exp(-vp1) * (1 - dv - exp(-dv)) / (exp(-2 * vp1) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ -6 * exp(vp0) * exp(efnp1) * (-(efnp0 - efnp1)) / dl * (3 + 2 * vp0 - 2 * vp1) \ / (6 + vp0 ** 2 + vp0 * (3 - 2 * vp1) + vp1 * (-3 + vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defn) < tol3) return mu * defn_i, mu * defn_ip1, mu * dv_i, mu * dv_ip1 def get_jp_derivs(sys, efp, v, sites_i, sites_ip1, dl): tol1 = 1e-12 tol2 = 1e-5 tol3 = 1e-9 vp0 = v[sites_i] + sys.bl[sites_i] + sys.Eg[sites_i] - np.log(sys.Nv[sites_i]) vp1 = v[sites_ip1] + sys.bl[sites_ip1] + sys.Eg[sites_ip1] - np.log(sys.Nv[sites_ip1]) dv = vp0 - vp1 dv0 = dv dv = dv + (np.abs(dv) < tol1) * tol1 efpp0 = -efp[sites_i] efpp1 = -efp[sites_ip1] defp = efpp1 - efpp0 mu = sys.mu_h[sites_i] ev0 = exp(vp0) ep1 = exp(efpp1) ep0 = exp(efpp0) defp_i = -(exp(efpp0 - vp0) * dv / (dl * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ exp(efpp0 - vp0) / (dl) / (1 - .5*(vp0-vp1) + 1/6.*(vp0-vp1)**2.) * (np.abs(dv0) < tol2)) * (np.abs(defp)>=tol3) + \ -(exp(efpp1) * exp(-vp0) * dv / (dl * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ exp(efpp1) * exp(-vp0) / (dl) / (1 - .5 * (vp0 - vp1) + 1 / 6. * (vp0 - vp1) ** 2.) * (np.abs(dv0) < tol2)) * (np.abs(defp) < tol3) defp_ip1 = -(-exp(efpp1 - vp0) * dv / (dl * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ -exp(efpp1 - vp0) / (dl) / (1 - .5*(vp0-vp1) + 1/6.*(vp0-vp1)**2.) * (np.abs(dv0) < tol2)) * (np.abs(defp)>=tol3) + \ -(-exp(efpp1) * exp(-vp0)*(1-(efpp0 - efpp1)) * dv / (dl * (1 - exp(-dv))) * (np.abs(dv0) >= tol2) + \ -exp(efpp1) * exp(-vp0)*(1-(efpp0 - efpp1)) / (dl) / (1 - .5*(vp0-vp1) + 1/6.*(vp0-vp1)**2.) * (np.abs(dv0) < tol2)) * (np.abs(defp) < tol3) dv_i = (-exp(efpp0)*(1 - exp(efpp1-efpp0)) * ev0 * (exp(-dv) + (-1 + dv)) / (dl * exp(2 * vp0) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ -6* exp(efpp0)*(1 - exp(efpp1-efpp0)) / dl * (-exp(-vp0)) * (3 + (-1 + vp0)*vp0 + vp1 - 2*vp0*vp1 + vp1**2) \ / (6 + vp0**2 + vp1*(3+vp1) - vp0*(3 + 2*vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defp) >= tol3) + \ (-exp(efpp0) * (-(efpp1 - efpp0)) * ev0 * (exp(-dv) + (-1 + dv)) / (dl * exp(2 * vp0) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ -6 * exp(efpp0) * (-(efpp1 - efpp0)) / dl * (-exp(-vp0)) * (3 + (-1 + vp0) * vp0 + vp1 - 2 * vp0 * vp1 + vp1 ** 2) \ / (6 + vp0 ** 2 + vp1 * (3 + vp1) - vp0 * (3 + 2 * vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defp) < tol3) dv_ip1 = (-exp(efpp0)*(1 - exp(efpp1-efpp0)) * ev0 * (1 + exp(-dv) * (-1 - dv)) / (dl * exp(2 * vp0) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ 6 * exp(efpp0)*(1 - exp(efpp1-efpp0)) / dl * (-exp(-vp0)) * (-3 + 2*vp0 - 2*vp1) \ / (6 + vp0 ** 2 + vp1 * (3 + vp1) - vp0 * (3 + 2 * vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defp) >= tol3) + \ (-exp(efpp0) * (-(efpp1 - efpp0)) * ev0 * (1 + exp(-dv) * (-1 - dv)) / (dl * exp(2 * vp0) * (1 - exp(-dv)) ** 2) * (np.abs(dv0) >= tol2) + \ 6 * exp(efpp0) * (-(efpp1 - efpp0)) / dl * (-exp(-vp0)) * (-3 + 2 * vp0 - 2 * vp1) \ / (6 + vp0 ** 2 + vp1 * (3 + vp1) - vp0 * (3 + 2 * vp1)) ** 2 * (np.abs(dv0) < tol2)) * (np.abs(defp) < tol3) return mu * defp_i, mu * defp_ip1, mu * dv_i, mu * dv_ip1 def get_srh_rr_derivs(sys, n, p, n1, p1, tau_e, tau_h): ni2 = n1 * p1 _np = n * p defn = (_np * (tau_h * (n + n1) + tau_e * (p + p1)) - (_np - ni2) * n * tau_h) \ / (tau_h * (n + n1) + tau_e * (p + p1)) ** 2 defp = -(_np * (tau_h * (n + n1) + tau_e * (p + p1)) - (_np - ni2) * p * tau_e) \ / (tau_h * (n + n1) + tau_e * (p + p1)) ** 2 dv = (_np - ni2) * (tau_e * p - tau_h * n) / (tau_h * (n + n1) + tau_e * (p + p1)) ** 2 return defn, defp, dv