Home Examples Screenshots User manual Bluesky logo YouTube
OghmaNano Multiphysics simulation platform for optoelectronic devices and photonic systems DOWNLOAD Quick Start guide

Speeding up device simulations

If you run a large number of simulations, the speed at which each one completes matters. This page explains how to make OghmaNano's electrical solver run faster. Because the useful settings only make sense once you understand what the solver is actually doing, the first half of the page covers the foundations of the model — the equations that are solved and how they are solved — and the second half shows how to tune the solver to shorten run times. The physics is unchanged by any of these settings; they affect only how quickly the numerical solution is reached.

This page has a little more maths than most. The key idea to carry through is that solving the device equations is really a root-finding problem: OghmaNano repeatedly improves a guess until an error function f(x) falls to zero. Everything in the tuning section is about reaching that point in fewer iterations.

1. The foundations of the model

Before looking at how to speed a simulation up, it helps to know what OghmaNano is computing. To account for charge transport in a device, OghmaNano solves the basic drift–diffusion equations together with Poisson's equation (Gauss's law). These are solved on a finite-difference mesh across the device, so that charge movement from one contact to the other can be tracked in both the conduction (LUMO) and valence (HOMO) levels.

1.1 Charge transport across the device

Poisson's equation relates the electrostatic potential to the free charge, while the two current equations describe the electron and hole driving terms (drift plus diffusion):

\[ \nabla \cdot \varepsilon_0 \varepsilon_r \nabla \phi = q\,(n - p) \] \[ J_n = q\,\mu_e\,n\,\nabla E_c + q\,D_n\,\nabla n \] \[ J_p = q\,\mu_h\,p\,\nabla E_v - q\,D_p\,\nabla p \]

These current densities are then substituted into the electron and hole continuity equations, which balance the flow of current against recombination, trapping and the time rate of change of the free-carrier populations:

\[ \nabla \cdot \mathbf{J}_n = q\left( R_n + T_n + \frac{\partial n_{\text{free}}}{\partial t} \right) \] \[ \nabla \cdot \mathbf{J}_p = -q\left( R_p + T_p + \frac{\partial p_{\text{free}}}{\partial t} \right) \]

Here \( \phi \) is the electrostatic potential, \( n \) and \( p \) the free electron and hole densities, \( \mu_e \) and \( \mu_h \) the mobilities, \( D_n \) and \( D_p \) the diffusion coefficients, \( E_c \) and \( E_v \) the band edges, \( R \) the recombination rate, and \( T \) the net rate at which carriers are captured into traps. The full derivation and sign conventions follow MacKenzie et al., J. Phys. Chem. C (doi:10.1021/jp200234m).

1.2 Charge trapping and recombination

Density-of-states diagram plotting electron energy against log(DOS). A green parabolic band of free electrons sits at the top at the electron mobility edge mu_e^0, a magenta parabolic band of free holes at the bottom at the hole mobility edge mu_h^0. Red exponential trap states descend from the electron trap edge E_e^d and blue exponential trap states rise from the hole trap edge E_h^d. Curved arrows labelled r1 and r2 connect the free electrons to the traps (capture and emission), and arrows r3 and r4 connect the traps to the free holes.
The Shockley–Read–Hall capture/escape picture solved at every mesh point. Free carriers (nfree, pfree) sit in parabolic bands at the mobility edges \( \mu_e^0 \) / \( \mu_h^0 \); the red and blue triangles are the exponential distributions of electron and hole trap states. The rates \( r_1 \)–\( r_4 \) are capture into and emission out of the traps.

Charge trapping and recombination are important in organic devices and in many other material systems, so they must be modelled explicitly. It is common to reduce Shockley–Read–Hall (SRH) recombination to a single steady-state expression, which is easy to solve. OghmaNano does not do this: because the goal is to solve the equations in the time domain, the full set of SRH capture/escape rate equations is solved at each mesh point on the finite-difference grid.

At each point the situation shown in ?? is solved. The parabolas at the top and bottom are the free-carrier bands at the electron and hole mobility edges. Descending from the electron trap edge \( E_e^d \) is an exponential distribution of electron traps (red); rising from the hole trap edge \( E_h^d \) is an exponential distribution of hole traps (blue). Every one of the discrete levels within these distributions is an individual trap, and for each one the full capture-and-escape rate equations are solved. The change in the trapped-electron population of a level is the balance of four rates:

\[ \frac{\partial n_t}{\partial t} = r_1 - r_2 - r_3 + r_4 \]

