Architecture of the Quantum Mechanics (QM) Component
The need for the QM component stemmed from the high-level architecture details described Architecture of Chemist.
What is the QM Component?
The chemical system component of Chemist is used to describe the chemistry the user wants to do. To compute the quantities of interest the chemical system must be mapped to quantum mechanical equations. The QM component is charged with describing the resulting equations.
Why do we need the QM component?
The QM component constitutes a DSL for specifying tensors and tensor elements using a bra-ket like syntax. This is the key to being able to specify electronic structure methods using programmatic abstractions that behave like the physics they implement. For example, want to do DFT vs SCF? Add an operator for the exchange-correlation potential. Want to freeze the core electrons in the calculation of the correlation energy? Simply delete the terms involving core excitations. Want to do MP2-F12 vs traditional MP2? Add a term to the wavefunction that is linear in the electron-electron separation. Ultimately, there are a ton of potential methods which stem from combinations of enabling/disabling operators and wavefunction choices. A DSL allows us to express them all, whether or not we have names for the approximation.
QM Considerations
- Dirac notation
The “natural” way to write QM equations is in Dirac notation. The QM component should start in Dirac notation and end in tensor equations
- tensor equations
Modern scientific computing is tensor-based. The resulting tensor equations should specify the tensor operations needed to compute the property of interest and know where to get the input values from.
- operators
To write Dirac notation we require two things: operators and wavefunctions. The operators describe the interactions/property to compute.
- wavefunctions
To write Dirac notation we require two things: operators and wavefunctions. The wavefunctions describe the QM state of the system.
Example Use Cases
The following pseudocode illustrates how pieces of the QM component are used to “calculate” quantities. This is an aspirational code snippet and may not reflect the final DSL.
Hamiltonian<ManyElectron, Nuclei> H = make_molecular_hamiltonian();
RDeterminant Psi = get_determinant();
// actually declares a BraKet instance, E, relying on C++17's CTAD to work
// out the template type parameters.
auto E = BraKet(Psi, H, Psi);
// Again E_elec is a BraKet instance and not the actual energy
auto E_elec = BraKet(Psi, H.electronic(), Psi);
// Use other operators to get other terms
Kinetic<ManyElectron> T_e = get_many_electron_kinetic_energy_operator();
auto E_kinetic = BraKet(Psi, T_e, Psi);
CMOs cmos = get_orbitals(); // Get the orbitals used to build Psi
Kinetic<Electron> t_e = get_one_electron_kinetic_energy_operator();
auto t_matrix = BraKet(cmos, t_e, cmos);
Design of the QM Component
TODO: BraKet class for Dirac notation TODO: SeQuant connection for tensor equations.
Operators
Main article: Architecture of Operator Component.
Wavefunctions
Main article: Architecture of Wavefunction Component.
QM Summary
- Dirac notation
We have…
- tensor equations
We have…
- operators
We have created the operator subcomponent to address this consideration.
- wavefunctions
We have created the wavefunction subcomponent to address this consideration.