Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * QuantumSystemProvenanceRecord — what a results file says about how it was
5 * produced, for the quantum system that was solved.
6 *
7 * A total energy without its provenance is a number, not a measurement: it
8 * cannot be reproduced, compared against another engine, or registered, because
9 * nothing in it says which code, which physical model, or which numerics
10 * produced it. This record is what makes a results file self-describing.
11 *
12 * What is here is what every quantum system has, whatever it is represented in:
13 * who computed it (generator), which Hamiltonian was solved (model), the
14 * numerics that solved it (method), and the convergence that was asked for
15 * (precision). What the run *achieved* is not here -- convergence and results
16 * are the rest of the results file.
17 *
18 * How the system was *represented* -- plane waves and pseudopotentials, or
19 * whatever else a future representation brings -- is deliberately not known at
20 * this level: a basis-set cutoff or a pseudopotential dataset is a fact about a
21 * representation, not about a quantum system, and a record that names one here
22 * would have to name every other one here too. A representation reports itself
23 * by deriving and overriding add_representation_method_details():
24 *
25 * QuantumSystemProvenanceRecord generator, model, k-points, precision
26 * -> PlanewaveProvenanceRecord + the basis-set cutoffs
27 * -> PseudopotentialProvenanceRecord + the per-species datasets
28 *
29 * (provenance/init.hpp, provenance/planewave/init.hpp,
30 * provenance/planewave/pseudopotential.hpp respectively; provenance/factory.hpp
31 * picks the one a given run needs.) Adding a representation therefore means
32 * adding a subclass beside those, not another branch here.
33 *
34 * Field names follow the provenance schema of the registry that consumes these
35 * files, so its reader maps rather than guesses. Two deliberate divergences,
36 * both about units: that schema states energies in electronvolt, while Q3 works
37 * and quotes in Rydberg. Rather than convert here -- which would report a
38 * threshold the user never typed -- the fields that would differ carry an
39 * explicit `_rydberg` suffix where the consumer's carry `_electronvolt`. A
40 * reader cannot then take a Rydberg number for an electronvolt one, which a
41 * shared name would have invited.
42 *
43 * The record is built once per run, after the calculation, from the same
44 * InputData the calculation consumed -- which it borrows rather than copies, so
45 * a record must not outlive the input it reports on.
46 */
47
48#include <string>
49
50#include <nlohmann/json.hpp>
51
52#include "io/input/data.hpp"
55
56namespace q3 {
57
58/// Map the number of spin components to the consumer schema's spin treatment.
59[[nodiscard]] inline std::string spin_treatment_name(int number_of_spin_components) {
60 if (number_of_spin_components == 4) {
61 return "non_collinear";
62 }
63 if (number_of_spin_components == 2) {
64 return "collinear";
65 }
66 return "unpolarized";
67}
68
70 public:
71 explicit QuantumSystemProvenanceRecord(const InputData& input) : input_(input) {}
72 virtual ~QuantumSystemProvenanceRecord() = default;
73
74 /// The provenance block, grouped the way the consumer's record is.
75 [[nodiscard]] nlohmann::json to_json() const {
76 nlohmann::json provenance;
77 provenance["generator"] = generator_json();
78 provenance["model"] = model_json();
79 provenance["method"] = method_json();
80 provenance["precision"] = precision_json();
81 if (input_.is_relaxation_step) {
82 provenance["relaxation"] = {
83 {"force_threshold_ry_per_bohr", input_.relax_force_threshold},
84 {"energy_threshold_ry", input_.relax_energy_threshold},
85 {"maximum_steps", input_.relax_maximum_steps}};
86 }
87 return provenance;
88 }
89
90 protected:
91 /// The input the calculation consumed, for a subclass to report on in turn.
92 [[nodiscard]] const InputData& input() const {
93 return input_;
94 }
95
96 /**
97 * Hook: add what the concrete representation contributes to "method".
98 *
99 * The base record describes a quantum system that has been solved; it
100 * cannot say what a basis set or a dataset was, because at this level there
101 * is none. A subclass that knows one adds it here.
102 */
103 virtual void add_representation_method_details(nlohmann::json& /*method*/) const {}
104
105 private:
106 [[nodiscard]] nlohmann::json generator_json() const {
107 nlohmann::json generator;
108 generator["engine_name"] = "q3";
109 generator["engine_version"] = version;
110 generator["engine_commit"] = commit;
111 generator["linear_algebra_libraries"] = linear_algebra_libraries;
112 /**
113 * The build-time add-ons compiled in, since a result can depend on one;
114 * an empty list for a core-only build, so absence is stated rather
115 * than inferred from a missing key.
116 */
117 nlohmann::json addons = nlohmann::json::array();
118 for (const AddonIdentity& addon : active_addons())
119 addons.push_back({{"name", addon.name}, {"version", addon.version}});
120 generator["addons"] = addons;
121 return generator;
122 }
123
124 [[nodiscard]] nlohmann::json model_json() const {
125 nlohmann::json model;
126 model["exchange_correlation_functional"] = input_.exchange_correlation_functional;
127 model["spin_treatment"] = spin_treatment_name(input_.number_of_spin_components);
128 if (input_.dispersion_correction != "none") {
129 model["dispersion_correction"] = input_.dispersion_correction;
130 }
131 if (!input_.hubbard.empty()) {
132 nlohmann::json hubbard_by_species = nlohmann::json::object();
133 for (const HubbardSpecification& specification : input_.hubbard) {
134 hubbard_by_species[specification.species_symbol + "-" +
135 specification.orbital_label] = specification.u_rydberg;
136 }
137 model["hubbard_u_rydberg_by_species"] = hubbard_by_species;
138 }
139 return model;
140 }
141
142 [[nodiscard]] nlohmann::json method_json() const {
143 nlohmann::json method;
144 method["kpoint_grid"] = {input_.kpoint_grid_dimension_1,
147 method["kpoint_shift"] = {
149 const bool uses_smearing = (input_.smearing != "none");
150 method["electronic_occupation"] = uses_smearing ? "smearing" : "fixed";
151 if (uses_smearing) {
152 method["smearing_kind"] = input_.smearing;
153 method["smearing_width_rydberg"] = input_.smearing_width;
154 }
156 return method;
157 }
158
159 [[nodiscard]] nlohmann::json precision_json() const {
160 nlohmann::json precision;
161 precision["energy_convergence_threshold_rydberg"] = input_.convergence_threshold;
162 precision["maximum_self_consistent_field_iterations"] = input_.maximum_iterations;
163 return precision;
164 }
165
166 const InputData& input_;
167};
168
169} // namespace q3
nlohmann::json to_json() const
The provenance block, grouped the way the consumer's record is.
Definition init.hpp:75
virtual ~QuantumSystemProvenanceRecord()=default
QuantumSystemProvenanceRecord(const InputData &input)
Definition init.hpp:71
virtual void add_representation_method_details(nlohmann::json &) const
Definition init.hpp:103
const InputData & input() const
The input the calculation consumed, for a subclass to report on in turn.
Definition init.hpp:92
const std::vector< AddonIdentity > & active_addons()
The add-ons compiled into this build, in the order the build discovered them.
constexpr const char * commit
Definition version.hpp:31
constexpr const char * version
Definition version.hpp:26
constexpr const char * linear_algebra_libraries
The BLAS/LAPACK libraries this build links, as CMake found them; empty if unknown.
Definition version.hpp:38
std::string spin_treatment_name(int number_of_spin_components)
Map the number of spin components to the consumer schema's spin treatment.
Definition init.hpp:59
One add-on compiled into this build.
Parsed input data — holds raw values read from input files.
Definition data.hpp:27
std::string dispersion_correction
Definition data.hpp:78
std::string smearing
Definition data.hpp:75
int kpoint_grid_dimension_3
Definition data.hpp:159
int kpoint_grid_shift_1
Definition data.hpp:160
Real relax_energy_threshold
Definition data.hpp:273
bool is_relaxation_step
Definition data.hpp:268
int maximum_iterations
Definition data.hpp:33
int kpoint_grid_dimension_1
Definition data.hpp:159
std::vector< HubbardSpecification > hubbard
Definition data.hpp:85
int kpoint_grid_dimension_2
Definition data.hpp:159
Real convergence_threshold
Definition data.hpp:32
Real relax_force_threshold
Definition data.hpp:272
int kpoint_grid_shift_2
Definition data.hpp:160
Real smearing_width
Definition data.hpp:76
int kpoint_grid_shift_3
Definition data.hpp:160
std::string exchange_correlation_functional
Definition data.hpp:41
int relax_maximum_steps
Definition data.hpp:271
int number_of_spin_components
Definition data.hpp:42