Closed lelemmen closed 3 years ago
BaseSpinResolvedFrozenCoreCIDMCalculator.hpp
// This file is part of GQCG-GQCP.
//
// Copyright (C) 2017-2020 the GQCG developers
//
// GQCG-GQCP is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GQCG-GQCP is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GQCG-GQCP. If not, see <http://www.gnu.org/licenses/>.
#include "DensityMatrix/CIDMCalculators/BaseSpinResolvedFrozenDMCalculator.hpp"
#include "Utilities/linalg.hpp"
namespace GQCP {
/*
* CONSTRUCTORS
*/
/**
* @param dm_calculator shared pointer to active (non-frozen core) DM builder
* @param X the number of frozen orbitals
*/
BaseSpinResolvedFrozenDMCalculator::BaseSpinResolvedFrozenDMCalculator(const std::shared_ptr<BaseSpinResolvedDMCalculator> dm_calculator, const size_t X) :
BaseSpinResolvedDMCalculator(),
active_dm_calculator {std::move(dm_calculator)},
X {X} {}
/*
* PUBLIC OVERRIDDEN METHODS
*/
/**
* @param x the coefficient vector representing the wave function
*
* @return all 1-DMs given a coefficient vector
*/
SpinResolved1DM<double> BaseSpinResolvedFrozenDMCalculator::calculateSpinResolved1DM(const VectorX<double>& x) const {
auto K = this->onvBasis()->numberOfOrbitals();
SpinResolved1DMComponent<double> D_aa = SpinResolved1DMComponent<double>::Zero(K);
SpinResolved1DMComponent<double> D_bb = SpinResolved1DMComponent<double>::Zero(K);
auto K_active = K - this->X;
// Set the values for the frozen orbital
for (size_t i = 0; i < this->X; i++) {
D_aa(i, i) = 1;
D_bb(i, i) = 1;
}
SpinResolved1DM<double> sub_1DMs = this->active_dm_calculator->calculateSpinResolved1DM(x);
// Incorporate the submatrices from the active space
D_aa.block(this->X, this->X, K_active, K_active) += sub_1DMs.alpha();
D_bb.block(this->X, this->X, K_active, K_active) += sub_1DMs.beta();
return SpinResolved1DM<double>(D_aa, D_bb);
};
/**
* @param x the coefficient vector representing the wave function
*
* @return all 2-DMs given a coefficient vector
*/
SpinResolved2DM<double> BaseSpinResolvedFrozenDMCalculator::calculateSpinResolved2DM(const VectorX<double>& x) const {
auto K = this->onvBasis()->numberOfOrbitals();
SpinResolved2DMComponent<double> d_aaaa = SpinResolved2DMComponent<double>::Zero(K);
SpinResolved2DMComponent<double> d_aabb = SpinResolved2DMComponent<double>::Zero(K);
SpinResolved2DMComponent<double> d_bbaa = SpinResolved2DMComponent<double>::Zero(K);
SpinResolved2DMComponent<double> d_bbbb = SpinResolved2DMComponent<double>::Zero(K);
SpinResolved1DM<double> one_DMs = this->active_dm_calculator->calculateSpinResolved1DM(x);
auto D_aa = one_DMs.alpha();
auto D_bb = one_DMs.beta();
// Implement frozen DM formulas
for (size_t p = 0; p < this->X; p++) { // iterate over frozen orbitals
// DM Overlap between frozen and active space:
// frozen orbital indices (p) must always have one annihilation and one creation index (always occupied)
// values are dictated by the 'active' orbital indices and correspond to that of the active 1DMs
// Hence we start adding the 1DMs starting from index 'X' the number frozen orbitals
d_aaaa.addBlock<0, 1>(D_aa, this->X, this->X, p, p);
d_aaaa.addBlock<2, 3>(D_aa, p, p, this->X, this->X);
d_aaaa.addBlock<2, 1>(-D_aa, p, this->X, this->X, p);
d_aaaa.addBlock<3, 0>(-D_aa, this->X, p, p, this->X);
d_bbbb.addBlock<0, 1>(D_bb, this->X, this->X, p, p);
d_bbbb.addBlock<2, 3>(D_bb, p, p, this->X, this->X);
d_bbbb.addBlock<2, 1>(-D_bb, p, this->X, this->X, p);
d_bbbb.addBlock<3, 0>(-D_bb, this->X, p, p, this->X);
d_aabb.addBlock<2, 3>(D_bb, p, p, this->X, this->X);
d_aabb.addBlock<0, 1>(D_aa, this->X, this->X, p, p);
d_bbaa.addBlock<2, 3>(D_aa, p, p, this->X, this->X);
d_bbaa.addBlock<0, 1>(D_bb, this->X, this->X, p, p);
// Set the values for the frozen orbital
d_bbaa(p, p, p, p) = 1;
d_aabb(p, p, p, p) = 1;
for (size_t q = p + 1; q < this->X; q++) { // iterate over frozen orbitals
d_aaaa(p, p, q, q) = 1;
d_aaaa(q, q, p, p) = 1;
d_aaaa(p, q, q, p) = -1;
d_aaaa(q, p, p, q) = -1;
d_bbbb(p, p, q, q) = 1;
d_bbbb(q, q, p, p) = 1;
d_bbbb(p, q, q, p) = -1;
d_bbbb(q, p, p, q) = -1;
d_aabb(p, p, q, q) = 1;
d_bbaa(p, p, q, q) = 1;
d_aabb(q, q, p, p) = 1;
d_bbaa(q, q, p, p) = 1;
}
}
// Incorporate the 2-DM subblocks into the total 2DMs
SpinResolved2DM<double> sub_2DMs = this->active_dm_calculator->calculateSpinResolved2DM(x);
d_aaaa.addBlock(sub_2DMs.alphaAlpha(), this->X, this->X, this->X, this->X);
d_bbbb.addBlock(sub_2DMs.betaBeta(), this->X, this->X, this->X, this->X);
d_aabb.addBlock(sub_2DMs.alphaBeta(), this->X, this->X, this->X, this->X);
d_bbaa.addBlock(sub_2DMs.betaAlpha(), this->X, this->X, this->X, this->X);
return SpinResolved2DM<double>(d_aaaa, d_aabb, d_bbaa, d_bbbb);
};
} // namespace GQCP
SpinResolvedFrozenDMCalculator.cpp
// This file is part of GQCG-GQCP.
//
// Copyright (C) 2017-2020 the GQCG developers
//
// GQCG-GQCP is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GQCG-GQCP is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GQCG-GQCP. If not, see <http://www.gnu.org/licenses/>.
#include "DensityMatrix/CIDMCalculators/SpinResolvedFrozenDMCalculator.hpp"
#include "DensityMatrix/CIDMCalculators/SpinResolvedDMCalculator.hpp"
namespace GQCP {
/*
* CONSTRUCTORS
*/
/**
* @param onv_basis the frozen spin-resolved ONV basis
*/
SpinResolvedFrozenDMCalculator::SpinResolvedFrozenDMCalculator(const SpinResolvedFrozenONVBasis& onv_basis) :
BaseSpinResolvedFrozenDMCalculator(std::make_shared<SpinResolvedDMCalculator>(onv_basis.activeONVBasis()), onv_basis.numberOfFrozenOrbitals()),
onv_basis {onv_basis} {}
} // namespace GQCP
// // This file is part of GQCG-GQCP.
// //
// // Copyright (C) 2017-2020 the GQCG developers
// //
// // GQCG-GQCP is free software: you can redistribute it and/or modify
// // it under the terms of the GNU Lesser General Public License as published by
// // the Free Software Foundation, either version 3 of the License, or
// // (at your option) any later version.
// //
// // GQCG-GQCP is distributed in the hope that it will be useful,
// // but WITHOUT ANY WARRANTY; without even the implied warranty of
// // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// // GNU Lesser General Public License for more details.
// //
// // You should have received a copy of the GNU Lesser General Public License
// // along with GQCG-GQCP. If not, see <http://www.gnu.org/licenses/>.
// #define BOOST_TEST_MODULE "SpinResolvedFrozenDMCalculator_test"
// #include <boost/test/unit_test.hpp>
// #include "DensityMatrix/CIDMCalculators/SpinResolvedFrozenDMCalculator.hpp"
// #include "DensityMatrix/CIDMCalculators/SpinResolvedSelectedDMCalculator.hpp"
// #include "Mathematical/Optimization/Eigenproblem/EigenproblemSolver.hpp"
// #include "Operator/SecondQuantized/SQHamiltonian.hpp"
// #include "QCMethod/CI/CI.hpp"
// #include "QCMethod/CI/CIEnvironment.hpp"
// /**
// * Check if the 1- and 2-DMs for a frozen core spin-resolved ONV basis are equal to the 'selected' case.
// * The system of interest is a linear chain of 5 H atoms, 1.1 bohr apart, using an STO-3G basisset.
// */
// BOOST_AUTO_TEST_CASE(FrozenCoreFCI_one_DMs) {
// // Set up the molecular Hamiltonian for H5//STO-3G in the Löwdin basis.
// const GQCP::Molecule molecule = GQCP::Molecule::HChain(5, 1.1);
// const auto N_alpha = 3;
// const auto N_beta = 2;
// GQCP::RSpinOrbitalBasis<double, GQCP::GTOShell> spinor_basis {molecule, "STO-3G"};
// const auto K = spinor_basis.numberOfSpatialOrbitals();
// spinor_basis.lowdinOrthonormalize();
// const auto sq_hamiltonian = GQCP::RSQHamiltonian<double>::Molecular(spinor_basis, molecule);
// // Do a dense frozen core CI calculation for 2 frozen orbitals.
// const GQCP::SpinResolvedFrozenONVBasis onv_basis {K, N_alpha, N_beta, 2};
// auto environment = GQCP::CIEnvironment::Dense(sq_hamiltonian, onv_basis);
// auto solver = GQCP::EigenproblemSolver::Dense();
// const auto linear_expansion = GQCP::QCMethod::CI<GQCP::SpinResolvedFrozenONVBasis>(onv_basis).optimize(solver, environment).groundStateParameters();
// // Calculate the 1-DMs using specialized spin-resolved and 'selected' routines, and check if they are equal.
// const GQCP::SpinResolvedFrozenDMCalculator spin_resolved_dm_calculator {onv_basis};
// const auto one_DMs_specialized = spin_resolved_dm_calculator.calculateSpinResolved1DM(linear_expansion.coefficients());
// const GQCP::SpinResolvedSelectedONVBasis selected_onv_basis {onv_basis};
// const GQCP::SpinResolvedSelectedDMCalculator selected_dm_calculator {selected_onv_basis};
// const auto one_DMs_selected = selected_dm_calculator.calculateSpinResolved1DM(linear_expansion.coefficients());
// BOOST_CHECK(one_DMs_specialized.orbitalDensity().isApprox(one_DMs_selected.orbitalDensity(), 1.0e-12));
// BOOST_CHECK(one_DMs_specialized.alpha().isApprox(one_DMs_selected.alpha(), 1.0e-12));
// BOOST_CHECK(one_DMs_specialized.beta().isApprox(one_DMs_selected.beta(), 1.0e-12));
// // Calculate the 2-DMs using specialized spin-resolved and 'selected' routines, and check if they are equal.
// const auto two_DMs_specialized = spin_resolved_dm_calculator.calculateSpinResolved2DM(linear_expansion.coefficients());
// const auto two_DMs_selected = selected_dm_calculator.calculateSpinResolved2DM(linear_expansion.coefficients());
// BOOST_CHECK(two_DMs_specialized.alphaAlpha().isApprox(two_DMs_selected.alphaAlpha(), 1.0e-12));
// BOOST_CHECK(two_DMs_specialized.alphaBeta().isApprox(two_DMs_selected.alphaBeta(), 1.0e-12));
// BOOST_CHECK(two_DMs_specialized.betaAlpha().isApprox(two_DMs_selected.betaAlpha(), 1.0e-12));
// BOOST_CHECK(two_DMs_specialized.betaBeta().isApprox(two_DMs_selected.betaBeta(), 1.0e-12));
// BOOST_CHECK(two_DMs_specialized.orbitalDensity().isApprox(two_DMs_selected.orbitalDensity(), 1.0e-12));
// }
Describe a change that would improve the code base We should make sure that this implementation is as clear as possible.