Troubleshooting & FAQ#

Common issues and their solutions. If your problem is not listed here, please open a GitHub issue.

Installation & Build#

libaims.so not found or cannot be loaded#

Cause: FHI-aims was built as a static library (default), or the path is incorrect.

Solution: Rebuild with -DBUILD_SHARED_LIBS=ON:

cd /path/to/FHI-aims/build
cmake -DUSE_MPI=ON -DUSE_LIBXS=OFF -DBUILD_SHARED_LIBS=ON ..
make -j 8

See Installation & Setup for full build instructions. AimsPy loads libaims.so via ctypes, so a shared library build is required.

aimspy patch --check fails#

Cause: The FHI-aims source tree is not on the patch’s base branch (currently dev), or the tree has been modified.

Solution:

cd /path/to/FHI-aims
git checkout dev
git clean -fd   # remove untracked files
aimspy patch --check

The patch must apply on a clean checkout. If you have previously applied a different patch version, uninstall it first:

aimspy patch --uninstall /path/to/FHI-aims

Note: The current patch supports FHI-aims versions 250822 and 250822_1 only. If your FHI-aims checkout is a different version, the patch will not apply. Patches for additional versions will be released in the future.

MPI errors or severe performance degradation#

Cause: mpi4py and libaims.so are linked against different MPI libraries (e.g. mpi4py uses system OpenMPI while libaims.so uses Intel MPI).

Solution: Source the Intel OneAPI environment before installing AimsPy and before building libaims.so:

source /path/to/intel/setvars.sh
pip install aimspy          # mpi4py compiles against Intel MPI

See Prerequisites for details.

Runtime Errors#

AimspyStateError: Cannot init() in state ...#

Cause: The Calculator is not in the UNINIT state. FHI-aims is a global singleton — only one init/finalize cycle per process.

Solution: Create a new Calculator instance for each SCF run. After close() or force_close(), the current instance is finalized and cannot be reused:

# First run
calc = Calculator(config)
calc.do(comm, work_dir="./run1")
calc.close()

# Second run — must create a NEW Calculator
calc2 = Calculator(config)
calc2.do(comm, work_dir="./run2")
calc2.close()

AimspyStateError: Cannot close() in RUNNING state#

Cause: close() was called while SCF is still running (inside calc()).

Solution: Use force_close() instead — it is safe from any state and swallows Fortran errors:

try:
    calc.do(comm, work_dir="./bad_input")
except Exception:
    calc.force_close()

AimspyBindingError: c_rs_hamiltonian() returned NULL#

Cause: A rank-0-only property was accessed on a non-root MPI rank. The properties rs_hamiltonian, rs_overlap, hamiltonian, and overlap (without capture_overlap=True) read from Fortran rank-0 buffers and raise AimspyBindingError on non-root ranks.

Solution: Guard with if rank == 0: or use the all-rank alternatives:

if rank == 0:
    H = calc.hamiltonian       # rank-0 only

# All-rank alternatives:
S = calc.overlap              # all ranks if capture_overlap=True
h0 = calc.initial_hamiltonian # all ranks if capture_initial_hamiltonian=True
info = calc.info              # all ranks

AimspyBindingError: C function ... not available in loaded libaims#

Cause: The loaded libaims.so was built with an older (or mismatched) patch version that does not export the requested symbol.

Solution: Re-patch and rebuild FHI-aims with the latest bundled patch:

aimspy patch --uninstall /path/to/FHI-aims   # remove old patch
aimspy patch /path/to/FHI-aims               # apply latest
# Rebuild libaims.so as described in Installation & Setup

AimspyCallbackError: N callback error(s) during calc()#

Cause: One or more Python callbacks raised an exception during SCF. AimsPy catches callback exceptions (to avoid crashing Fortran) and aggregates them into a single AimspyCallbackError after aimspy_run returns.

Solution: Inspect the callback_errors attribute for details:

try:
    calc.do(comm, work_dir="./MoS2")
except AimspyCallbackError as e:
    for name, exc, tb_str in e.callback_errors:
        print(f"[{name}] {exc}")
        print(tb_str)

modify_init_ham seems to have no effect#

Cause: modify_init_ham() was called after init() or do(). The callback wiring (_wire_callbacks) runs inside init(), so setting self._modify afterwards has no effect — the modify_h0 callback is never registered.

Solution: Always call modify_init_ham() before init() / do():

calc = Calculator(config)
calc.modify_init_ham(source=data, strategy=Strategy.REPLACE)  # BEFORE do()
calc.do(comm, work_dir="./MoS2")                               # correct order

Common Gotchas#

FHI-aims is a global singleton#

Only one init/finalize cycle per process. A finalized Calculator cannot be reused — always create a new instance. This also means Calculator is not thread-safe (FHI-aims uses chdir(2) internally).

work_dir must contain control.in and geometry.in#

AimsPy chdirs into work_dir because FHI-aims uses chdir(2) internally. The directory must contain control.in and geometry.in (or use CalculatorConfig.control_path / geometry_path to have them copied automatically).

Forces return None#

calc.forces returns None when:

  • calc() has not been called yet

  • compute_forces .true. is not set in control.in

  • The Calculator has been closed/finalized

Add compute_forces .true. to your control.in to enable force calculation.

When exporting to DeepH format, passing force=calc.forces while calc.forces is None will raise AimspyConfigError (invalid force shape). Either enable compute_forces in control.in, or simply omit the force= argument — DeepHData.from_aimspy(...) works without forces.

Matrix extraction/injection requires periodic systems#

Forward SCF calculations work with any system type. However, extracting or injecting matrices (Hamiltonian, overlap, H_init — via capture_overlap, capture_initial_hamiltonian, modify_init_ham, or reading calc.hamiltonian / calc.overlap) requires:

  1. A periodic system (lattice vectors in geometry.in, k_grid in control.in)

  2. use_local_index = .false.

For isolated molecules, use a sufficiently large periodic cell with vacuum and a Gamma-only k_grid:

# geometry.in — periodic box with vacuum
lattice_vector  30.0  0.0  0.0
lattice_vector   0.0 30.0  0.0
lattice_vector   0.0  0.0 30.0
# control.in
k_grid 1 1 1

The from_scratch/run.py example demonstrates this vacuum-box approach for H₂O.