Configuration and Tuning

Overview

All gauNEGF default parameters live in gauNEGF.config. You can override them locally by passing them as arguments to contact setup functions (eta=, T=) or to SCF (conv=, damping=). This guide covers the parameters most likely to need tuning when optimizing convergence for your system.

Note

Module-level constants (SCF_DAMPING, ETA, SURFACE_GREEN_CONVERGENCE, etc.) are bound into gauNEGF.scf/scfE/density at import time (from gauNEGF.config import ...) and as function default-argument values. Setting config.X = ... after those modules are already imported has NO effect (this includes config.CLEAR_JAX_CACHES_PER_CYCLE and config.USE_INERTIA_EMIN). config.HOST_BLAS_THREADS is the exception: it is read each time the density step runs. To change a default globally, set config.X = ... before importing gauNEGF.scf/scfE/density for the first time – otherwise pass the value per-call (conv=, damping=, eta=, T=, tol=, maxcycles=), which always works regardless of import order.

Default Configuration

The table below lists the configuration constants that control convergence behavior. You need not change most of them; the defaults are conservative and appropriate for most DFT + NEGF calculations.

Tunable Configuration Parameters

Parameter

Default

Type

Purpose

SCF_DAMPING

0.02

float

Controls density matrix update aggressiveness in SCF

SCF_CONVERGENCE_TOL

1e-3

float

SCF convergence threshold (eV or a.u.)

SCF_MAX_CYCLES

100

int

Maximum number of SCF iterations before stopping

ETA

1e-5

float (eV)

Imaginary broadening for Green’s function

TEMPERATURE

0.0

float (K)

Temperature for Fermi-Dirac distribution in contacts

FERMI_CALCULATION_TOL

1e-3

float

Tolerance for Fermi energy search

FERMI_SEARCH_CYCLES

10

int

Maximum search cycles before returning Fermi energy

SURFACE_GREEN_CONVERGENCE

1e-5

float

Green’s function convergence tolerance for iterative inversion

ADAPTIVE_INTEGRATION_TOL

1e-4

float

Tolerance for adaptive energy integration

PULAY_MIXING_SIZE

4

int

Number of previous densities in Pulay mixing history

USE_INERTIA_EMIN

True

bool

Lower integration bound from find_lower_bound (single contour); False uses the older two-contour split

HOST_BLAS_THREADS

None

int or None

