HEFFSO Build And Usage#

HEFFSO builds and diagonalizes the spin-orbit effective Hamiltonian after DIAGPT. Determinants, effective Hamiltonian matrices, orbital metadata, and spin-orbit integrals are read from an explicit shared HDF5 dump and one DIAGPT HEFFSO handoff file.

Interpret degeneracies with the MPPT symmetry and convergence rules. Reconstructing MPPT need not preserve non-Kramers multiplets. S and applicable L/J completeness, selection and retained states affect the result; larger spaces need not reduce splittings monotonically. Passive covariance of fixed matrices and conditional time-reversal protection remain separate requirements.

Complete the environment-manager setup and MPPT installation before using the build sections below. Miniforge is the recommended bootstrap on Linux, including glibc 2.17 servers; Micromamba is the lightweight fallback when a full base environment is undesirable. The setup guide lists the distinct conda, mamba, and micromamba commands.

After activating mppt in a new shell, repeat the GNU compiler exports from the installation guide before configuring any build profile on this page.

Runtime Model#

The recommended route is the unified cipsixx workflow, which validates all inputs, generates the runtime namelist, and checkpoints completion. For a manual run, provide:

  • An HDF5 dump from pyscf2mppt; it must contain orbital metadata and intso. Select it with MPPT_HDF5_FILE=/path/to/calculation.h5. When the variable is unset, HEFFSO opens pyscf_dump.h5.

  • The fixed <prefix>heffso.h5 handoff from DIAGPT, for example Pr_heffso.h5.

  • A HEFFSO input file with &sofil, a title line, &sort, and &ic.

Minimal input:

&sofil prefix='Pr_', &end
Pr
&sort
  nvectw=228, primme_guess_space=-1,
  primme_max_basis=0, primme_max_block=0, primme_max_matvecs=0,
  primme_eps=1.d-6, primme_initial_vector_tolerance=1.d-7,
  primme_print_level=1, primme_progress_interval_seconds=60,
  primme_allow_constrained_basis=.false.,
  primme_preconditioner=.true., primme_direct_sparse=.true.,
&end
&ic iorder=2, &end

iorder=2 reads the h2 matrix from the HDF5 handoff. Use iorder=1 for h1.

Properties#

Properties are enabled by default. Set properties=.false. in &sort, or set mppt.heffso.properties: false in the unified YAML input, only when the properties result is not needed. The enabled route requires full-space intdip and intang datasets in the PySCF HDF5 file.

For each Cartesian one-body operator Q in L, S, J, and the length-gauge dipole r, HEFFSO stores V^dagger Q V in the HEFFSO eigenstate basis, where the columns of V are the computed HEFFSO eigenvectors. The total angular-momentum matrices satisfy J = L + S component by component. The oscillator strength from state 1 is (2/3) * (E_f - E_1) * sum_c |D_c(f,1)|^2; state 1 has oscillator strength zero. The Cartesian sum is also stored as the state-indexed E1 line strength. For Q in L, S, and J, HEFFSO stores Q2(n) = sum_(c,m) |Q_c(n,m)|^2 and the nonnegative effective value q defined by q(q+1)=Q2. These values describe the retained HEFFSO state basis; they do not assign term symbols or certify complete multiplets.

The run writes <prefix>heffso_properties.h5 with schema mppt_heffso_properties_v4. For n HEFFSO states, its required root attributes are:

Attribute

Value or meaning

schema, schema_version

mppt_heffso_properties_v4, 4

index_base, state_count, write_complete

one-based state IDs, n, completion marker 1

energy_unit, energy_reference

hartree, absolute_electronic

vacuum_energy_hartree

vacuum energy added to the HEFFSO eigenvalues

cartesian_components, matrix_axis_order

x,y,z, component,bra_state,ket_state

state_basis, property_transform

heffso_eigenvectors, V_dagger_Q_V

dipole_operator, dipole_origin_bohr

r and its three-component origin in bohr

oscillator_strength_definition, oscillator_strength_unit

electric_dipole_from_state_1, dimensionless

line_strength_definition, line_strength_unit

Cartesian state-1 dipole norm, atomic_unit

angular_squared_definition, effective_angular_definition

retained-state Cartesian norm and q(q+1) inversion

hermiticity_residual_order, commutator_residual_order

l,s,j,dipole and l,s,j

j_consistency_residual, oscillator_strength_formula_residual

scalar consistency residuals

Required datasets are:

Dataset

Shape

Meaning

state_id

(n,)

contiguous one-based state IDs

state_energy_hartree

(n,)

absolute electronic energies in Hartree

oscillator_strength

(n,)

dimensionless oscillator strength from state 1

