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

Green's Functions #13

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e95c43f
Added GF functionalities. TODO: Fix the outputs to console, polish th…
CarlosMejZ Jun 2, 2023
dbea9ae
Filling in the doxygen docu for the GF-relevant routines.
CarlosMejZ Jun 2, 2023
88353d3
Committing license headers
Jun 2, 2023
c4704b2
Merge branch 'master' into feature/gf
Jun 2, 2023
90c234a
Committing clang-format changes
Jun 2, 2023
2f9d5ee
Remove extra omp.h inclusion
Jun 2, 2023
e23c537
Committing clang-format changes
Jun 2, 2023
a5946ab
Merge branch 'master' into feature/gf
Jun 2, 2023
2ffd1e2
Applied review comments from pull request, started reformulating the …
CarlosMejZ Jun 5, 2023
91e506b
Committing clang-format changes
Jun 5, 2023
5175a96
Added Hubbard Hamiltonian generator + UT
Jun 7, 2023
ebb7ef4
Committing clang-format changes
Jun 7, 2023
84b219d
Committing license headers
Jun 7, 2023
65f56b3
Add PBC
Jun 13, 2023
e0ef771
Committing clang-format changes
Jun 13, 2023
9ab4627
Merge branch 'master' into feature/model
Jun 13, 2023
414fdd1
Merge branch 'master' into feature/gf
Jun 13, 2023
302feef
Implemented suggestions for GF routines. Most importantly, vectorized…
CarlosMejZ Jun 15, 2023
a806f13
Committing clang-format changes
Jun 15, 2023
f02e8b0
Cleaned GF routines from omp pragmas, only one remaining to paralleli…
CarlosMejZ Jun 21, 2023
a08ebf0
Committing clang-format changes
Jun 21, 2023
5baea2e
BUG FIXED: Passing wrong vector length to Band Lanczos. Also, include…
CarlosMejZ Sep 11, 2023
74702c2
Committing clang-format changes
Sep 11, 2023
d56989c
Included new HamiltonianGenerator, particularly efficient for impurit…
CarlosMejZ Sep 19, 2023
3241bc4
Merged with feature/model, to get the single-double Hamiltonian Gener…
CarlosMejZ Sep 20, 2023
d4a7e4a
Adding clang format changes from bot.
CarlosMejZ Sep 20, 2023
3d3277d
Committing clang-format changes
Sep 20, 2023
41cc116
Added option to read in vectors of ints and bools from input file, to…
CarlosMejZ Sep 22, 2023
a51b754
Committing clang-format changes
Sep 22, 2023
ff65ee7
Fixed Bug in GF calculation: Call to band diagonalization through Lap…
CarlosMejZ Oct 5, 2023
b797e30
Committing clang-format changes
Oct 5, 2023
f838450
Added functionalities to specify GF frequency grid.
CarlosMejZ Oct 9, 2023
65db897
Committing clang-format changes
Oct 9, 2023
93e48e8
Updating calls to submdspan, since mdspan library changed in which na…
CarlosMejZ Nov 6, 2023
18415d5
Committing clang-format changes
Nov 6, 2023
e38bdbf
Added option to ask for multiple eigenstates in selected_ci_diag. Cal…
CarlosMejZ Oct 28, 2024
fa2442a
Committing clang-format changes
Oct 28, 2024
b2d334e
Added minor modification to make Band Lanczos computation of the GF c…
CarlosMejZ Nov 26, 2024
365a871
Committing clang-format changes
Nov 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 292 additions & 0 deletions include/macis/gf/bandlan.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
/*
* MACIS Copyright (c) 2023, The Regents of the University of California,
* through Lawrence Berkeley National Laboratory (subject to receipt of
* any required approvals from the U.S. Dept. of Energy). All rights reserved.
*
* See LICENSE.txt for details
*/

/**
* @file bandlan.h++
*
* @brief Implements simple Band Lanczos routine.
*
* @author Carlos Mejuto Zaera
* @date 25/04/2022
*/
#pragma once
#include <assert.h>
#include <sys/stat.h>

