Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
q3::NonSelfConsistentFieldFlavor Class Reference

#include <non_self_consistent_field.hpp>

+ Inheritance diagram for q3::NonSelfConsistentFieldFlavor:

Public Member Functions

 NonSelfConsistentFieldFlavor (IteratorFactory iterator_factory={})
 
- Public Member Functions inherited from q3::Flavor
virtual ~Flavor ()=default
 
generated::Results run (const InputData &input)
 

Protected Member Functions

generated::Results run_calculation (const InputData &input) override
 

Detailed Description

Definition at line 68 of file non_self_consistent_field.hpp.

Constructor & Destructor Documentation

◆ NonSelfConsistentFieldFlavor()

q3::NonSelfConsistentFieldFlavor::NonSelfConsistentFieldFlavor ( IteratorFactory  iterator_factory = {})
inlineexplicit

iterator_factory carries the entry point's execution policy (see IteratorFactory); empty runs serially on the CPU.

Definition at line 74 of file non_self_consistent_field.hpp.

Member Function Documentation

◆ run_calculation()

generated::Results q3::NonSelfConsistentFieldFlavor::run_calculation ( const InputData &  input)
inlineoverrideprotectedvirtual

Execute the calculation described by the input and return results.

Implementations must be self-contained: they set up, run, and finalize the calculation entirely. The caller receives fully-populated results, minus what run() adds.

─── Step 2: Build iterator with explicit k-points ──────────────────── Set maximum_iterations = 1 so the base iterate() loop runs exactly once (performs initialization + one diagonalization pass).

Use the same convergence threshold as the SCF run (irrelevant for NSCF since we do only one iteration, but must be set to avoid division by zero).

The potential below is loaded whole, onto every rank, as the SCF saved it. That fits a rank holding whole k-points – one rank per pool, the topology the SCF itself needs to write the checkpoint at all – and nothing else: ranks sharing a pool split the density grid between them, and nothing scatters a whole grid onto that split. Asked after the iterator exists, because building it is where a pool count above the k-point count is clamped back into shared pools.

─── Step 3: Inject preloaded V_eff ────────────────────────────────── load_effective_potential() sets has_preloaded_effective_potential_ = true, which prevents update_effective_potential() from overwriting it during initialize_single_particle_states(). Instead, only the G-space FFT is done to populate total_potential_g_ (needed by prepare_hamiltonian()).

─── Step 3a: Hand over the PAW on-site occupations ─────────────────── A PAW dataset's D carries a one-centre term built from ρ_ij, which the SCF refreshes each time it constructs a density. This run diagonalizes before it constructs any, so without the converged ρ_ij that term is empty and every eigenvalue is wrong – copper's 3s by 103 eV. A checkpoint written before the occupations were stored cannot supply them, and a result built without them is refused rather than returned.

─── Step 3b: Set tight diagonalization tolerance ───────────────────── The SCF iterator uses a loose initial tolerance (1e-2 Ry) for iteration 1, which is appropriate for SCF where the potential evolves anyway. For NSCF the potential is frozen and we run only one pass, so we must start with a tight tolerance to ensure Davidson converges all bands to the true lowest eigenvalues. Without this, high-index conduction bands at special k-points (e.g. the 10th band at K in Si: 14.5 eV) can converge to spurious excited states instead of the correct ground-state eigenvectors.

─── Step 4b: Mean-field export (BerkeleyGW, etc.) ───────────────────── This is the flavor BerkeleyGW normally consumes: an NSCF run with many empty (conduction) bands beyond what SCF itself needs, at whatever k-point set input.kpoints_list requests. Format selection lives in the factory ("none" resolves to the Null object), so there is no branching on the format name here – see io/mean_field_export/init.hpp.

The exported charge density must be the CONVERGED SCF density from the checkpoint, not the one this pass leaves on the iterator. Step 4 runs a single turn of the shared per-iteration flow, which ends in a mixing step, so the iterator's density is a blend of the atomic-superposition initial guess and this pass's output – governed by mixing.beta, a parameter that has no meaning for a non-self-consistent run. Measured on the silicon example (beta 0.3): 12% off the converged density in L2 over the whole G set (19% when the NSCF k-set is the symmetry-reduced IBZ), against 0.01% once mixing is bypassed – and, being a recomputed density, it would additionally degrade with a coarse k-set even without mixing. pw2bgw draws the same line: write_rhog writes QE's saved charge density, and recomputing it from the bands is a separate opt-in diagnostic (calc_rhog, reached only via rhog_nvmin/rhog_nvmax).

Vxc(G) likewise belongs to the converged density, and this pass never computes it at all: the potential came from the checkpoint whole, so without this the state carries an empty Vxc(G) and BerkeleyGW's vxc.dat cannot be written. pw2bgw evaluates Vxc from the same saved density (its vxc_flag path), and from the valence part of it: see valence_exchange_correlation_potential_g_of().

Which rank (if any) writes is decided by the execution topology – see export_and_record_mean_field_under_topology()'s comment, which the MPI entry points reach through this flavor as the SCF's do.

An NSCF total energy is meaningless — list it as 0 to signal this. A single-pass NSCF is always "converged" — there is no iterative convergence criterion applicable. The SCF iterator reports is_converged()=false because the KohnShamSCFIterator convergence check requires iteration_>1 (which is never reached with maximum_iterations=1). Override to true so that the Python layer does not raise SCFNotConvergedError on a valid NSCF result.

Every k-point state of the run, gathered across pools – each pool diagonalized only its own share of the list – in the list's order.

This pool's k-point states: the projections are taken where the wavefunctions are, then gathered like the eigenvalues above. The state index is spin-major over the pool's physical k-points, so a state splits into the physical k-point (G-space basis, spin-independent) and the state (wavefunction storage, spin-dependent).

Kept alive alongside the operator that reads it: the ultrasoft overlap holds the matrix by reference.

Implements q3::Flavor.

Definition at line 78 of file non_self_consistent_field.hpp.

References q3::assemble_global_eigenvalues_at_kpoints(), q3::assemble_global_kpoint_state_blocks(), q3::capture_interpolation_record(), q3::KohnShamQuantumSystemSnapshot::charge_density_real, q3::InputData::compute_projections, q3::InputData::convergence_threshold, q3::create_iterator(), q3::InputData::davidson_basis_expansion_factor, q3::InputData::davidson_basis_expansion_factor_set_by_deck, q3::KohnShamQuantumSystemSnapshot::effective_potential_real, q3::export_and_record_mean_field_under_topology(), q3::log::info(), q3::InputData::interpolation, q3::InputData::kpoints_list, q3::Q3PlanewaveKohnShamQuantumSystemCheckpoint::load(), q3::InputData::maximum_iterations, q3::math::tolerances::minimum_eigenvalue_tolerance, q3::new_results(), q3::non_self_consistent_field_davidson_basis_expansion_factor(), q3::constants::non_self_consistent_field_maximum_davidson_iterations, q3::constants::non_self_consistent_field_minimum_davidson_basis_expansion_factor, q3::KohnShamQuantumSystemSnapshot::one_center_occupations, q3::InputData::output_directory, q3::InputData::prefix, q3::InterpolationSpecification::requested(), q3::set_energy_records(), q3::set_fermi_energy(), q3::set_record(), q3::log::warn(), and q3::write_and_export_interpolation_record().


The documentation for this class was generated from the following file: