Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] DLPNO-CCSD PR #2915

Draft
wants to merge 71 commits into
base: master
Choose a base branch
from
Draft

[Draft] DLPNO-CCSD PR #2915

wants to merge 71 commits into from

Conversation

andyj10224
Copy link
Contributor

@andyj10224 andyj10224 commented Mar 30, 2023

Description

HERE IT IS!!! This is a draft of the DLPNO-CCSD PR that will be coming in the next few months. The purpose of this is for the developers and research groups to be able to run and test DLPNO-CCSD before it is officially part of the code.

Credit to @JoseMadriaga for the derivations
LocalCCSD1to10.pdf

Useful References:
Original DLPNO-CCSD Paper
Sparse Maps II Paper

Example Input File

memory 20 GB

molecule mol {
  0 1
  O    0.705    0.744    0.16
  H    -0.071    0.264    0.45
  H    1.356    0.064    -0.014
  symmetry c1
}

set {
  basis cc-pVDZ
  scf_type df
  freeze_core true
  pno_convergence normal
}
energy('dlpno-ccsd')

Results (Waterclusters in TZ)

[Speedups, relative to DF-CCSD]
wc_tz_speedups

[Percent Correlation Energy Recovered, relative to DF-CCSD, all >= 99.9%]
wc_tz_percent_corr_recovered

User API & Changelog headlines

  • Implement the DLPNO-CCSD algorithm

Dev notes & details

  • Feel free to use this code, it is not fully tested yet, but preliminary tests show encouraging results, and is MUCH faster than conventional CCSD
  • If you benchmark my code, please post results in the thread

Questions

  • Question1

Checklist

Status

  • Ready for review
  • Ready for merge

andyj10224 and others added 2 commits April 1, 2023 18:45
Co-authored-by: TiborGY <tibor.gyori@chem.u-szeged.hu>
Co-authored-by: Lori A. Burns <lori.burns@gmail.com>
@andyj10224
Copy link
Contributor Author

Just implemented some of Lori and Tibor's suggestions. I have also implemented SC-LMP2 for "weak pairs" to reduce the cost of the LCCSD computation, per the Sparse Maps II paper.

Copy link
Contributor

@TiborGY TiborGY left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2, mostly more of the same: const correctness, a few unused variables, a docstring suggestion, and a possible suggestion to eliminate a bit of code duplication,

Comment on lines +97 to +102
/* Utility function for making C_DGESV calls
*
* C_DGESV solves AX=B for X, given symmetric NxN matrix A and NxM matrix B
* B is expected in fortran layout, which complicates the call when (M > 1)
* The workaround used here is to switch the layout of B before and after the call
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* Utility function for making C_DGESV calls
*
* C_DGESV solves AX=B for X, given symmetric NxN matrix A and NxM matrix B
* B is expected in fortran layout, which complicates the call when (M > 1)
* The workaround used here is to switch the layout of B before and after the call
*/

Moving this to the .h should make it more digestible for IDEs and doc generators.


void common_init();

// Helper functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Helper functions
// Helper functions
/// @brief Utility function for making C_DGESV calls. C_DGESV solves AX=B for X, given symmetric NxN matrix A and NxM
/// matrix B, but B is expected in fortran layout, which complicates the call when (M > 1).
/// The workaround used here is to switch the layout of B before and after the call.
///
/// @param A On entry, the n-by-n coefficient matrix A. On exit, the factors L and U from the factorization A = P*L*U;
/// the unit diagonal elements of L are not stored.
/// @param B On entry, the n-by-m matrix of right hand side matrix B. On exit, the n-by-m solution matrix X.
/// \ingroup DLPNO

Moved here from the .cc, rewritten for machine-readability.

0);
auto X = orthog.basis_to_orthog_basis();

int nmo_initial = X->rowspi(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int nmo_initial = X->rowspi(0);

Unused variable

}

auto flat = std::make_shared<Vector>("flattened matrix list", total_size);
double* flatp = flat->pointer();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
double* flatp = flat->pointer();
double* const flatp = flat->pointer();

The pointer itself can be const