line_strength

(n,)

Cartesian state-1 E1 line strength

state_l2, state_s2, state_j2

(n,)

squared angular values from retained-state matrices

state_jz

(n,)

real diagonal of J_z

state_l, state_s, state_j

(n,)

effective angular values from q(q+1)=q2

hermiticity_residual

(4,)

normalized L, S, J, and dipole residuals

commutator_residual

(3,)

normalized L, S, and J algebra residuals

l_matrix_real, l_matrix_imag

(3,n,n)

split-complex Cartesian L matrices

s_matrix_real, s_matrix_imag

(3,n,n)

split-complex Cartesian S matrices

j_matrix_real, j_matrix_imag

(3,n,n)

split-complex Cartesian J = L + S matrices

dipole_matrix_real, dipole_matrix_imag

(3,n,n)

split-complex Cartesian dipole matrices

Schema v4 also requires complete /solver, /determinant_identity and /magnetic groups. The root write_complete=1 marker is written only after all groups and root datasets are complete.

Magnetic controls#

Magnetic output inherits enabled properties. The YAML subsection is mppt.heffso.magnetic_properties; the manual &sort equivalents are:

  magnetic_properties=.true.,
  magnetic_spin_g=2.00231930436092,
  magnetic_degeneracy_tolerance=1.d-8,
  magnetic_nfields=2, magnetic_ntemperatures=2,
  magnetic_fields(:,1)=0.d0,0.d0,0.d0,
  magnetic_fields(:,2)=0.d0,0.d0,1.d0,
  magnetic_temperatures(1)=2.d0, magnetic_temperatures(2)=300.d0,
  magnetic_susceptibility=.true., magnetic_store_field_matrices=.false.,

Fields are in tesla and temperatures in kelvin; both counts default to zero and are bounded by 256. The magnetic-moment operator at zeroth order in the MPPT perturbation is -(L + spin_g*S) in μB, projected into retained SOC states. The MPPT2 Hamiltonian does not add first- or second-order corrections to this operator. The Zeeman interaction is linear in the external field. HEFFSO preserves zero-field gaps, reports principal g only for eligible isolated Kramers pairs, and computes optional M and differential χB natively. See Magnetic Properties for the model, formulas and interpretation, the YAML controls for defaults and dependencies, and Outputs for the magnetic-v1 datasets and applicability codes.

/solver uses schema mppt_heffso_solver_diagnostics_v1. It records the PRIMME backend and method, matrix dimension, requested and converged root counts, return status, iteration/restart/matvec/preconditioner counters, eps, a_norm, inv_b_norm, the resulting convergence limit, bounded orthogonality metrics, and solver timings. Its root_residual_norm_hartree dataset has shape (n,). The matrix dimension must equal the number of determinant rows, every requested root must converge, and every residual must satisfy the stored convergence limit.

/determinant_identity uses schema mppt_heffso_determinant_identity_v1. It stores contiguous one-based determinant_id with shape (ndet,) and signed-int64 determinant_alpha_bits and determinant_beta_bits with shape (ndet,nword). Bits are least-significant-bit first. The stored spatial-orbital window is the smallest interval in which any final determinant differs from the closed-shell vacuum; orbitals outside it are defined by that vacuum. An all-vacuum catalog uses determinant_orbital_start=0, count and word count zero, and bit-matrix shape (ndet,0). The determinant_content_hash_fnv1a64 attribute binds dimensions, row IDs, and both determinant-major bit matrices using signed-int64 little-endian FNV-1a.

An explicit properties=.false., invalid-input, or failed run removes any existing current properties artifact, so stale enabled-run output is not exposed as current. MPPT_HDF5_FILE must not name or alias that prefix-owned artifact; native HEFFSO checks file identity before cleanup and rejects the run instead of deleting its input.

Caspy provides a typed eager reader:

from caspy import read_heffso_properties

result = read_heffso_properties("Pr_heffso_properties.h5")
print(result.state_energy_hartree)
print(result.oscillator_strength)
print(result.line_strength)
print(result.state_j)
print(result.j_matrix.shape)  # (3, n, n)
print(result.solver.root_residual_norm_hartree)
print(result.determinant_identity.alpha_bits.shape)  # (ndet, nword)

The returned arrays own their data and are read-only; the source HDF5 handle is closed before the reader returns. The reader validates the v4 metadata, shapes, finiteness, Hermiticity, J = L + S, derived angular values, line strengths, oscillator strengths, persisted residuals, solver evidence, determinant minimality, and the determinant hash.

Human Report#

