Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
local_potential_table.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * LocalPotentialTable — tabulated local pseudopotential on a uniform q-grid.
5 *
6 * Pre-computes V_loc(q) for each species on the same uniform q-grid used by
7 * BetaFunctionTable, enabling O(1) interpolation instead of O(N_radial)
8 * Simpson integration per q-point. This eliminates the dominant bottleneck
9 * in stress tensor calculations.
10 *
11 * Only the short-range part is tabulated; the long-range Coulomb tail is added
12 * analytically at each q, and q = 0 returns the α_Z constant computed directly. The
13 * whole of V_loc(q) used to be tabulated, and a 4-point fit across its 1/q²
14 * divergence is off by roughly (dq/q)⁴ of that term near the origin. Bulk cells,
15 * whose smallest |G| is near 1/bohr, never noticed; a cell with a long vacuum
16 * direction has G-vectors close to the origin, and slabs and molecules picked up a
17 * spurious energy that grew roughly as c⁵ with the cell length c, -59 mRy on a
18 * Ni/CO slab in a 20 Å cell.
19 */
20
21#include <cmath>
22#include <vector>
23
30
31namespace q3 {
32
34 public:
36
37 /**
38 * Initialize the table by evaluating the short-range part of V_loc(q) on a uniform
39 * q-grid for each species.
40 */
42 const PseudopotentialSet& pseudopotential_set,
43 const std::vector<int>& mesh_sizes,
44 Real cell_volume,
45 int number_of_species_types) {
46 q_grid_ = q_grid;
47 cell_volume_ = cell_volume;
48 std::vector<Real> q_point_values = q_grid_.q_point_values();
49
50 species_.assign(number_of_species_types, SpeciesTable{});
51 for (int type_index = 0; type_index < number_of_species_types; type_index++) {
52 const auto& pseudopotential = pseudopotential_set[type_index];
53 SpeciesTable& species = species_[type_index];
54 species.short_range.resize(q_grid_);
55 for (int q_index = 0; q_index < q_grid_.number_of_q_points; q_index++) {
56 species.short_range[q_index] = calculate_local_potential_short_range_at_q(
57 pseudopotential, mesh_sizes[type_index], q_point_values[q_index], cell_volume);
58 }
59 species.zero_q_value = calculate_local_potential_at_q(
60 pseudopotential, mesh_sizes[type_index], 0.0, cell_volume);
61 species.valence_charge = pseudopotential.valence_charge;
62 species.bare_coulomb_tail = local_potential_is_tabulated_reciprocally(pseudopotential);
63 }
64 }
65
66 /**
67 * V_loc(q) for a given species at arbitrary q value: α_Z at q = 0, otherwise the
68 * interpolated short-range part plus the exact long-range part.
69 */
70 [[nodiscard]] Real interpolate(int species_type_index, Real q_value) const {
71 const SpeciesTable& species = species_[species_type_index];
73 return species.zero_q_value;
74 return species.short_range.interpolate(q_value) +
76 species.valence_charge, species.bare_coulomb_tail, q_value, cell_volume_);
77 }
78
79 /**
80 * The derivative dV_loc/dq for a given species at arbitrary q value, assembled the
81 * same way.
82 */
83 [[nodiscard]] Real interpolate_derivative(int species_type_index, Real q_value) const {
84 const SpeciesTable& species = species_[species_type_index];
85 return species.short_range.interpolate_derivative(q_value) +
87 species.valence_charge, species.bare_coulomb_tail, q_value, cell_volume_);
88 }
89
90 [[nodiscard]] const UniformQGrid& q_grid() const {
91 return q_grid_;
92 }
93
94 private:
95 struct SpeciesTable {
96 UniformQGridTable short_range;
97 Real zero_q_value = 0.0;
98 Real valence_charge = 0.0;
99 bool bare_coulomb_tail = false;
100 };
101
102 UniformQGrid q_grid_;
103 Real cell_volume_ = 0.0;
104 std::vector<SpeciesTable> species_;
105};
106
107} // namespace q3
Real interpolate(int species_type_index, Real q_value) const
Real interpolate_derivative(int species_type_index, Real q_value) const
const UniformQGrid & q_grid() const
void initialize(const UniformQGrid &q_grid, const PseudopotentialSet &pseudopotential_set, const std::vector< int > &mesh_sizes, Real cell_volume, int number_of_species_types)
constexpr double zero_vector_magnitude_threshold
Real calculate_local_potential_short_range_at_q(const Pseudopotential &pseudopotential, int mesh_size, Real q_value, Real cell_volume)
double Real
Real calculate_local_potential_long_range_derivative_at_q(Real valence_charge, bool bare_coulomb_tail, Real q_value, Real cell_volume)
bool local_potential_is_tabulated_reciprocally(const Pseudopotential &pseudopotential)
Real calculate_local_potential_long_range_at_q(Real valence_charge, bool bare_coulomb_tail, Real q_value, Real cell_volume)
Real calculate_local_potential_at_q(const Pseudopotential &pseudopotential, int mesh_size, Real q_value, Real cell_volume)
std::vector< Real > q_point_values() const