where \( r_1 \) is electron capture, \( r_2 \) electron emission, \( r_3 \) hole capture and \( r_4 \) hole emission, each following the usual capture/emission form set by the trap density, the carrier density, the capture cross-section and the thermal velocity (see the reference above). Detailed balance is maintained across all levels. Summing the net capture over the trap distribution gives the free-carrier recombination rate:

\[ R_n = \sum_{0}^{n_{\text{band}}} \left( r_1^{\,e} - r_2^{\,e} \right) \]

Why this matters for speed. Solving the trap distribution in energy space, at every point in position space, produces a full map of charge density as a function of both energy and position. This is what lets OghmaNano perform transient calculations without the usual steady-state approximations — but it is also why there are many coupled equations to solve at once, and therefore why the choice of numerical method, and its settings, has a real effect on run time.

2. How the equations are solved: Newton's method

All of the equations above are solved with Newton's method, published by Isaac Newton in 1671 in Method of Fluxions. It is one of the most efficient and robust methods available for this type of coupled equation set: if an equation cannot be solved by hand, Newton's method will almost always find an answer.

2.1 Roots and the error function

Start with something easy. For what values of x does the following equation equal zero?

\[ 0 = (x - 3)(x - 40) \]

By inspection the answer is \( x = 3 \) and \( x = 40 \). These are the roots of the equation. The same problem can be written as a function,

\[ f(x) = (x - 3)(x - 40), \]

and if \( f(x) \) is plotted against \( x \), the roots are simply the places where the curve crosses the axis, i.e. where \( f(x) = 0 \). Thinking of the equation as an error function that is driven to zero is the key idea. In the device model, \( x \) is replaced by the physical unknowns — the potential \( \phi \), and the electron and hole quasi-Fermi levels \( E_{Fn} \) and \( E_{Fp} \) — and the values of those variables are adjusted until \( f(x) = 0 \).

Roots are only obvious by eye for simple equations. Consider instead

\[ f(x) = \frac{(x^2 + 10x - 3)\,\cos^2(4x)}{\tan(x)}. \]

Plotting this to find its roots would be a lot of effort, and the device equations are far worse. This is exactly where Newton's method earns its place.

2.2 The method, step by step