The bounded primary console report contains:

  • SOLVER DIAGNOSTICS, a fixed-size PRIMME summary; complete per-root residuals remain in HDF5;

  • SPIN-ORBIT STATES, with state, absolute Eh, dE / eV, dE / cm-1, S^2, J^2, and oscillator strength when properties are enabled;

  • ANGULAR PROPERTIES;

  • PROPERTIES VALIDATION;

  • PROPERTIES SUMMARY.

HEFFSO writes active-orbital occupations to <prefix>heffso_occupancy_analysis.log and dominant configuration weights to <prefix>heffso_configuration_analysis.log. Both files are required for every successful run, including properties=.false.. The primary report then contains only SOLVER DIAGNOSTICS and SPIN-ORBIT STATES in disabled mode.

Property matrices and complete state-1 line strengths are HDF5-only. The primary state table already prints every relative energy and oscillator strength, so no separate E1 transition table duplicates those rows. Oscillator strengths in the state table and strongest-transition summary use scientific notation; every other HEFFSO report and solver value uses fixed decimal notation. Hermiticity, J = L + S, and the oscillator-strength formula use strict PASS/FAIL status. Angular commutators use PASS/OPEN, because algebra closure is not guaranteed in an incomplete retained state span.

Runtime Controls#

Raw &sort controls and defaults are:

Setting

Default

Role

primme_guess_space

-1

p-space size; negative selects min(n, max(512, 2*nev))

primme_max_basis

0

search basis; zero selects min(n, max(nev+64, 4*nev))

primme_max_block

0

block size; zero selects min(nev, 8, OpenMP threads, max(1, floor(B/4))), where B is the resolved search basis

primme_max_matvecs

0

matrix-vector budget; zero selects max(10000, 400*nev)

primme_eps

1.0e-6

relative residual convergence tolerance

primme_initial_vector_tolerance

1.0e-7

minimum norm accepted for an initial vector

primme_print_level

1

compact progress reporting

primme_progress_interval_seconds

60

maximum progress interval at outer-iteration boundaries

primme_allow_constrained_basis

.false.

permit an explicit basis smaller than 2*nev

primme_preconditioner

.true.

diagonal preconditioner policy

primme_direct_sparse

.true.

direct complex sparse callback policy

configuration_weight_percent

10.0

