def plot_charge(device=None,regions=None, charge_names=None): """ Plots the charge along the device :param device: :param regions: :param charge_names: :return: """ if device is None: device = ds.get_device_list()[0] if regions is None: regions = ds.get_region_list(device=device) if charge_names is None: charge_names = ("Electrons", "Holes", "Donors", "Acceptors") plt.figure(figsize=(6, 2.7)) labels = [] for var_name in charge_names: total_x = np.array([]) total_y = [] for region in regions: labels.append(f"{var_name} in {region}") x = np.array(ds.get_node_model_values(device=device, region=region, name="x")) # print(var_name, min(x), max(x), min(x)*1e4, max(x)*1e4) total_x = np.append(total_x, x) y=ds.get_node_model_values(device=device, region=region, name=var_name) total_y.extend(y) # plt.axis([min(x), max(x), ymin, ymax]) plt.semilogy(x*1e4, y) plt.xlabel('x (um)') plt.ylabel('Density (#/cm^3)') plt.legend(labels) plt.title('Charge Density')
def get_ds_status(): devices = ds.get_device_list() for device in devices: print("Device: " + device) regions = ds.get_region_list(device=device) for region in regions: print("\tRegion :" + region) params = ds.get_parameter_list(device=device, region=region) for param in params: val = ds.get_parameter(device=device, region=region, name=param) print(f"\t\t{param} = {val}") n_models = ds.get_node_model_list(device=device, region=region) for node_model in n_models: nmvals = ds.get_node_model_values(device=device, region=region, name=node_model) print(f"\t\t Node Model '{node_model}' = {nmvals!s}") e_models = ds.get_edge_model_list(device=device, region=region) for edge_model in e_models: emvals = ds.get_edge_model_values(device=device, region=region, name=edge_model) print(f"\t\t Edge Model '{edge_model}' = {emvals!s}") contacts = ds.get_contact_list(device=device) for contact in contacts: print("\tContact : " + contact) c_eqs = ds.get_contact_equation_list(device=device, contact=contact) for ceq in c_eqs: print("\t\tContact Equation : " + ceq)
def plot_band_diagram(device=None, regions=None, ec_name='EC', ev_name='EV'): if device is None: device = ds.get_device_list()[0] if regions is None: regions = ds.get_region_list(device=device) plt.figure(figsize=(6, 2.7)) labels = [] for region in regions: x = np.array(ds.get_node_model_values(device=device, region=region, name="x")) for band in [ec_name, ev_name]: band_edge = ds.get_node_model_values(device=device, region=region, name=band) plt.plot(x * 1e4, band_edge, marker='o', linestyle='-', markersize=3) labels.append(f'{band} in {region}') plt.legend(labels) plt.xlabel('x (µm)') plt.ylabel('Energy (eV)') plt.title('Band Diagram')
def plot_potential(device=None, regions=None, potential='Potential'): if device is None: device = ds.get_device_list()[0] if regions is None: regions = ds.get_region_list(device=device) plt.figure() pots = np.array([]) total_x = np.array([]) for region in regions: x = np.array(ds.get_node_model_values(device=device, region=region, name="x")) # print(var_name, min(x), max(x), min(x)*1e4, max(x)*1e4) total_x = np.append(total_x, x) new_pots = ds.get_node_model_values(device=device, region=region, name=potential) pots = np.append(pots, new_pots) plt.plot(x*1e4, new_pots, marker='o', linestyle='-', markersize=3) plt.legend(regions) # plt.plot(total_x*1e4, pots) plt.xlabel('X (um)') plt.ylabel('Potential (V)') plt.title(potential)
def solve(self, *args, **kwargs): for region in self.device.mesh.regions: log.info('Computing photogeneration for region: %s' % region) # Assume 1D for now nodes = ds.get_node_model_values(device=self.device.name, region=region, name='x') pg = np.zeros((len(nodes), len(self.light_source)), dtype=float) rfidx = RefractiveIndex(region.material) for idλ, λ in enumerate(self.light_source): # I know, using unicode names here is asking for trouble # ... but looks nice when using greek letters # TODO: compute the real reflection R = 0 # λ is nm, but irradiance's units are W⋅m–2⋅nm–1 P = self.light_source.irradiance(λ) Φ_0 = (P * λ * 1e-9 / PhysicalConstants.hc) * (1 - R) # α(λ)'s units are cm-1. But we use m α = rfidx.alpha(λ) * 1e+2 # TODO: do not assume conversion efficiency is 100% (1 photon = 1EHP by now) η_g = 1.0 # Debug print('\n' + '-' * 70) print('Photogeneration dump. Parameters:') print( 'λ={:.2f} nm; P(λ)={:.2f}; Φ_0(λ)={:8.2e} m-2 s-1; α(λ)={:8.2e} m-1' .format(λ, P, Φ_0, α)) print('-' * 24) print(' x(μm) | G_op(x, λ)') print('-' * 24) for idx, x in enumerate(nodes): pg[idx, idλ] = η_g * Φ_0 * exp(-α * x) print('{:8.2f} | {:8.2e}'.format(x * 1e6, pg[idx, idλ])) # Total photogeneration for each node # Conditions: # 100% quantum efficiency # Ignoring reflection pgen_by_node = np.add.reduce(pg, 1) for i, v in enumerate(pgen_by_node): ds.set_node_value(device=self.device.name, region=region, name='G_op', index=i, value=float(v)) if 'type' in kwargs: ds.solve(**kwargs) else: ds.solve(type='dc', **kwargs)
def get_ds_status(short=True): """ Prints the status of the current devsim setup and all variables, solutions, node models and edge models :return: """ for device in ds.get_device_list(): print("Device: " + device) for region in ds.get_region_list(device=device): print("\tRegion :" + region) params = ds.get_parameter_list(device=device, region=region) for param in params: val = ds.get_parameter(device=device, region=region, name=param) print(f"\t\t{param} = {val}") for node_model in ds.get_node_model_list(device=device, region=region): nmvals = ds.get_node_model_values(device=device, region=region, name=node_model) nmstr = ','.join([f'{val:.3g}' for val in nmvals]) print(f"\t\tNode Model '{node_model}' = {nmstr!s}") e_models = ds.get_edge_model_list(device=device, region=region) for edge_model in e_models: emvals = ds.get_edge_model_values(device=device, region=region, name=edge_model) emstr = ','.join([f'{val:.3g}' for val in emvals]) print(f"\t\tEdge Model '{edge_model}' = {emstr}") for interface in ds.get_interface_list(device=device): print("\tInterface: " + interface) for imodel in ds.get_interface_model_list(device=device, interface=interface): intstr = ','.join([ f'{val:.3g}' for val in ds.get_interface_model_values( device=device, interface=interface, name=imodel) ]) print(f"\t\tInterface Model: '{imodel}' = {intstr}") for ieq in ds.get_interface_equation_list(device=device, interface=interface): # comm = ds.get_interface_equation_command(device=device, interface=interface, name=ieq) print(f"\t\tInterface Equation: {ieq}") contacts = ds.get_contact_list(device=device) for contact in contacts: print("\tContact : " + contact) c_eqs = ds.get_contact_equation_list(device=device, contact=contact) for ceq in c_eqs: print("\t\tContact Equation : " + ceq)
def test_node_model(self): # Define mesh (default units are micrometers) mesh = Mesh('Test Mesh') mesh.add_line(0.0, 0.01, 'left') mesh.add_line(10.0, 1.0, 'right') mesh.add_contact(name='left', tag='left', material=materials.Metals.generic) mesh.add_contact(name='right', tag='right', material=materials.Metals.generic) mesh.add_region(name='Bulk', material=materials.Silicon(), tag1='left', tag2='right') mesh.finalize() class SolarCell(Device): def __init__(self, name=None, mesh=None): super(SolarCell, self).__init__(name, mesh) # This is specific to this device self.set_node_model('Bulk', 'Acceptors', '1.0e16*step(0.5e-5-x)') self.set_node_model('Bulk', 'Donors', '1.0e18*step(x-0.5e-5)') self.set_node_model('Bulk', 'NetDoping', 'Donors-Acceptors') scell = SolarCell('MySolarCell', mesh=mesh) # Stablish conditions (light) # Setup the model from devsim.materials.light_sources import AM0 from devsim.models import BeerLambertModel mdl = BeerLambertModel(scell, AM0(samples=25)) scell.setup_model(mdl) # Solve scell.initial_solution('Bulk') scell.solve(type="dc", absolute_error=1.0, relative_error=1e-10, maximum_iterations=30) scell.export('scell.dat') # Check results results = [ n for n in get_node_model_values( device=scell.name, region=scell.mesh.regions[0], name='G_op') ] self.assertEqual(len(results), 47)
# PrintCurrents(device, "bot") tot_top, tot_bot = get_total_current(device) top_currents.append(tot_top) bot_currents.append(tot_bot) print(f"Total top: {tot_top:.2E} and total bottom: {tot_bot:.2E}") # bias_volt += 0.1 # v += 1 # plt.plot(volt_sweep, top_currents) # plt.plot(volt_sweep, bot_currents) plt.semilogy(volt_sweep, np.abs(np.array(top_currents) - np.array(bot_currents))) plt.show() write_devices(file="boring diode.dat", type="tecplot") x = get_node_model_values(device=device, region=region, name="x") ymax = 10 ymin = 10 fields = ("Electrons", "Holes", "Donors", "Acceptors") for i in fields: node_m_vals = get_node_model_values(device=device, region=region, name=i) if (max(node_m_vals) > ymax): ymax = max(node_m_vals) plt.semilogy(x, node_m_vals) plt.xlabel('x (cm)') plt.ylabel('Density (#/cm^3)') plt.legend(fields) ymax *= 10 plt.axis([min(x), max(x), ymin, ymax]) plt.savefig("diode_1d_density.png")
ds.create_device(mesh=meshname, device=device) setup_physical_constants(device, region) setup_poisson_parameters(device, region, p_doping=1e18) setup_poisson(device, region) get_ds_status() ds.solve(type="dc", absolute_error=10, relative_error=10, maximum_iterations=30) get_ds_status() print("Post solve") setup_continuity(device, region) ds.solve(type="dc", absolute_error=10, relative_error=1e1, maximum_iterations=30) for volt in [-1, 0, 1]: ds.set_parameter(device=device, name='top_contact_bias', value=float(volt)) chrg = ds.get_node_model_values(device=device, region=region, name=total_charge) pot = ds.get_edge_model_values(device=device, region=region, name=e_field) for data in [chrg, pot]: plt.figure() plt.plot(data) plt.show() # Ei = (Ec + Ev) / 2