Take a concrete example, \( f(x) = x^2 + 10x - 3 \). Newton's method proceeds as follows:

  1. Differentiate the equation with respect to the variable being solved for: \( f'(x) = 2x + 10 \).
  2. Guess the root. Any value will do — take \( x = 10 \). It is a poor guess (\( f(10) = 197 \), nowhere near zero), but that does not matter.
  3. Evaluate the function and its derivative at the guess: \( f(10) = 197 \) and \( f'(10) = 30 \).
  4. Compute a better guess using Newton's update:
\[ x_{+1} = x - \frac{f(x)}{f'(x)} \]

Substituting the values gives a better estimate, \( x_{+1} = 10 - 197/30 = 3.433 \). The procedure is then simply repeated: feed the improved guess back in, evaluate again (\( f(3.433) = 43.115 \), \( f'(3.433) = 16.866 \)), and obtain a still-better estimate of \( 0.877 \), and so on. Each pass drives the error function closer to zero and the estimate closer to the true root.

2.3 A worked example

The whole method is only a few lines of code. The loop below implements it for \( f(x) = x^2 + 10x - 3 \), printing the current estimate and the error at each pass:

x = 10;                       % our guess for the answer
for i = 1:10                  % loop ten times
    y  = x*x + 10*x - 3;      % f(x)
    dy = 2*x + 10;            % f'(x)
    new_x = x - (y/dy);       % calculate a better x
    x = new_x;                % update x
    sprintf("%f %f", x, y)    % print the estimate and the error
end                           % repeat
A code editor on the left showing the Newton iteration loop for f(x) = x*x + 10x - 3, and a terminal on the right showing the printed output. The two printed columns are the running estimate of the root and the error f(x): 3.433333 and 197.0, then 0.876746 and 43.12, then 0.320644 and 6.54, then 0.291582 and 0.309, then 0.291503 and 0.000845, then 0.291503 and 0.000000 for the remaining iterations.
The iteration in action. The left column is the running estimate of the root, the right column is the error \( f(x) \). The estimate settles on \( 0.291503 \) and the error collapses to zero within a handful of passes.

The output is instructive. The estimate moves \( 10 \rightarrow 3.433 \rightarrow 0.877 \rightarrow 0.321 \rightarrow 0.292 \rightarrow 0.291503 \), and the error drops \( 197 \rightarrow 43 \rightarrow 6.5 \rightarrow 0.31 \rightarrow 0.00085 \rightarrow 0 \). Notice how the number of correct decimal places roughly doubles each pass. This is called super-linear convergence, and it is what makes Newton's method such an efficient way to find the root of an equation.

2.4 The same idea in matrix form

The device is not a single equation but a large coupled set — the potential, the electron and hole Fermi levels and the trap occupations at every mesh point. Written in matrix form, Newton's method becomes:

\[ [J]\,[\Delta x] = -[f(x)] \]

\( [J] \) is the Jacobian, the matrix of derivatives of all the device equations (Poisson, drift–diffusion, SRH) with respect to all the unknowns. \( [f(x)] \) is the error in those equations for the current guess, and \( [\Delta x] \) is the resulting update — the improvement to the field, the Fermi levels and the trap populations across the whole device. The update is added to the current solution,

\[ [x] = [x] + [\Delta x], \]

and the process is iterated until \( f(x) \approx 0 \), at which point the device equations are solved. Two points carry directly into the tuning that follows: \( f(x) \) is the quantity we are driving to zero, so it is the natural measure of convergence; and the better the initial guess, the closer the solver starts to the answer, and the fewer iterations it needs.

3. Speeding up a simulation in practice

With the foundations in place, the practical settings make sense. The example used here is a two-dimensional field-effect transistor (a 2D device, with all traps included), but the same ideas apply to any simulation.

3.1 Turn off writing to disk

The single easiest change is to stop writing so much data to disk. Writing files is slow and, for a simulation that produces a great deal of output, it can dominate the run time. OghmaNano provides a control that minimises the amount of data written to disk in one click; the individual output-file options (for example the dumping of dynamic time-domain data) can also be toggled on and off individually in the output settings, so you can keep only the files you actually need. For the fastest possible run, write as little to disk as you can.

Try this first. Before touching any of the numerical settings below, disable the output you do not need and re-run. On disk-heavy simulations this alone can produce the largest single speed-up, and it changes nothing about the physics or the accuracy of the result.

3.2 Watching the solver converge

A plot of solver error on a logarithmic vertical axis against iteration number on the horizontal axis. From 0 to about 1000 iterations the error wanders down from around 1e15 to a noisy floor near 1e-7: this is the initial equilibrium solve. After that the trace shows a series of sharp spikes that rise and then decay, each spike corresponding to a voltage step where the error jumps and is then driven back down.
Solver error \( f(x) \) against iteration number. The long descent on the left is the initial equilibrium solve; each spike on the right is a voltage step, where changing the bias throws the equations out and the solver drives the error back down.

To tune the solver you first need to see it working. OghmaNano can print the Newton (current) error for each iteration and write the convergence history to a file, rather than printing a single line per voltage step. Enable the Newton-error output and the convergence log, then re-run.

The first simulation step is special. When the model starts it has no good guess for the device state — it does not yet know the potential or the Fermi levels — so it begins a long way from the solution. In ?? the error starts enormous (around \( 10^{15} \)) and is driven down over many iterations until it reaches a noisy floor near \( 10^{-7} \) to \( 10^{-9} \), at which point the equations are essentially solved. Because this first solve is so far from the answer, two things are done deliberately: the Newton step is heavily clamped (see below) so the solver converges slowly and safely rather than jumping somewhere that might crash, and it is allowed a large number of iterations — typically around a thousand — to give it a proper chance to settle.

After the equilibrium solve, the model steps through the requested voltages. Each voltage step moves the device slightly away from the previous solution, so the error jumps up and is then very quickly driven back down — the sequence of spikes on the right of the plot. Because each step starts close to the last answer, these solves converge rapidly.

3.3 Tuning the solver

The convergence plot is exactly the error function \( f(x) \) from Section 2, and the goal of tuning is to make it shorter — to reach convergence in fewer iterations. The main controls in the solver configuration are:

The workflow. Re-plot the convergence file after each change and watch the graph shrink: trim the flat tail of the first solve, relax the first-step target error, then increase the clamps to steepen the descents. On the example device these changes together took the run from roughly fifteen seconds to about eight — without changing the answer. The input files shipped with the model use conservative values, so there is usually headroom to push them on your own structures.

Spend the saved time on accuracy. Once the solver is tuned, the time you have won back can be reinvested in a harder problem — for instance increasing the number of mesh points. A well-tuned Newton configuration is what makes it practical to solve larger, finer, or more strongly coupled devices in a reasonable time.

Common pitfalls

Summary & next steps

Next: see the Materials database for how the material parameters that feed these equations are defined.