Exemple #1
0
def setup_poisson(device, region, variable_update='log_damp', **kwargs):
    """
    Sets up poisson equation solution
    Requires:
     setup physical constants and setup poisson parameters
    :param kwargs:
    :return:
    """
    logger.debug("Setting up Poisson Equation")
    # These are variables that are to be solved during the simulation
    # for sol_variable in [hole_density, electron_density, potential, qfn, qfp]:
    for sol_variable in [potential, electron_density, hole_density]:
        create_solution(device, region, sol_variable)
    total_charge_eq = f'kahan3({hole_density},-{electron_density},{p_doping})' #f'{hole_density}-{electron_density}+{p_doping}-{n_doping}' #f'-{q}*kahan4({hole_density}, -{electron_density}, {p_doping}, -{n_doping})'
    int_chg_eq = '1e11'# f'({Nc}*{Nv})^(1/2)*exp(-{bandgap}/(2*k*T))'
    # Order matters!
    for name, eq in zip([intrinsic_charge,  total_charge, ],
                        [int_chg_eq, total_charge_eq,]):
        create_node_and_derivatives(device, region, name, eq, [potential, electron_density, hole_density])
    ds.edge_from_node_model(device=device, region=region,node_model=electron_density)
    ds.edge_from_node_model(device=device, region=region, node_model=hole_density)

    e_field_eq = f"({potential}@n0-{potential}@n1)*EdgeInverseLength"
    d_field_eq = f'{e_field}*{permittivity}*{eps_0}'
    for name, eq in zip([e_field, d_field],[e_field_eq, d_field_eq]):
        create_edge_and_derivatives(device, region, name, eq, [potential])

    # Lastly, setup the equation to solve for 'potential'
    # TODO check initial values
    ds.set_node_values(device=device, region=region, name=electron_density, init_from=intrinsic_charge)
    ds.set_node_values(device=device, region=region, name=hole_density, init_from=intrinsic_charge)
    ds.equation(device=device, region=region, name='PoissonEq', variable_name=potential,
                node_model=total_charge, edge_model=d_field, variable_update=variable_update)
