pynitride.physics.solvers module

class pynitride.physics.solvers.Equilibrium(mesh)

Bases: object

Simplest Fermi solver, E_F=0 everywhere.

Parameters:

mesh – the Mesh on which to perform the solve

solve()

Sets E_F=0 everywhere.

class pynitride.physics.solvers.Linear_Fermi(mesh, contacts={'gate': 0, 'subs': -1})

Bases: object

Allows for a specified piecewise linear Fermi potential.

An arbitrary number of “contacts” can be designated, and at each of these locations, a call to solve() may specify a voltage.

Parameters:
  • mesh – the Mesh on which to perform the solve

  • contacts – a dictionary mapping names of contacts to locations in the mesh. Keys are arbitrary names, values are either (1) integers, in which case they will be interpreted as designating a layer interface (0 is the top surface, -1 is the bottom point), or (2) floats, in which case they will be interpreted as designating a nearest point to a z-value

solve(**voltages)

Sets the Fermi level to a linear interpolation of the specific values

Parameters:

**voltages – keyword arguments of the form name=voltage where name is one of the keys to the contacts dictionary supplied at initialization.

class pynitride.physics.solvers.PoissonSolver(mesh)

Bases: object

Solves the Poisson equation on a mesh.

The boundary conditions assumed are Dirichelet at the surface (ie fixed surface barrier) and Neumann at the bottom (ie thick substrate). Accounts for charge from (1) carriers which are filled into mesh[‘n’] and mesh[‘p’] by some Carrier Model (2) polarization which is filled into mesh[‘P’] (generally by the MaterialSystem), differentiating that to fill mesh[‘DP’], and (3) dopants which for which the values are drawn from the mesh (see ionized_dopants()).

Two solve functions are available: solve() and newton_step(). The former is a direct solution, which can be obtained directly from charge integration. The latter is a Newton-method solver appropriate for self-consistent iteration with a carrier solver. For use with this method, the carrier models must implement not just n and p but also nderiv and pderiv to supply the relevant derivative information.

A static convenience function update_bands_to_potential() is also available to set bands for simulations where the Poisson equation is not needed.

Parameters:

mesh – the Mesh on which to perform the solve

static get_sbh(m)

Get the surface barrier for a given mesh.

If the mesh boundary is specified numerically, that’s the surface barrier, otherwise asks the topmost material system for it’s surface barrier given the mesh.

Parameters:

m – the global Mesh

Returns:

the surface barrier (float)

ionized_dopants()

Computes the ionized dopant densities and their derivatives

Fills the values Ndp, Ndpderiv, Nam, Namderiv onto the mesh for the total ionized donor and acceptor densities and derivatives.

newton_step(activation=1)

Solves the phi for one step of Newton iteration.

