Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
system_builder.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * Shared builders from parsed InputData to layer-1 structures.
5 *
6 * Single source of truth for crystal construction and global k-point grid
7 * setup (explicit list or generation, IBZ reduction, LSDA spin-channel weight
8 * scaling). Both production entry points — the iterator factory and the
9 * q3_core bindings — must build through these helpers so that input semantics
10 * can never drift between them.
11 */
12
13#include <utility>
14#include <vector>
15
16#include "io/input/data.hpp"
20
21namespace q3 {
22
23/**
24 * Per-atom symmetry partition implied by per-atom starting moments.
25 *
26 * Atoms of one species seeded with different moments (a same-species
27 * antiferromagnet) must not be interchanged by a symmetry operation, or the
28 * k-point reduction and the density symmetrization would average the two
29 * sublattices back together. Returns one class per atom -- distinct
30 * (species, moment) pairs numbered in order of first appearance -- or an
31 * EMPTY vector when every species is uniform, which leaves the crystal on its
32 * default species partition (and the run bit-identical to per-species input).
33 */
34inline std::vector<int> site_symmetry_classes_from_input(const InputData& input) {
35 const auto& moments = input.atomic_starting_magnetization;
36 if (input.number_of_spin_components != 2 || moments.empty() ||
37 moments.size() != input.atoms.size())
38 return {};
39 std::vector<int> classes(input.atoms.size(), -1);
40 std::vector<std::pair<int, Real>> class_keys;
41 bool splits_a_species = false;
42 for (size_t atom = 0; atom < input.atoms.size(); ++atom) {
43 int species = input.atoms[atom].species_index;
44 int found = -1;
45 for (size_t key = 0; key < class_keys.size(); ++key) {
46 if (class_keys[key].first != species)
47 continue;
48 if (class_keys[key].second == moments[atom]) {
49 found = static_cast<int>(key);
50 break;
51 }
52 splits_a_species = true;
53 }
54 if (found < 0) {
55 found = static_cast<int>(class_keys.size());
56 class_keys.emplace_back(species, moments[atom]);
57 }
58 classes[atom] = found;
59 }
60 return splits_a_species ? classes : std::vector<int>{};
61}
62
63/**
64 * Build the Crystal described by the input: explicit lattice vectors ("free"
65 * lattice) when present, Bravais-index construction otherwise.
66 *
67 * @param species Species list to install (callers pass the pseudopotential-
68 * patched copy, which is why this is a parameter rather than
69 * read from input.species).
70 */
72 const std::vector<AtomSpecies>& species) {
75 input.cell_dimension_1, input.lattice_vectors, species, input.atoms)
77 input.cell_dimension_1,
78 species,
79 input.atoms,
80 input.cell_dimension_2,
81 input.cell_dimension_3,
82 input.cell_dimension_4,
83 input.cell_dimension_5,
84 input.cell_dimension_6);
86 return crystal;
87}
88
89/**
90 * Build the GLOBAL k-point grid for a calculation:
91 *
92 * 1. explicit kpoints_list when given (NSCF paths), else Monkhorst-Pack
93 * generation from the input grid dimensions and shifts;
94 * 2. IBZ reduction (spglib or internal) unless symmetry is disabled;
95 * 3. LSDA weight scaling — generated weights embed the spin degeneracy of 2,
96 * and with two explicit spin channels each k-point state carries half of
97 * that weight.
98 *
99 * Pool distribution (the per-rank subset) remains the caller's concern.
100 */
102 const Crystal& crystal) {
103 KPointsGrid global_kpoint_grid;
104 if (!input.kpoints_list.empty()) {
105 for (const auto& [coordinates, weight] : input.kpoints_list) {
106 KPoint kpoint;
107 kpoint.coordinates = coordinates;
108 kpoint.weight = weight;
109 global_kpoint_grid.add_kpoint(kpoint);
110 }
111 } else {
112 global_kpoint_grid.generate(input.kpoint_grid_dimension_1,
117 input.kpoint_grid_shift_3);
118
119 /**
120 * Gated on the mesh having more than one point, not on its first
121 * dimension having more than one: a 1x4x4 mesh -- a slab or a wire,
122 * sampled only across the two periodic directions -- has sixteen
123 * points and an irreducible wedge like any other, and the old test
124 * left every one of them in the sum. Q3 then solved up to a whole
125 * point group's worth of duplicate k-points, correctly and slowly.
126 * A single point (1x1x1, shifted or not) is its own wedge, so the
127 * reduction has nothing to do and is skipped rather than called.
128 */
129 const int number_of_mesh_points = input.kpoint_grid_dimension_1 *
132 if (!input.disable_symmetry && number_of_mesh_points > 1) {
133 if (input.ibz_reduction_method == "spglib") {
134 global_kpoint_grid = SymmetryAnalyzer::reduce_kpoints(crystal, global_kpoint_grid);
135 } else {
136 global_kpoint_grid =
137 SymmetryAnalyzer::reduce_kpoints_internal(crystal, global_kpoint_grid);
138 }
139 }
140 }
141
142 if (input.number_of_spin_components == 2) {
143 global_kpoint_grid.scale_weights(0.5);
144 }
145
146 return global_kpoint_grid;
147}
148
149} // namespace q3
static Crystal from_lattice_vectors(Real lattice_parameter, const Matrix3x3 &lattice_vectors, const std::vector< AtomSpecies > &species, const std::vector< Atom > &atoms)
Definition crystal.hpp:75
static Crystal from_input_data(int bravais_lattice_index, Real cell_dimension_1, const std::vector< AtomSpecies > &species, const std::vector< Atom > &atoms, Real cell_dimension_2=0, Real cell_dimension_3=0, Real cell_dimension_4=0, Real cell_dimension_5=0, Real cell_dimension_6=0)
Definition crystal.hpp:40
void set_site_symmetry_classes(const std::vector< int > &classes)
Definition crystal.hpp:295
void scale_weights(Real factor)
void add_kpoint(const KPoint &kpoint)
void generate(int grid_dimension_x, int grid_dimension_y, int grid_dimension_z, int shift_x, int shift_y, int shift_z)
static KPointsGrid reduce_kpoints_internal(const Crystal &crystal, const KPointsGrid &input_grid, bool use_time_reversal=true, Real symmetry_precision=math::tolerances::default_symmetry_precision)
Definition symmetry.hpp:262
static KPointsGrid reduce_kpoints(const Crystal &crystal, const KPointsGrid &input_grid, Real symmetry_precision=math::tolerances::default_symmetry_precision)
Definition symmetry.hpp:131
Crystal build_crystal_from_input(const InputData &input, const std::vector< AtomSpecies > &species)
std::vector< int > site_symmetry_classes_from_input(const InputData &input)
KPointsGrid build_global_kpoint_grid_from_input(const InputData &input, const Crystal &crystal)
Parsed input data — holds raw values read from input files.
Definition data.hpp:27
Real cell_dimension_4
Definition data.hpp:139
int kpoint_grid_dimension_3
Definition data.hpp:159
int kpoint_grid_shift_1
Definition data.hpp:160
int kpoint_grid_dimension_1
Definition data.hpp:159
std::vector< Atom > atoms
Definition data.hpp:156
Real cell_dimension_6
Definition data.hpp:141
bool has_explicit_lattice_vectors
Definition data.hpp:148
std::vector< std::pair< Vector3D, Real > > kpoints_list
Definition data.hpp:125
bool disable_symmetry
Definition data.hpp:192
int kpoint_grid_dimension_2
Definition data.hpp:159
std::vector< Real > atomic_starting_magnetization
Definition data.hpp:57
int kpoint_grid_shift_2
Definition data.hpp:160
Real cell_dimension_1
Definition data.hpp:129
std::string ibz_reduction_method
Definition data.hpp:193
int kpoint_grid_shift_3
Definition data.hpp:160
int bravais_lattice_index
Definition data.hpp:128
Real cell_dimension_2
Definition data.hpp:137
Real cell_dimension_5
Definition data.hpp:140
Real cell_dimension_3
Definition data.hpp:138
Matrix3x3 lattice_vectors
Definition data.hpp:147
int number_of_spin_components
Definition data.hpp:42
Vector3D coordinates