Loading...
Searching...
No Matches
q3::UltrasoftPlanewaveEffectivePotential Class Reference

#include <init.hpp>

+ Inheritance diagram for q3::UltrasoftPlanewaveEffectivePotential:

Public Member Functions

 UltrasoftPlanewaveEffectivePotential ()=default
 
void add_per_atom_d_terms (const std::vector< std::vector< Real > > &terms_by_atom)
 
void add_per_atom_d_terms_for_spin (int spin, const std::vector< std::vector< Real > > &terms)
 
const std::vector< std::vector< Complex > > & cached_structure_factors () const
 
void compute (const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const UltrasoftPlanewaveBasis &ultrasoft_pseudopotential_basis, const std::vector< Complex > &total_potential_g)
 
void compute_by_spin (const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis, const UltrasoftPlanewaveBasis &ultrasoft_pseudopotential_basis, const std::vector< std::vector< Complex > > &total_potential_g_by_spin)
 
Real element (int atom_index, int projector_index_i, int projector_index_j, int spin=0) const
 
bool is_initialized () const
 
void precompute_structure_factors (const Crystal &crystal_structure, const PlanewaveBasis &planewave_basis)
 
- Public Member Functions inherited from q3::NormConservingPlanewaveEffectivePotential
virtual ~NormConservingPlanewaveEffectivePotential () override=default
 
 PlanewaveEffectivePotential ()=default
 
 PlanewaveEffectivePotential (const PlanewaveBasis &basis, int number_of_spin_components)
 
- Public Member Functions inherited from q3::PlanewaveEffectivePotential
 PlanewaveEffectivePotential ()=default
 
 PlanewaveEffectivePotential (const PlanewaveBasis &basis, int number_of_spin_components)
 
const PlanewaveBasis & basis () const
 
std::vector< Complex > & charge_density_reciprocal ()
 
const std::vector< Complex > & charge_density_reciprocal () const
 
std::vector< Complex > & exchange_correlation_reciprocal_space_data ()
 
const std::vector< Complex > & exchange_correlation_reciprocal_space_data () const
 
int grid_size () const
 
void initialize_kinetic_potential ()
 
std::vector< std::vector< Real > > & kinetic_potential_data ()
 
const std::vector< std::vector< Real > > & kinetic_potential_data () const
 
void log_summary () const
 
std::vector< Real > & real_space_by_spin_index (int spin_index)
 
const std::vector< Real > & real_space_by_spin_index (int spin_index) const
 
void to_real_space () override
 
void to_reciprocal_space () override
 
- Public Member Functions inherited from q3::EffectivePotential
virtual ~EffectivePotential ()=default
 
- Public Member Functions inherited from q3::SpinResolvedEntity
virtual ~SpinResolvedEntity ()=default
 
bool is_spin_polarized () const
 
int number_of_spin_components () const
 
- Public Member Functions inherited from q3::FFTransformable< SpinResolvedPotentialGrid, PotentialReciprocalCoefficients >
virtual ~FFTransformable ()=default
 
SpinResolvedPotentialGrid & real_space_representation ()
 
const SpinResolvedPotentialGrid & real_space_representation () const
 
PotentialReciprocalCoefficients & reciprocal_space_representation ()
 
const PotentialReciprocalCoefficients & reciprocal_space_representation () const
 

Protected Attributes

std::vector< std::vector< Real > > effective_d_matrix_
 
std::vector< std::vector< std::vector< Real > > > effective_d_matrix_by_spin_
 One D per spin channel; empty when the spin-free compute was used.
 
- Protected Attributes inherited from q3::SpinResolvedEntity
int number_of_spin_components_ = 1
 
- Protected Attributes inherited from q3::FFTransformable< SpinResolvedPotentialGrid, PotentialReciprocalCoefficients >
SpinResolvedPotentialGrid real_space_data_
 
PotentialReciprocalCoefficients reciprocal_space_data_
 

Additional Inherited Members

- Public Attributes inherited from q3::PlanewaveEffectivePotential
Real exchange_correlation_energy = 0.0
 
Real exchange_correlation_potential_energy = 0.0
 
Real hartree_energy = 0.0
 

Detailed Description

Definition at line 30 of file init.hpp.

Constructor & Destructor Documentation

◆ UltrasoftPlanewaveEffectivePotential()

q3::UltrasoftPlanewaveEffectivePotential::UltrasoftPlanewaveEffectivePotential ( )
default

Member Function Documentation

◆ add_per_atom_d_terms()

void q3::UltrasoftPlanewaveEffectivePotential::add_per_atom_d_terms ( const std::vector< std::vector< Real > > &  terms_by_atom)
inline

Add per-atom terms that a layered flavor contributes to D.

PAW's D is this D plus a one-center term:

