Source code for solcore.absorption_calculator.absorption_QW

from solcore.constants import *
from numpy import array
import numpy as np
from solcore.science_tracker import science_reference

H = lambda x: 0 if x < 0 else 1  ### blindly changed this !!
D = lambda x, width: 1 if (x >= -width) and (x <= width) else 0  # Delta function
L = lambda x, centre, hwhm: 1 / pi * (0.5 * hwhm) / (
    (x - centre) ** 2 + (0.5 * hwhm) ** 2)  # Lorenzian (area normalised to 1)
Gauss = lambda x, centre, hwhm: 1 / np.sqrt(2 * pi) / (0.5 * hwhm) * np.exp(
    -0.5 * (x - centre) ** 2 / (0.5 * hwhm) ** 2)  # Gaussian (area normalised to 1)


[docs]def exciton_rydberg_energy_2d(me, mh, eps_r): """ :param me: electron effective mass (units: kg) :param mh: hole effective mass (units: kg) :param eps_r: dielectic constant (units: SI) :return: The exciton Rydberg energy """ science_reference("Definition of the exciton Rydberg Energy for a quantum well.", "S. L. Chuang, Physics of Optoelectonic Devices, Second Edition, p.554, Table 13.1") mr = me * mh / (me + mh) # reduced effective mass if True: return mr * q ** 4 / (2 * hbar ** 2 * (4 * np.pi * eps_r * vacuum_permittivity) ** 2) Ry = 13.6 * 1.6e-19 m0 = electron_mass Ry_eff = (mr / m0) * Ry / eps_r ** 2 # Effective Rydberg return Ry_eff
[docs]def exciton_bohr_radius(me, mh, eps): """ :param me: electron effective mass (units: kg) :param mh: hole effective mass (units: kg) :param eps: dielectic constant (units: SI) :return: Exciton Borh radius """ science_reference("Definition of the exciton bohr radius for a quantum well.", "S. L. Chuang, Physics of Optoelectonic Devices, Second Edition, p.554, Table 13.1") mr = me * mh / (me + mh) # reduced effective mass return hbar ** 2 / mr * (4 * np.pi * eps / q ** 2)
[docs]def alpha_c_hh_TE(E, z, E_e, E_hh, psi_e, psi_hh, well_width, me, mhh, Ep, nr): """ Absortion coefficient for incident light forming a transision between hh and c band of a quantum well NB. Assumes that valence band is a zero energy, might need to manually apply an offset. :param E: photon energy (units: J) :param z: mesh points along growth direction (units: m) :param E_e: Electron state energy (units: J) :param E_hh: Heavy hole state energy (units: J) :param psi_e: Electron envelope function (psi_e^2 must be normalised) :param psi_hh: Heavy hole envelope function (psi_hh^2 must be normalised) :param well_width: (units: m) :param me: electron effective mass (units: kg) :param mhh: heavy hole effective mass (units: kg) :param Ep: the Kane parameter "Optical dipole matrix elemet", sometimes "Momentum matrix element", e.g. Ep for GaAs ~ 28eV :param nr: refractive index :return: """ m0 = electron_mass C0 = np.pi * q ** 2 / (nr * c * vacuum_permittivity * m0 ** 2 * E / hbar) mr = me * mhh / (me + mhh) # reduced effective mass DOS_2D = mr / (np.pi * hbar ** 2 * well_width) Mbsq_3D = m0 / 6 * Ep Mbsq_2D = 3 / 2 * Mbsq_3D Ieh = np.trapz(psi_e * psi_hh, z) ** 2 return C0 * Ieh * Mbsq_2D * DOS_2D * H(E - (E_e - E_hh))
[docs]def alpha_c_lh_TE(E, z, E_e, E_lh, psi_e, psi_lh, well_width, me, mlh, Ep, nr): """ Absortion coefficient for incident light forming a transision between hh and c band of a quantum well NB. Assumes that valence band is a zero energy, might need to manually apply an offset. :param E: photon energy (units: J) :param z: mesh points along growth direction (units: m) :param E_e: Electron state energy (units: J) :param E_hh: Heavy hole state energy (units: J) :param psi_e: Electron envelope function (psi_e^2 must be normalised) :param psi_hh: Heavy hole envelope function (psi_hh^2 must be normalised) :param well_width: (units: m) :param me: electron effective mass (units: kg) :param mhh: heavy hole effective mass (units: kg) :param Ep: the Kane parameter "Optical dipole matrix elemet", sometimes "Momentum matrix element", e.g. Ep for GaAs ~ 28eV :param nr: refractive index :return: """ m0 = electron_mass C0 = np.pi * q ** 2 / (nr * c * vacuum_permittivity * m0 ** 2 * E / hbar) mr = me * mlh / (me + mlh) # reduced effective mass DOS_2D = mr / (np.pi * hbar ** 2 * well_width) Mbsq_3D = m0 / 6 * Ep Mbsq_2D = 1 / 2 * Mbsq_3D Ieh = np.trapz(psi_e * psi_lh, z) ** 2 return C0 * Ieh * Mbsq_2D * DOS_2D * H(E - (E_e - E_lh))
[docs]def alpha_exciton_ehh_TE(exciton_index, E, z, E_e, E_hh, psi_e, psi_hh, well_width, me, mhh, Ep, nr, eps, hwhm=6e-3 * 1.6e-19, dimensionality=0.15, line_shape="Lorenzian"): """ :param exciton_index: :param E: :param z: :param E_e: :param E_hh: :param psi_e: :param psi_hh: :param well_width: :param me: :param mhh: :param Ep: :param nr: :param eps: :param hwhm: :param dimensionality: :param line_shape: :return: """ if exciton_index < 1: raise ValueError("The excition index must start on 1.") if dimensionality < 0 or dimensionality > 0.5: raise ValueError("The dimensionality parameter of the exciton must be a number between 0 and 0.5 (inclusive).") # Borrow constants from the bound-to-bound calculation m0 = electron_mass C0 = np.pi * q ** 2 / (nr * c * vacuum_permittivity * m0 ** 2 * E / hbar) mr = me * mhh / (me + mhh) # reduced effective mass DOS_2D = mr / (np.pi * hbar ** 2 * well_width) Mbsq_3D = m0 / 6 * Ep Mbsq_2D = 3 / 2 * Mbsq_3D Ieh = np.trapz(psi_e * psi_hh, z) ** 2 # Excitions are considered by modiftying the bulk absorption coefficient using an oscillator strength Ry_eff = exciton_rydberg_energy_2d(me, mhh, eps / vacuum_permittivity) En = -Ry_eff / ((exciton_index - dimensionality) ** 2) # Exciton binding energy Et = (E_e - E_hh) # import pdb; pdb.set_trace() # NOTE TO MARKUS: Added the possiblity of using a Gauss lineshape if line_shape is "Gauss": shape = Gauss(E, Et + En, hwhm) else: shape = L(E, Et + En, hwhm) # NOTE TO MARKUS: It seems that there was a factor 2 missing in the oscilator strength as well as the exciton index. # See: P C Klipstein and N Apsley 1986 J. Phys. C: Solid State Phys. 19 6461 doi:10.1088/0022-3719/19/32/020 oscillator_strength = (2 * Ry_eff / (exciton_index - dimensionality) ** 3) return C0 * Ieh * Mbsq_2D * DOS_2D * oscillator_strength * shape
[docs]def alpha_exciton_elh_TE(exciton_index, E, z, E_e, E_lh, psi_e, psi_lh, well_width, me, mlh, Ep, nr, eps, hwhm=6e-3 * 1.6e-19, dimensionality=0.15, line_shape="Lorenzian"): """ :param exciton_index: :param E: :param z: :param E_e: :param E_lh: :param psi_e: :param psi_lh: :param well_width: :param me: :param mlh: :param Ep: :param nr: :param eps: :param hwhm: :param dimensionality: :param line_shape: :return: """ if exciton_index < 1: raise ValueError("The excition index must start on 1.") if dimensionality < 0 or dimensionality > 0.5: raise ValueError("The dimensionality parameter of the exciton must be a number between 0 and 0.5 (inclusive).") # Borrow constants from the bound-to-bound calculation m0 = electron_mass C0 = np.pi * q ** 2 / (nr * c * vacuum_permittivity * m0 ** 2 * E / hbar) mr = me * mlh / (me + mlh) # reduced effective mass DOS_2D = mr / (np.pi * hbar ** 2 * well_width) Mbsq_3D = m0 / 6 * Ep Mbsq_2D = 1 / 2 * Mbsq_3D Ieh = np.trapz(psi_e * psi_lh, z) ** 2 # Excitions are considered by modiftying the bulk absorption coefficient using an oscillator strength Ry_eff = exciton_rydberg_energy_2d(me, mlh, eps / vacuum_permittivity) En = -Ry_eff / ((exciton_index - dimensionality) ** 2) # Exciton binding energy Et = (E_e - E_lh) # NOTE TO MARKUS: Added the possiblity of using a Gauss lineshape if line_shape is "Gauss": shape = Gauss(E, Et + En, hwhm) else: shape = L(E, Et + En, hwhm) # NOTE TO MARKUS: It seems that there was a factor 2 missing in the oscilator strength as well as the exciton index. # See: P C Klipstein and N Apsley 1986 J. Phys. C: Solid State Phys. 19 6461 doi:10.1088/0022-3719/19/32/020 oscillator_strength = (2 * Ry_eff / (exciton_index - dimensionality) ** 3) return C0 * Ieh * Mbsq_2D * DOS_2D * oscillator_strength * shape
[docs]def sum_alpha_c_hh_TE(E, z, E_e, E_hh, psi_e, psi_hh, well_width, me, mh, Ep, nr): """ :param E: :param z: :param E_e: :param E_hh: :param psi_e: :param psi_hh: :param well_width: :param me: :param mh: :param Ep: :param nr: :return: """ alpha = 0 for ee, pe in zip(E_e, psi_e): for eh, ph in zip(E_hh, psi_hh): alpha += alpha_c_hh_TE(E, z, ee, eh, pe, ph, well_width, me, mh, Ep, nr) return alpha
[docs]def sum_alpha_c_lh_TE(E, z, E_e, E_lh, psi_e, psi_lh, well_width, me, mh, Ep, nr): """ :param E: :param z: :param E_e: :param E_lh: :param psi_e: :param psi_lh: :param well_width: :param me: :param mh: :param Ep: :param nr: :return: """ alpha = 0 for ee, pe in zip(E_e, psi_e): for eh, ph in zip(E_lh, psi_lh): alpha += alpha_c_lh_TE(E, z, ee, eh, pe, ph, well_width, me, mh, Ep, nr) return alpha
[docs]def sum_alpha_exciton_c_hh_TE(E, z, E_e, E_hh, psi_e, psi_hh, well_width, me, mh, Ep, nr, eps, hwhm=6e-3 * 1.6e-19, dimensionality=0.5, line_shape="Lorenzian"): """ :param E: :param z: :param E_e: :param E_hh: :param psi_e: :param psi_hh: :param well_width: :param me: :param mh: :param Ep: :param nr: :param eps: :param hwhm: :param dimensionality: :param line_shape: :return: """ alpha = 0 eh_pairs_with_zero_angular_momentum = zip(range(len(E_e)), range(len(E_hh))) # l=0 for optically allowed transitions for exciton_index, eh_quantum_numbers in enumerate(eh_pairs_with_zero_angular_momentum): e_index = eh_quantum_numbers[0] hh_index = eh_quantum_numbers[1] ee = E_e[e_index] ehh = E_hh[hh_index] pe = psi_e[e_index] phh = psi_hh[e_index] alpha += alpha_exciton_ehh_TE(exciton_index + 1, E, z, ee, ehh, pe, phh, well_width, me, mh, Ep, nr, eps, hwhm=hwhm, dimensionality=dimensionality, line_shape=line_shape) return alpha
[docs]def sum_alpha_exciton_c_lh_TE(E, z, E_e, E_lh, psi_e, psi_lh, well_width, me, mlh, Ep, nr, eps, hwhm=6e-3 * 1.6e-19, dimensionality=0.5, line_shape="Lorenzian"): """ :param E: :param z: :param E_e: :param E_lh: :param psi_e: :param psi_lh: :param well_width: :param me: :param mlh: :param Ep: :param nr: :param eps: :param hwhm: :param dimensionality: :param line_shape: :return: """ alpha = 0 eh_pairs_with_zero_angular_momentum = zip(range(len(E_e)), range(len(E_lh))) # l=0 for optically allowed transitions for exciton_index, eh_quantum_numbers in enumerate(eh_pairs_with_zero_angular_momentum): e_index = eh_quantum_numbers[0] lh_index = eh_quantum_numbers[1] ee = E_e[e_index] elh = E_lh[lh_index] pe = psi_e[e_index] plh = psi_lh[e_index] alpha += alpha_exciton_elh_TE(exciton_index + 1, E, z, ee, elh, pe, plh, well_width, me, mlh, Ep, nr, eps, hwhm=hwhm, dimensionality=dimensionality, line_shape=line_shape) return alpha
[docs]def calc_alpha(QM_result, well_width, kane_parameter=28 * 1.6e-19, refractive_index=3.5, hwhm=6e-3 * 1.6e-19, dimensionality=0.5, theta=0, eps=12.9 * vacuum_permittivity, espace=None, line_shape="Lorenzian"): """ Calculates the absorption coeficient of a quantum well structure assuming the parabolic approximation for the effective masses. :param QM_result: The output of the Schrodinger solver, incldued in the 'quantum_mechanics' package :param well_width: The well width :param kane_parameter: The Kane parameter :param refractive_index: Refractive (effective) index of the QW :param hwhm: Full width at half maximum of the excitonic lineshape :param dimensionality: :param theta: :param eps: :param espace: :param line_shape: :return: """ results = QM_result # We pick the effective mass at the center of the structure as THE efective mass of the QW points = len(results["effective_masses"]["me"]) me = results["effective_masses"]["me"][round(points / 2.0)] try: mhh = results["effective_masses"]["mhh"][round(points / 2.0)] mlh = results["effective_masses"]["mlh"][round(points / 2.0)] except KeyError: # If the calculation mode for the bands is kp4x4 or kp6x6, we have to use the effective mass transverse to the # growth direction (in the QW plane). mhh = results["effective_masses"]["mhh_t"][round(points / 2.0)] mlh = results["effective_masses"]["mlh_t"][round(points / 2.0)] # print (results["effective_masses"]["me"][round(points/2.0)]) # print (results["effective_masses"]["mhh"][round(points/2.0)]) # print (results["effective_masses"]["mlh"][round(points/2.0)]) result_c_hh_TE = [] result_c_lh_TE = [] result_ex_c_hh_TE = [] result_ex_c_lh_TE = [] for e in espace: c_hh = sum_alpha_c_hh_TE(e, results['x'], results['E']['Ee'], results['E']['Ehh'], results["wavefunctions"]['psi_e'], results["wavefunctions"]['psi_hh'], well_width, me, mhh, kane_parameter, refractive_index) c_lh = sum_alpha_c_lh_TE(e, results['x'], results['E']['Ee'], results['E']['Elh'], results["wavefunctions"]['psi_e'], results["wavefunctions"]['psi_lh'], well_width, me, mlh, kane_parameter, refractive_index) ex_c_hh = sum_alpha_exciton_c_hh_TE(e, results['x'], results['E']['Ee'], results['E']['Ehh'], results["wavefunctions"]['psi_e'], results["wavefunctions"]['psi_hh'], well_width, me, mhh, kane_parameter, refractive_index, eps, hwhm=hwhm, dimensionality=dimensionality, line_shape=line_shape) ex_c_lh = sum_alpha_exciton_c_lh_TE(e, results['x'], results['E']['Ee'], results['E']['Elh'], results["wavefunctions"]['psi_e'], results["wavefunctions"]['psi_lh'], well_width, me, mlh, kane_parameter, refractive_index, eps, hwhm=hwhm, dimensionality=dimensionality, line_shape=line_shape) result_c_hh_TE.append(c_hh) result_c_lh_TE.append(c_lh) result_ex_c_hh_TE.append(ex_c_hh) result_ex_c_lh_TE.append(ex_c_lh) result_c_hh_TE = array(result_c_hh_TE) result_c_lh_TE = array(result_c_lh_TE) result_c_lh_TM = 4 * array(result_c_lh_TE) result_ex_c_hh_TE = array(result_ex_c_hh_TE) result_ex_c_lh_TE = array(result_ex_c_lh_TE) result_ex_c_lh_TM = 4 * array(result_ex_c_lh_TE) result_TE_raw = result_c_hh_TE + result_c_lh_TE + result_ex_c_hh_TE + result_ex_c_lh_TE result_TE = result_TE_raw * (np.cos(theta) ** 2 + 0.5 * np.sin(theta) ** 2) result_TM_raw = result_c_lh_TM + result_ex_c_lh_TM result_TM = 0.5 * result_TM_raw * np.sin(theta) ** 2 result_sum = result_TE + result_TM return espace, result_sum, result_TE, result_TM, result_TE_raw, result_TM_raw
[docs]def NonBlackBodyEmission(E, voltage=0, nr=3.5, T=300): """ :param E: :param voltage: :param nr: :param T: :return: """ A = 2 * nr ** 2 / h ** 3 / c ** 2 B = (E - q * voltage) / kb / T bb = A * E ** 2 / (np.exp(B) - 1) return bb
[docs]def calc_emission(QM_result, well_width, voltage=0, theta=0): """ :param QM_result: :param well_width: :param voltage: :param theta: :return: """ alfa = QM_result["alpha"] aTE = alfa[4] aTM = alfa[5] result_TE = [] result_TM = [] result = [] for index, e in enumerate(alfa[0]): bb = NonBlackBodyEmission(e) TE = bb * (1 - np.exp(-aTE[index] * well_width * (np.cos(theta) ** 2 + 0.5 * np.sin(theta) ** 2))) TM = bb * (1 - np.exp(-aTM[index] * well_width * 0.5 * np.sin(theta) ** 2)) # All = bb*(1-np.exp(-(aTE[index]+aTM[index])*well_width)) All = TE + TM result_TE.append(TE) result_TM.append(TM) result.append(All) result_TE = array(result_TE) result_TM = array(result_TM) result = array(result) return alfa[0], result, result_TE, result_TM