Introduction to EDRIXS

EDRIXS computes X-ray absorption (XAS) and resonant inelastic X-ray scattering (RIXS) spectra by exact diagonalization (ED) of model Hamiltonians for correlated electrons.

Every calculation follows the same path, with the following four stages:

  • Defining the physical model – constructing the single-particle matrices of the Hamiltonian, the Fock basis, and the transition operators for the excitations.

  • Building the many-body operators – expressing those Hamiltonians and transition operators in the full Fock basis.

  • Using exact diagonalization to obtain the low-energy eigenvalues and eigenstates of the Hamiltonians.

  • Constructing the spectrum from the transition operators, eigenvalues and eigenvectors.

Each stage is a thin layer of functions that can accommodate different backends. We review each of them with the help of the flow chart below.

Flow chart of the stages of an EDRIXS calculation.

The stages of an EDRIXS calculation. The quantities passed from one stage to the next are shown in gray to the right of the arrows.

The sections below follow the figure box by box. The Backend that carries out the linear algebra for the last three stages is described on its own page. The units, naming, orbital orderings, single-particle bases, Fock-basis encoding and spectral conventions are collected separately on the Conventions page, and the pedagogical examples work through the same material in more physical detail.

If you prefer to begin with a complete calculation, skip ahead to either the NiO crystal-field example or the NiO Anderson impurity example and return to this overview as needed.

The physical model

There are four edrixs.models constructors:

  • model_1v1c() – one valence shell and one core shell (for example, Cu \(3d\) and \(2p\)).

  • model_2v1c() – two valence shells and one core shell.

  • model_siam() – an Anderson impurity model.

  • model_siam_2d1p() – a commonly used special case of the Anderson impurity model with one \(d\) impurity shell, one bath shell, and one \(p\) core shell (for L-edge spectroscopy).

Each returns a description of the problem, building no operators itself:

  • the one-body matrices emat_i / emat_n,

  • the Coulomb tensors umat_i / umat_n,

  • compact Fock-basis specifications basis_i / basis_n, and

  • the Cartesian photon transition matrices trans_mat.

The _i suffix marks the initial and final states, which have no core hole, and _n the intermediate state, which has one.

emat and umat are the coefficients of a second-quantized Hamiltonian

\[\hat{H} = \sum_{ij} t_{ij}\, \hat{f}_i^{\dagger} \hat{f}_j + \sum_{ijlk} U_{ijlk}\, \hat{f}_i^{\dagger} \hat{f}_j^{\dagger} \hat{f}_k \hat{f}_l ,\]

with the one-body coefficients \(t_{ij}\) passed as emat and the two-body coefficients \(U_{ijkl}\) as umat. Their single-particle index runs over spin-orbitals in the default basis and orbital order set out in Conventions, where the units and the naming of these quantities are also collected.

emat carries all of the one-body physics, and the separate contributions simply add together:

  • the on-site orbital energies, including any crystal-field splitting,

  • the spin-orbit coupling of the valence and core shells,

  • the hopping and hybridization between sites, or between an impurity and its bath, and

  • external field terms, such as the Zeeman coupling to an applied magnetic field.

Because they are additive, a crystal-field, hopping or Zeeman matrix that you construct yourself is simply added into emat – after transforming it into the default single-particle basis if it is not already expressed there.

umat carries the two-body Coulomb interaction. It is parameterized by Slater integrals \(F^k\), with \(G^k\) for the core-valence terms.

Many-body operators

The second stage picks the many-body Fock basis \(\lvert \Phi \rangle\) defined above and evaluates the Hamiltonian in it.

build_op() prepares one many-body operator:

  • emat, umat – the one- and two-body coefficients from the first stage. Pass None for whichever of the two is absent.

  • basis – a Fock-basis specification, or a realized basis.

  • backend – the representation the operator is returned in.

It returns a zero-argument callable with a .backend label. Calling it builds the matrix \(\langle \Phi_l \rvert \hat{H} \lvert \Phi_r \rangle\) of the one- and two-body terms above. Each call builds a fresh matrix.

get_ops() is the spectroscopy-oriented wrapper, which prepares everything an XAS or RIXS calculation needs in one call:

  • emat_i, umat_i, basis_i and their _n counterparts – the two Fock spaces, without and with a core hole.

  • trans_mat – the Cartesian photon transition matrices from the model.

It returns hmat_i, hmat_n and the many-body transition operators trans_ops as labeled factories for numerical backends, or disk handles for Fortran. Pass these directly to ed, xas, and rixs; the solvers read their .backend labels and pass the factories to the backend for matrix construction. These solver functions do not accept a backend keyword. Because XAS and RIXS connect states with no core hole to states with exactly one core hole, keeping the two Hamiltonians separate avoids the need to generate a Hamiltonian that spans both spaces and makes the calculation more efficient.

The Fock-basis encoding and the valence-before-core orbital ordering that both functions assume are set out in Conventions.

Exact diagonalization

The third stage finds the low-energy eigenstates of the many-body Hamiltonian.

ed() diagonalizes a many-body Hamiltonian and returns its num_evals lowest eigenpairs as eval_i, evec_i:

  • eval_i is a 1D real array ordered by increasing energy.

  • For the dense and scipy backends evec_i is a 2D complex array; the eigenvector belonging to eval_i[k] is the column evec_i[:, k].

  • For the petsc backend evec_i is a list of distributed PETSc vectors, one for each value in eval_i.

Dense, SciPy, and PETSc ED accept shift=shift, where shift is the eighth output of a model constructor. They diagonalize \(H - \mathrm{shift} I\) and restore the offset in eval_i. The Hamiltonian supplied by the caller remains unchanged, so XAS and RIXS continue using the same energy reference. Pass only the first seven model outputs to get_ops. Fortran ED warns when shift is nonzero and continues without applying the shift.

XAS

xas() provides spectra as a function of the incident photon energy ominc and returns an array of shape (len(ominc), len(pol_type)). Its main arguments are gamma_c, the inverse core-hole lifetime; pol_type, a list of (kind, angle) polarization channels; the incident-beam angle thin and azimuth phi; and temperature, which sets Boltzmann weights over the retained initial states (so num_evals in ed must cover every thermally populated one). The geometry and polarization conventions are on the Conventions page.

RIXS

RIXS reuses eval_i, evec_i, hmat_i, hmat_n and trans_ops from the XAS setup unchanged. In addition to ominc you supply the energy-loss grid eloss, the emitted-beam angle thout, the final-state / resolution width gamma_f, and 4-tuple (in_kind, in_angle, out_kind, out_angle) polarization channels. rixs() returns an array of shape (len(ominc), len(eloss), len(pol_type)). It is very common to compute two different emitted polarizations and sum them, since this is what happens for RIXS with no scattered-polarization analysis.

See RIXS calculations for an atomic model for a fully worked calculation of the model_1v1c() model including plotting the incident-energy / energy-loss map. Other models have more parameters to pay attention to but are, in most ways, not fundamentally more complicated.

Where to go next

  • Conventions – units and naming, orbital orderings, single-particle bases, the Fock-basis encoding, and the geometry / polarization / broadening conventions for spectra.

  • Backend – the interchangeable linear-algebra backends and their numerical options.

  • Examples – pedagogical scripts that build up each concept above with physical commentary.

  • EDRIXS Reference – the full API reference.

To put the complete workflow into practice, continue with the NiO crystal-field example or the NiO Anderson impurity example.