D_ij = D⁰_ij  +  ∫ v_eff Q_ij  +  (D¹ − D̃¹)_Hxc
       └─ dataset ─┘ └─ here ─┘    └─ passed in ─┘

The first two are what compute() built and are never recomputed for PAW — the kinetic and core-reference pieces baked into PP_DIJ/DION at generation time would be double-counted if they were. So the one-center term is a decoration of this result, and this is the seam it arrives through: the correction depends on the on-site occupancies, which only the SCF loop knows, so it is passed in rather than computed here.

Expressed as a method rather than a subclass override deliberately. The iterators hold this type by value, so a PawPlanewaveEffectivePotential could not actually be substituted for it without pointer-ifying every holder — a subclass that cannot be substituted is worse than a named operation on the object that owns D.

Call after compute(), once per SCF step. An empty entry means "no terms for this atom", so a mixed PAW/ultrasoft cell needs no special case.

A size mismatch means the caller's channel expansion disagrees with the projector mapping table's, which would otherwise write plausible numbers into the wrong elements. There is no partial-overlap reading of these matrices that is meaningful, so refusing is the only safe response.

Definition at line 347 of file init.hpp.

References effective_d_matrix_.

Referenced by add_per_atom_d_terms_for_spin().

◆ add_per_atom_d_terms_for_spin()

void q3::UltrasoftPlanewaveEffectivePotential::add_per_atom_d_terms_for_spin ( int  spin,
const std::vector< std::vector< Real > > &  terms 
)
inline

Add per-atom terms to one spin channel's D (PAW's one-center term).

Refuses a channel that was never computed rather than returning quietly. A silent no-op would leave that channel's Hamiltonian carrying the other channel's one-center D — via element()'s fallback — while the double-counting term still subtracted its own, so the SCF would converge to a stationary point of something that is not the energy it prints.

Definition at line 88 of file init.hpp.

References add_per_atom_d_terms(), effective_d_matrix_, and effective_d_matrix_by_spin_.

◆ cached_structure_factors()

const std::vector< std::vector< Complex > > & q3::UltrasoftPlanewaveEffectivePotential::cached_structure_factors ( ) const
inline

Return the cached structure factors (computed on first call to compute()). Useful for sharing with augmentation charge code.

Definition at line 431 of file init.hpp.

Referenced by q3::UltrasoftPlanewavePseudopotentialKohnShamSCFIterator::add_augmentation_to_charge_density().

◆ compute()

void q3::UltrasoftPlanewaveEffectivePotential::compute ( const Crystal &  crystal_structure,
const PlanewaveBasis &  planewave_basis,
const UltrasoftPlanewaveBasis &  ultrasoft_pseudopotential_basis,
const std::vector< Complex > &  total_potential_g 
)
inline

Phase 1: For each US species, precompute aux_ij(G) = conj(V(G)) * Q_ij(G) This is done once per species, not once per atom.

Correct formula: D_ij = ∫ Q(r−R)·V(r) dr = Σ_G Q(G)·conj(V(G))·e^{−iGR}·Ω [For real V: V(−G)=V*(G), so the integral picks up V*(G).] Taking conj(Q) instead of conj(V) gives the same result only when Im(V(G)) = 0 — true for symmetric structures but NOT for displaced atoms.

A species contributes ∫v_eff·Q_ij here exactly when it has augmentation charges — which PAW does. Skipping on != ultrasoft would leave a PAW atom's D at D_ion alone, a large and entirely silent error.

D_ij = ∫ Q(r−R)·V(r) dr = Σ_G Q(G)·V*(G)·e^{−iGR}·Ω Must conjugate V, NOT Q (Q may also be complex due to (−i)^l factor).

Phase 2: Compute D_eff for all atoms using batched BLAS zgemm per species. Instead of 54 individual zgemv calls, we group atoms by species and compute all integrals in a single zgemm: result = aux^T × sf_matrix. aux is (n_g × n_pairs), sf_matrix is (n_g × n_atoms_of_species), result is (n_pairs × n_atoms_of_species).

zgemm: result = aux^T × sf_matrix aux is (n_g × n_pairs) column-major, sf_matrix is (n_g × n_atoms) column-major result = aux^T × sf = (n_pairs × n_g) × (n_g × n_atoms) = (n_pairs × n_atoms)

Unpack results into per-atom D-matrices For gamma-only: multiply by 2 (half-sphere → full sphere), then subtract the G=0 contribution once (it was double-counted).

If gamma-only, precompute the G=0 correction: G=0 term = Re(conj(V(0))*Q_ij(0)*sf(0)) = Re(conj(V(0))*Q_ij(0)*1) sf(G=0) = exp(i·0·τ) = 1 for all atoms. At G=0, V(0) is real and Q(0) is real (l=0 only), so conj(V(0))=V(0). This correction is the same for all atoms of this species.

