Skip to content

Super-Charged Pow() for Faster Mobility

Simon Spannagel requested to merge perf_powfast into master

This MR adds a "new" mobility model called canali_fast which provides a significantly faster calculation ob charge carrier mobilities from the Canali model. The main culprit of the model'\s function are the two calls to std::pow(x, y):

\mu(E) = \frac{v_m}{E_c} \frac{1}{\left(1 + (E / E_c)^\beta \right)^{1 / \beta}}

where \beta is a floating-point number. In some simulations, exactly these calculations were representing by far the hottest code snippet of the entire framework as demonstrated in this Intel OneAPI VTune snippet (bottom-up list):

image

What can we do about it? There are loads of (sometimes wonky) approximations to power calculations around - but would we really want to include something that affects our charge carrier velocity in odd and abrupt ways like this?

image

Certainly not. This might be good enough for a game engine, but not a scientific simulation.

But wait - can't we have a closer look at our equation? Do we really need the full power (haha, pun intended) of std::pow(double, double)? After all, out \beta is a constant (and also 1/\beta fwiw). How about making a nice table of std::pow(x, beta) for all the values we need?

So this is what this MR implements - a TabulatedPow class that pre-calculates a table of std::pow(x, Y) values where Y is fixed and x has a specified range. Values are looked up from this table and linearly interpolated between the neighboring bins such that the distribution is smooth.

The following parameter values have been chose:

  • 1000 bins per table - this seems reasonable and is definitely enough judging from the precision plots below
  • For the two std::pow calls with different exponents (and also for the two carrier types) separate tables are calculated.
    • For the \beta table, the range is set to [0, 100kV/cm/E_c]
    • For the 1/\beta table, the range is configured as [1, (100kV/cm/E_c)^{\beta}]
  • The ranges are chosen such that a smooth interpolation is provided for electric field strengths (this is \sqrt{\vec{E}} and therefore positive!) between 0kV/cm and 100kV/cm, and a linear extrapolation beyond those ranges.

Now - bring it on, how precise is it in comparison with the regular Canali implementation? Well, here's the inverse mobility:

icanali

And the drift velocity:

canali

Less than 0.2% uncertainty on the drift velocity at very low electric field values - where drift will play a significant role.

Enjoy.

Merge request reports