ampsci
High-precision calculations for one- and two-valence atomic systems
GenerateOperator.hpp
1#pragma once
2#include "DiracOperator/TensorOperator.hpp"
3#include "IO/InputBlock.hpp"
4#include "Wavefunction/Wavefunction.hpp"
5#include <memory>
6#include <string>
7#include <string_view>
8#include <vector>
9
10namespace DiracOperator {
11
12/*!
13 @brief Operators are self-registering: each operator class exposes a static
14 generate() factory and registers it via a file-scope Register<T> object.
15
16 ## Adding a new operator
17
18 **Internal operators** (need concrete type access from outside): add a
19 `static generate()` to the class in its `.hpp`, and add a `Register<T>`
20 entry in `RegisterOperators.cpp`.
21
22 **External operators** (never constructed directly from outside): put the
23 class definition, `static generate()`, and `Register<T>` all in a single
24 `.cpp` file. Drop it in the build and it self-registers at startup.
25
26 The minimal static factory signature:
27
28 \code{.cpp}
29 static std::unique_ptr<TensorOperator>
30 generate(const IO::InputBlock &input, const Wavefunction &wf);
31 \endcode
32
33 From the command line:
34 ```shell
35 ampsci -o # list all operators
36 ampsci -o OperatorName # show options for OperatorName
37 ```
38*/
39
40//! Function-pointer signature shared by every operator factory.
41using FactoryFn = std::unique_ptr<TensorOperator> (*)(const IO::InputBlock &,
42 const Wavefunction &);
43
44/*!
45 @brief One entry in the operator registry.
46*/
48 std::string name;
49 std::string description;
50 FactoryFn factory;
51};
52
53/*!
54 @brief Singleton registry of all compiled-in operators.
55 @details
56 Populated at program startup via static initialisers (one per operator) and
57 never modified once main() begins. Uses construct-on-first-use to avoid the
58 static-initialisation order fiasco.
59*/
60class Registry {
61public:
62 //! Access the singleton instance.
63 static Registry &get() {
64 static Registry instance;
65 return instance;
66 }
67
68 //! Append a new entry. Normally called only by Register<T>.
69 void add(std::string name, std::string description, FactoryFn fn) {
70 m_entries.push_back({std::move(name), std::move(description), fn});
71 }
72
73 //! All registered operators, in registration order.
74 const std::vector<OperatorEntry> &entries() const { return m_entries; }
75
76private:
77 Registry() : m_entries{} {}
78 std::vector<OperatorEntry> m_entries;
79};
80
81/*!
82 @brief Constructing a Register<T> adds T::generate to the Registry.
83 @details
84 Place one of these at file scope (inside an anonymous namespace) in a .cpp
85 file to register an operator. T must have a static generate() with the
86 FactoryFn signature; the template instantiation enforces this at compile time.
87
88 \code{.cpp}
89 namespace {
90 const DiracOperator::Register<MyOp> r{"MyOp", "One-line description"};
91 }
92 \endcode
93*/
94template <typename T>
95struct Register {
96 Register(const char *name, const char *description) {
97 Registry::get().add(name, description, &T::generate);
98 }
99};
100
101/*!
102 @brief Constructs and returns a TensorOperator by name.
103 @details
104 Looks up @p operator_name in the Registry (case-insensitive) and calls its
105 factory with @p input and @p wf. Returns a NullOperator and prints a warning
106 if the name is not found.
107
108 This is the main runtime entry point for operator construction -- used by
109 modules such as \ref Module::MatrixElements and by `ampsci -o`.
110
111 @param operator_name Name of the operator as registered (case-insensitive).
112 @param input Input block containing run-time options for the operator.
113 May be empty if the operator takes no options.
114 @param wf Solved wavefunction; provides the grid, nuclear model,
115 and orbitals needed by the factory.
116 @return Owning pointer to the constructed operator, or a
117 NullOperator if @p operator_name is not found.
118*/
119std::unique_ptr<DiracOperator::TensorOperator>
120generate(std::string_view operator_name, const IO::InputBlock &input,
121 const Wavefunction &wf);
122
123//! Print the list of compiled-in operators (name + description).
124void list_operators();
125
126} // namespace DiracOperator
Singleton registry of all compiled-in operators.
Definition GenerateOperator.hpp:60
void add(std::string name, std::string description, FactoryFn fn)
Append a new entry. Normally called only by Register<T>.
Definition GenerateOperator.hpp:69
const std::vector< OperatorEntry > & entries() const
All registered operators, in registration order.
Definition GenerateOperator.hpp:74
static Registry & get()
Access the singleton instance.
Definition GenerateOperator.hpp:63
Holds a named list of key=value options and nested InputBlocks.
Definition InputBlock.hpp:154
Stores Wavefunction (set of valence orbitals, grid, HF etc.)
Definition Wavefunction.hpp:37
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition GenerateOperator.cpp:6
std::unique_ptr< DiracOperator::TensorOperator > generate(std::string_view operator_name, const IO::InputBlock &input, const Wavefunction &wf)
Constructs and returns a TensorOperator by name.
Definition GenerateOperator.cpp:10
void list_operators()
Print the list of compiled-in operators (name + description).
Definition GenerateOperator.cpp:39
std::unique_ptr< TensorOperator >(*)(const IO::InputBlock &, const Wavefunction &) FactoryFn
Operators are self-registering: each operator class exposes a static generate() factory and registers...
Definition GenerateOperator.hpp:42
One entry in the operator registry.
Definition GenerateOperator.hpp:47
Constructing a Register<T> adds T::generate to the Registry.
Definition GenerateOperator.hpp:95