Host BLAS threads inside FockToP; None means min(16, ncpu // 4) (at least 1)

CLEAR_JAX_CACHES_PER_CYCLE

False

bool

Purge the compiled-kernel cache and JAX caches every SCF cycle

Lower Integration Bound (USE_INERTIA_EMIN)

With USE_INERTIA_EMIN = True (default), each NEGFE.FockToP cycle calls gauNEGF.density.find_lower_bound(). It starts EMIN_BUFFER below the lowest device eigenvalue and steps down until the inertia count (number of negative eigenvalues) of the Hermitian part of E*S - F - Sigma(E) equals its value at ENERGY_MIN, i.e. until every pole lies above, then moves a further EMIN_BUFFER down. A single complex contour is integrated from that floor to the Fermi energy. Set USE_INERTIA_EMIN = False before importing gauNEGF.scfE to use the two-contour path always. A fixed grid set with setIntegralLimits(N1=..., N2=..., Emin=...) bypasses both.

Host BLAS Threads (HOST_BLAS_THREADS)

FockToP runs inside gauNEGF.utils.blas_limit(), which caps the host NumPy/SciPy BLAS thread pools with threadpoolctl for the duration of the density step and restores them afterwards. The default cap is min(16, ncpu // 4) (at least 1), where ncpu is the number of cores the process may run on (its CPU affinity, not the node total). Set config.HOST_BLAS_THREADS to an integer to override the cap. If threadpoolctl is not installed, gauNEGF warns once and runs uncapped. gauNEGF no longer sets XLA_FLAGS; JAX sizes its own thread pool.

Kernel Cache (CLEAR_JAX_CACHES_PER_CYCLE)

The integrators compile their JAX kernels once per contact object and reuse them across SCF cycles; contact Fermi shifts enter as traced arguments, so a Fermi update does not trigger a recompile. CLEAR_JAX_CACHES_PER_CYCLE = True drops that cache (gauNEGF.integrate.clear_kernel_cache()) and calls jax.clear_caches() after every SCF cycle. Leave it off unless memory use grows from cycle to cycle; turning it on forces a recompile every cycle.

Fermi Search Method (fermiMethod)

The fermiMethod parameter controls the root-finding algorithm used to determine the Fermi energy during the SCF. This is passed to gauNEGF.scfE.NEGFE.setVoltage() to select how gauNEGF solves for the electron count. Which electrons are counted is set separately by the fermiCount argument of the contact setup call (setContact1D default 'contact', setContactBethe default 'device_bare'); see 1D Chain Contacts in gauNEGF and Bethe Lattice Contacts. When the previous cycle’s electron-count error is already below the tolerance, the search is skipped for that cycle (the log prints Fermi frozen) and re-engages when the count moves.

Warning

For 1D contacts set up with atom indices only (no explicit tau/alpha/beta matrices), DO NOT specify a fermi energy in setVoltage or the electron count will become unphysical! Instead use defaults or set fermiMethod . Example: negf.setVoltage(0.0)

Fermi Search Algorithms

Method

Stability

Speed

When to use

'bisect'

Highest

Slow

Always safe; default fallback when others fail. Guaranteed convergence but requires many iterations.

'muller' (default)

High

Medium

Good general-purpose default. Overshoot unlikely, defaults to bisection upon failure.

'poly'

Medium

Medium-Fast

Slightly faster than muller; muller remains the safer default. Balances stability and speed with 3rd order polynomial fitting.

'secant'

Low

Fast

Best for highly coupled contacts, unstable for weak contacts. Defaults to bisection upon failure

'predict'

Lowest

Very fast

Stable only for weakly coupled contacts, uses previous guess upon failure (check warnings). Also rescales the density matrix every cycle to force the target electron count (P *= ne/nActual) – this hides count mismatches from the usual dN diagnostics, so a bad fermi under 'predict' will not show up as a charge-count error. Raises ValueError with fermiCount='contact'.

This stability/speed ranking applies uniformly across contact types (1D, Bethe, constant sigma): 'muller' is the safe default everywhere; 'poly' trades a little stability for speed and is a reasonable choice when you have already validated a system converges cleanly.

See Choosing a Contact Type for guidance on which contact type is appropriate, and 1D Chain Contacts in gauNEGF for detailed setup instructions.

SCF_DAMPING

The SCF_DAMPING parameter controls how aggressively the density matrix is updated each SCF iteration. It acts as a mixing coefficient: new density = (1 - damping) * old + damping * computed.

Default: 0.02

Tuning guidelines:

  • Recommended Range: 0.02 to 0.05 – the default range for production runs. Wider excursions (down toward 0.005 or up to 0.1) are reasonable when diagnosing a specific problem (see the two-phase strategy below, or the SCF tuning workflow’s Steps 2-3), but 0.02-0.05 is the range to start from and return to.

  • High Mixing (up to 0.1) for saddle points Use if iterations seem “stuck”, try with or without pulay interpolation.

  • Low Mixing (down toward 0.005) for unstable systems Use when SCF oscillates or overshoots, increase nPulay if unstable.

Production strategy:

For difficult systems, use a two-phase approach: run SCF with low mixing first to find the convergence basin, then switch to higher mixing to escape any saddle points.

# Phase 1: Can be unstable until contacts mixed into system
negf.updatePulay(10)
negf.SCF(conv=1e-3, damping=0.002, maxcycles=100)

# Phase 2: Ensure not in a saddle point
negf.updatePulay(4)
negf.SCF(conv=1e-3, damping=0.1, maxcycles=100)

ETA (Broadening Parameter)

The ETA parameter controls the imaginary part of the energy (eta: E -> E + i*eta) added to the Green’s function. This broadening stabilizes the inversion and smooths spectral features.

Default: 1e-5 eV

Typical overrides:

  • 1e-3 eV: Higher eta values can improve stability of 1D contacts especially at band edges

  • 1e-5 eV (default): Recommended for most production transport calculations. Provides sharp spectral resolution while maintaining good conditioning.

  • 1e-6 eV: Use for precise calculations to capture band edges exactly, may cause numerical issues if the Green’s function is poorly conditioned.

Trade-off: Higher ETA speeds convergence and broadens spectral features; lower ETA gives sharper spectra but requires better conditioning. For production transport calculations, use the default (1e-5) unless specifically tuning spectral resolution.

Pass locally:

# Set ETA for 1D contact
negf.setContact1D([[1,2,3],[4,5,6]], eta=1e-3)

# Set ETA for Bethe contact
negf.setContactBethe([[1,2,3],[4,5,6]], eta=1e-5)

TEMPERATURE

The TEMPERATURE parameter controls thermal broadening in the contacts. It does not directly affect the device Hamiltonian, only the Fermi-Dirac distribution in the contact self-energy.

Default: 0.0 K (zero temperature, sharp Fermi cutoff)

Common values:

  • 0.0 K (default): Zero-temperature transport. Sharp electron/hole cutoff at the Fermi energy. Appropriate for single-point transmission calculations and most DFT+NEGF workflows.

  • 300 K: Room temperature. Adds thermal broadening (kT ~ 0.026 eV); electrons and holes leak slightly across the Fermi energy. Use for finite-temperature transport or to model thermal effects.

Note

The finite-temperature equilibrium contour was corrected in this release (see CHANGELOG.md); T > 0 results computed with earlier versions should be recomputed. As a side benefit, finite T moves the contour’s real-axis touchdown away from the Fermi energy, which can improve integration robustness for metallic systems with frontier states at E_F.

Pass locally:

# Set temperature for 1D contact
negf.setContact1D([[1,2,3],[4,5,6]], T=300)

# Set temperature for Bethe contact
negf.setContactBethe([[1,2,3],[4,5,6]], T=300)

Fermi Energy Search Tolerances

Two tolerances control Fermi energy accuracy:

FERMI_CALCULATION_TOL (default 1e-3):

Tolerance on the electron count during the Fermi search, as an absolute electron count (per spin for spin='r'; total for 'u'/'ro'/'g'). Inside the SCF the search converges when |N_computed - N_target| < min(FERMI_CALCULATION_TOL, convLevel), where convLevel is the current SCF convergence level. Loosen to 1e-2 if Fermi search oscillates; tighten to 1e-4 for strict charge neutrality.

FERMI_SEARCH_CYCLES (default 10):

Maximum number of root-finding iterations before returning. If the solver does not converge within this limit, gauNEGF returns the best estimate and logs a warning. Increase to 20-30 for difficult systems; decrease to 5 if Fermi search is a bottleneck.

Surface Green’s Function Convergence

SURFACE_GREEN_CONVERGENCE (default 1e-5):

Convergence threshold for the iterative inversion that builds the contact surface Green’s function. The default is the lowest safe value: going below 1e-5 can produce numerical instability, because the recursion simply stops at its internal iteration cap (MAX_ITER=10000) before reaching the tighter tolerance, leaving an unconverged surface Green’s function baked into the contour integration – this is not recommended. Going above 1e-5 (e.g. 1e-4) speeds up contact setup at the cost of slightly less accurate self-energies, which is useful for exploratory runs or initial convergence sweeps.

Integration Tolerances

ADAPTIVE_INTEGRATION_TOL (default 1e-4):

Tolerance for adaptive energy integration in density matrix calculations. Set as a threshold for the maximum error (element-wise) in the density matrix. NOTE: should be below SCF convergence criteria

Integration Methods: Complex Contour vs Real-Axis

For hands-on comparison of gauNEGF integration approaches, see Integration Demo (docs/source/examples/IntegralDemo.ipynb) – a step-by-step notebook that illustrates the trade-offs between complex contour integration and real-axis energy integration.

Workflow: Tuning Convergence

Step 1: Start with defaults.

Most systems converge with factory settings. Run SCF and check the convergence history.

Step 2: If SCF oscillates or diverges:
  • Tighten mixing to lower value: negf.SCF(conv=1e-3, damping=0.005)

  • Adjust Pulay mixing value if unstable: negf.updatePulay(9)

  • Check that contacts are physically reasonable (see Choosing a Contact Type)

Step 3: If SCF is very slow:
  • Use two-phase approach: higher mixing (0.1) then lower (0.01)

  • Increase ETA in initial runs: negf.setContact1D([[1,2],[5,6]], eta=1e-3)

  • Use closed shell spin for initial runs, then add spin degrees of freedom later

Step 4: If Fermi search fails or gives non-physical electrons:
  • Turn on fermi search in initial runs - fermi energy setpoint may be near orbital energies

  • Explicitly set fermiMethod in setVoltage: negf.setVoltage(0.0, fermiMethod='muller')

  • Add a finite temperature to smooth out integration: negf.setContact1D([[1,2],[5,6]], T=300)

  • Otherwise revert back to bisection (fermiMethod='bisect') if all else fails

See Also