Loading...
Searching...
No Matches
projections.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * PlanewaveTrialOrbitalProjectionCalculator — the A_mn(k) = <psi_mk|S|g_n>
5 * projections a Wannier initial guess needs, and the S-metric Löwdin
6 * orthogonalization of the trial orbitals that makes projectability-based
7 * disentanglement meaningful (p_nk = sum_m |A_mn(k)|^2 in [0,1] only when
8 * the trial orbitals are orthonormal in the S metric: O_ij = <g_i|S|g_j>).
9 *
10 * Where the trial orbitals come from is not this class's concern: it is
11 * handed a PlanewaveLocalOrbitalSet -- the pseudopotentials' atomic
12 * wavefunctions, hydrogenic orbitals at explicit centres, anything else that
13 * renders itself in plane waves -- and does the same two things to any of
14 * them. That is what lets the interface builder have one path instead of
15 * one per orbital source.
16 *
17 * Differs from the PDOS / Löwdin population analysis in one way that
18 * matters for Wannier functions: it returns the complex projection amplitude
19 * rather than its squared modulus, because a Wannier initial guess needs the
20 * phase and PDOS does not. The S metric itself is shared -- both hand the
21 * same overlap operator to orbital_metric.hpp.
22 */
23
24#include <complex>
25#include <vector>
26
35
36namespace q3 {
37
39 public:
41 const PlanewaveLocalOrbitalSet& trial_orbitals)
42 : trial_orbitals_(trial_orbitals) {}
43
44 [[nodiscard]] int number_of_orbitals() const {
45 return trial_orbitals_.number_of_orbitals();
46 }
47
48 /**
49 * Compute A_mn(k) = <psi_mk|S|g'_n>, where g'_n is the trial-orbital
50 * set Löwdin-orthogonalized in the S metric: projections[band_index]
51 * [orbital_index]. `overlap_operator` is null for norm-conserving
52 * pseudopotentials (S = I); ultrasoft/PAW callers pass
53 * create_overlap_operator()'s result, built from the live SCF state
54 * at this k-point (the projector matrix it needs is k-point
55 * dependent, so it cannot be cached across k-points inside this
56 * calculator).
57 */
58 [[nodiscard]] std::vector<std::vector<Complex>>
60 int kpoint_state_index,
61 int number_of_plane_waves,
62 int number_of_bands,
63 const std::vector<int>& g_vector_indices,
64 const Crystal& crystal_structure,
65 const KPointsGrid& kpoint_grid,
66 const PlanewaveBasis& planewave_basis,
67 const PlanewaveKohnShamQuantumSystem& quantum_system,
68 const OverlapOperator* overlap_operator,
69 int first_band_index = 0) const {
70 std::vector<std::vector<Complex>> orbitals;
71 trial_orbitals_.build(kpoint_index,
72 number_of_plane_waves,
73 g_vector_indices,
74 crystal_structure,
75 kpoint_grid,
76 planewave_basis,
77 orbitals);
78
79 std::vector<Complex> overlap_in_s_metric =
80 compute_orbital_overlap_matrix_in_s_metric(orbitals, overlap_operator);
81 lowdin_orthogonalize_orbitals(orbitals, overlap_in_s_metric);
82
83 int orbital_count = static_cast<int>(orbitals.size());
84 std::vector<std::vector<Complex>> s_applied_orbitals =
85 apply_overlap_operator_to_orbitals(orbitals, overlap_operator);
86
87 std::vector<std::vector<Complex>> projections(
88 number_of_bands, std::vector<Complex>(orbital_count, Complex(0.0, 0.0)));
89
90 for (int band_index = 0; band_index < number_of_bands; band_index++) {
91 const Complex* band_data = quantum_system.wavefunction_band_data(
92 kpoint_state_index, first_band_index + band_index);
93 for (int orbital_index = 0; orbital_index < orbital_count; orbital_index++) {
94 Complex overlap(0.0, 0.0);
95 const std::vector<Complex>& s_applied_orbital = s_applied_orbitals[orbital_index];
96 for (int g_index = 0; g_index < number_of_plane_waves; g_index++) {
97 overlap += std::conj(band_data[g_index]) * s_applied_orbital[g_index];
98 }
99 projections[band_index][orbital_index] = overlap;
100 }
101 }
102 return projections;
103 }
104
105 private:
106 const PlanewaveLocalOrbitalSet& trial_orbitals_;
107};
108
109} // namespace q3
Complex * wavefunction_band_data(int kpoint_state_index, int band_index)
Definition init.hpp:107
virtual int number_of_orbitals() const =0
virtual void build(int kpoint_index, int number_of_plane_waves, const std::vector< int > &g_vector_indices, const Crystal &crystal_structure, const KPointsGrid &kpoint_grid, const PlanewaveBasis &planewave_basis, std::vector< std::vector< Complex > > &orbitals) const =0
std::vector< std::vector< Complex > > compute_projections_at_kpoint(int kpoint_index, int kpoint_state_index, int number_of_plane_waves, int number_of_bands, const std::vector< int > &g_vector_indices, const Crystal &crystal_structure, const KPointsGrid &kpoint_grid, const PlanewaveBasis &planewave_basis, const PlanewaveKohnShamQuantumSystem &quantum_system, const OverlapOperator *overlap_operator, int first_band_index=0) const
PlanewaveTrialOrbitalProjectionCalculator(const PlanewaveLocalOrbitalSet &trial_orbitals)
std::vector< std::vector< Complex > > apply_overlap_operator_to_orbitals(const std::vector< std::vector< Complex > > &orbitals, const OverlapOperator *overlap_operator)
void lowdin_orthogonalize_orbitals(std::vector< std::vector< Complex > > &orbitals, std::vector< Complex > overlap_column_major)
std::vector< Complex > compute_orbital_overlap_matrix_in_s_metric(const std::vector< std::vector< Complex > > &orbitals, const OverlapOperator *overlap_operator)
std::complex< double > Complex