OO-DOCI calculations#
DOCI is, in essence, just another type of CI, so doing DOCI calculations is very analogous to doing FCI calculations. In the OO-DOCI case, we enhance the regular DOCI method with the use of an orbital optimizer.
# Force the local gqcpy to be imported
import sys
sys.path.insert(0, '../../build/gqcpy/')
import gqcpy
import numpy as np
Preparing the Hamiltonian in the canonical RHF basis#
As always, we’ll first set up the Hamiltonian in an orthonormal spinor basis. For this example, we’ll use the canonical RHF basis
molecule = gqcpy.Molecule.ReadXYZ("../../gqcp/tests/data/h2_cristina.xyz" , 0) # Create a neutral molecule
N = molecule.numberOfElectrons()
N_P = N // 2 # number of electron pairs
spinor_basis = gqcpy.RSpinOrbitalBasis_d(molecule, "STO-3G")
K = spinor_basis.numberOfSpatialOrbitals()
S = spinor_basis.quantize(gqcpy.OverlapOperator())
nuc_rep = gqcpy.NuclearRepulsionOperator(molecule.nuclearFramework()).value()
sq_hamiltonian = spinor_basis.quantize(gqcpy.FQMolecularHamiltonian(molecule))
environment = gqcpy.RHFSCFEnvironment_d.WithCoreGuess(N, sq_hamiltonian, S)
solver = gqcpy.RHFSCFSolver_d.Plain()
objective = gqcpy.DiagonalRHFFockMatrixObjective_d(sq_hamiltonian) # use the default threshold of 1.0e-08
rhf_parameters = gqcpy.RHF_d.optimize(objective, solver, environment).groundStateParameters()
C = rhf_parameters.expansion()
spinor_basis.transform(C)
sq_hamiltonian.transform(C)
Dense OO-DOCI calculations#
For FCI, we would create the full spin-resolved ONV basis. For DOCI, we need the full seniority-zero ONV basis.
onv_basis = gqcpy.SeniorityZeroONVBasis(K, N_P) # number of spatial orbitals, number of electron pairs
The subsequent steps are very analogous. We create a solver and associated environment, and use the CI QCMethod to find the optimal parameters and energies.
solver = gqcpy.EigenproblemSolver.Dense_d()
environment = gqcpy.CIEnvironment.Dense(sq_hamiltonian, onv_basis)
We now have to declare our orbital optimizer.
optimizer = gqcpy.DOCINewtonOrbitalOptimizer(onv_basis, solver, environment)
The orbital optimizer can now do the required optimization given the spinor basis and the second quantized Hamiltonian.
optimizer.optimize(spinor_basis, sq_hamiltonian)
print(optimizer.eigenvalue() + nuc_rep)
-1.137263337693952
optimized_orbitals = optimizer.eigenvector()
energies = optimizer.eigenvalues()
print(optimized_orbitals)
[-0.99360078 0.11294904]