Comment on lines +197 to +198
void DLPNOBase::copy_flat_mats(SharedVector flat, std::vector<SharedMatrix>& mat_list) {
double* flatp = flat->pointer();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void DLPNOBase::copy_flat_mats(SharedVector flat, std::vector<SharedMatrix>& mat_list) {
double* flatp = flat->pointer();
void DLPNOBase::copy_flat_mats(const SharedVector flat, std::vector<SharedMatrix>& mat_list) {
const double* const flatp = flat->pointer();

Comment on lines +512 to +513
int centerU = basisset_->function_to_center(u);
double p_uu = P_i->get(u, u);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int centerU = basisset_->function_to_center(u);
double p_uu = P_i->get(u, u);
const int centerU = basisset_->function_to_center(u);
const double p_uu = P_i->get(u, u);

Comment on lines +516 to +517
int centerV = basisset_->function_to_center(v);
double p_vv = P_i->get(v, v);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int centerV = basisset_->function_to_center(v);
double p_vv = P_i->get(v, v);
const int centerV = basisset_->function_to_center(v);
const double p_vv = P_i->get(v, v);

double p_vv = P_i->get(v, v);

// off-diag pops (p_uv) split between u and v prop to diag pops
double p_uv = P_i->get(u, v);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
double p_uv = P_i->get(u, v);
const double p_uv = P_i->get(u, v);

Comment on lines 567 to 603
if (options_.get_str("DLPNO_ALGORITHM") == "MP2") {
for (size_t i = 0, ij = 0; i < naocc; i++) {
for (size_t j = 0; j < naocc; j++) {
bool overlap_big = (DOI_ij_->get(i, j) > options_.get_double("T_CUT_DO_ij"));
bool energy_big = (fabs(dipole_pair_e_bound_->get(i, j)) > options_.get_double("T_CUT_PRE"));

if (overlap_big || energy_big) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
de_dipole_ += dipole_pair_e_->get(i, j);
i_j_to_ij_[i].push_back(-1);
}
}
}
} else {
for (size_t i = 0, ij = 0; i < naocc; i++) {
for (size_t j = 0; j < naocc; j++) {
bool overlap_big = (DOI_ij_->get(i, j) > options_.get_double("T_CUT_DO_ij"));
bool energy_big = (fabs(dipole_pair_e_bound_->get(i, j)) > options_.get_double("T_CUT_PRE"));

if ((i == j) || (overlap_big && energy_big)) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
if (overlap_big || energy_big)
weak_pairs_.push_back(std::make_pair(i,j));
else
de_dipole_ += dipole_pair_e_->get(i, j);

i_j_to_ij_[i].push_back(-1);
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (options_.get_str("DLPNO_ALGORITHM") == "MP2") {
for (size_t i = 0, ij = 0; i < naocc; i++) {
for (size_t j = 0; j < naocc; j++) {
bool overlap_big = (DOI_ij_->get(i, j) > options_.get_double("T_CUT_DO_ij"));
bool energy_big = (fabs(dipole_pair_e_bound_->get(i, j)) > options_.get_double("T_CUT_PRE"));
if (overlap_big || energy_big) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
de_dipole_ += dipole_pair_e_->get(i, j);
i_j_to_ij_[i].push_back(-1);
}
}
}
} else {
for (size_t i = 0, ij = 0; i < naocc; i++) {
for (size_t j = 0; j < naocc; j++) {
bool overlap_big = (DOI_ij_->get(i, j) > options_.get_double("T_CUT_DO_ij"));
bool energy_big = (fabs(dipole_pair_e_bound_->get(i, j)) > options_.get_double("T_CUT_PRE"));
if ((i == j) || (overlap_big && energy_big)) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
if (overlap_big || energy_big)
weak_pairs_.push_back(std::make_pair(i,j));
else
de_dipole_ += dipole_pair_e_->get(i, j);
i_j_to_ij_[i].push_back(-1);
}
}
}
}
const bool DLPNO_MP2 = (options_.get_str("DLPNO_ALGORITHM") == "MP2");
for (size_t i = 0, ij = 0; i < naocc; i++) {
for (size_t j = 0; j < naocc; j++) {
const bool overlap_big = (DOI_ij_->get(i, j) > options_.get_double("T_CUT_DO_ij"));
const bool energy_big = (fabs(dipole_pair_e_bound_->get(i, j)) > options_.get_double("T_CUT_PRE"));
if(DLPNO_MP2){
if (overlap_big || energy_big) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
de_dipole_ += dipole_pair_e_->get(i, j);
i_j_to_ij_[i].push_back(-1);
}
}else{
if ((i == j) || (overlap_big && energy_big)) {
i_j_to_ij_[i].push_back(ij);
ij_to_i_j_.push_back(std::make_pair(i, j));
ij++;
} else {
if (overlap_big || energy_big)
weak_pairs_.push_back(std::make_pair(i, j));
else
de_dipole_ += dipole_pair_e_->get(i, j);
i_j_to_ij_[i].push_back(-1);
}
}
}
}

This would eliminate some code duplication. Thoughts?

}
}

int n_lmo_pairs = ij_to_i_j_.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int n_lmo_pairs = ij_to_i_j_.size();
const int n_lmo_pairs = ij_to_i_j_.size();

@davpoolechem
Copy link
Contributor

One thing we will need to discuss up-front, is what to do with a DLPNO-CC Psi4NumPy implementation. I know @JonathonMisiewicz talked about this in a previous PR, and I see his point. It would be useful to have an easier-to-understand reference for DLPNO-CC somewhere, especially to help others understand the DLPNO formalism.

A lot of the work done in this PR was previously prototyped in Python, so that gives us a start in a potential Psi4NumPy implementation.

@loriab loriab added this to the Psi4 1.9 milestone Apr 18, 2023
@loriab loriab added feature Extends an existing Psi feature or develops a new one. cc For all issues involving the CC module, ground-state energies to response properties. labels Apr 18, 2023
@loriab loriab modified the milestones: Psi4 1.9, Psi4 1.10 Nov 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cc For all issues involving the CC module, ground-state energies to response properties. feature Extends an existing Psi feature or develops a new one.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants