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 CreateSiliconPotentialOnly(device, region): """ Creates the physical models for a Silicon region """ if not "Potential" in get_node_model_list(device=device, region=region): logger.debug("Creating Node Solution Potential") CreateSolution(device, region, "Potential") # require NetDoping intrinsics = (("IntrinsicElectrons", "n_i*exp(Potential/V_t)"), ("IntrinsicHoles", "n_i^2/IntrinsicElectrons"), ("IntrinsicCharge", "kahan3(IntrinsicHoles, -IntrinsicElectrons, NetDoping)"), ("PotentialIntrinsicCharge", "-ElectronCharge * IntrinsicCharge")) for name, eq in intrinsics: create_node_model(device, region, name, eq) CreateNodeModelDerivative(device, region, name, eq, "Potential") # TODO: Edge Average Model electrics = (("ElectricField", "(Potential@n0-Potential@n1)*EdgeInverseLength"), ("PotentialEdgeFlux", "Permittivity * ElectricField")) for name, eq in electrics: CreateEdgeModel(device, region, name, eq) create_edge_model_derivatives(device, region, name, eq, "Potential") equation(device=device, region=region, name="PotentialEquation", variable_name="Potential", node_model="PotentialIntrinsicCharge", edge_model="PotentialEdgeFlux", variable_update="log_damp")
def ensure_edge_from_node_model_exists(device, region, nodemodel): """ Checks if the edge models exists """ if nodemodel not in get_node_model_list(device=device, region=region): raise ValueError(f"{nodemodel} must exist") # emlist = get_edge_model_list(device=device, region=region) emtest = ("{0}@n0".format(nodemodel) and "{0}@n1".format(nodemodel)) if not emtest: logger.debug("INFO: Creating ${0}@n0 and ${0}@n1".format(nodemodel)) edge_from_node_model(device=device, region=region, node_model=nodemodel)
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 CreateSiliconPotentialOnlyContact(device, region, contact, is_circuit=False): """ Creates the potential equation at the contact if is_circuit is true, than use node given by GetContactBiasName """ # Means of determining contact charge # Same for all contacts if "contactcharge_node" not in get_node_model_list(device=device, region=region): create_node_model(device, region, "contactcharge_node", "ElectronCharge*IntrinsicCharge") # TODO: This is the same as D-Field if "contactcharge_edge" not in get_edge_model_list(device=device, region=region): CreateEdgeModel(device, region, "contactcharge_edge", "Permittivity*ElectricField") create_edge_model_derivatives(device, region, "contactcharge_edge", "Permittivity*ElectricField", "Potential")
def InNodeModelList(device, region, model): """ Checks to see if this node model is available on device and region """ return model in get_node_model_list(device=device, region=region)
region=region, node_model="x", edge_model="xmid") xmid = get_edge_model_values(device=device, region=region, name="xmid") efields = ( "ElectronCurrent", "HoleCurrent", ) node_m_vals = get_edge_model_values(device=device, region=region, name="ElectronCurrent") ymin = min(node_m_vals) ymax = max(node_m_vals) for i in efields: node_m_vals = get_edge_model_values(device=device, region=region, name=i) if min(node_m_vals) < ymin: ymin = min(node_m_vals) elif max(node_m_vals) > ymax: ymax = max(node_m_vals) print(get_node_model_list(device=device)) plt.plot(xmid, node_m_vals) plt.xlabel('x (cm)') plt.ylabel('J (A/cm^2)') plt.legend(efields) # plt.axis([min(x), max(x), 0.5*ymin, 2*ymax]) plt.savefig("diode_1d_current.png") plt.show() print(ymin) print(ymax)
def setup_drift_diffusion(self, dielectric_const=11.9, intrinsic_carriers=1E10, work_function=4.05, band_gap=1.124, Ncond=3E19, Nval=3E19, mobility_n=1107, mobility_p=424.6, Nacceptors=0, Ndonors=0): """ Sets up equations for a drift-diffusion style of dc current transport. kwargs here are device-level parameters, imbuing all regions with these properties If a specific region or material is to have a different set of parameters, they can be set through the Region constructor. :param dielectric_const: :param intrinsic_carriers: :param work_function: :param band_gap: :param Ncond: :param Nval: :param mobility_n: :param mobility_p: :param Nacceptors: :param Ndonors: :return: """ # Begin legacy copy-paste job # Set silicon parameters device = self.name region = self.regions[0].name eps_si = dielectric_const n_i = 1E10 k = kb mu_n = mobility_n mu_p = mobility_p set_parameter(device=device, region=region, name="Permittivity", value=eps_si * eps_0) set_parameter(device=device, region=region, name="ElectronCharge", value=q) set_parameter(device=device, region=region, name="n_i", value=n_i) set_parameter(device=device, region=region, name="T", value=T) set_parameter(device=device, region=region, name="kT", value=k * T) set_parameter(device=device, region=region, name="V_t", value=k * T / q) set_parameter(device=device, region=region, name="mu_n", value=mu_n) set_parameter(device=device, region=region, name="mu_p", value=mu_p) # default SRH parameters set_parameter(device=device, region=region, name="n1", value=n_i) set_parameter(device=device, region=region, name="p1", value=n_i) set_parameter(device=device, region=region, name="taun", value=1e-5) set_parameter(device=device, region=region, name="taup", value=1e-5) # CreateNodeModel 3 times for name, value in [('Acceptors', "1.0e18*step(0.5e-5-x)"), ('Donors', "1.0e18*step(x-0.5e-5)"), ('NetDoping', "Donors-Acceptors")]: result = node_model(device=device, region=region, name=name, equation=value) logger.debug(f"NODEMODEL {device} {region} {name} '{result}'") print_node_values(device=device, region=region, name="NetDoping") model_name = "Potential" node_solution(name=model_name, device=device, region=region) edge_from_node_model(node_model=model_name, device=device, region=region) # Create silicon potentialOnly if model_name not in get_node_model_list(device=device, region=region): logger.debug("Creating Node Solution Potential") node_solution(device=device, region=region, name=model_name) edge_from_node_model(node_model=model_name, device=device, region=region) # require NetDoping for name, eq in ( ("IntrinsicElectrons", "n_i*exp(Potential/V_t)"), ("IntrinsicHoles", "n_i^2/IntrinsicElectrons"), ("IntrinsicCharge", "kahan3(IntrinsicHoles, -IntrinsicElectrons, NetDoping)"), ("PotentialIntrinsicCharge", "-ElectronCharge * IntrinsicCharge")): node_model(device=device, region=region, name=name, equation=eq) node_model(device=device, region=region, name=f"{name}:{model_name}", equation=f"simplify(diff({eq},{model_name}))") # CreateNodeModelDerivative(device, region, name, eq, model_name) ### TODO: Edge Average Model for name, eq in (("ElectricField", "(Potential@n0-Potential@n1)*EdgeInverseLength"), ("PotentialEdgeFlux", "Permittivity * ElectricField")): edge_model(device=device, region=region, name=name, equation=eq) edge_model(device=device, region=region, name=f"{name}:{model_name}@n0", equation=f"simplify(diff({eq}, {model_name}@n0))") edge_model(device=device, region=region, name=f"{name}:{model_name}@n1", equation=f"simplify(diff({eq}, {model_name}@n1))") equation(device=device, region=region, name="PotentialEquation", variable_name=model_name, node_model="PotentialIntrinsicCharge", edge_model="PotentialEdgeFlux", variable_update="log_damp") # Set up the contacts applying a bias is_circuit = False for contact_name in get_contact_list(device=device): set_parameter(device=device, name=f"{contact_name}_bias", value=0.0) # CreateSiliconPotentialOnlyContact(device, region, contact_name) # Start # Means of determining contact charge # Same for all contacts if not InNodeModelList(device, region, "contactcharge_node"): create_node_model(device, region, "contactcharge_node", "ElectronCharge*IntrinsicCharge") #### TODO: This is the same as D-Field if not InEdgeModelList(device, region, "contactcharge_edge"): CreateEdgeModel(device, region, "contactcharge_edge", "Permittivity*ElectricField") create_edge_model_derivatives(device, region, "contactcharge_edge", "Permittivity*ElectricField", "Potential") # set_parameter(device=device, region=region, name=GetContactBiasName(contact), value=0.0) contact_bias_name = f"{contact_name}_bias" contact_model_name = f"{contact_name}nodemodel" contact_model = f"Potential -{contact_bias_name} + ifelse(NetDoping > 0, -V_t*log({CELEC_MODEL!s}/n_i), V_t*log({CHOLE_MODEL!s}/n_i))"\ CreateContactNodeModel(device, contact_name, contact_model_name, contact_model) # Simplify it too complicated CreateContactNodeModel( device, contact_name, "{0}:{1}".format(contact_model_name, "Potential"), "1") if is_circuit: CreateContactNodeModel( device, contact_name, "{0}:{1}".format(contact_model_name, contact_bias_name), "-1") if is_circuit: contact_equation(device=device, contact=contact_name, name="PotentialEquation", variable_name="Potential", node_model=contact_model_name, edge_model="", node_charge_model="contactcharge_node", edge_charge_model="contactcharge_edge", node_current_model="", edge_current_model="", circuit_node=contact_bias_name) else: contact_equation(device=device, contact=contact_name, name="PotentialEquation", variable_name="Potential", node_model=contact_model_name, edge_model="", node_charge_model="contactcharge_node", edge_charge_model="contactcharge_edge", node_current_model="", edge_current_model="") # Biggie # Initial DC solution solve(type="dc", absolute_error=1.0, relative_error=1e-10, maximum_iterations=30) drift_diffusion_initial_solution(device, region) solve(type="dc", absolute_error=1e10, relative_error=1e-10, maximum_iterations=30)
def model_exists(device, region, model): """ Checks whether this node model is available on any device and region """ return model in ds.get_node_model_list(device=device, region=region)