Exemple #2
0
def CreateSiliconPotentialOnly(device, region):
    """
        Creates the physical models for a Silicon region
    """
    if not InNodeModelList(device, region, "Potential"):
        log("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:
        CreateNodeModel(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)
        CreateEdgeModelDerivatives(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")
Exemple #3
0
def setup_poisson(device, region, variable_update='log_damp', **kwargs):
    """
    Sets up poisson equation solution
    Requires:
     setup physical constants and setup poisson parameters
    :param kwargs:
    :return:
    """
    # These are variables that are to be solved during the simulation
    # for sol_variable in [hole_density, electron_density, potential, qfn, qfp]:
    for sol_variable in [potential, qfn, qfp]:
        create_solution(device, region, sol_variable)
    hole_density_eq = f'n_i*exp( ({qfp}-{potential})*k*T/{q})'
    electron_density_eq = f'n_i*exp(({potential}-{qfn})*k*T/{q})'
    # ds.equation(device, region, name='HoleQFL', variable_name=qfn,
    #             node_model=hole_density, edge_model=)
    total_charge_eq = f'-{q}*kahan4({hole_density}, -{electron_density}, {p_doping}, -{n_doping})'

    for name, eq in zip(
        [electron_density, hole_density, total_charge],
        [electron_density_eq, hole_density_eq, total_charge_eq]):
        create_node_and_derivatives(device, region, name, eq, [potential])

    # # These are variables that exist per each node and may be spatially dependant
    # intrinsic_charge_eq = f'-{q}*kahan4({intrinsic_holes}, -{intrinsic_electrons}, {p_doping}, -{n_doping})'
    # create_node_and_derivatives(device, region, total_charge, total_charge_eq, [hole_density, electron_density, potential])
    # # intrinsic_electrons_eq = f'n_i*exp(({potential}-{qfn})/(k*T/q))'  # TODO this is not intrinsic, thsi is any!
    # # intrinsic_holes_eq = f'n_i*exp(({qfp}-{potential})/(k*T/q))'
    # # Homojunction
    # intrinsic_holes_eq = f'{10E10}^2/{intrinsic_electrons}'# f'{intrinsic_charge}^2/{intrinsic_electrons}'
    # intrinsic_electrons_eq = f"{Vt}*exp({potential}*{Vt})"# f"{intrinsic_charge}*exp({potential}*q/(k*T))"
    #
    # for name, eq in zip([intrinsic_electrons, intrinsic_holes, intrinsic_charge],
    #                     [intrinsic_electrons_eq, intrinsic_holes_eq, intrinsic_charge_eq]):
    #     create_node_and_derivatives(device, region, name, eq, [potential])

    # for name, eq in zip([qfn, qfp], [])
    # These are the variables for each edge, and connect nodes together
    e_field_eq = f"({potential}@n0-{potential}@n1)*EdgeInverseLength"
    d_field_eq = f'{e_field}*{permittivity}*{eps_0}'
    for name, eq in zip([e_field, d_field], [e_field_eq, d_field_eq]):
        create_edge_and_derivatives(device, region, name, eq, [potential])

    # Lastly, setup the equation to solve for 'potential'
    # ds.set_node_values(device=device, region=region, name=qfp, init_from=intrinsic_holes)
    # ds.set_node_values(device=device, region=region, name=qfn, init_from=intrinsic_electrons)
    ds.equation(device=device,
                region=region,
                name='PoissonEq',
                variable_name=potential,
                node_model=total_charge,
                edge_model=d_field,
                variable_update=variable_update)
Exemple #4
0
def setup_continuity(device, region, **kwargs):
    """

    :param device:
    :param region:
    :param kwargs:
    :return:
    """
    logger.debug("Setting up continuity equation")
    # These are variables that are to be solved during the simulation
    # # TODO check if these already exist?
    # for sol_variable in [hole_density, electron_density, potential]:
    #     create_solution(device, region, sol_variable)

    # These are variables that exist per each node and may be spatially dependant
    # Generation rate
    # U_SRH_eq = f'{q}*({electron_density}*{hole_density} - {intrinsic_charge}^2)/(tau_p*({electron_density}+{intrinsic_charge}) + tau_n*({hole_density}+{intrinsic_charge}))'
    # U_SRH_eq = f'({electron_density}*{hole_density} - {intrinsic_charge}^2)/(tau_p*({electron_density}+{intrinsic_charge}) + tau_n*({hole_density}+{intrinsic_charge}))'
    # for name, eq in zip([U_SRH, e_gen, h_gen], [U_SRH_eq, f'-{q}*{U_SRH_eq}', f"{q}*{U_SRH_eq}"]) :
    #     # TODO can we move SRH to its own function/method/module? yes, yes we can.
    #     create_node_and_derivatives(device, region, name, eq, [electron_density, hole_density])

    # Bernouli setup
    # ds.node_model(device=device, region=region, name='dp', equation=f'{delta_pot}*{Vt}_inv*0.5')
    # Begin finite difs of phi
    # e_current_eq = f"{ q}*mobility_n*EdgeInverseLength*k*T/{q}*kahan3({electron_density}@n1*Bern01, {electron_density}@n1*{delta_pot}, -{electron_density}@n0*Bern01)"

    for name, eq in [(f'{delta_pot}', f"q/(k*T)*({potential}@n1 - {potential}@n0)"),
                     (f'Bern01', f'B({delta_pot})'),
                     (f'Bern00', f'B(-{delta_pot})'),
                     (f'{delta_pot}:{potential}@n0', f'-q/(k*T)'),
                     (f'{delta_pot}:{potential}@n1', f'-{delta_pot}:{potential}@n0'),
                     (f'Bern01:{potential}@n0', f'dBdx({delta_pot})*{delta_pot}:{potential}@n0'),
                     (f'Bern01:{potential}@n1', f'-Bern01:{potential}@n0'),
                     (f'Bern00:{potential}@n0', f'-dBdx(-{delta_pot})*{delta_pot}:{potential}@n0'),
                     (f'Bern00:{potential}@n1', f'-Bern00:{potential}@n0')]:
        ds.edge_model(device=device, region=region, name=name, equation=eq)

    # electron continuity
    e_current_eq = f"-mobility_n*k*T*EdgeInverseLength*(Bern00*{electron_density}@n0 - Bern01*{electron_density}@n1)"
    create_edge_and_derivatives(device, region, e_current_name, e_current_eq, [electron_density, hole_density, potential])
    ds.equation(device=device, region=region, name='ECE', variable_name=electron_density,
                time_node_model=electron_density,
                edge_model=e_current_name, node_model=e_gen)

    # hole continuity
    h_current_eq =f"mobility_p*k*T*EdgeInverseLength*(-Bern00*{hole_density}@n1 + Bern01*{hole_density}@n0)"
    create_edge_and_derivatives(device, region, h_current_name, h_current_eq, [electron_density, hole_density, potential])
    ds.equation(device=device, region=region, name='HCE', variable_name=hole_density,
                time_node_model=hole_density,
                edge_model=h_current_name, node_model=h_gen)
Exemple #5
0
def CreateHCE(device, region, mu_p):
    CreateHoleCurrent(device, region, mu_p)
    PCharge = "-ElectronCharge * Holes"
    CreateNodeModel(device, region, "PCharge", PCharge)
    CreateNodeModelDerivative(device, region, "PCharge", PCharge, "Holes")

    equation(device=device,
             region=region,
             name="HoleContinuityEquation",
             variable_name="Holes",
             time_node_model="PCharge",
             edge_model="HoleCurrent",
             variable_update="positive",
             node_model="HoleGeneration")
Exemple #6
0
def CreateECE(device, region, mu_n):
    CreateElectronCurrent(device, region, mu_n)

    NCharge = "ElectronCharge * Electrons"
    CreateNodeModel(device, region, "NCharge", NCharge)
    CreateNodeModelDerivative(device, region, "NCharge", NCharge, "Electrons")

    equation(device=device,
             region=region,
             name="ElectronContinuityEquation",
             variable_name="Electrons",
             time_node_model="NCharge",
             edge_model="ElectronCurrent",
             variable_update="positive",
             node_model="ElectronGeneration")
Exemple #7
0
def CreatePE(device, region):
    pne = "-ElectronCharge*kahan3(Holes, -Electrons, NetDoping)"
    CreateNodeModel(device, region, "PotentialNodeCharge", pne)
    CreateNodeModelDerivative(device, region, "PotentialNodeCharge", pne,
                              "Electrons")
    CreateNodeModelDerivative(device, region, "PotentialNodeCharge", pne,
                              "Holes")

    equation(device=device,
             region=region,
             name="PotentialEquation",
             variable_name="Potential",
             node_model="PotentialNodeCharge",
             edge_model="PotentialEdgeFlux",
             time_node_model="",
             variable_update="log_damp")
Exemple #8
0
def create_hole_continuity_eq(device, region, mu_p):
    """
    Creates the hole continuity equation
    :param device:
    :param region:
    :param mu_p: mobility of holes
    :return:
    """
    create_hole_current(device, region, mu_p)
    PCharge = "-ElectronCharge * Holes"
    create_node_model(device, region, "PCharge", PCharge)
    CreateNodeModelDerivative(device, region, "PCharge", PCharge, "Holes")

    equation(device=device,
             region=region,
             name="HoleContinuityEquation",
             variable_name="Holes",
             time_node_model="PCharge",
             edge_model="HoleCurrent",
             variable_update="positive",
             node_model="HoleGeneration")
Exemple #9
0
def create_electron_continuity_eq(device, region, mu_n):
    """
    Creates the electron continuity equation to be solved
    :param device:
    :param region:
    :param mu_n: mobility of electrons
    :return:
    """
    create_electron_current(device, region, mu_n)

    NCharge = "ElectronCharge * Electrons"
    create_node_model(device, region, "NCharge", NCharge)
    CreateNodeModelDerivative(device, region, "NCharge", NCharge, "Electrons")

    equation(device=device,
             region=region,
             name="ElectronContinuityEquation",
             variable_name="Electrons",
             time_node_model="NCharge",
             edge_model="ElectronCurrent",
             variable_update="positive",
             node_model="ElectronGeneration")
Exemple #10
0
def set_dd_parameters(device,
                      region,
                      permittivity=11.1,
                      n_i=1E10,
                      T=300,
                      mu_n=400,
                      mu_p=200,
                      taun=1E-5,
                      taup=1E-5):
    names = [
        'permittivity', 'q', 'n_i', 'T', 'k', 'kT', 'V_t', 'mobility_n',
        'mobility_p', 'n1', 'p1', 'taun', 'taup'
    ]
    values = [
        permittivity * eps_0, q, n_i, T, k, k * T, k * T / q, mu_n, mu_p, n_i,
        n_i, taun, taup
    ]
    for name, value in zip(names, values):
        ds.set_parameter(device=device, region=region, name=name, value=value)

    # Setup the solutions for the potential, electron and hole densities
    pot = 'potential'
    electron_density = 'electron_density'
    hole_density = 'hole_density'
    for var in [pot, electron_density, hole_density]:
        create_solution(device=device, region=region, name=var)

    # Now for some poisson's equation
    # Create some nodemodels
    n_ie = 'n_ie', f"n_i*exp(q*{pot}/k*T)"  # Intrinsic electron density
    n_ih = 'n_ih', f'n_i^2/{n_ie[0]}'  # Intrinsic hole density
    net_n_i = 'net_n_i', f'kahan4(-{n_ie[0]}, {n_ih[0]}, p_doping, -n_doping)'  # Net intrinsic charge
    net_n_i_charge = 'net_n_i_charge', f'q*{net_n_i[0]}'  #PotentialIntrinsicCharge
    for name, eq in [n_ie, n_ih, net_n_i, net_n_i_charge]:
        ds.node_model(device=device, region=region, name=name, equation=eq)
        create_derivatives(device, region, name, eq, pot)

    E_field = 'E_field', f'({pot}@n0-{pot}@n1)*EdgeInverseLength'
    D_field = 'D_field', 'E_field * permittivity'  #PotentialEdgeFlux ?? wtf

    # Initialize the electron and hole densities
    for carrier, init in zip([electron_density, hole_density], [n_ie, n_ih]):
        ds.set_node_values(device=device,
                           region=region,
                           name=carrier,
                           init_from=init[0])

    # setup edge nodes
    for edge_name, eq in [E_field, D_field]:
        ds.edge_model(device=device,
                      region=region,
                      name=edge_name,
                      equation=eq)
        create_derivatives(device, region, edge_name, eq, pot)

    # Create PE
    poisson_RHS = 'PoissonRHS', f'({hole_density} - {electron_density} + p_doping - n_doping)'  #*q/(permittivity)'
    # AKA pne
    ds.node_model(device=device,
                  region=region,
                  name=poisson_RHS[0],
                  equation=poisson_RHS[1])
    create_derivatives(device, region, poisson_RHS[0], poisson_RHS[1],
                       hole_density, electron_density)
    ds.equation(device=device,
                region=region,
                name="PoissonEquation",
                variable_name=pot,
                node_model=poisson_RHS[0],
                edge_model=D_field[0])

    # Use stupid bernouli formalism
    # Check if exists?
    ds.edge_from_node_model(device=device, region=region, node_model=pot)
    beta_vdiff = 'beta_vdiff', f'({pot}@n0 - {pot}@n1)*q/kT'
    ds.edge_model(device=device,
                  region=region,
                  name=beta_vdiff[0],
                  equation=beta_vdiff[1])
    bernouli = 'bern', f'B({beta_vdiff[0]})'
    ds.edge_model(device=device,
                  region=region,
                  name=bernouli[0],
                  equation=bernouli[1])

    # Create continuity equations
    E_qf_n = (
        'quasi_fermi_n',
        f'q*({pot}-electron_affinity) + k*T*log({electron_density}/N_cond)')
    E_qf_p = (
        'quasi_fermi_p',
        f'q*({pot}-electron_affinity) - k*T*log({hole_density}/N_val) - band_gap'
    )
    J_e = 'e_current', f'q*mobility_n*{electron_density}*EdgeInverseLength*({E_qf_n[0]}@n0-{E_qf_n[0]}@n1)'
    J_h = 'h_current', f'q*mobility_p*{hole_density}*EdgeInverseLength*({E_qf_p[0]}@n0-{E_qf_p[0]}@n1)'

    for J in [E_qf_n, E_qf_p, J_e, J_h]:
        ds.edge_model(device=device, region=region, name=J[0], equation=J[1])
        ds.node_model(device=device, region=region, name=J[0], equation=J[1])
        for node_model in [pot, electron_density, hole_density]:
            # Check if exists?!
            ds.edge_from_node_model(device=device,
                                    region=region,
                                    node_model=node_model)
            create_derivatives(device, region, J[0], J[1], node_model)

    for node_model in [n_ie, n_ih, net_n_i, net_n_i_charge]:
        ds.print_node_values(device=device, region=region, name=node_model[0])

    for edge_model in [E_qf_n, E_qf_p, J_e, J_h]:
        ds.print_edge_values(device=device, region=region, name=edge_model[0])
Exemple #11
0
    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)
Exemple #12
0
def setup_continuity(device, region, **kwargs):
    """

    :param device:
    :param region:
    :param kwargs:
    :return:
    """
    # These are variables that are to be solved during the simulation
    # TODO check if these already exist?
    for sol_variable in [hole_density, electron_density, potential]:
        create_solution(device, region, sol_variable)

    # These are variables that exist per each node and may be spatially dependant
    # Generation rate
    U_SRH_eq = f'{q}*({electron_density}*{hole_density} - {intrinsic_charge}^2)/(tau_p*({electron_density}+{intrinsic_electrons}) + tau_n*({hole_density}+{intrinsic_holes}))'
    for name, eq in zip([U_SRH, e_gen, h_gen],
                        [U_SRH_eq, '-' + U_SRH_eq, U_SRH_eq]):
        # TODO can we move SRH to its own function/method/module? yes, yes we can.
        create_node_and_derivatives(device, region, name, eq,
                                    [electron_density, hole_density])

    # Bernouli setup
    ds.node_model(device=device, region=region, name=Vt, equation='k*T/q')
    ds.node_model(device=device,
                  region=region,
                  name=Vt + "_inv",
                  equation='q/(k*T)')
    for name, eq in [
        (f'{delta_pot}', f"q/(k*T)*({potential}@n0 - {potential}@n1)"),
        (f'Bern01', f'B({delta_pot})'),
        (f'{delta_pot}:{potential}@n0', f'q/(k*T)'),
        (f'{delta_pot}:{potential}@n1', f'-{delta_pot}:{potential}@n0'),
        (f'Bern01:{potential}@n0',
         f'dBdx({delta_pot})*{delta_pot}:{potential}@n0'),
        (f'Bern01:{potential}@n1', f'-Bern01:{potential}@n0')
    ]:
        ds.edge_model(device=device, region=region, name=name, equation=eq)
    # electron continuity
    e_current = f"{q}*mobility_n*EdgeInverseLength*k*T/{q}*kahan3({electron_density}@n1*Bern01, {electron_density}@n1*{delta_pot}, -{electron_density}@n0*Bern01)"
    create_edge_and_derivatives(device, region, e_current_name, e_current,
                                [electron_density, hole_density, potential])
    ds.equation(device=device,
                region=region,
                name='ECE',
                variable_name=electron_density,
                time_node_model=electron_density,
                edge_model=e_current_name,
                node_model=e_gen)

    # hole continuity
    h_current = f"-{q}*mobility_p*EdgeInverseLength*k*T/{q}*kahan3({hole_density}@n1*Bern01, -{hole_density}@n0*vdiff, -{hole_density}@n0*Bern01)"
    create_edge_and_derivatives(device, region, h_current_name, h_current,
                                [electron_density, hole_density, potential])
    ds.equation(device=device,
                region=region,
                name='HCE',
                variable_name=hole_density,
                time_node_model=hole_density,
                edge_model=h_current_name,
                node_model=h_gen)