strict `

configuration_top_n

3

minimum configurations per state

The automatic block is bounded by the resolved basis, including a small explicit primme_max_basis. This leaves room for PRIMME’s retained vectors and restart space: a 14-dimensional full-spectrum problem with eight threads now selects block 3 instead of block 8. The requested root count and tolerance are unchanged. Explicit nonzero block sizes are not automatically reduced.

PRIMME tolerances are finite and positive. Explicit PRIMME limits are rejected instead of clamped. A basis below 2*nev requires primme_allow_constrained_basis=.true., and any basis below the recommended 4*nev emits a performance warning. Before allocating solver storage, HEFFSO reports the complex n * max_basis basis lower bound and the returned n * nev vectors in GiB. PRIMME working memory is higher than this portable lower bound. configuration_weight_percent must be finite and in [0,100]; configuration_top_n must be positive.

HEFFSO always uses the repository-pinned PRIMME 3.2.3 eigensolver. CMake fetches and builds this mandatory dependency; configuration or compilation fails rather than producing a binary with a different eigensolver.

Plain BLAS/LAPACK Build#

This path is useful for portability checks and systems without oneMKL. It is not the preferred performance path.

MPPT_PREFIX="$CONDA_PREFIX"
cmake -S . -B build_heffso_blas \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_PREFIX_PATH="$MPPT_PREFIX" \
  -DHDF5_ROOT="$MPPT_PREFIX" \
  -DOpenMP_gomp_LIBRARY="$MPPT_PREFIX/lib/libgomp.so.1" \
  -DMPPT_COPY_TO_HOME_BIN=OFF \
  -DINSTALL_PYSCF2MPPT=OFF \
  -DWITH_LIBGRPP=OFF \
  -DWITH_MKL=OFF \
  -DWITH_MKL_SPARSE=OFF \
  -DWITH_CUDA_SPARSE=OFF
cmake --build build_heffso_blas --target heffso

To force system BLAS/LAPACK instead of whatever CMake finds first, provide the host’s actual library paths. This example uses Debian/Ubuntu Linux x86-64:

cmake -S . -B build_heffso_blas \
  -DBLAS_LIBRARIES=/usr/lib/x86_64-linux-gnu/libblas.so.3 \
  -DLAPACK_LIBRARIES=/usr/lib/x86_64-linux-gnu/liblapack.so.3 \
  ...

With no sparse backend compiled, PRIMME falls back to the split real/imaginary Fortran/OpenMP Hamiltonian callback.

Optional CUDA Build#

CUDA/cuSPARSE is an experimental acceleration backend for the PRIMME sparse matrix products. It is not selected implicitly at runtime.

Build CUDA together with MKL:

MPPT_PREFIX="$CONDA_PREFIX"
cmake -S . -B build_heffso_cuda \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_PREFIX_PATH="$MPPT_PREFIX" \
  -DHDF5_ROOT="$MPPT_PREFIX" \
  -DOpenMP_gomp_LIBRARY="$MPPT_PREFIX/lib/libgomp.so.1" \
  -DMPPT_COPY_TO_HOME_BIN=OFF \
  -DINSTALL_PYSCF2MPPT=OFF \
  -DWITH_LIBGRPP=OFF \
  -DWITH_MKL=ON \
  -DWITH_MKL_SPARSE=ON \
  -DWITH_CUDA_SPARSE=ON \
  -DCUDAToolkit_ROOT="$CUDA_HOME" \
  -DCMAKE_CUDA_COMPILER="$CUDA_HOME/bin/nvcc" \
  -DCMAKE_CUDA_ARCHITECTURES=86
cmake --build build_heffso_cuda --target heffso

Runtime:

export HEFFSO_SPMM=cuda

build_heffso_cuda/bin/heffso < Pr_heffso.inp > heffso.log 2> heffso.stderr

CUDA controls:

  • HEFFSO_CUDA_SPMM_ALG=csr_alg3 is the tuned default.

  • HEFFSO_CUDA_SPMM_ALG=csr_alg1, csr_alg2, or default can be used for comparisons.

  • HEFFSO_CUDA_TIMING=1 prints aggregate CUDA setup, transfer, and SpMM times.

The Python workflow requires direct_sparse: true for the CUDA backend and includes both CUDA controls in HEFFSO checkpoint identity.

Use CUDA only after the MKL path is working and validated on the same input.

Validation#

For every build profile:

For oneMKL or CUDA profiles, set MKL_THREADING_LAYER=GNU in the test shell.

cmake --build <build_dir> --target heffso mppt_heffso_unit_tests \
  mppt_heffso_properties_writer_probe
ctest --test-dir <build_dir> -L HEFFSO --output-on-failure

Smoke-test the Python/MPPT path:

ctest --test-dir <build_dir> -R '^workflows_yaml_hf_H2O_no_symm$' \
  --output-on-failure

For CUDA builds add HEFFSO_SPMM=cuda to the smoke-test environment.

mppt.heffso.print_level and raw primme_print_level use these levels:

  • 0: final completion or failure summary only.

  • 1: compact progress after another 5% of roots converge or after 60 seconds.

  • 2: PRIMME per-root convergence output.

  • 3 and above: increasingly detailed iteration diagnostics.

The compact lines start with HEFFSO PRIMME, so the Python workflow mirrors only those lines live while retaining the complete output in logs/heffso.log. Raw &sort input accepts the complete primme_* contract listed above. Workflow YAML PRIMME controls are authoritative at launch.

With PRIMME hard locking, compact progress counts locked roots, matching PRIMME’s monotonic completed-root contract. An exact zero Hamiltonian is also a valid converged case when both its scaled residual limit and residual are zero. Debug builds suspend IEEE exception halting only while inside zprimme and restore the caller’s modes before HEFFSO post-processing.

The repository test-light target injects exact paths to the current CMake targets. See the installation guide for the supported test command.

Outputs#

HEFFSO writes:

  • <prefix>sovec (for YAML prefix Pr, this is Pr_sovec)

  • <prefix>heffso_occupancy_analysis.log

  • <prefix>heffso_configuration_analysis.log

  • <prefix>heffso_properties.h5 when properties=.true.

  • the console table headed state Eh dE / eV dE / cm-1 S^2 J^2 oscillator strength when properties are enabled

Internal unformatted sequential and stream work units are anonymous compiler-managed scratch. They have no stable filenames and are neither durable outputs nor workflow cleanup targets.

Successful logs end with:

fin heffso

Performance Notes#

  • MKL Sparse BLAS is the default performance target on CPU.

  • Property calculation traverses the finite determinant catalog and skips every generated daughter that is not in that catalog. Cost scales with the catalog, operator connectivity, and requested state count; no external determinant image map is built.

  • CUDA can improve large sparse PRIMME matvecs on the local RTX 3090, but profiling shows the remaining wall time is mostly CPU-side PRIMME and projected-vector work, not host-device transfer.

  • Automatic guess space uses min(n, max(512, 2*nev)). Set guess_space explicitly only for a controlled comparison or memory-constrained run.