The equation is \(-\left[\partial_z\epsilon\partial_z+\rho_0'\right]\delta\phi=\rho + \partial_z\epsilon\partial_z\phi_0\).

Parameters:

activation – a factor (generally <=1) by which to multiply the determined change \(\delta\phi\) before adding it.

restore_state()

Restores the most recently saved phi.

Useful in iterative self-consistent solves for returning back to “the last point where things worked”. See store_state().

shorten_last_step(factor)

Shortens the phi step taken by the most recent solve by the given factor.

Parameters:

factor (float) – the amount (0-1) by which the previous step should be rescaled

solve()

Solves the Poisson equation directly (not good for self-consistent looping)

The equation is \(-\partial_z\epsilon\partial_z\phi=\rho\). Do not use this function in a self-consistent poisson-carrier loop, because that’s not super stable. Instead use newton_step().

store_state()

Stores the current phi in case we want to return to this current solution.

Useful in iterative self-consistent solves for returning back to “the last point where things worked”. See restore_state().

static update_bands_to_potential(m, phi=None, sbh=None)

Updates Ec, Ev, and phi to match the phi (potential) given.

Parameters:
  • m – the Mesh

  • phi – the new phi to use (MidFunction or scalar), None to just use current

  • sbh – the surface potential, if not specified, will be calculated from the mesh

update_epsfactor(epsfactor)

Scales the epsilon used by this solver without actually changing epsilon on the mesh.

The higher the epsfactor, the less coupling between phi and charge, iterative solutions are easier. The resulting solution is, of course, not correct for epsfactor!=1, but ramping epsfactor from a large value where the problem is easy down to 1 is a useful way to smoothly approach the solution.

Parameters:

epsfactor – the factor (generally >=1) by which epsilon should be scaled

class pynitride.physics.solvers.SelfConsistentLoop(fieldsolvers=[], carriermodels=[])

Bases: object

For Newton-iteration of field and carrier solvers.

Dielectric ramping is provided for initial solutions and carrier models can be swapped in and out to allow for sequential solves by different methods.

Parameters:
  • fieldsolvers – a list of PoissonSolver

  • carriermodels – a list of CarrierModel

add_carrier_model(cs)

Add a carrier solver for consideration.

Parameters:

cs – a CarrierModel

loop(tol=1e-05, max_iter=100, min_activation=0.05, init_activation=1, dec_activation=2, inc_activation=1.1, max_activation=1)

Loops the Newton field solution and carrier models until they agree

If the error increases during a step, the step will be retried with a smaller activation (see newton_solve()). If the activation becomes too small or the maximum number of iterations is passed, will raise an exception.

Note, the first step in the solve is always the carriers, so they may be in any state before this function is called, whereas the fields must already be defined, eg by update_bands_to_potential().

Parameters:
  • tol – the absolute tolerance for the error as returned by newton_step()

  • max_iter – Maximum number of iterations allowed (not including any lower-activation re-attempts made)

  • min_activation – the smallest activation allowed.

  • init_activation – activation to start looping at

  • dec_activation – factor by which to reduce the activation if a step fails

  • inc_activation – factor by which to increase the activation if a step succeeds

newton_fields(activation=1)

Perform one Newton step of the fields (just the fields, not the carriers).

Calls the newton_step() for each field solver.

Parameters:

activation – the proportion by which to change the fields (see ~pynitride.solvers.PoissonSolver.newton_step)

Returns:

the summed error from each field solver’s newton_step

ramp_epsfactor(start=10000.0, stop=1, dlefstart=0.1, dlefmax=0.5, dlefmin=0.005, **loop_opts)

Ramp the dielectric constant for an easy initial condition.

Performs self-consistent loops at successive values of the epsfactor (see update_epsfactor()) from start until the stop value is reached. If the loops do not converge, smaller steps of the epsilon factor are attempted, this robustness is controlled by the dlef arguments, which constrain dlef (the logarithmic change in the epsilon factor from step to step, ie log10(epsfactor) changes by dlef). If the step cannot be reduced further but the loop does not converge, an exception will be raised.

Parameters:
  • start – initial value of epsfactor

  • stop – final value of epsfactor

  • dlefstart – initial logarithmic delta for epsfactor stepping

  • dlefmax – maximum allowed logarithmic delta for epsfactor stepping

  • dlefmin – minimum allowed logarithmic delta for epsfactor stepping

  • loop_opts – passed to each pynitride.solvers.SelfConsistentLoop.loop

ramp_temperature(temp_solver, start=300, stop=300, dlTstart=0.025, dlTmax=0.1, dlTmin=0.005, **loop_opts)

Ramp the temperature for an easy initial condition.

Performs self-consistent loops at successive values of the temperature from start until the stop value is reached. If the loops do not converge, smaller steps of the temperature are attempted, this robustness is controlled by the dlT arguments, which constrain dlT (the logarithmic change in the temperature from step to step, ie log10(temperature) changes by dlT). If the step cannot be reduced further but the loop does not converge, an exception will be raised.

Parameters:
  • start – initial value of temperature

  • stop – final value of temperature

  • dlTstart – initial logarithmic delta for temperature stepping

  • dlTmax – maximum allowed logarithmic delta for temperature stepping

  • dlTmin – minimum allowed logarithmic delta for temperature stepping

  • loop_opts – passed to each pynitride.solvers.SelfConsistentLoop.loop

remove_carrier_model(cs)

Remove a carrier solver from consideration.

Parameters:

cs – a CarrierModel which should be in the list currently considered

solve_carriers()

Perform a direct solve of the carriers (just the carriers, not the fields).

Calls the solve() for each.

solve_fields()

Perform a direct solve of the fields (just the fields, not the carriers).

Calls the solve() for each field solver.

swap_carrier_model(remove, add)

Swaps out one CarrierModel for another

Parameters:
  • remove – the model to remove

  • add – the model to add