def runTest4(): rhoGBlist = np.linspace(1e6*1e-4,1e18*1e-4,2) sys = system(rhoGBlist[0]) solution = sesame.solve_equilibrium(sys, periodic_bcs=False, verbose=False) s0 = 1e-18*1e4 rhoGBlist = [1e6*1e-4, 1e18*1e-4] for idx, rhoGB in enumerate(rhoGBlist): sys = system(rhoGB,s0) solution = sesame.solve_equilibrium(sys, solution, maxiter=5000, periodic_bcs=False, verbose=False) veq = np.copy(solution['v']) efn = np.zeros((sys.nx * sys.ny,)) efp = np.zeros((sys.nx * sys.ny,)) solution.update({'efn': efn, 'efp': efp}) junction = .1e-6*1e2 # Define a function for the generation rate G = 1 phi0 = 1e21 * G * 1e-4 alpha = 2.3e6 * 1e-2 # alpha = 2e4 cm^-1 for CdTe f = lambda x, y: phi0 * alpha * np.exp(-alpha * x) sys.generation(f) slist = [1e-18 * 1e4] sys = system(rhoGBlist[1],slist[0]) sys.generation(f) solution = sesame.solve(sys, solution, maxiter=5000, verbose=False) az = sesame.Analyzer(sys, solution) tj = -az.full_current() voltages = np.linspace(.0, .8, 9) result = solution # sites of the right contact nx = sys.nx s = [nx - 1 + j * nx + k * nx * sys.ny for k in range(sys.nz) \ for j in range(sys.ny)] # sign of the voltage to apply if sys.rho[nx - 1] < 0: q = 1 else: q = -1 j = [] # Loop over the applied potentials made dimensionless Vapp = voltages / sys.scaling.energy for idx, vapp in enumerate(Vapp): # Apply the voltage on the right contact result['v'][s] = veq[s] + q * vapp # Call the Drift Diffusion Poisson solver result = sesame.solve(sys, result, maxiter=1000, periodic_bcs=False, verbose=False) # Compute current az = sesame.Analyzer(sys, result) tj = az.full_current() * sys.scaling.current * sys.scaling.length / (3e-6*1e2) * 1e4 j.append(tj) jcomsol = np.array([-136.07, -135.73, -135.30, -134.73, -133.61, -129.76, -119.33, -83.149, 115.90]) jcomsol = -jcomsol error = np.max(np.abs((jcomsol - np.transpose(j)) / (.5 * (jcomsol + np.transpose(j))))) print("error = {0}".format(error))
def runTest7(): L = 4e-4 # length of the system in the x-direction [m] dd = .05e-4 Ly = 2e-4 # Mesh x = np.concatenate( (np.linspace(0, 1e-4 - dd, 70, endpoint=False), np.linspace(1e-4 - dd, 1e-4 + dd, 20, endpoint=False), np.linspace(1e-4 + dd, 3e-4 - dd, 140, endpoint=False), np.linspace(3e-4 - dd, 3e-4 + dd, 20, endpoint=False), np.linspace(3e-4 + dd, L, 70))) y = np.concatenate( (np.linspace(0, 1e-4 - dd, 70, endpoint=False), np.linspace(1e-4 - dd, 1e-4 + dd, 20, endpoint=False), np.linspace(1e-4 + dd, 2e-4, 70))) #x = np.linspace(0,L, 1000) # Create a system sys = sesame.Builder(x, y) tau = 1e-8 vt = 0.025851991024560 Nc1 = 1e17 Nv1 = 1e18 Nc2 = 1e17 Nv2 = 1e18 # Dictionary with the material parameters mat1 = { 'Nc': Nc1, 'Nv': Nv1, 'Eg': 1., 'epsilon': 10, 'Et': 0, 'mu_e': 100, 'mu_h': 40, 'tau_e': tau, 'tau_h': tau, 'affinity': 4.15 } mat2 = { 'Nc': Nc2, 'Nv': Nv2, 'Eg': 1.1, 'epsilon': 100, 'Et': 0, 'mu_e': 100, 'mu_h': 40, 'tau_e': tau, 'tau_h': tau, 'affinity': 4.05 } junction = 2e-4 # extent of the junction from the left contact [m] def region1(pos): x, y = pos val = x <= 1e-4 return val def region2(pos): x, y = pos val = (x > 1e-4) & (x < 3e-4) & (y >= 1e-4) return val def region3(pos): x, y = pos val = (x > 1e-4) & (x < 3e-4) & (y < 1e-4) return val def region4(pos): x, y = pos val = x >= 3e-4 return val # Add the material to the system sys.add_material(mat1, region1) sys.add_material(mat1, region2) sys.add_material(mat2, region3) sys.add_material(mat2, region4) # Add the donors nD1 = 1e15 # [cm^-3] sys.add_donor(nD1, region1) sys.add_donor(nD1, region2) nD2 = 1e15 # [cm^-3] sys.add_acceptor(nD2, region3) sys.add_acceptor(nD2, region4) # Define the surface recombination velocities for electrons and holes [m/s] sys.contact_type('Ohmic', 'Ohmic') SS = 1e50 Sn_left, Sp_left, Sn_right, Sp_right = SS, SS, SS, SS sys.contact_S(Sn_left, Sp_left, Sn_right, Sp_right) # Electrostatic potential dimensionless solution = sesame.solve_equilibrium(sys, periodic_bcs=False, verbose=False) veq = np.copy(solution['v']) solution.update({ 'x': sys.xpts, 'y': sys.ypts, 'chi': sys.bl, 'eg': sys.Eg, 'Nc': sys.Nc, 'Nv': sys.Nv, 'epsilon': sys.epsilon }) # IV curve solution.update({ 'efn': np.zeros((sys.nx * sys.ny, )), 'efp': np.zeros((sys.nx * sys.ny, )) }) G = 1 * 1e18 f = lambda x, y: G sys.generation(f) solution = sesame.solve(sys, solution, maxiter=5000, periodic_bcs=False, verbose=False) az = sesame.Analyzer(sys, solution) tj = -az.full_current() voltages = np.linspace(.0, .8, 9) result = solution # sites of the right contact nx = sys.nx s = [nx - 1 + j * nx + k * nx * sys.ny for k in range(sys.nz) \ for j in range(sys.ny)] # sign of the voltage to apply if sys.rho[nx - 1] < 0: q = 1 else: q = -1 j = [] # Loop over the applied potentials made dimensionless Vapp = voltages / sys.scaling.energy for idx, vapp in enumerate(Vapp): # Apply the voltage on the right contact result['v'][s] = veq[s] + q * vapp # Call the Drift Diffusion Poisson solver result = sesame.solve(sys, result, maxiter=1000, periodic_bcs=False, verbose=False) # Compute current az = sesame.Analyzer(sys, result) tj = az.full_current() * sys.scaling.current * sys.scaling.length / ( 2e-4) j.append(tj) jcomsol = np.array([ 0.50272, 0.48515, 0.40623, -0.16696, -5.1204, -58.859, -819.11, -7024.4, -27657 ]) jcomsol = jcomsol * 1e-4 error = np.max( np.abs( (jcomsol - np.transpose(j)) / (.5 * (jcomsol + np.transpose(j)))))
# Define contacts: CdS contact is Ohmic, CdTe contact is Schottky Lcontact_type, Rcontact_type = 'Ohmic', 'Schottky' Lcontact_workFcn, Rcontact_workFcn = 0, 5.0 # Lcontact work function irrelevant because L contact is Ohmic # Add the contacts sys.contact_type(Lcontact_type, Rcontact_type, Lcontact_workFcn, Rcontact_workFcn) # Define the surface recombination velocities for electrons and holes [m/s] Scontact = 1.16e7 # [cm/s] # non-selective contacts Sn_left, Sp_left, Sn_right, Sp_right = Scontact, Scontact, Scontact, Scontact # This function specifies the simulation contact recombination velocity sys.contact_S(Sn_left, Sp_left, Sn_right, Sp_right) # First find the equilibrium solution result = sesame.solve_equilibrium(sys) # Add illumination phi0 = 1e17 # incoming flux [1/(cm^2 sec)] alpha = 2.3e4 # absorbtion coefficient [1/cm] # Define a function for illumination profile f = lambda x,y: phi0*alpha*np.exp(-x*alpha) # f is an "inline" function # This function adds generation to the simulation sys.generation(f) # Specify the applied voltage values voltages = np.linspace(0,1,21) # Perform I-V calculation j = sesame.IVcurve(sys, voltages, result, '1dhetero_V') j = j * sys.scaling.current
# GB defect state properties rho_GB = 1e14 # defect density [1/cm^2] S_GB = 1e-14 # capture cross section [cm^2] E_GB = 0.4 # energy of gap state from intrinsic level [eV] # Specify the two points that make the line containing additional charges p1 = (.1e-4, 1.5 * 1e-4) # [cm] p2 = (2.9e-4, 1.5 * 1e-4) # [cm] # add donor defect along GB sys.add_line_defects([p1, p2], rho_GB, S_GB, E=E_GB, transition=(1, 0)) # add acceptor defect along GB sys.add_line_defects([p1, p2], rho_GB, S_GB, E=E_GB, transition=(0, -1)) # Solve equilibirum problem first solution = sesame.solve_equilibrium(sys) # define a function for generation profile f = lambda x, y: 2.3e21 * np.exp(-2.3e4 * x) # add generation to the system sys.generation(f) # Solve problem under short-circuit current conditions solution = sesame.solve(sys, solution) # Get analyzer object to compute observables az = sesame.Analyzer(sys, solution) # Compute short-circuit current j = az.full_current() # Print Jsc print(j * sys.scaling.current * sys.scaling.length * 1e3)
def runTest2(): L = 4e-6*1e2 # length of the system in the x-direction [m] dd = .005e-6*1e2 # Mesh x = np.concatenate((np.linspace(0,L/2-dd, 100, endpoint=False), np.linspace(L/2-dd, L/2+dd, 20, endpoint=False), np.linspace(L/2+dd,L, 100))) # Create a system sys = sesame.Builder(x, input_length='cm') tau = 1e8 vt = 0.025851991024560; Nc1 = 2.2*1e18 Nv1 = 2.2*1e18 Nc2 = 2.2*1e18 Nv2 = 2.2*1e18 # Dictionary with the material parameters mat1 = {'Nc':Nc1, 'Nv':Nv1, 'Eg':1.5, 'epsilon':1000, 'Et': 0, 'mu_e':100, 'mu_h':40, 'tau_e':tau, 'tau_h':tau, 'band_offset': 4.05} mat2 = {'Nc':Nc2, 'Nv':Nv2, 'Eg':1.5, 'epsilon':10000, 'Et': 0, 'mu_e':100, 'mu_h':40, 'tau_e':tau, 'tau_h':tau, 'band_offset': 4.05} junction = 2e-6*1e2 # extent of the junction from the left contact [m] def region1(pos): return pos < junction # Add the acceptors region2 = lambda pos: 1 - region1(pos) # Add the material to the system sys.add_material(mat1, region1) sys.add_material(mat2, region2) # Define Ohmic contacts sys.contact_type('Ohmic', 'Ohmic') # Add the donors nD1 = 1e15 # [m^-3] sys.add_donor(nD1, region1) nD2 = 1e15 # [m^-3] sys.add_acceptor(nD2, region2) # Define the surface recombination velocities for electrons and holes [m/s] SS = 1e50 Sn_left, Sp_left, Sn_right, Sp_right = SS, SS, SS, SS sys.contact_S(Sn_left, Sp_left, Sn_right, Sp_right) # Electrostatic potential dimensionless solution = sesame.solve_equilibrium(sys, verbose=False) veq = np.copy(solution['v']) G = 1*1e24*1e-6 f = lambda x: G sys.generation(f) solution = sesame.solve(sys, solution, verbose=False) solution.update({'x': sys.xpts, 'chi': sys.bl, 'eg': sys.Eg, 'Nc': sys.Nc, 'Nv': sys.Nv}) voltages = np.linspace(0, 0.9, 10) result = solution # sites of the right contact nx = sys.nx s = [nx-1 + j*nx + k*nx*sys.ny for k in range(sys.nz)\ for j in range(sys.ny)] # sign of the voltage to apply if sys.rho[nx-1] < 0: q = 1 else: q = -1 j = [] # Loop over the applied potentials made dimensionless Vapp = voltages / sys.scaling.energy for idx, vapp in enumerate(Vapp): # Apply the voltage on the right contact result['v'][s] = veq[s] + q*vapp # Call the Drift Diffusion Poisson solver result = sesame.solve(sys, result, maxiter=1000, verbose=False) # Compute current az = sesame.Analyzer(sys, result) tj = az.full_current()* sys.scaling.current j.append(tj) jcomsol = np.array([0.55569,0.54937,0.5423,0.53436,0.52535,0.51499,0.50217,0.4622,-0.47448,-31.281]) jcomsol = jcomsol * 1e-4 error = np.max(np.abs((jcomsol-np.transpose(j))/(.5*(jcomsol+np.transpose(j))))) print("error = {0}".format(error))
def runTest3(): rhoGBlist = np.linspace(1e6 * 1e-4, 1e18 * 1e-4, 2) sys = system(rhoGBlist[0]) solution = sesame.solve_equilibrium(sys, verbose=False) s0 = 1e-18 * 1e4 rhoGBlist = [1e6 * 1e-4, 1e18 * 1e-4] for idx, rhoGB in enumerate(rhoGBlist): sys = system(rhoGB, s0) solution = sesame.solve_equilibrium(sys, solution, maxiter=5000, verbose=False) veq = np.copy(solution['v']) efn = np.zeros((sys.nx * sys.ny, )) efp = np.zeros((sys.nx * sys.ny, )) solution.update({'efn': efn, 'efp': efp}) junction = .1e-6 * 1e2 # Define a function for the generation rate G = 1 phi0 = 1e21 * G * 1e-4 alpha = 2.3e6 * 1e-2 # alpha = 2e4 cm^-1 for CdTe f = lambda x, y: phi0 * alpha * np.exp(-alpha * x) sys.generation(f) slist = [1e-18 * 1e4] sys = system(rhoGBlist[1], slist[0]) sys.generation(f) solution = sesame.solve(sys, solution, maxiter=5000, verbose=False) az = sesame.Analyzer(sys, solution) tj = -az.full_current() voltages = np.linspace(.0, .8, 9) result = solution # sites of the right contact nx = sys.nx s = [nx - 1 + j * nx + k * nx * sys.ny for k in range(sys.nz) \ for j in range(sys.ny)] # sign of the voltage to apply if sys.rho[nx - 1] < 0: q = 1 else: q = -1 j = [] # Loop over the applied potentials made dimensionless Vapp = voltages / sys.scaling.energy for idx, vapp in enumerate(Vapp): # Apply the voltage on the right contact result['v'][s] = veq[s] + q * vapp # Call the Drift Diffusion Poisson solver result = sesame.solve(sys, result, maxiter=1000, verbose=False) # Compute current az = sesame.Analyzer(sys, result) tj = az.full_current() * sys.scaling.current * sys.scaling.length / ( 3e-6 * 1e2) j.append(tj) jSesame_12_4_2017 = np.array([ 135.14066065175203, 134.97430561196626, 134.70499402818209, 134.28271667573679, 133.27884008619145, 129.49875552490002, 119.14704988797484, 83.157765739151415, -114.57979137988193 ]) jSesame_12_4_2017 = jSesame_12_4_2017 * 1e-4 error = np.max( np.abs((jSesame_12_4_2017 - np.transpose(j)) / (.5 * (jSesame_12_4_2017 + np.transpose(j))))) print("error = {0}".format(error))
def runTest1(): L = 3e-4 # length of the system in the x-direction [cm] dd = 1e-7 * 1e2 # Mesh x = np.concatenate( (np.linspace(0, 5e-7 * 1e2 - dd, 50, endpoint=False), np.linspace(5e-7 * 1e2 - dd, 5e-7 * 1e2 + dd, 20, endpoint=False), np.linspace(5e-7 * 1e2 + dd, 1e-6 * 1e2, 100, endpoint=False), np.linspace(1e-6 * 1e2, L, 200))) # Create a system sys = sesame.Builder(x, input_length='cm') tau = 1e-8 vt = 0.025851991024560 Nc1 = 8 * 1e17 Nv1 = 1.8 * 1e19 Nc2 = 8 * 1e17 Nv2 = 1.8 * 1e19 # Dictionary with the material parameters mat1 = { 'Nc': Nc1, 'Nv': Nv1, 'Eg': 2.4, 'epsilon': 10, 'Et': 0, 'mu_e': 320, 'mu_h': 40, 'tau_e': tau, 'tau_h': tau, 'affinity': 4.15 } mat2 = { 'Nc': Nc2, 'Nv': Nv2, 'Eg': 1.5, 'epsilon': 10, 'Et': 0, 'mu_e': 320, 'mu_h': 40, 'tau_e': tau, 'tau_h': tau, 'affinity': 4.05 } junction = 5e-7 * 1e2 # extent of the junction from the left contact [m] def region1(pos): x = pos return x < junction # Add the acceptors region2 = lambda pos: 1 - region1(pos) # Add the material to the system sys.add_material(mat1, region1) sys.add_material(mat2, region2) # Add the donors nD1 = 1e17 # [cm^-3] sys.add_donor(nD1, region1) nD2 = 1e15 # [cm^-3] sys.add_acceptor(nD2, region2) # Define Ohmic contacts sys.contact_type('Ohmic', 'Ohmic') # Define the surface recombination velocities for electrons and holes [m/s] SS = 1e50 * 1e2 Sn_left, Sp_left, Sn_right, Sp_right = SS, SS, SS, SS sys.contact_S(Sn_left, Sp_left, Sn_right, Sp_right) solution = sesame.solve_equilibrium(sys, verbose=False) veq = np.copy(solution['v']) G = 1 * 1e24 * 1e-6 f = lambda x: G sys.generation(f) solution = sesame.solve(sys, solution, verbose=False) solution.update({ 'x': sys.xpts, 'chi': sys.bl, 'eg': sys.Eg, 'Nc': sys.Nc, 'Nv': sys.Nv }) voltages = np.linspace(0, 0.8, 9) result = solution # sites of the right contact nx = sys.nx s = [nx-1 + j*nx + k*nx*sys.ny for k in range(sys.nz)\ for j in range(sys.ny)] # sign of the voltage to apply if sys.rho[nx - 1] < 0: q = 1 else: q = -1 j = [] # Loop over the applied potentials made dimensionless Vapp = voltages / sys.scaling.energy for idx, vapp in enumerate(Vapp): # Apply the voltage on the right contact result['v'][s] = veq[s] + q * vapp # Call the Drift Diffusion Poisson solver result = sesame.solve(sys, result, maxiter=1000, verbose=False) # Compute current az = sesame.Analyzer(sys, result) tj = az.full_current() * sys.scaling.current j.append(tj) jcomsol = np.array([ 0.32117, 0.31672, 0.31198, 0.30683, 0.30031, 0.28562, 0.20949, -0.39374, -7.0681 ]) jcomsol = jcomsol * 1e-4 # converting to A/cm^2 error = np.max( np.abs( (jcomsol - np.transpose(j)) / (.5 * (jcomsol + np.transpose(j))))) print("error = {0}".format(error))