#include <complex>
#include <fstream>
#include <iomanip>
#include <limits>
#include <lobpcgxx/lobpcg.hpp>
#include <map>
#include <sparsexx/matrix_types/csr_matrix.hpp>
#include <sparsexx/spblas/pspmbv.hpp>
#include <sparsexx/spblas/spmbv.hpp>
#include <utility>

#include "macis/gf/inn_prods.hpp"
#include "macis/solvers/davidson.hpp"

typedef std::numeric_limits<double> dbl;

namespace macis {

/**
* @ brief Wrapper for QR decomposition in LAPACK, basically
* calling dgeqrf and dorgqr to evaluate the R and
* Q matrices, which are returned. Here, the input
* matrix has more rows than columns.
*
* @param[inout] std::vector<std::vector<double> > &Q: On input,
* matrix for which to evaluate the QR decomposition.
* On output, Q-matrix.
* @param[out] std::vector<std::vector<double> > &R: On output, R
* matrix in the QR decomposition.
*
* @returns bool: Error code from LAPACK routines.
*
* @author Carlos Mejuto-Zaera
* @date 25/04/2022
*/
bool QRdecomp(std::vector<std::vector<double> > &Q,
wavefunction91 marked this conversation as resolved.
Show resolved Hide resolved
std::vector<std::vector<double> > &R);

/**
* @ brief Wrapper for QR decomposition in LAPACK, basically
* calling dgeqrf and dorgqr to evaluate the R and
* Q matrices, which are returned. Here, the input
* matrix has more columns than rows.
*
* @param[inout] std::vector<std::vector<double> > &Q: On input,
* matrix for which to evaluate the QR decomposition.
* On output, Q-matrix.
* @param[out] std::vector<std::vector<double> > &R: On output, R
* matrix in the QR decomposition.
*
* @returns bool: Error code from LAPACK routines.
*
* @author Carlos Mejuto-Zaera
* @date 25/04/2022
*/
bool QRdecomp_tr(std::vector<std::vector<double> > &Q,
std::vector<std::vector<double> > &R);

/**
* @brief Wrapper to LAPACK routine to evaluate the eigenvectors
* and eigenvalues of the symmetric matrix mat.
*
* @param[inout] std::vector<std::vector<double> > &mat: Matrix for
* which to compute the eigenvalues/vectors. Erased
* during computation.
* @param[out] std::vector<double> &eigvals: Eigenvalues, sorted from smallest
* to largest.
* @param[out] std::vector<std::vector<double> > &eigvecs: Eigenvectors,
* stored as row vectors.
*
* @returns bool: Error code from LAPACK.
*
* @author Carlos Mejuto Zaera
* @date 25/04/2022
*/
bool GetEigsys(std::vector<std::vector<double> > &mat,
std::vector<double> &eigvals,
std::vector<std::vector<double> > &eigvecs);

/**
* @brief Wrapper to LAPACK routine to evaluate the eigenvectors
* and eigenvalues of the symmetric band matrix mat.
*
* @param[inout] std::vector<std::vector<double> > &mat: Matrix for
* which to compute the eigenvalues/vectors. Erased
* during computation.
* @param[in] int nSupDiag: Nr. of bands.
* @param[out] std::vector<double> &eigvals: Eigenvalues, sorted from smallest
* to largest.
* @param[out] std::vector<std::vector<double> > &eigvecs: Eigenvectors,
* stored as row vectors.
*
* @returns bool: Error code from LAPACK.
*
* @author Carlos Mejuto Zaera
* @date 25/04/2022
*/
bool GetEigsysBand(std::vector<std::vector<double> > &mat, int nSupDiag,
std::vector<double> &eigvals,
std::vector<std::vector<double> > &eigvecs);

/**
* @brief Perform a band Lanczos calculation on the Hamiltonian operator H,
* starting from vectors qs, for at most nLanIts iterations. The resulting
* band-diagonal matrix Hamiltonian will be stored in bandH. Note that this
* implementation does not account for deflations (i.e., pruning the span of the
* qs for linear dependencies in higher powers of H).
*
* @param[in] const sparseexx::csr_matrix<double, int32_t> &H: Hamiltonian
* oprator. Just needs to implement a matrix vector product.
* @param[in] std::vector<std::vector<Cont> > &qs: Initial set of vetors to
* perform the band Lanczos on. Deleted on exit.
* @param[in] std::vector<std::vector<Cont> > &bandH: On exit, band-diagonal
* Hamiltonian approximation.
* @param[in] int &nLanIts: Number of Lanczos iterations to perform.
* @param[in] double thres: Threshold determining when to ignore beta's for
* being too small.
* @param[in] bool print: If true, write intermediate results to file.
*
* @author Carlos Mejuto Zaera
* @date 25/04/2022
*/
template <class Cont, class Functor>
void MyBandLan(const Functor &H,
// std::vector<std::vector<Cont> > &qs,
// std::vector<std::vector<Cont> > &bandH,
std::vector<Cont> &qs, std::vector<std::vector<Cont> > &bandH,
int &nLanIts, int nbands, int N, double thres = 1.E-6,
bool print = false) {
// BAND LANCZOS ROUTINE. TAKES AS INPUT THE HAMILTONIAN H, INITIAL VECTORS qs
// AND RETURNS THE BAND HAMILTONIAN bandH. IT PERFORMS nLanIts ITERATIONS,
// STOPPING IF THE NORM OF ANY NEW KRYLOV VECTOR IS BELOW thres. IF LANCZOS IS
// STOPPED PREMATURELY , nLanIts IS OVERWRITTEN WITH THE ACTUAL NUMBER OF
// ITERATIONS! THE qs VECTOR IS ERASED AT THE END OF THE CALCULATION
bandH.clear();
bandH.resize(nLanIts, std::vector<Cont>(nLanIts, 0.));

// MAKE SPACE FOR 2 * nbands VECTORS
// qs.resize(2 * nbands, std::vector<Cont>(qs[0].size(), 0.));
qs.resize(2 * nbands * N);
// std::vector<Cont> temp(qs[0].size(), 0.);
std::vector<Cont> temp(N, 0.);
if(print) {
for(int i = 0; i < nbands; i++) {
std::ofstream ofile("lanvec_" + std::to_string(i + 1) + ".dat",
std::ios::out);
ofile.precision(dbl::max_digits10);
// for(size_t el = 0; el < qs[i].size(); el++)
for(size_t el = 0; el < N; el++)
// ofile << std::scientific << qs[i][el] << std::endl;
ofile << std::scientific << qs[el + i * N] << std::endl;
ofile.close();
}
}
// DICTIONARY TO KEEP THE REAL INDICES OF THE KRYLOV VECTORS
// THIS IS NECESSARY IN ORDER TO ONLY STORE 2* nbands OF THEM
// AT ANY POINT IN TIME, PLUS ONE SCRATCH VECTOR TO BE DEFINED
// INSIDE THE FOR LOOP
std::vector<int> true_indx(nLanIts + 1);
for(int i = 0; i < nbands; i++) true_indx[i + 1] = i;
int next_indx = nbands;

for(int it = 1; it <= nLanIts; it++) {
int band_indx_i =
true_indx[it]; // TO WHAT ELEMENT OF THE VECTOR SET DO WE APPLY THIS
Copy link
Owner

Choose a reason for hiding this comment

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

Can you explain this indirection here? Generally we want to avoid things like this (to e.g. allow for better usage of Level-3 BLAS when possible), but if its completely necessary, it's fine.

Copy link
Collaborator Author

@CarlosMejZ CarlosMejZ Jun 19, 2023

Choose a reason for hiding this comment

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

You mean the use of the effective index true_indx? (I'm afraid I don't know what you mean by indirection)

This is what I came up with to apply the matvecs in the right order to the right vector, since in band Lanczos, unlike in the regular one, at every iteration you act on a different vector in your set of nbands. Why is this a problem for BLAS? Shouldn't it be fine as long as you pass the right memory sector to act on?

I guess that a way to avoid this true_indx variable could be to turn the for loop over it into two, one external loop going over nLanIts // nbands and one internal loop going over nbands. I think that should be completely equivalent, and then the index in the internal loop would be essentially iterating over which vector in the basis to act on with the Hamiltonian. Do you think this would make the code better?

// H.operator_action( 1, 1., qs[band_indx_i].data(), temp.size(), 0.,
// temp.data(), temp.size() );
H.operator_action(1, 1., qs.data() + band_indx_i * N, N, 0., temp.data(),
N);
if(print) {
std::ofstream ofile("Htimes_lanvec_" + std::to_string(it) + ".dat",
std::ios::out);
ofile.precision(dbl::max_digits10);
for(size_t el = 0; el < temp.size(); el++)
ofile << std::scientific << temp[el] << std::endl;
ofile.close();
}
for(int jt = std::max(1, it - nbands); jt <= std::min(it - 1, nLanIts);
jt++) {
int band_indx_j = true_indx[jt];
#pragma omp parallel for
for(size_t coeff = 0; coeff < temp.size(); coeff++)
// temp[coeff] -= bandH[it - 1][jt - 1] * qs[band_indx_j][coeff];
temp[coeff] -= bandH[it - 1][jt - 1] * qs[N * band_indx_j + coeff];
}
for(int jt = it; jt <= std::min(it + nbands - 1, nLanIts); jt++) {
int band_indx_j = true_indx[jt];
// bandH[it - 1][jt - 1] = MyInnProd(temp, qs[band_indx_j]);
bandH[it - 1][jt - 1] =
blas::dot(N, temp.data(), 1, qs.data() + band_indx_j * N, 1);
bandH[jt - 1][it - 1] = bandH[it - 1][jt - 1];
#pragma omp parallel for
for(size_t coeff = 0; coeff < temp.size(); coeff++)
// temp[coeff] -= bandH[it - 1][jt - 1] * qs[band_indx_j][coeff];
temp[coeff] -= bandH[it - 1][jt - 1] * qs[N * band_indx_j + coeff];
}
if(it + nbands <= nLanIts) {
bandH[it - 1][it + nbands - 1] =
std::sqrt(std::real(MyInnProd(temp, temp)));
bandH[it + nbands - 1][it - 1] = bandH[it - 1][it + nbands - 1];
true_indx[it + nbands] = next_indx;
if(std::abs(bandH[it - 1][it + nbands - 1]) < thres) {
std::cout
<< "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY "
<< bandH[it - 1][it + nbands - 1]
<< ", STOPPED AT ITERATION: " << it << std::endl;
nLanIts = it;
for(int i = 0; i < nLanIts; i++) bandH[i].resize(nLanIts);
bandH.resize(nLanIts);
break;
#pragma omp parallel for
for(size_t coeff = 0; coeff < temp.size(); coeff++)
Copy link
Owner

Choose a reason for hiding this comment

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

I'd either use scal with alpha=0 or a memset here since it's contiguous

// qs[true_indx[it + nbands]][coeff] = 0.;
qs[true_indx[it + nbands] * N + coeff] = 0.;
std::cout << "FOUND A ZERO VECTOR AT POSITION " << next_indx
<< std::endl;
} else {
#pragma omp parallel for
for(size_t coeff = 0; coeff < temp.size(); coeff++)
Copy link
Owner

Choose a reason for hiding this comment

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

This is an axpy with alpha = 1.0/bandH(it-1,jt-1) and beta = 0

// qs[true_indx[it + nbands]][coeff] =
qs[true_indx[it + nbands] * N + coeff] =
temp[coeff] / bandH[it - 1][it + nbands - 1];
if(print) {
std::ofstream ofile("lanvec_" + std::to_string(it + nbands) + ".dat",
std::ios::out);
ofile.precision(dbl::max_digits10);
// for(size_t el = 0; el < qs[true_indx[it + nbands]].size(); el++)
for(size_t el = 0; el < N; el++)
// ofile << std::scientific << qs[true_indx[it + nbands]][el]
ofile << std::scientific << qs[true_indx[it + nbands] * N + el]
<< std::endl;
ofile.close();
}
}
next_indx = (next_indx + 1 >= 2 * nbands) ? 0 : next_indx + 1;
}
}
qs.clear();
}

/**
* @brief Evaluates the expectation values of the resolvent of Hamiltonian H
* along a frequency grid ws with respect to the vectors vecs, using the band
* Lanczos algorithm.
*
* @param[in] const sparsex::dist_sparse_matrix<sparsexx::csr_matrix<double,
* int32_t> > &H: Hamiltonian operator.
* @param[in] std::vector<std::vector<double> > &vecs: Vectors for which to
* compute the resolvent matrix elements.
* @param[in] std::vector<std::complex<double> > &ws: Frequency grid over which
* to evaluate the resolvent.
* @param[out] std::vector<std::vector<std::vector<std::complex<double> > > >
* &res: On exit, resolvent elements.
* @param[in] int nLanIts: Max number of iterations.
* @param[in] double E0: Ground state energy, for shifting the resolvent.
* @param[in] bool ispart: If true, computes resolvent for particle GF,
* otherwise for hole GF.
* @param[in] bool print: If true, write intermediate results to file.
*
* @author Carlos Mejuto Zaera
* @date 25/04/2022
*/
void BandResolvent(
const sparsexx::dist_sparse_matrix<sparsexx::csr_matrix<double, int32_t> >
&H,
std::vector<std::vector<double> > &vecs,
wavefunction91 marked this conversation as resolved.
Show resolved Hide resolved
const std::vector<std::complex<double> > &ws,
std::vector<std::vector<std::vector<std::complex<double> > > > &res,
int nLanIts, double E0, bool ispart, bool print = false,
bool saveGFmats = false);

} // namespace macis
57 changes: 57 additions & 0 deletions include/macis/gf/eigsolver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* MACIS Copyright (c) 2023, The Regents of the University of California,
* through Lawrence Berkeley National Laboratory (subject to receipt of
* any required approvals from the U.S. Dept. of Energy). All rights reserved.
*
* See LICENSE.txt for details
*/