Definition at line 100 of file init.hpp.

References q3::Crystal::cell_volume(), effective_d_matrix_, q3::PlanewaveBasis::first_nonzero_g_index(), q3::PlanewaveBasis::is_gamma_only(), q3::Crystal::number_of_atoms(), q3::PlanewaveBasis::number_of_g_vectors(), precompute_structure_factors(), q3::NormConservingPlanewaveBasis::projector_mapping_table(), q3::NormConservingPlanewaveBasis::pseudopotential_set(), q3::UltrasoftPlanewaveBasis::q_function_g_data(), q3::Crystal::species_type_index(), and q3::blas::zgemm_().

Referenced by compute_by_spin().

◆ compute_by_spin()

void q3::UltrasoftPlanewaveEffectivePotential::compute_by_spin ( const Crystal &  crystal_structure,
const PlanewaveBasis &  planewave_basis,
const UltrasoftPlanewaveBasis &  ultrasoft_pseudopotential_basis,
const std::vector< std::vector< Complex > > &  total_potential_g_by_spin 
)
inline

Compute the effective D-matrix for all atoms from the current V_eff(G).

Uses the pre-computed Q_ij(G) table from the ultrasoft basis to avoid per-G interpolation. The computation reduces to: D_eff(i,j) = D_ion(i,j) + Re(Σ_G conj(V(G)) * Q_ij(G) * e^{-iG·τ}) * Ω

Parameters
crystal_structureCrystal geometry
planewave_basisPlane-wave basis (G-vectors)
ultrasoft_pseudopotential_basisUltrasoft basis (pre-computed Q(G), projector mappings)
total_potential_gTotal effective potential in G-space Compute D for every spin channel.

D_ij = D_ion + ∫v_eff·Q_ij, and v_eff is spin-dependent, so D is too. Calling this with one potential reproduces the unpolarized result exactly; calling it with two gives each channel its own D, which is what a magnetic system needs and what a shared, spin-averaged D silently denies it.

Leave effective_d_matrix_ holding channel 0 so anything still reading the spin-free accessor sees a real D rather than whatever the last loop iteration left behind.

Definition at line 57 of file init.hpp.

References compute(), effective_d_matrix_, and effective_d_matrix_by_spin_.

Referenced by q3::UltrasoftPlanewavePseudopotentialKohnShamSCFIterator::prepare_hamiltonian().

◆ element()

Real q3::UltrasoftPlanewaveEffectivePotential::element ( int  atom_index,
int  projector_index_i,
int  projector_index_j,
int  spin = 0 
) const
inline

Read an element of the effective D-matrix.

Falls back to the spin-free matrix when no per-spin one was computed, which is every unpolarized run and every path that still calls the single-potential compute.

Definition at line 377 of file init.hpp.

References effective_d_matrix_, and effective_d_matrix_by_spin_.

Referenced by q3::UltrasoftPlanewaveKohnShamQuantumSystem::d_matrix_element().

◆ is_initialized()

bool q3::UltrasoftPlanewaveEffectivePotential::is_initialized ( ) const
inline

◆ precompute_structure_factors()

void q3::UltrasoftPlanewaveEffectivePotential::precompute_structure_factors ( const Crystal &  crystal_structure,
const PlanewaveBasis &  planewave_basis 
)
inline

Precompute and cache structure factors for all atoms. These are constant during SCF since atomic positions don't change.

Definition at line 410 of file init.hpp.

References q3::compute_phase_factor(), q3::Crystal::convert_from_crystal_to_cartesian(), q3::PlanewaveBasis::g_vectors(), q3::Crystal::number_of_atoms(), q3::PlanewaveBasis::number_of_g_vectors(), and q3::constants::two_pi.

Referenced by compute().

Member Data Documentation

◆ effective_d_matrix_

std::vector<std::vector<Real> > q3::UltrasoftPlanewaveEffectivePotential::effective_d_matrix_
protected

Effective D-matrix: per-atom × (projector_channels²).

Protected rather than private because PAW's D is this D plus a one-center term — the seam named in the A3 addendum. A subclass adds to it in place; nothing else may.

Definition at line 443 of file init.hpp.

Referenced by add_per_atom_d_terms(), add_per_atom_d_terms_for_spin(), compute(), compute_by_spin(), element(), and is_initialized().

◆ effective_d_matrix_by_spin_

std::vector<std::vector<std::vector<Real> > > q3::UltrasoftPlanewaveEffectivePotential::effective_d_matrix_by_spin_
protected

One D per spin channel; empty when the spin-free compute was used.

Definition at line 446 of file init.hpp.

Referenced by add_per_atom_d_terms_for_spin(), compute_by_spin(), and element().


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