def calculate(args): Si, Electrode, T, V_p, V_rb = args sample_data_dir = join(dirname(__file__), '03-data') db_name = '03_Au_nSi_BW_transient' + '_%02.2fVp_%02.2fVrb_%03.2fK' % ( V_p, abs(V_rb), T) + '.db' db_name = join(sample_data_dir, db_name) MyProject = Project(db_name=db_name, backend='sqlite', hostname='', overwrite=False) MyDiode = SchottkyDiode(MyProject, 'Au-Si_BW', Electrode, Si, DeadLayer=1.5e-7, L=5e-6) MyDiode.set_T(T) MyDiode.set_Va(V_p) type_sign = -1 if MyDiode.Semiconductor.dop_type == 'n' else 1 Psi = Psi_approx(MyDiode.L, -(MyDiode.V_bi(eV=True) + type_sign * V_p), 0.0) Psi, E, z_nodes, rho_err_points, Vd, Vd_err, J, J_err, \ BI_F, dopants_F, ic_id = Poisson.Reccurent_Poisson_solver(MyDiode, Psi, Vd_error=1e-6, equilibrium_filling=True, t=mp.inf, initial_condition_id=-1, rho_rel_err=Poisson_rel_err, max_iter=100, debug=False) #plt.plot(z_nodes, -Psi(z_nodes), 'r-o') #plt.show() MyDiode.set_Va(V_rb) Psi, E, z_nodes, rho_err_points, Vd, Vd_err, J, J_err, \ BI_F, dopants_F, ic_id = Poisson.Reccurent_Poisson_solver(MyDiode, Psi, Vd_error=1e-6, equilibrium_filling=False, fast_traps=['Phosphorus'], t=0.0, initial_condition_id=ic_id, rho_rel_err=Poisson_rel_err, max_iter=100, debug=False) #plt.plot(z_nodes, -Psi(z_nodes), 'r-o') #plt.show() t_points, potential_t, field_d, z_t, diode_voltage_drop_t, current_density_t, \ bonding_interfaces_f_t, dopants_f_t, last_state_id = Kinetics.traps_kinetics(MyDiode, ic_id, 1e-9, 10e-3, 100e-3, fast_traps=['Phosphorus'], rho_rel_err=Poisson_rel_err, df_threshold=1e-2, debug=True) return [T, t_points, bonding_interfaces_f_t, dopants_f_t]
def calculate(args): Si, Electrode, T, V_p = args sample_data_dir = join(dirname(__file__), '03-data') db_name = '03_Au_nSi_BW_transient' + '_%02.2fVp_%02.2fVrb_%03.2fK' % ( V_p, abs(V_rb), T) + '.db' db_name = join(sample_data_dir, db_name) MyProject = Project(db_name=db_name, backend='sqlite', hostname='', overwrite=False) MyDiode = SchottkyDiode(MyProject, 'Au-Si_BW', Electrode, Si, DeadLayer=1.5e-7, L=5e-6) MyDiode.set_T(T) MyDiode.set_Va(V_p) print T type_sign = -1 if MyDiode.Semiconductor.dop_type == 'n' else 1 Psi = Psi_approx(MyDiode.L, -(MyDiode.V_bi(eV=True) + type_sign * V_p), 0.0) Psi, E, z_nodes, rho_err_points, Vd, Vd_err, J, J_err, \ BI_F, dopants_F, ic_id = Poisson.Reccurent_Poisson_solver(MyDiode, Psi, Vd_error=1e-6, equilibrium_filling=True, t=mp.inf, initial_condition_id=-1, rho_rel_err=Poisson_rel_err, max_iter=100, debug=False) return db_name
def dopants_df_dt(schottky_diode, initial_condition_id): ic_found, potential, field, z_nodes, _, \ diode_voltage_drop, _, current_density, _, bonding_interfaces_f, dopants_f, \ measurement_id = Poisson.load_diode_state(schottky_diode, initial_condition_id, debug=True) if not ic_found: raise ( Exception('Initial condition not found. Please check everything')) #schottky_diode.dopants_set_eq_F(z_nodes, potential, debug=False) _, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, sharex=True) ax1.plot(z_nodes, -potential(z_nodes)) for dopant_name in dopants_f.keys(): ax2.plot(z_nodes, dopants_f[dopant_name]) fermi_level = schottky_diode.EfEc(potential, z_nodes, eV=False) n, p = schottky_diode.n_carriers_theory(potential, z_nodes) if schottky_diode.Semiconductor.dop_type == 'n': p = np.zeros_like(p) elif schottky_diode.Semiconductor.dop_type == 'p': n = np.zeros_like(n) ax4.plot(z_nodes, n) for dopant in schottky_diode.Semiconductor.dopants: dopant_f = dopant.equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) ax2.plot(z_nodes, dopant_f) df_dt, tau = dopant.df_dt(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], n, p, barrier_lowering_e=None, barrier_lowering_h=None, use_mpmath=False, debug=False) capture_e, capture_h, capture_tau_e, capture_tau_h = dopant.capture_rate( schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], n, p, debug=False) emission_e, emission_h, emission_tau_e, emission_tau_h = dopant.emission_rate( schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], barrier_lowering_e=None, barrier_lowering_h=None, use_mpmath=False, debug=False) print 'electrons: capture tau = %2.2g s, emission tau = %2.2g s' % ( min(capture_tau_e), min(emission_tau_e)) print 'holes: capture tau = %2.2g s, emission tau = %2.2g s' % ( min(capture_tau_h), min(emission_tau_h)) print 'tau = %2.2g s' % tau #ax3.plot(z_nodes, emission_h - emission_e) ax3.plot(z_nodes, df_dt) #ax5.plot(z_nodes, capture_tau_e) plt.show()
def dopants_df_dt(schottky_diode, initial_condition_id): ic_found, potential, field, z_nodes, _, \ diode_voltage_drop, _, current_density, _, bonding_interfaces_f, dopants_f, \ measurement_id = Poisson.load_diode_state(schottky_diode, initial_condition_id, debug=True) if not ic_found: raise(Exception('Initial condition not found. Please check everything')) #schottky_diode.dopants_set_eq_F(z_nodes, potential, debug=False) _, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, sharex=True) ax1.plot(z_nodes, -potential(z_nodes)) for dopant_name in dopants_f.keys(): ax2.plot(z_nodes, dopants_f[dopant_name]) fermi_level = schottky_diode.EfEc(potential, z_nodes, eV=False) n, p = schottky_diode.n_carriers_theory(potential, z_nodes) if schottky_diode.Semiconductor.dop_type == 'n': p = np.zeros_like(p) elif schottky_diode.Semiconductor.dop_type == 'p': n = np.zeros_like(n) ax4.plot(z_nodes, n) for dopant in schottky_diode.Semiconductor.dopants: dopant_f = dopant.equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) ax2.plot(z_nodes, dopant_f) df_dt, tau = dopant.df_dt(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], n, p, barrier_lowering_e=None, barrier_lowering_h=None, use_mpmath=False, debug=False) capture_e, capture_h, capture_tau_e, capture_tau_h = dopant.capture_rate(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], n, p, debug=False) emission_e, emission_h, emission_tau_e, emission_tau_h = dopant.emission_rate(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_name], barrier_lowering_e=None, barrier_lowering_h=None, use_mpmath=False, debug=False) print 'electrons: capture tau = %2.2g s, emission tau = %2.2g s' % (min(capture_tau_e), min(emission_tau_e)) print 'holes: capture tau = %2.2g s, emission tau = %2.2g s' % (min(capture_tau_h), min(emission_tau_h)) print 'tau = %2.2g s' % tau #ax3.plot(z_nodes, emission_h - emission_e) ax3.plot(z_nodes, df_dt) #ax5.plot(z_nodes, capture_tau_e) plt.show()
MyDiode = SchottkyDiode(MyProject, 'Au-Si_BW', Electrode, Si, DeadLayer=1.5e-7, L=5e-6) MyDiode.set_T(T) MyDiode.set_Va(V_p) type_sign = -1 if MyDiode.Semiconductor.dop_type == 'n' else 1 Psi = Psi_approx(MyDiode.L, -(MyDiode.V_bi(eV=True) + type_sign * V_p), 0.0) Psi, E, z_nodes, rho_err_points, Vd, Vd_err, J, J_err, \ BI_F, dopants_F, ic_id = Poisson.Reccurent_Poisson_solver(MyDiode, Psi, Vd_error=1e-6, equilibrium_filling=True, t=mp.inf, initial_condition_id=-1, rho_rel_err=Poisson_rel_err, max_iter=100, debug=False) z_nodes = np.linspace(0, 3e-6, num=500, dtype=np.float) _, (ax1, ax2) = plt.subplots(2, sharex=True) Visual.BandsBendingDiagram(ax1, MyDiode, Psi, Vd, z_nodes, BI_F, dopants_F, eV=True, draw_metal=True, label_bands=True, fancy_ticks=False,
def traps_kinetics(schottky_diode, initial_condition_id, delta_t_min, delta_t_max, t_stop, fast_traps=None, rho_rel_err=1e-1, df_threshold=1e-3, debug=False, debug_plot=False): t_points = [] potential_t = [] field_d = [] z_t = [] diode_voltage_drop_t = [] current_density_t = [] bonding_interfaces_f_t = [] dopants_f_t = [] ic_found, potential, z_nodes, _, _, _, _, _, _, _, _, _ = Poisson.load_diode_state(schottky_diode, initial_condition_id, debug=True) if not ic_found: raise(Exception('Initial condition not found. Please check everything')) if debug_plot: plt.ion() axes = Visual.prepare_debug_axes(['Potential', 'Dopants', 'Localized traps']) potential_lines = Visual.create_lines(axes['Potential'], ['Start potential', 'Current potential']) dopants_lines_names = [dopant.name + '_F' for dopant in schottky_diode.Semiconductor.dopants] localized_traps_lines_names = [] for bi in schottky_diode.Semiconductor.bonding_interfaces: localized_traps_lines_names += [bi.label + '_tilt_' + trap[0].name + '_F' for trap in bi.dsl_tilt.traps] localized_traps_lines_names += [bi.label + '_twist_' + trap[0].name + '_F' for trap in bi.dsl_twist.traps] dopants_lines = Visual.create_lines(axes['Dopants'], dopants_lines_names) localized_traps_lines = Visual.create_lines(axes['Localized traps'], localized_traps_lines_names) t = 0 last_state_id = initial_condition_id if fast_traps is None: fast_traps = [] while t <= t_stop: print 't =', t potential, field, z_nodes, _, \ diode_voltage_drop, _, current_density, _, \ bonding_interface_f, dopants_f, \ last_state_id = Poisson.Reccurent_Poisson_solver(schottky_diode, potential, equilibrium_filling=False, fast_traps=fast_traps, t=t, initial_condition_id=last_state_id, rho_rel_err=rho_rel_err, max_iter=100, debug=False) t_points.append(t) potential_t.append(potential) field_d.append(field) z_t.append(z_nodes) diode_voltage_drop_t.append(diode_voltage_drop) current_density_t.append(current_density) bonding_interfaces_f_t.append(bonding_interface_f) dopants_f_t.append(dopants_f) fermi_level = schottky_diode.EfEc(potential, z_nodes, eV=False) if debug_plot: if t == 0: potential_lines['Start potential'].set_data(z_nodes * 1e6, -potential(z_nodes)) potential_lines['Current potential'].set_data(z_nodes * 1e6, -potential(z_nodes)) for dopant_line_name in dopants_lines_names: dopants_lines[dopant_line_name].set_data(z_nodes * 1e6, dopants_f[dopant_line_name]) for localized_trap_line_name in localized_traps_lines_names: localized_trap_f_t = [] for bonding_interfaces_f_t_i in bonding_interfaces_f_t: localized_trap_f_t.append(bonding_interfaces_f_t_i[localized_trap_line_name]) localized_traps_lines[localized_trap_line_name].set_data(t_points, localized_trap_f_t) Visual.autoscale_axes(axes) plt.draw() dt = delta_t_max if t_stop - t > delta_t_max else t_stop - t if dt == 0: break if debug: print '\n\nT = %2.2f K, t = %2.2g s, dt = %2.2g s' % (schottky_diode.T, t, dt) n, p = schottky_diode.n_carriers_theory(potential, z_nodes) if schottky_diode.Semiconductor.dop_type == 'n': p = np.zeros_like(p) elif schottky_diode.Semiconductor.dop_type == 'p': n = np.zeros_like(n) #fast_traps = [] dopants_skip_list = [] df_dopants = {} for dopant in schottky_diode.Semiconductor.dopants: dopant_key = dopant.name + '_F' if dopant.name in fast_traps: if debug: print 'This dopant is in a fast-traps list, skipping.' # dopant_f = dopant.equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, # electron_volts=False, debug=False) # dopant.set_F_interp(z_nodes, dopant_f) # dopant.set_dF_interp(z_nodes, np.zeros_like(dopant_f)) # fast_traps.append(dopant.name) dopants_skip_list.append(dopant_key) continue poole_frenkel_e = 1.0 poole_frenkel_h = 1.0 barrier_lowering_e = np.zeros_like(n, dtype=np.float) barrier_lowering_h = np.zeros_like(p, dtype=np.float) df_dt, tau = dopant.df_dt(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_key], n, p, poole_frenkel_e=poole_frenkel_e, poole_frenkel_h=poole_frenkel_h, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) df_dopants[dopant_key] = df_dt max_dt = df_threshold / np.max(np.abs(df_dt)) if debug: print '\nDopant:', dopant.name print 'time constant %2.2g s' % tau print 'Max dF:', np.max(np.abs(df_dt)), 'th:', df_threshold print 'Max dt:', max_dt, 'dt:', dt if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if debug: print 'Traps are too fast. Setting dopant occupation to equilibrium value' dopant_f = dopant.equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) dopant.set_F_interp(z_nodes, dopant_f) dopant.set_dF_interp(z_nodes, np.zeros_like(dopant_f)) # fast_traps.append(dopant.name) dopants_skip_list.append(dopant_key) localized_traps_skip_list = [] df_bonding_interfaces = {} for bi in schottky_diode.Semiconductor.bonding_interfaces: fermi_level_at_bi = schottky_diode.EfEc(potential, bi.depth, eV=False) electric_field_at_bi = field(bi.depth) n_bi, p_bi = schottky_diode.n_carriers_theory(potential, bi.depth) if schottky_diode.Semiconductor.dop_type == 'n': p_bi = 0.0 elif schottky_diode.Semiconductor.dop_type == 'p': n_bi = 0.0 if debug: print '\nBI:', bi.label print 'n_BI = %2.4g' % n_bi print 'p_BI = %2.4g' % p_bi bi_tilt_f = [] for trap_idx, trap in enumerate(bi.dsl_tilt.traps): localized_trap_key = bi.label + '_tilt_' + trap[0].name + '_F' print 'BI Density of Charge = %2.2g cm-2' % (bi.density_of_charge / 1e4) print 'TILT F = %2.2f' % bi.dsl_tilt_f[trap_idx] dsl_charge_density = bi.dsl_tilt_f[trap_idx] * trap[1] print 'TILT Density of Charge = %2.2g cm-1' % (dsl_charge_density / 1e2) print 'EXT FIELD = %2.2g V*cm' % (electric_field_at_bi / 1e2) electric_field_at_bi_r = abs(electric_field_at_bi) electric_field_at_bi_theta = 0 if electric_field_at_bi >= 0 else np.pi electric_field_at_bi_3d = (electric_field_at_bi_r, electric_field_at_bi_theta, 0.0) trap[0].trap_potential.get_potential_by_name('Charged Dislocation').set_linear_charge_density(dsl_charge_density) trap[0].trap_potential.get_potential_by_name('External Field').external_field = electric_field_at_bi_3d kT = to_numeric(k * schottky_diode.T / q) theta = np.linspace(0, np.pi, num=100, endpoint=True) barrier_lowering = np.array([trap[0].trap_potential.barrier_lowering(theta_i) for theta_i in theta]) poole_frenkel = 0.5 * np.trapz(np.sin(theta) * np.exp(abs(barrier_lowering[:, 0]) / kT), theta) poole_frenkel_e = 1.0 poole_frenkel_h = 1.0 if np.sum(barrier_lowering[:, 0]) < 0: poole_frenkel_e = poole_frenkel print 'emission boost e: %2.4g' % poole_frenkel elif np.sum(barrier_lowering[:, 0]) > 0: poole_frenkel_h = poole_frenkel print 'emission boost h: %2.4g' % poole_frenkel barrier_lowering_e = 0.0 barrier_lowering_h = 0.0 df_dt, tau = trap[0].df_dt(schottky_diode.T, schottky_diode.Semiconductor, bonding_interface_f[localized_trap_key], n_bi, p_bi, poole_frenkel_e=poole_frenkel_e, poole_frenkel_h=poole_frenkel_h, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) df_bonding_interfaces[localized_trap_key] = df_dt try: max_dt = df_threshold / abs(df_dt) except ZeroDivisionError: max_dt = 1e250 if debug: print '\nTrap:', trap[0].name print 'time constant %2.2g s' % tau print 'dF: %2.4g, th: %2.2f'% (df_dt, df_threshold) print 'Max dt:', max_dt, 'dt:', dt if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if dt > 10 * max_dt: if debug: print 'Trap is too fast. Setting trap occupation to equilibrium value' bonding_interface_f[localized_trap_key] = trap[0].equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level_at_bi, electron_volts=False, debug=False) localized_traps_skip_list.append(localized_trap_key) else: if debug: print 'Setting dt to', max_dt dt = max_dt # fast_traps.append(bi.label + '_tilt_' + trap[0].name) bi_tilt_f.append(bonding_interface_f[localized_trap_key]) bi_twist_f = [] for trap in bi.dsl_twist.traps: localized_trap_key = bi.label + '_twist_' + trap[0].name + '_F' trap[0].trap_potential.get_potential_by_name('External Field').external_field = electric_field_at_bi print 'EXT FIELD = %2.2g V*cm' % (electric_field_at_bi / 1e2) print trap[0].trap_potential.barrier_lowering() barrier_lowering_e = 0.0 barrier_lowering_h = 0.0 df_dt, tau = trap[0].df_dt(schottky_diode.T, schottky_diode.Semiconductor, bonding_interface_f[localized_trap_key], n_bi, p_bi, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) df_bonding_interfaces[localized_trap_key] = df_dt try: max_dt = df_threshold / abs(df_dt) except ZeroDivisionError: max_dt = 1e250 if debug: print '\nTrap:', trap[0].name print 'time constant %2.2g s' % tau print 'dF: %2.4g, th: %2.2f'% (df_dt, df_threshold) print 'Max dt:', max_dt, 'dt:', dt if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if dt > 10 * max_dt: if debug: print 'Trap is too fast. Setting trap occupation to equilibrium value' bonding_interface_f[localized_trap_key] = trap[0].equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) localized_traps_skip_list.append(localized_trap_key) else: if debug: print 'Setting dt to', max_dt dt = max_dt # fast_traps.append(bi.label + '_twist_' + trap[0].name) bi_twist_f.append(bonding_interface_f[localized_trap_key]) bi.set_traps_f(np.array(bi_tilt_f), np.array(bi_twist_f)) bi.set_traps_df(np.zeros(len(bi_tilt_f)), np.zeros(len(bi_twist_f))) dt = np.float(dt) for dopant in schottky_diode.Semiconductor.dopants: dopant_key = dopant.name + '_F' if dopant_key in dopants_skip_list: if debug: print 'Dopant', dopant_key, 'does not need an update' continue dopants_f[dopant_key] += df_dopants[dopant_key] * dt dopants_f[dopant_key][np.where(dopants_f[dopant_key] > 1.0)] = 1.0 dopants_f[dopant_key][np.where(dopants_f[dopant_key] < 0.0)] = 0.0 dopant.set_F_interp(z_nodes, dopants_f[dopant_key]) dopant.set_dF_interp(z_nodes, np.zeros_like(dopants_f[dopant_key])) for bi in schottky_diode.Semiconductor.bonding_interfaces: bi_tilt_f = [] for trap in bi.dsl_tilt.traps: localized_trap_key = bi.label + '_tilt_' + trap[0].name + '_F' if localized_trap_key not in localized_traps_skip_list: bonding_interface_f[localized_trap_key] += df_bonding_interfaces[localized_trap_key] * dt if bonding_interface_f[localized_trap_key] > 1: bonding_interface_f[localized_trap_key] = 1 elif bonding_interface_f[localized_trap_key] < 0: bonding_interface_f[localized_trap_key] = 0 if debug: print 'F:', bonding_interface_f[localized_trap_key] bi_tilt_f.append(bonding_interface_f[localized_trap_key]) bi_twist_f = [] for trap in bi.dsl_twist.traps: localized_trap_key = bi.label + '_twist_' + trap[0].name + '_F' if localized_trap_key not in localized_traps_skip_list: bonding_interface_f[localized_trap_key] += df_bonding_interfaces[localized_trap_key] * dt if bonding_interface_f[localized_trap_key] > 1: bonding_interface_f[localized_trap_key] = 1 elif bonding_interface_f[localized_trap_key] < 0: bonding_interface_f[localized_trap_key] = 0 if debug: print 'F:', bonding_interface_f[localized_trap_key] bi_twist_f.append(bonding_interface_f[localized_trap_key]) bi.set_traps_f(np.array(bi_tilt_f), np.array(bi_twist_f)) bi.set_traps_df(np.zeros(len(bi_tilt_f)), np.zeros(len(bi_twist_f))) t += dt if debug_plot: plt.ioff() return t_points, potential_t, field_d, z_t, diode_voltage_drop_t, current_density_t, \ bonding_interfaces_f_t, dopants_f_t, last_state_id
def calculate_for_temperature(args): silicon, electrode, temperature, voltage_range = args print temperature db_name = prefix + '_dc_%03.2fK.db' % temperature db_name = join(data_dir, db_name) project = Project(db_name=db_name, backend='sqlite', hostname='', overwrite=False) diode = SchottkyDiode(project, 'Au-nSi_BW', electrode, silicon, DeadLayer=1.5e-7, L=5e-6) diode.set_T(temperature) potential = [] field = [] diode_voltage = [] diode_voltage_error = [] current_density = [] current_density_error = [] bonding_interface_f = {} dopants_f_sum = {} z = [] dopants_f = [] for voltage in voltage_range: diode.set_Va(voltage) type_sign = -1 if silicon.dop_type == 'n' else 1 potential_i = Psi_approx(diode.L, -(diode.V_bi(eV=True) + type_sign * voltage), 0.0) potential_i, field_i, z_nodes, rho_err_points, \ diode_voltage_i, diode_voltage_error_i, \ current_density_i, current_density_error_i, \ bonding_interface_f_i, dopants_f_i, \ measurement_id = Poisson.Reccurent_Poisson_solver(diode, potential_i, Vd_error=1e-6, equilibrium_filling=True, t=mp.inf, initial_condition_id=-1, rho_rel_err=poisson_relative_error, max_iter=100, debug=False) potential.append(potential_i) field.append(field_i) diode_voltage.append(diode_voltage_i) diode_voltage_error.append(diode_voltage_error_i) current_density.append(current_density_i) current_density_error.append(current_density_i) z.append(z_nodes) dopants_f.append(dopants_f_i) for trap_key in bonding_interface_f_i.keys(): try: bonding_interface_f[trap_key].append( bonding_interface_f_i[trap_key]) except KeyError: bonding_interface_f[trap_key] = [ bonding_interface_f_i[trap_key] ] for dopant_key in dopants_f_i.keys(): try: dopants_f_sum[dopant_key].append( np.sum(dopants_f_i[dopant_key])) except KeyError: dopants_f_sum[dopant_key] = [np.sum(dopants_f_i[dopant_key])] data = { temperature: { 'applied_voltage': voltage_range, 'diode_voltage': diode_voltage, 'diode_voltage_error': diode_voltage_error, 'current_density': current_density, 'current_density_error': current_density_error } } for trap_key in bonding_interface_f.keys(): data[temperature][trap_key] = bonding_interface_f[trap_key] for dopant_key in dopants_f_sum.keys(): data[temperature][dopant_key + '_sum'] = dopants_f_sum[dopant_key] return potential, field, data, z, dopants_f
def traps_kinetics(schottky_diode, initial_condition_id, delta_t_min, delta_t_max, t_stop, fast_traps=None, rho_rel_err=1e-1, df_threshold=1e-3, min_t_points=50, dopants_deriv_threshold=5.0e-5, dopants_deriv_window=9, dopants_deriv_z_limit=None, save_to_db=True, potential=None, debug=False, debug_plot=False): if dopants_deriv_z_limit is None: dopants_deriv_z_limit = 1e8 z_limit_f = 1e8 dopants_f_total = {} t_points = [] potential_t = [] field_d = [] z_t = [] diode_voltage_drop_t = [] current_density_t = [] bonding_interfaces_f_t = [] dopants_f_t = [] n_t = [] p_t = [] if save_to_db: ic_found, potential, _, z_nodes, _, _, _, _, _, _, _, _ = Poisson.load_diode_state( schottky_diode, initial_condition_id, debug=True) if not ic_found: raise (Exception( 'Initial condition not found. Please check everything')) if debug_plot: plt.ion() axes = Visual.prepare_debug_axes( ['Potential', 'Dopants', 'Localized traps']) potential_lines = Visual.create_lines( axes['Potential'], ['Start potential', 'Current potential']) dopants_lines_names = [ dopant.name + '_F' for dopant in schottky_diode.Semiconductor.dopants ] localized_traps_lines_names = [] for bi in schottky_diode.Semiconductor.bonding_interfaces: localized_traps_lines_names += [ bi.label + '_tilt_' + trap[0].name + '_F' for trap in bi.dsl_tilt.traps ] localized_traps_lines_names += [ bi.label + '_twist_' + trap[0].name + '_F' for trap in bi.dsl_twist.traps ] dopants_lines = Visual.create_lines(axes['Dopants'], dopants_lines_names) localized_traps_lines = Visual.create_lines( axes['Localized traps'], localized_traps_lines_names) t = 0 last_state_id = initial_condition_id if fast_traps is None: fast_traps = [] slow_traps = {} while t <= t_stop: print '\n\nt =', t potential, field, z_nodes, _, \ diode_voltage_drop, _, current_density, _, \ bonding_interface_f, dopants_f, \ last_state_id = Poisson.Reccurent_Poisson_solver(schottky_diode, potential, equilibrium_filling=False, fast_traps=fast_traps, t=t, initial_condition_id=last_state_id, rho_rel_err=rho_rel_err, max_iter=100, save_to_db=save_to_db, debug=False) t_points.append(t) potential_t.append(potential) field_d.append(field) z_t.append(z_nodes) diode_voltage_drop_t.append(diode_voltage_drop) current_density_t.append(current_density) bonding_interfaces_f_t.append(bonding_interface_f.copy()) dopants_f_t.append(dopants_f.copy()) fermi_level = schottky_diode.EfEc(potential, z_nodes, eV=False) n, p = schottky_diode.n_carriers_theory(potential, z_nodes) if schottky_diode.Semiconductor.dop_type == 'n': p = np.zeros_like(p) elif schottky_diode.Semiconductor.dop_type == 'p': n = np.zeros_like(n) n_t.append(n.copy()) p_t.append(p.copy()) if debug_plot: if t == 0: potential_lines['Start potential'].set_data( z_nodes * 1e6, -potential(z_nodes)) potential_lines['Current potential'].set_data( z_nodes * 1e6, -potential(z_nodes)) for dopant_line_name in dopants_lines_names: dopants_lines[dopant_line_name].set_data( z_nodes * 1e6, dopants_f[dopant_line_name]) for localized_trap_line_name in localized_traps_lines_names: localized_trap_f_t = [] for bonding_interfaces_f_t_i in bonding_interfaces_f_t: localized_trap_f_t.append( bonding_interfaces_f_t_i[localized_trap_line_name]) localized_traps_lines[localized_trap_line_name].set_data( t_points, localized_trap_f_t) Visual.autoscale_axes(axes) plt.draw() dt = delta_t_max if t_stop - t > delta_t_max else t_stop - t if dt == 0: for dopant in schottky_diode.Semiconductor.dopants: dopant_key = dopant.name + '_F' dopants_f_t[-1].update( {dopant_key + '_pf': np.ones_like(z_nodes)}) dopants_f_t[-1].update( {dopant_key + '_df': np.zeros_like(z_nodes)}) break if debug: print '\n\nT = %2.2f K, t = %2.2g s, dt = %2.2g s' % ( schottky_diode.T, t, dt) #fast_traps = [] dopants_skip_list = [] df_dopants = {} for dopant in schottky_diode.Semiconductor.dopants: dopant_key = dopant.name + '_F' dopants_deriv_z_limit_idx = np.where( z_nodes < dopants_deriv_z_limit) if t == 0: dopants_f_total[dopant_key] = [ np.trapz( dopants_f_t[0][dopant_key][dopants_deriv_z_limit_idx], x=z_nodes[dopants_deriv_z_limit_idx]) ] else: dopants_f_total[dopant_key].append( np.trapz( dopants_f_t[-1][dopant_key][dopants_deriv_z_limit_idx], x=z_nodes[dopants_deriv_z_limit_idx])) print 'Total Donor charge %2.2g' % dopants_f_total[dopant_key][-1] if t > 0: loc_der = (dopants_f_total[dopant_key][-1] - dopants_f_total[dopant_key][-2]) \ / (t_points[-1] - t_points[-2]) / dopants_f_total[dopant_key][0] print 'local derivative %2.2g%%' % (loc_der * 100) if dopant.name in fast_traps: if debug: print '\nDopant:', dopant.name print 'This dopant is in a fast-traps list, skipping.' dopants_skip_list.append(dopant_key) continue if dopant.name in slow_traps.keys(): if debug: print '\nDopant:', dopant.name print 'This dopant is in a slow-traps list, skipping.' df_dt = np.zeros_like(z_nodes) for wp in range(dopants_deriv_window): df_dt[dopants_deriv_z_limit_idx] += dopants_f_t[-wp - 2][ dopant_key + '_df'][dopants_deriv_z_limit_idx] df_dt /= dopants_deriv_window dopants_f_t[-1].update({dopant_key + '_df': df_dt}) df_dopants[dopant_key] = df_dt #dopants_skip_list.append(dopant_key) continue poole_frenkel_e = np.ones_like(z_nodes, dtype=np.float) poole_frenkel_h = np.ones_like(z_nodes, dtype=np.float) barrier_lowering_e = np.zeros_like(n, dtype=np.float) barrier_lowering_h = np.zeros_like(p, dtype=np.float) field_z = field(z_nodes) if dopant.trap_potential.get_potential_by_name( 'Charged Dislocation') is not None: kT = to_numeric(k * schottky_diode.T / q) theta_points = 90 theta = np.linspace(0, np.pi, num=theta_points, endpoint=True) #theta = np.linspace(0, np.pi / 2, num=theta_points, endpoint=True) barrier_lowering = np.zeros((theta_points, len(z_nodes)), dtype=np.float) max_N_l = dopant.trap_potential.get_potential_by_name('Charged Dislocation')\ .max_linear_charge_density dsl_charge_density = max_N_l * dopant.F(z_nodes) for z_num, local_electric_field in enumerate(field_z): #print z_num, 'of', len(z_nodes) #dsl_charge_density = max_N_l * dopant.F(z_nodes[z_num]) local_electric_field_r = abs(local_electric_field) local_electric_field_theta = 0 if local_electric_field >= 0 else np.pi local_electric_field_3d = (local_electric_field_r, local_electric_field_theta, 0.0) dopant.trap_potential.get_potential_by_name('Charged Dislocation')\ .set_linear_charge_density(dsl_charge_density[z_num]) dopant.trap_potential.get_potential_by_name('External Field')\ .external_field = local_electric_field_3d loc_f = local_electric_field_r loc_a = dopant.trap_potential.get_potential_by_name( 'Charged Dislocation').a loc_b = -dopant.trap_potential.get_potential_by_name( 'Deformation').a r0 = np.zeros_like(theta) if loc_f < 1.0e-5: if z_nodes[z_num] < z_limit_f: z_limit_f = z_nodes[z_num] #print 'here', loc_f, z_nodes[z_num]*1e6 try: r0[:] = loc_b / loc_a except FloatingPointError: pass #print len(r0), r0 else: determinant = loc_a**2 + 4 * loc_b * loc_f * np.cos( theta) idx = np.where(determinant >= 0) sqrt = np.sqrt(loc_a**2 + 4 * loc_b * loc_f * np.cos(theta[idx])) sol1 = (-loc_a - sqrt) / (2 * loc_f * np.cos(theta[idx])) sol2 = (-loc_a + sqrt) / (2 * loc_f * np.cos(theta[idx])) sol1[np.where(sol1 < 0.0)] = 0.0 #sol2[np.where(sol2 < 0.0)] = 0.0 sol = sol1.copy() #sol2_selection = np.where(sol2 > 0) sol2_selection = np.where((sol2 > 0) & (sol2 < sol1)) sol[sol2_selection] = sol2[sol2_selection] sol2_selection = np.where((sol2 > 0) & (sol1 <= 0)) sol[sol2_selection] = sol2[sol2_selection] r0[idx] = sol #idx = np.where(r0 < loc_b / loc_a / 3) #r0[idx] = loc_b / loc_a zero_theta_idx = np.where( abs(loc_f * np.cos(theta)) < 1.0e-5) try: r0[zero_theta_idx] = loc_b / loc_a except FloatingPointError: r0[zero_theta_idx] = 0.0 non_zero_r_idx = np.where(r0 > 0.0) bl_grid = dopant.trap_potential.potential( r0[non_zero_r_idx], theta[non_zero_r_idx], 0) #np.save('./bl_grid_'+str(z_nodes[z_num]*1e6)+'_'+str(t), bl_grid) #print np.rad2deg(theta[non_zero_r_idx]) #print bl_grid[0,:,0].shape, theta.shape #print bl_grid[0,:,0] bl_flat = np.zeros_like(theta) try: bl_flat[non_zero_r_idx] = bl_grid[0, :, 0] except IndexError: pass #print kT #print bl_flat #barrier_lowering[:,z_num] = np.array([dopant.trap_potential.barrier_lowering(theta_i)[0] for theta_i in theta]) barrier_lowering[:, z_num] = bl_flat #print barrier_lowering[:, z_num] #print bl_flat - barrier_lowering[:, z_num] #poole_frenkel = 0.5 * np.trapz(np.sin(theta) * np.exp(abs(barrier_lowering[:, 0]) / kT), theta) #poole_frenkel = 0.5 * np.trapz(np.exp(abs(barrier_lowering) / kT), theta, axis=0) #poole_frenkel = 0.5 + np.trapz(np.exp(abs(barrier_lowering) / kT), theta, axis=0) / np.pi poole_frenkel = np.trapz( np.exp(abs(barrier_lowering) / kT), theta, axis=0) / np.pi #print poole_frenkel if np.sum(barrier_lowering[:, 0]) < 0: poole_frenkel_e = poole_frenkel #print 'emission boost e:', poole_frenkel elif np.sum(barrier_lowering[:, 0]) > 0: poole_frenkel_h = poole_frenkel #print 'emission boost h:', poole_frenkel try: dopants_f_t[-1].update({dopant_key + '_pf': poole_frenkel}) except: dopants_f_t[-1].update( {dopant_key + '_pf': np.ones_like(z_nodes)}) df_dt, tau = dopant.df_dt(schottky_diode.T, schottky_diode.Semiconductor, dopants_f[dopant_key], n, p, poole_frenkel_e=poole_frenkel_e, poole_frenkel_h=poole_frenkel_h, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) z_limit_f_idx = np.where(z_nodes < z_limit_f) z_limit_f_idx0 = np.where(z_t[0] < z_limit_f) dopants_f_t[-1].update({dopant_key + '_df': df_dt}) df_dopants[dopant_key] = df_dt #print df_dt df_total = np.sum(df_dt[z_limit_f_idx]) / np.sum( dopants_f_t[0][dopant_key][z_limit_f_idx0]) max_dt_local = df_threshold / np.max(np.abs(df_dt)) max_dt_total = df_threshold / np.max(np.abs(df_total)) max_dt = min(max_dt_local, max_dt_total) if debug: print '\nDopant:', dopant.name print 'Z limit of %2.2g m: left %d points of %d' % ( z_limit_f, len(z_nodes[z_limit_f_idx]), len(z_nodes)) print 'Min time constant %2.2g s' % tau print 'Max dF local:', np.max( np.abs(df_dt)), 'th:', df_threshold print 'Max dF total:', np.max( np.abs(df_total)), 'th:', df_threshold print 'Max dt:', max_dt, 'dt:', dt if len(t_points) > dopants_deriv_window: deriv = np.array(dopants_f_total[dopant_key][-dopants_deriv_window + 1:]) \ - np.array(dopants_f_total[dopant_key][-dopants_deriv_window:-1]) deriv /= dopants_f_total[dopant_key][0] deriv /= np.array( t_points[-dopants_deriv_window + 1:]) - np.array( t_points[-dopants_deriv_window:-1]) deriv = np.average(deriv) if debug: print 'Dopants derivative: %2.2g%%' % (deriv * 100) print 'Derivative threshold: %2.2g%%' % ( dopants_deriv_threshold * 100) else: deriv = 1e8 if abs(deriv) < dopants_deriv_threshold and len( t_points) >= min_t_points: if debug: print 'Traps are all set. Adding dopant to slow traps.' slow_traps[dopant.name] = deriv if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if debug: print 'Traps are too fast. Setting dopant occupation to equilibrium value' dopant_f = dopant.equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) dopant.set_F_interp(z_nodes, dopant_f) dopant.set_dF_interp(z_nodes, np.zeros_like(dopant_f)) fast_traps.append(dopant.name) dopants_skip_list.append(dopant_key) localized_traps_skip_list = [] df_bonding_interfaces = {} for bi in schottky_diode.Semiconductor.bonding_interfaces: fermi_level_at_bi = schottky_diode.EfEc(potential, bi.depth, eV=False) electric_field_at_bi = field(bi.depth) n_bi, p_bi = schottky_diode.n_carriers_theory(potential, bi.depth) if schottky_diode.Semiconductor.dop_type == 'n': p_bi = 0.0 elif schottky_diode.Semiconductor.dop_type == 'p': n_bi = 0.0 if debug: print '\nBI:', bi.label print 'n_BI = %2.4g' % n_bi print 'p_BI = %2.4g' % p_bi bi_tilt_f = [] for trap_idx, trap in enumerate(bi.dsl_tilt.traps): localized_trap_key = bi.label + '_tilt_' + trap[0].name + '_F' print 'BI Density of Charge = %2.2g cm-2' % ( bi.density_of_charge / 1e4) print 'TILT F = %2.2f' % bi.dsl_tilt_f[trap_idx] dsl_charge_density = bi.dsl_tilt_f[trap_idx] * trap[1] print 'TILT Density of Charge = %2.2g cm-1' % ( dsl_charge_density / 1e2) print 'EXT FIELD = %2.2g V*cm' % (electric_field_at_bi / 1e2) electric_field_at_bi_r = abs(electric_field_at_bi) electric_field_at_bi_theta = 0 if electric_field_at_bi >= 0 else np.pi electric_field_at_bi_3d = (electric_field_at_bi_r, electric_field_at_bi_theta, 0.0) trap[0].trap_potential.get_potential_by_name( 'Charged Dislocation').set_linear_charge_density( dsl_charge_density) trap[0].trap_potential.get_potential_by_name( 'External Field').external_field = electric_field_at_bi_3d kT = to_numeric(k * schottky_diode.T / q) theta = np.linspace(0, np.pi, num=100, endpoint=True) barrier_lowering = np.array([ trap[0].trap_potential.barrier_lowering(theta_i) for theta_i in theta ]) poole_frenkel = 0.5 * np.trapz( np.sin(theta) * np.exp(abs(barrier_lowering[:, 0]) / kT), theta) poole_frenkel_e = 1.0 poole_frenkel_h = 1.0 if np.sum(barrier_lowering[:, 0]) < 0: poole_frenkel_e = poole_frenkel print 'emission boost e: %2.4g' % poole_frenkel elif np.sum(barrier_lowering[:, 0]) > 0: poole_frenkel_h = poole_frenkel print 'emission boost h: %2.4g' % poole_frenkel barrier_lowering_e = 0.0 barrier_lowering_h = 0.0 df_dt, tau = trap[0].df_dt( schottky_diode.T, schottky_diode.Semiconductor, bonding_interface_f[localized_trap_key], n_bi, p_bi, poole_frenkel_e=poole_frenkel_e, poole_frenkel_h=poole_frenkel_h, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) df_bonding_interfaces[localized_trap_key] = df_dt try: max_dt = df_threshold / abs(df_dt) except ZeroDivisionError: max_dt = 1e250 if debug: print '\nTrap:', trap[0].name print 'time constant %2.2g s' % tau print 'dF: %2.4g, th: %2.2f' % (df_dt, df_threshold) print 'Max dt:', max_dt, 'dt:', dt if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if dt > 10 * max_dt: if debug: print 'Trap is too fast. Setting trap occupation to equilibrium value' bonding_interface_f[localized_trap_key] = trap[ 0].equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level_at_bi, electron_volts=False, debug=False) localized_traps_skip_list.append(localized_trap_key) else: if debug: print 'Setting dt to', max_dt dt = max_dt # fast_traps.append(bi.label + '_tilt_' + trap[0].name) bi_tilt_f.append(bonding_interface_f[localized_trap_key]) bi_twist_f = [] for trap in bi.dsl_twist.traps: localized_trap_key = bi.label + '_twist_' + trap[0].name + '_F' trap[0].trap_potential.get_potential_by_name( 'External Field').external_field = electric_field_at_bi print 'EXT FIELD = %2.2g V*cm' % (electric_field_at_bi / 1e2) print trap[0].trap_potential.barrier_lowering() barrier_lowering_e = 0.0 barrier_lowering_h = 0.0 df_dt, tau = trap[0].df_dt( schottky_diode.T, schottky_diode.Semiconductor, bonding_interface_f[localized_trap_key], n_bi, p_bi, barrier_lowering_e=barrier_lowering_e, barrier_lowering_h=barrier_lowering_h, use_mpmath=False, debug=False) df_bonding_interfaces[localized_trap_key] = df_dt try: max_dt = df_threshold / abs(df_dt) except ZeroDivisionError: max_dt = 1e250 if debug: print '\nTrap:', trap[0].name print 'time constant %2.2g s' % tau print 'dF: %2.4g, th: %2.2f' % (df_dt, df_threshold) print 'Max dt:', max_dt, 'dt:', dt if dt > max_dt > delta_t_min: if debug: print 'Setting dt to', max_dt dt = max_dt elif max_dt < delta_t_min: if dt > 10 * max_dt: if debug: print 'Trap is too fast. Setting trap occupation to equilibrium value' bonding_interface_f[localized_trap_key] = trap[ 0].equilibrium_f(schottky_diode.T, schottky_diode.Semiconductor, fermi_level, electron_volts=False, debug=False) localized_traps_skip_list.append(localized_trap_key) else: if debug: print 'Setting dt to', max_dt dt = max_dt # fast_traps.append(bi.label + '_twist_' + trap[0].name) bi_twist_f.append(bonding_interface_f[localized_trap_key]) bi.set_traps_f(np.array(bi_tilt_f), np.array(bi_twist_f)) bi.set_traps_df(np.zeros(len(bi_tilt_f)), np.zeros(len(bi_twist_f))) dt = np.float(dt) for dopant in schottky_diode.Semiconductor.dopants: dopant_key = dopant.name + '_F' if dopant_key in dopants_skip_list: if debug: print '\nDopant', dopant.name, 'does not need an update' continue dopants_f_corr = dopants_f[dopant_key] + df_dopants[dopant_key] * dt dopants_f_corr[np.where(dopants_f_corr > 1.0)] = 1.0 dopants_f_corr[np.where(dopants_f_corr < 0.0)] = 0.0 dopants_f_corr[np.where( z_nodes >= z_limit_f)] = dopants_f_corr[z_limit_f_idx][-1] dopant.set_F_interp(z_nodes, dopants_f_corr) dopant.set_dF_interp(z_nodes, np.zeros_like(dopants_f_corr)) for bi in schottky_diode.Semiconductor.bonding_interfaces: bi_tilt_f = [] for trap in bi.dsl_tilt.traps: localized_trap_key = bi.label + '_tilt_' + trap[0].name + '_F' if localized_trap_key not in localized_traps_skip_list: bonding_interface_f[ localized_trap_key] += df_bonding_interfaces[ localized_trap_key] * dt if bonding_interface_f[localized_trap_key] > 1: bonding_interface_f[localized_trap_key] = 1 elif bonding_interface_f[localized_trap_key] < 0: bonding_interface_f[localized_trap_key] = 0 if debug: print 'F:', bonding_interface_f[localized_trap_key] bi_tilt_f.append(bonding_interface_f[localized_trap_key]) bi_twist_f = [] for trap in bi.dsl_twist.traps: localized_trap_key = bi.label + '_twist_' + trap[0].name + '_F' if localized_trap_key not in localized_traps_skip_list: bonding_interface_f[ localized_trap_key] += df_bonding_interfaces[ localized_trap_key] * dt if bonding_interface_f[localized_trap_key] > 1: bonding_interface_f[localized_trap_key] = 1 elif bonding_interface_f[localized_trap_key] < 0: bonding_interface_f[localized_trap_key] = 0 if debug: print 'F:', bonding_interface_f[localized_trap_key] bi_twist_f.append(bonding_interface_f[localized_trap_key]) bi.set_traps_f(np.array(bi_tilt_f), np.array(bi_twist_f)) bi.set_traps_df(np.zeros(len(bi_tilt_f)), np.zeros(len(bi_twist_f))) t += dt if debug_plot: plt.ioff() return t_points, potential_t, field_d, z_t, diode_voltage_drop_t, current_density_t, \ bonding_interfaces_f_t, dopants_f_t, n_t, p_t, last_state_id