/**
* @file eigsolver.h++
* @brief Wrapper to Lapack routine for diagonalizing
* a tridiagonal, symmetric matrix.
*
* @author Carlos Mejuto Zaera
* @date 05/04/2021
*/
#pragma once
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <lapack.hh>

namespace macis {

typedef Eigen::VectorXd VectorXd;
wavefunction91 marked this conversation as resolved.
Show resolved Hide resolved
typedef Eigen::MatrixXd eigMatD;
typedef Eigen::SparseMatrix<double, Eigen::RowMajor> SpMatD;

/**
* @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric
* matrix using Lapack.
*
* @param [in] const std::vector<double> &alphas: Diagonal of the matrix.
* @param [in] const std::vector<double> &betas: Off-diagonal of the matrix.
* @param [out] Eigen::VectorXd &eigvals: Eigenvalues.
* @param [out] Eigen::MatrixXd &eigvecs: Eigenvectors.
*
* @author Carlos Mejuto Zaera
* @date 05/04/2021
*/
void Hste_v(const std::vector<double> &alphas, const std::vector<double> &betas,
Eigen::VectorXd &eigvals, eigMatD &eigvecs);

/**
* @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric
* matrix using Lapack.
*
* @param [in] const std::vector<double> &alphas: Diagonal of the matrix.
* @param [in] const std::vector<double> &betas: Off-diagonal of the matrix.
* @param [out] Eigen::VectorXd &eigvals: Eigenvalues.
* @param [out] Eigen::MatrixXd &eigvecs: Eigenvectors.
*
* @author Carlos Mejuto Zaera
* @date 05/04/2021
*/
void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs);

} // namespace macis
Loading