Loading...
Searching...
No Matches
factory.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * create_flavor — factory for Q3 calculation flavors.
5 *
6 * Dispatches by calculation type string to the appropriate Flavor subclass.
7 * run_flavor() below is the entry point callers should reach for: it is the one
8 * place a completed result is stamped with its provenance.
9 */
10
11#include <memory>
12#include <stdexcept>
13#include <string>
14#include <utility>
15
21
22namespace q3 {
23
24/**
25 * Create a Flavor from a calculation type string.
26 *
27 * `iterator_factory` is the entry point's execution environment -- the MPI binaries'
28 * execution policy, the GPU binaries' diagonalizer -- and reaches every flavor
29 * that builds an iterator, so a unit of a workflow runs on the same setup
30 * whichever flavor it is. Empty means serial, on the CPU.
31 *
32 * Supported types:
33 * - "self_consistent_field" → SelfConsistentFieldFlavor
34 * - "non_self_consistent_field" → NonSelfConsistentFieldFlavor
35 * - "verification" → VerificationFlavor
36 *
37 * A "relaxation" ("relax", "vc-relax") never reaches this factory: parse_input()
38 * runs it as one self_consistent_field step of the relaxation q3.workflows drives.
39 *
40 * "band_structure" ("bands") and "density_of_states" ("dos") are deliberately
41 * NOT single-flavor calculation types (see main.cpp's
42 * dispatch comment): each is a multi-step workflow that chains
43 * self_consistent_field/non_self_consistent_field runs from the Python layer
44 * (q3.workflows.band_structure/dos). The YAML schema and parser accept
45 * them (io/input/parser/yaml.hpp normalizes the short aliases and validates
46 * the workflow-specific control keys, e.g. band_path), because that Python
47 * layer reads the same input file -- but the engine itself never receives
48 * these strings as calculation_type. A caller that reaches this factory
49 * with one of them is running the file directly instead of through its
50 * workflow function, so the error says exactly that instead of just "unsupported".
51 */
52inline std::unique_ptr<Flavor> create_flavor(const std::string& calculation_type,
53 IteratorFactory iterator_factory = {}) {
54 if (calculation_type == "self_consistent_field") {
55 return std::make_unique<SelfConsistentFieldFlavor>(std::move(iterator_factory));
56 }
57 if (calculation_type == "non_self_consistent_field") {
58 return std::make_unique<NonSelfConsistentFieldFlavor>(std::move(iterator_factory));
59 }
60 if (calculation_type == "verification") {
61 /**
62 * A verification compares the engine against a reference on one
63 * process; an MPI or GPU setup handed in here would be silently
64 * dropped, so it is refused instead.
65 */
66 if (iterator_factory) {
67 throw std::runtime_error(
68 "create_flavor: 'verification' runs on the serial q3 binary only; run this "
69 "input with q3.");
70 }
71 return std::make_unique<VerificationFlavor>();
72 }
73 if (calculation_type == "band_structure") {
74 throw std::runtime_error(
75 "create_flavor: 'band_structure' is a multi-step workflow (SCF, then NSCF along "
76 "the requested k-point path), orchestrated by the Python layer, not a single "
77 "engine flavor -- the q3 binary never runs it directly. Run this file through "
78 "q3.workflows.run_band_structure_workflow(scf_input_path=<this file>) instead, "
79 "or set calculation: self_consistent_field for a single-point SCF run.");
80 }
81 if (calculation_type == "interpolation") {
82 throw std::runtime_error(
83 "create_flavor: 'interpolation' evaluates a model a previous NSCF run saved "
84 "(control.interpolation on calculation: nscf), which is post-processing rather "
85 "than an engine flavor -- the q3 binary never runs it directly. Run this file "
86 "with `q3_utility interpolate <file>` instead.");
87 }
88 if (calculation_type == "density_of_states") {
89 throw std::runtime_error(
90 "create_flavor: 'density_of_states' is a multi-step workflow (SCF, then a dense "
91 "NSCF k-mesh, then Gaussian-broadened binning), orchestrated by the Python layer, "
92 "not a single engine flavor -- the q3 binary never runs it directly. Run this "
93 "file through q3.workflows.run_dos_workflow(scf_input_path=...) instead, or set "
94 "calculation: self_consistent_field for a single-point SCF run.");
95 }
96 throw std::runtime_error("create_flavor: unsupported calculation type '" + calculation_type +
97 "'. Supported: self_consistent_field, non_self_consistent_field, "
98 "verification");
99}
100
101/**
102 * Create the flavor named by the input and run it.
103 *
104 * A convenience for the callers that dispatch by name; the provenance stamp is
105 * not applied here but in Flavor::run(), which every path reaches, including
106 * the MPI and GPU entry points that construct their flavor directly rather than
107 * through this factory.
108 */
109[[nodiscard]] inline generated::Results run_flavor(const InputData& input) {
110 auto flavor = create_flavor(input.calculation);
111 return flavor->run(input);
112}
113
114} // namespace q3
std::unique_ptr< Flavor > create_flavor(const std::string &calculation_type, IteratorFactory iterator_factory={})
Definition factory.hpp:52
std::function< std::unique_ptr< PlanewaveKohnShamSCFIterator >(const InputData &)> IteratorFactory
Definition factory.hpp:59
generated::Results run_flavor(const InputData &input)
Definition factory.hpp:109
Parsed input data — holds raw values read from input files.
Definition data.hpp:27
std::string calculation
Definition data.hpp:116