Iteration Engine
This page breaks down the main forward iteration in terms of the actual coordination functions in c++/core.hpp.
The Main Loop
The outer loop is nrg_loop(...) in c++/core.hpp.
At a high level it does:
for each Step:
iterate(...)
Step packages the current iteration index, energy scale, runtime mode, and convenience helpers used throughout the loop.
One Iteration: iterate(...)
iterate(...) is the main coordinator for a single NRG step.
Its structure is:
- construct
SubspaceStructurefrom the previousDiagInfo - build a
TaskListfrom the subspace structure - optionally persist structure information to HDF5
- run diagonalization via
do_diag(...) - run post-diagonalization processing via
after_diag(...) - trim operator matrices and drop dense eigenvectors no longer needed
- print timing/memory summary
Diagonalization: do_diag(...)
do_diag(...) is responsible for the part of the loop that may restart if too few states were computed.
The flow is:
- print iteration information through
step.infostring() - report Wilson-chain coefficients via
Sym->show_coefficients(...) - attempt to obtain the eigenspectra with
load_or_compute_diag(...) - initialize the energy reference with
initialize_diag_energy_reference(...) - prepare truncation metadata with
prepare_diag_for_truncation(...) - catch
NotEnoughand optionally retry with a largerdiagratio
This is where the eigensolver policy and restart behavior meet.
Hamiltonian Construction
The actual block Hamiltonian for one invariant subspace is built by hamiltonian(...).
That function:
- computes the ancestor list for the target
Invar - constructs
SubspaceDimensions - initializes the diagonal from the previous shell's corrected eigenvalues
- delegates symmetry-specific matrix filling to
Sym->make_matrix(...)
This is the point where the generic iteration engine hands off to the symmetry backend.
Post-Diagonalization: after_diag(...)
after_diag(...) is the second half of an iteration. It is where the freshly computed eigenspectra are turned into data products and next-step state.
The main branches are:
- if this is an NRG step:
- handle Floquet-specific postprocessing or split eigenvectors into blocks
- finalize metadata such as scale and total-energy shifts
- persist outputs for the current iteration
- optionally recalculate operators and measure before truncation
- perform actual truncation with
diag.truncate_perform() - archive iteration state into
ThermoStoreandBackiterStore - if not at the last step, recalculate irreducible operators for the next step
- optionally recalculate operators and measure after truncation
- optionally check operator sum rules and write operator HDF5 output
Measurement And Recalculation Boundary
The helper recalculate_and_measure(...) in core.hpp is a useful conceptual boundary. It does exactly two things:
Oprecalc::recalculate_operators(...)calculate_spectral_and_expv(...)
That means operator recalculation and measurement are treated as a paired operation in the main loop.
docalc0(...)
Before the first real NRG step, run_phase(...) may call docalc0(...) if P.calc0 is enabled.
This phase performs measurements using the seed data from data without advancing the iteration loop. It is effectively a pre-iteration measurement stage.
Function Map
The most useful function-level reading order in core.hpp is:
nrg_loop(...)iterate(...)do_diag(...)hamiltonian(...)after_diag(...)recalculate_and_measure(...)archive_iteration_state(...)