From e95c43f9e957ed8bd23a41069fec19de2f97acab Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Fri, 2 Jun 2023 16:01:14 +0200 Subject: [PATCH 01/35] Added GF functionalities. TODO: Fix the outputs to console, polish the doxygen docu. --- include/macis/gf/bandlan.hpp | 178 ++++++++++ include/macis/gf/eigsolver.hpp | 54 +++ include/macis/gf/gf.hpp | 604 +++++++++++++++++++++++++++++++++ include/macis/gf/inn_prods.hpp | 108 ++++++ include/macis/gf/lanczos.hpp | 555 ++++++++++++++++++++++++++++++ src/macis/CMakeLists.txt | 3 + src/macis/gf/bandlan.cxx | 484 ++++++++++++++++++++++++++ src/macis/gf/eigsolver.cxx | 100 ++++++ src/macis/gf/gf.cxx | 52 +++ tests/standalone_driver.cxx | 62 ++++ 10 files changed, 2200 insertions(+) create mode 100644 include/macis/gf/bandlan.hpp create mode 100644 include/macis/gf/eigsolver.hpp create mode 100644 include/macis/gf/gf.hpp create mode 100644 include/macis/gf/inn_prods.hpp create mode 100644 include/macis/gf/lanczos.hpp create mode 100644 src/macis/gf/bandlan.cxx create mode 100644 src/macis/gf/eigsolver.cxx create mode 100644 src/macis/gf/gf.cxx diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp new file mode 100644 index 00000000..80a186b3 --- /dev/null +++ b/include/macis/gf/bandlan.hpp @@ -0,0 +1,178 @@ +/** + * @file bandlan.h++ + * + * @brief Implements simple Band Lanczos routine. + * + * @author Carlos Mejuto Zaera + * @date 25/04/2022 + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "macis/gf/inn_prods.hpp" + +typedef std::numeric_limits< double > dbl; + +namespace macis +{ + + extern "C" { + extern int dgeqrf_(int*, int*, double*, int*, double*, double*, int*, int*); + extern int dorgqr_(int*, int*, int*, double*, int*, double*, double*, int*, int*); + extern int dsbtrd_(char*, char*, int*, int*, double*, int*, double*, double*, double*, int*, double*, int*); + extern int dsytrd_(char*, int*, double*, int*, double*, double*, double*, double*, int*, int*); + extern int dorgtr_(char*, int*, double*, int*, double*, double*, int*, int*); + extern int dsteqr_(char*, int*, double*, double*, double*, int*, double*, int*); + } + + bool QRdecomp(std::vector > &Q, std::vector > &R); + + bool QRdecomp_tr(std::vector > &Q, std::vector > &R); + + bool GetEigsys(std::vector > & mat, std::vector &eigvals, std::vector > & eigvecs); + + bool GetEigsysBand( std::vector > &mat, int nSupDiag, std::vector &eigvals, std::vector > &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 &H: Hamiltonian oprator. Just needs to implement a matrix vector product. + * @param[in] std::vector > &qs: Initial set of vetors to perform the band Lanczos on. Deleted on exit. + * @param[in] std::vector > &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 + void MyBandLan( + const sparsexx::dist_sparse_matrix > &H, + std::vector > &qs, + std::vector > &bandH, + int & nLanIts, + 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(nLanIts, 0.)); + + int nbands = qs.size(); + auto spmv_info = sparsexx::spblas::generate_spmv_comm_info( H ); + //MAKE SPACE FOR 2 * nbands VECTORS + qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); + std::vector temp(qs[0].size(), 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++) ofile << std::scientific << qs[i][el] << 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 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 + sparsexx::spblas::pgespmv( 1., H, qs[band_indx_i].data(), + 0., temp.data(), spmv_info ); + 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]; + } + 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[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]; + } + 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++) qs[true_indx[it+nbands]][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++) qs[true_indx[it+nbands]][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++) ofile << std::scientific << qs[true_indx[it+nbands]][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 > &H: Hamiltonian operator. + * @param[in] std::vector > &vecs: Vectors for which to compute the resolvent matrix elements. + * @param[in] std::vector > &ws: Frequency grid over which to evaluate the resolvent. + * @param[out] std::vector > > > &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 > &H, + std::vector > &vecs, + const std::vector > &ws, + std::vector > > > &res, + int nLanIts, + double E0, + bool ispart, + bool print = false, + bool saveGFmats = false ); + +}// namespace macis diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp new file mode 100644 index 00000000..8e5e9005 --- /dev/null +++ b/include/macis/gf/eigsolver.hpp @@ -0,0 +1,54 @@ +/** + * @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 +#include + +namespace macis +{ + + using namespace Eigen; + + typedef MatrixXd eigMatD; + typedef SparseMatrix SpMatD; + + extern "C" { + extern int dsteqr_(char*, int*, double*, double*, double*, int*, double*, int*); + extern int dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*); + } + + /** + * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric matrix + * using Lapack. + * + * @param [in] const std::vector &alphas: Diagonal of the matrix. + * @param [in] const std::vector &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 &alphas, const std::vector &betas, VectorXd &eigvals, eigMatD &eigvecs); + + /** + * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric matrix + * using Lapack. + * + * @param [in] const std::vector &alphas: Diagonal of the matrix. + * @param [in] const std::vector &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, VectorXd &eigvals, eigMatD &eigvecs); + +}// namespace macis diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp new file mode 100644 index 00000000..e4a670c7 --- /dev/null +++ b/include/macis/gf/gf.hpp @@ -0,0 +1,604 @@ +/** + * @brief Collection of routines to compute Green's functions + * within ED or CI-based approaches. By this, we mean + * any approximated approach where the wave function for + * which we want to compute the Green's function is written + * as a list of determinants. + * + * @author Carlos Mejuto Zaera + * @date 25/04/2022 + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "macis/gf/lanczos.hpp" +#include "macis/gf/bandlan.hpp" +#include "macis/sd_operations.hpp" +#include "macis/hamiltonian_generator.hpp" +#include "macis/csr_hamiltonian.hpp" +#if __has_include() + #define MACIS_USE_BOOST_SORT + #include +#endif + +namespace macis +{ + + using namespace Eigen; + + typedef std::numeric_limits< double > dbl; + typedef std::chrono::high_resolution_clock Clock; + + struct GFSettings{ + size_t norbs = 0; + size_t trunc_size = 0; + int tot_SD = 1; + double GFseedThres = 1.E-4; + double asThres = 1.E-4; + bool use_bandLan = true; + std::vector GF_orbs_basis = std::vector(0); + std::vector GF_orbs_comp = std::vector(0); + std::vector is_up_basis = std::vector(0); + std::vector is_up_comp = std::vector(0); + int nLanIts = 1000; + bool writeGF = false; + bool print = false; + bool saveGFmats = false; + }; + + template + inline double GetInsertionUpSign( const std::bitset &st, size_t orb ) + { + std::bitset mask = full_mask( orb ); + return ((st & mask).count() % 2 == 1 ? -1. : 1.); + } + + template + inline double GetInsertionDoSign( const std::bitset &st, size_t orb ) + { + std::bitset mask = full_mask( orb + nbits/2 ); + return ((st & mask).count() % 2 == 1 ? -1. : 1.); + } + + /** + * @brief Routine to compute single diagonal Green's function element. + * Essentially, evaluates the resolvent + * G(w) = + * using one-band Lanczos and continuous fraction representation. + * + * @param [in] const VectorXd &state_0: Reference state, for which to evaluate + * the resolvent. + * @param [in] const MatOp &H: Matrix operator representing the effective + * Hamiltonian. + * @param [in] const std::vector > &freqs: Frequency grid over which to evaluate the + * resolvent. + * @param [inout] std::vector > &gf: On successful exit, green's function along the + * frequency grid. + * @param [in] int nLanIts: Max. number of Lanczos iterations. + * @param [in] bool saveABtofile: If true, save the alpha and beta parameters + * from the Lanczos calculation to file. + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ + template + void GF_Diag( + const VectorXd &state_0, + const MatOp &H, + const std::vector > &freqs, + std::vector > &gf, + double E0, + bool ispart, + int nLanIts = 1000, + bool saveABtofile = false, + std::string fpref = ""){ + + //FIRST, WE HAVE TO COMPUTE THE LANCZOS alphas AND betas + double tol = 1.E-6; + std::vector alphas, betas; + + + MyLanczos(state_0, H, nLanIts, alphas, betas, tol); + + int kry_size = 0; + for(int i = 1; i < nLanIts; i++){ + if(abs(betas[i]) <= tol) break; + kry_size++; + } + + double sign = ispart ? -1. : 1.; + + if( saveABtofile ) + { + std::ofstream ofile( fpref + "alphas.dat", std::ios::out); + ofile.precision( dbl::max_digits10 ); + for(int i = 0; i <= kry_size; i++) ofile << std::scientific << alphas[i] << std::endl; + ofile.close(); + ofile.open(fpref + "betas.dat", std::ios::out); + ofile.precision( dbl::max_digits10 ); + for(int i = 0; i <= kry_size; i++) ofile << std::scientific << betas[i] << std::endl; + ofile.close(); + } + + //FINALLY, WE CAN COMPUTE THE GREEN'S FUNCTION + gf.clear(); + gf.resize(freqs.size(), std::complex(0.,0.)); + + #pragma omp parallel for + for (int indx_w = 0; indx_w < freqs.size(); indx_w++){ + gf[indx_w] = betas[kry_size] * betas[kry_size] / (freqs[indx_w] + sign * ( alphas[kry_size] - E0 ) ); + for(int i = kry_size - 1; i >= 0; i--) gf[indx_w] = betas[i] * betas[i] / (freqs[indx_w] + sign * ( alphas[i] - E0 ) - gf[indx_w]); //SINCE I CHOSE betas[0] = normpsi^2 + } + } + + template + class BitSetComparator { + public: + bool operator()(const std::bitset& c1, const std::bitset& c2) const + { + return bitset_less( c1, c2 ); + } + }; + + /** + * @brief Routine to build basis to compute the basis for Green's function + * calculation on the state |wfn> considering orbital orb. Templated + * to allow for differente slater determinant implementations (thinking + * beyond ED). + * + * @tparam class DetType: Slater determiant type. Should implement functions to check + * for orbital occupation, returning state bitstring and finding single excitations + * accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, + * should allow for basic bit operations, and being an index in a dictionary. + * + * @param [in] int orb: Orbital index for the Green's function basis. + * @param [in] bool sp_up: If true, the orbital is spin up, otherwise it's spin + * down. + * @param [in] bool is_part: If true, compute GF basis for particle sector (particle addition), + * otherwise compute it for hole sector (particle removal). + * @param [in] const VectorXd: Coefficient of the wave function describing the + * state whose Green's function we are computing. + * @param [in] const std::vector &old_basis: Basis of determinants describing the + * wave function wfn. + * @param [out] std::vector &new_basis: On return, the built basis for the Green's + * function calculation. + * @param [in] const std::vector &occs: Occupation numbers of all orbitals. Used to define + * active spaces. + * @param [in] const GFSettings &settings: Includes input parameters, in particular: + * o) double asThres: Threshold for the occupation numbers to define the + * active space. If 0+asThres <= occ[i] <= 2 - asThres, then the orbital + * i is added into the active space. + * o) double GFseedThreshold: Threshold to determine from which determinants to get + * excitations in the basis construction. + * o) int tot_SD: Number of layers of single excitations to build the basis. + * o) size_t trunc_size: Max. size for the Green's function basis. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ + template + void get_GF_basis_AS_1El( + int orb, + bool sp_up, + bool is_part, + const VectorXd &wfn, + const std::vector > &old_basis, + std::vector > &new_basis, + const std::vector &occs, + const GFSettings &settings) + { + //CARLOS: BUILDS BASIS FOR THE ADD SPACE NEEDED TO DESCRIBE THE DIAGONAL PARTICLE + //GF ELEMENT OF ORBITAL orb. + + size_t norbs = settings.norbs; + size_t trunc_size = settings.trunc_size; + int tot_SD = settings.tot_SD; + double GFseedThreshold = settings.GFseedThres; + double asThres = settings.asThres; + + std::cout << "COMPUTING GF SPACE IN *" << (is_part? "PARTICLE" : "HOLE") << "* SECTOR FOR ORBITAL " << orb << ", WITH SPIN *" << (sp_up ? "UP" : "DOWN") << "*" << std::endl; + + time_t loop1 = time(NULL); + auto loop1C = Clock::now(); + size_t ndets = old_basis.size(); + size_t cgf = -1; + size_t sporb = sp_up ? orb : orb + nbits / 2; + std::bitset uni_string; + std::vector > founddets; + founddets.reserve(trunc_size); + std::map, size_t, BitSetComparator > founddet_pos, basedet_pos; + typename std::map, size_t, BitSetComparator >::iterator it; + //ACTIVE SPACE + std::vector as_orbs; + for(size_t i = 0; i < occs.size(); i++){ + if(occs[i] >= asThres && occs[i] <= (1. - asThres)) as_orbs.push_back(i); + } + std::cout << "ACTIVE SPACE: ["; + for(int iii = 0; iii < as_orbs.size(); iii++) std::cout << as_orbs[iii] << ", "; + std::cout << "]" << std::endl; + + //INITIALIZE THE DICTIONARY OF BASE DETERMINANTS + for(size_t iii = 0; iii < ndets; iii++) + basedet_pos[old_basis[iii]] = iii; + + //LOOP OVER ALL STATES IN THE BASIS AND BUILD THE BASIS + for(size_t iii = 0; iii < ndets; iii++) + { + size_t norb1 = orb; + //CHECK WHETHER IT CORRESPONDS TO this GF: a_i^+|wfn> OR a_i|wfn> + bool ingf = false; + if( is_part && !old_basis[iii][sporb]) // PARTICLE + ingf = true; + else if( !is_part && old_basis[iii][sporb]) // HOLE + ingf = true; + if( ingf ) + { + //YES, ADD TO LIST + std::bitset temp = old_basis[iii]; + temp.flip(sporb); + it = founddet_pos.find(temp); + if(it == founddet_pos.end()) + { + cgf++; + founddet_pos[temp] = cgf; + founddets.push_back(temp); + } + } + } + + //IF NO STATE FOUND, THIS BASIS IS EMPTY + if(cgf+1 == 0) + { + new_basis.resize(cgf+1); + return; + } + //NOW, ADD SINGLE-DOUBLES. THIS AMOUNTS TO ADDING THE + //SINGLE EXCITATIONS ON TOP OF FOUNDDET + std::cout << "BEFORE ADDING SINGLE-DOUBLES, cgf = " << cgf << std::endl; + size_t orig_cgf = cgf; + + std::cout << "Nr. OF STATES: " << cgf+1 << std::endl; + + size_t norb = orb; + VectorXd b = Eigen::VectorXd::Zero(cgf+1); + //COMPUTE VECTOR b IN THE NEW BASIS + for(size_t ndet = 0; ndet < cgf+1; ndet++) + { + //CHECK, CAN ndet COME FROM ai^+|GS> / ai|wfn> WITH THE ORBITAL *orb? + bool fromwfn = false; + if( is_part && founddets[ndet][sporb]) + fromwfn = true; + else if ( !is_part && !founddets[ndet][sporb] ) + fromwfn = true; + if( fromwfn ) + { + //YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE DETERMINANT SPACE + std::bitset temp = founddets[ndet]; + temp.flip(sporb); + it = basedet_pos.find(temp); + if(it != basedet_pos.end()){ + //IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE + //THUS, IT CONTRIBUTES TO wfns1 + double sign = sp_up ? GetInsertionUpSign( temp, orb ) : GetInsertionDoSign( temp, orb ); + double fac = wfn(it->second); + b(ndet) += fac * sign; + } + } + } + + std::cout << "GOING TO ITERATIVELY ADD SINGLES AND DOUBLES!" << std::endl; + std::cout << "--BEFORE ADDING SINGLE-DOUBLES, nterms = " << cgf+1 << std::endl; + size_t orig_nterms = cgf+1; + + int startSD = 0, endSD = orig_nterms-1, GFseed = 0; + for(int nSD = 1; nSD <= tot_SD && cgf <= trunc_size; nSD++){ + for(int iii = startSD; iii <= endSD && cgf <= trunc_size; iii++){ + if(nSD == 1) if(abs(b(iii)) < GFseedThreshold) continue; //FROM THE ORIGINAL SET, ONLY CONSIDER THE MOST IMPORTANT ONES + //GET SINGLES + GFseed += (nSD == 1) ? 1 : 0; + std::vector > tdets; + generate_singles_spin_as( norbs, founddets[iii], tdets, as_orbs ); + + for(size_t jjj = 0; jjj < tdets.size(); jjj++){ + it = founddet_pos.find(tdets[jjj]); + if(it == founddet_pos.end()){ // FOR ZERO STATES ONLY, ADD: and matches > 0 + cgf++; + founddet_pos[tdets[jjj]] = cgf; + founddets.push_back(tdets[jjj]); + } + } + } + startSD = endSD + 1; + endSD = cgf; + } + std::cout << "--AFTER CUTTING BY: " << GFseedThreshold << ", GF-SPACE WITH GF SEED: " << GFseed << ", WE HAVE STATES: " << cgf+1 << std::endl; + + //NOW THAT WE FOUND THE BASIS, JUST STORE IT + new_basis.resize(cgf+1); + new_basis.assign(founddets.begin(), founddets.end()); + } + + /** + * @brief Routine to prepare the wave functions for the Lanczos computation of the Green's function (be it + * Band Lanczos or regular Lanczos). + * + * @tparam class DetType: Slater determiant type. Should implement functions to check + * for orbital occupation, returning state bitstring and finding single excitations + * accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, + * should allow for basic bit operations, and being an index in a dictionary. + * + * @param [in] const VectorXd &base_wfn: Wave function from which to compute the Green's function. + * @param [in] const std::vector &GF_orbs: Orbital indices for which to compute the GF. + * @param [in] const std::vector &is_up: Flags regarding the spin of each orbital. True means + * spin up, false means spin down. + * @param [in] const std::vector &base_dets: Vector of the Slater determinants in the basis. + * @param [in] const std::vector &GF_gets: Vector of the Slater determinants in the GF basis. + * @param [in] bool is_part: Flag to determine GF sector. For true, we are in the particle sector. For + * false we are in the hole sector. + * @param [out] std::vector& todelete: On return, contains a list of the orbitals for which the + * Green's function vector ai/ai+|base_wfn> vanishes, and hence is + * eliminated from the list of wave functions. + * @param [in] double zero_thresh: Threshold to decide whether a computed vector is zero or not, judging by + * the magnitude of the norm. + * + * @author Carlos Mejuto Zaera + * @date 01/02/2022 + */ + template + std::vector> BuildWfn4Lanczos( + const VectorXd &base_wfn, + const std::vector &GF_orbs, + const std::vector &is_up, + const std::vector > &base_dets, + const std::vector > &GF_dets, + bool is_part, + std::vector &todelete, + double zero_thresh = 1.E-7 ) + { + //INITIALIZE THE DICTIONARY OF BASE DETERMINANTS + std::map, size_t, BitSetComparator > base_dets_pos; + for(size_t iii = 0; iii < base_dets.size(); iii++) + base_dets_pos[base_dets[iii]] = iii; + + //PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS + size_t nterms = GF_dets.size(); + std::vector> wfns(GF_orbs.size(), std::vector(nterms,0.)); + for(size_t iorb = 0; iorb < GF_orbs.size(); iorb++){ + int orb = GF_orbs[iorb]; + bool sp_up = is_up[iorb]; + //int sporb = sp_up ? orb : orb + Norbs; + int sporb = sp_up ? orb : orb + nbits/2; + //BUILD THE WAVEFUNCTION FOR ORBITAL orb + for(size_t ndet = 0; ndet < nterms; ndet++){ + //CHECK, CAN ndet COME FROM ai^+|GS> *OR* ai|GS> WITH THE ORBITAL orb? + bool in_gf = false; + if( is_part && GF_dets[ndet][sporb]) // PARTICLE + in_gf = true; + else if( !is_part && !GF_dets[ndet][sporb] ) // HOLE + in_gf = true; + if( in_gf ) + { + //YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE DETERMINANT SPACE + std::bitset temp( GF_dets[ndet] ); + temp.flip(sporb); + typename std::map, size_t, BitSetComparator >::const_iterator it = base_dets_pos.find(temp); + if(it != base_dets_pos.end()){ + //IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE + //THUS, IT CONTRIBUTES TO wfns1 + double sign = sp_up ? GetInsertionUpSign( temp, orb ) : GetInsertionDoSign( temp, orb ); + double fac = base_wfn(it->second); + wfns[iorb][ndet] += fac * sign; + } + } + } + } + + //CHECK WHETHER ANY OF THE VECTORS IS EXACTLY ZERO. IF SO, TAKE IT OUT! + todelete.clear(); + for(int orb_indx = 0; orb_indx < GF_orbs.size(); orb_indx++){ + double st_nrm = 0.; + #pragma omp declare reduction \ + (Vsum:double:omp_out=omp_out+omp_in)\ + initializer(omp_priv=0.) + #pragma omp parallel for reduction (Vsum:st_nrm) + for(size_t iii = 0; iii < nterms; iii++) st_nrm += wfns[orb_indx][iii] * wfns[orb_indx][iii]; + if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); + } + for(int i = 0; i < todelete.size(); i++) wfns.erase(wfns.begin() + todelete[i] - i); + std::cout << "ORBITALS WITH NO CORRESPONING ADD-VECTOR: ["; + for(int i = 0; i < todelete.size(); i++) std::cout << todelete[i] << ", "; + std::cout << "]" << std::endl; + + return wfns; + } + + /** + * @brief Routine to write Green's function to file. It stores the frequency grid together with + * the full GF matrix. Also, in case of a multi-orbitla GF, it stores the orbital + * indices in a separate file. + * + * @param [in] const std::vector > > > &GF: + * GF to store. Written as GF[freq-axis][orb1][orb2]. + * @param [in] const std::vector > &ws: Frequency grid. + * @param [in] const std::vector &GF_orbs: Orbital indices for the Green's function, as requested + * originally in the GF computation. Some of them may not have been actually + * used, if the corresponding ai/ai+|wfn0> states were zero. + * @param [in] const std::vector &todelete: List of deleted orbital indices in the case just described. + * @param [in] const bool is_part: Flag to label GF file depending on whether it is a particle + * GF (True), or a hole GF (False). + * + * @author Carlos Mejuto Zaera + * @date 02/02/2022 + */ + void write_GF( const std::vector > > > &GF, const std::vector > &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part ); + + /** + * @brief Routine to run Green's function calculation at zero temperature from some input ref. wave function. + * Allows for choosing to compute particle/hole GF, using normal/band Lanczos, + * and simplifying the calculation by virtue of exploiting some active space structure. + * + * @tparam class DetType: Slater determiant type. Should implement functions to check + * for orbital occupation, returning state bitstring and finding single excitations + * accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, + * should allow for basic bit operations, and being an index in a dictionary. + * + * @param [out] std::vector > > >: On output, + * contains the computed Green's function, in format GF[freq.][orb1][orb2]. + * @param [in] const VectorXd &wfn0: Reference wave function from which to compute the GF. + * @param [in] const FermionHamil &H: Fermionic Hamiltonian defining the system. + * @param [in] const std::vector &base_dets: Basis of Slater determinants for the + * description of wfn0. + * @param [in] const double energ: Energy of reference state wfn0. + * @param [in] const bool is_part: Flag to determine GF sector. For true, we are in + * the particle sector. Otherwise, we are in the hole sector. + * @param [in] const std::vector > &ws: Frequency grid over which to compute the Green's function. + * @param [in] const std::vector &occs: Occupation numbers for each orbital. + * @param [in] const GFSettings &settings: Structure with various parameters for Green's function calculation. + * + * @author Carlos Mejuto Zaera + * @date 01/02/2022 + */ + template + void RunGFCalc( + std::vector > > > &GF, + const VectorXd &wfn0, + HamiltonianGenerator &Hgen, + const std::vector > &base_dets, + const double energ, + const bool is_part, + const std::vector >& ws, + const std::vector & occs, + const GFSettings &settings) + { + + // READ INPUT + const size_t trunc_size = settings.trunc_size; + const int tot_SD = settings.tot_SD; + const double GFseedThreshold = settings.GFseedThres; + const double asThres = settings.asThres; + const bool use_bandLan = settings.use_bandLan; + const std::vector GF_orbs_basis = settings.GF_orbs_basis; + const std::vector GF_orbs_comp = settings.GF_orbs_comp; + const std::vector is_up_basis = settings.is_up_basis; + const std::vector is_up_comp = settings.is_up_comp; + + double h_el_tol = 1.E-6; + int nLanIts = settings.nLanIts; + bool print = settings.print; + bool writeGF = settings.writeGF; + bool saveGFmats = settings.saveGFmats; + + time_t loop1 = time(NULL), loop2 = time(NULL); + auto loop1C = Clock::now(), loop2C = Clock::now(); + size_t ndets = base_dets.size(); + + //FIRST, BUILD THE BASIS SEQUENTIALLY BY FORMING THE BASES OF EACH ORBITAL AND + //ADDING THEM TOGETHER + std::vector > gf_dets, gf_dets_tmp; + for(size_t iorb = 0; iorb < GF_orbs_basis.size(); iorb++){ + get_GF_basis_AS_1El( GF_orbs_basis[iorb], is_up_basis[iorb], is_part, wfn0, base_dets, + gf_dets_tmp, occs, settings ); + gf_dets.insert( gf_dets.end(), gf_dets_tmp.begin(), + gf_dets_tmp.end() ); + + gf_dets_tmp.clear(); + + auto comparator = [](const auto& x, const auto& y) { + return bitset_less(x, y); + }; + #ifdef MACIS_USE_BOOST_SORT + boost::sort::pdqsort_branchless + #else + std::sort + #endif + ( gf_dets.begin(), gf_dets.end(), comparator); + + typename std::vector >::iterator b_it = std::unique(gf_dets.begin(), gf_dets.end()); + gf_dets.resize(std::distance(gf_dets.begin(), b_it)); + std::cout << "---> BASIS HAS NOW: " << gf_dets.size() << " ELMENTS!! BY ORBITAL " << iorb + 1 << "/" << GF_orbs_basis.size() << std::endl; + } + + size_t nterms = gf_dets.size(); + std::cout << "---> FINAL ADD BASIS HAS " << nterms << " ELEMENTS" << std::endl; + + loop1 = time(NULL); + loop1C = Clock::now(); + auto hamil = make_dist_csr_hamiltonian( MPI_COMM_WORLD, gf_dets.begin(), + gf_dets.end(), Hgen, h_el_tol ); + loop2 = time(NULL); + loop2C = Clock::now(); + std::cout << std::setprecision(3)<<"Building " << (is_part ? "*PARTICLE*" : "*HOLE*") << " Hamiltonian: " << double(std::chrono::duration_cast(loop2C - loop1C).count())/1000 << std::endl; + //NOW, PERFORM THE BAND LANCZOS ON THE TRUNCATED SPACE + //WE ALREADY BUILT THE HAMILTONIANS + + if(nterms < nLanIts) + nLanIts = nterms; + + //PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS + std::vector todelete; + std::vector> wfns = BuildWfn4Lanczos( wfn0, GF_orbs_comp, is_up_comp, + base_dets, gf_dets, is_part, todelete ); + + // //ACTUALLY COMPUTE THE GF! + time_t GF_loop1 = time(NULL); + auto GF_loop1C = Clock::now(); + + if( use_bandLan ) + { + BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, print, saveGFmats); + } + else + { + //DO SIMPLE LANCZOS FOR ALL GF ELEMENTS + SparsexDistSpMatOp hamil_wrap( hamil ); + GF.resize(ws.size(), std::vector > >(wfns.size(), std::vector >(wfns.size(), std::complex(0.,0.)) )); + for(int i = 0; i < wfns.size(); i++) + { + std::vector > tGF; + //DIAGONAL ELEMENT + std::cout << "DOING ELEMENT (" << i << ", " << i << ")" << std::endl; + VectorXd twfn = Eigen::Map(wfns[i].data(), nterms); + std::string fpref_basis = is_part ? "particle" : "hole"; + std::string fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( i ); + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); + for(int iw = 0; iw < ws.size(); iw++) + GF[iw][i][i] = tGF[iw]; + for(int j = i+1; j < wfns.size(); j++) + { + //OFF DIAGONAL ELEMENTS + std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; + for(size_t iii = 0; iii < nterms; iii++) + twfn(iii) = wfns[i][iii] + wfns[j][iii]; + fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( j ) + "_a"; + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); + for(int iw = 0; iw < ws.size(); iw++) + GF[iw][i][j] += 0.25 * tGF[iw]; + for(size_t iii = 0; iii < nterms; iii++) + twfn(iii) = wfns[i][iii] - wfns[j][iii]; + fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( j ) + "_b"; + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts); + for(int iw = 0; iw < ws.size(); iw++) + { + GF[iw][i][j] -= 0.25 * tGF[iw]; + GF[iw][j][i] = GF[iw][i][j]; + } + } + } + } + + time_t GF_loop2 = time(NULL); + auto GF_loop2C = Clock::now(); + std::cout << std::setprecision(3)<<"Computing GF with " << (use_bandLan ? " *Band Lanczos*" : "*Regular Lanczos*") << double(std::chrono::duration_cast(GF_loop2C - GF_loop1C).count())/1000 << std::endl; + + if( writeGF ) + write_GF( GF, ws, GF_orbs_comp, todelete, is_part ); + } + +}// namespace macis diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp new file mode 100644 index 00000000..a5dfa3b8 --- /dev/null +++ b/include/macis/gf/inn_prods.hpp @@ -0,0 +1,108 @@ +/** + * @file inn_prods.h++ + * + * @brief Inner product routines between vectors. + * + * @author Carlos Mejuto Zaera + * @date 02/06/2023 + */ +#pragma once +#include +#include +#include + +namespace macis +{ + /** + * @brief Simple inner product routine between two std::vector + * + * @param [in] const std::vecotr& vecR + * @param [in] const std::vecotr& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + inline double MyInnProd(const std::vector& vecR, const std::vector& vecL){ + //SIMPLE INNER PRODUCT ROUTINE + double res = 0.; + #pragma omp declare reduction \ + (Vsum:double:omp_out=omp_out+omp_in)\ + initializer(omp_priv=0.) + #pragma omp parallel for reduction (Vsum:res) + for(size_t i = 0; i < vecR.size();i++) res += vecR[i] * vecL[i]; + return res; + } + + /** + * @brief Simple inner product routine between two std::vector > + * + * @param [in] const std::vecotr >& vecR + * @param [in] const std::vecotr >& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + inline std::complex MyInnProd(const std::vector >& vecR, const std::vector >& vecL){ + //SIMPLE INNER PRODUCT ROUTINE + std::complex res(0.,0.); + #pragma omp declare reduction \ + (Vsum:std::complex:omp_out=omp_out+omp_in)\ + initializer(omp_priv=std::complex(0.,0.)) + #pragma omp parallel for reduction (Vsum:res) + for(size_t i = 0; i < vecR.size();i++) res += conj(vecR[i]) * vecL[i]; + return res; + } + + /** + * @brief Simple inner product routine between std::vector and std::vector > + * + * @param [in] const std::vecotr >& vecR + * @param [in] const std::vecotr& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + inline std::complex MyInnProd(const std::vector >& vecR, const std::vector& vecL){ + //SIMPLE INNER PRODUCT ROUTINE + std::complex res(0.,0.); + #pragma omp declare reduction \ + (Vsum:std::complex:omp_out=omp_out+omp_in)\ + initializer(omp_priv=std::complex(0.,0.)) + #pragma omp parallel for reduction (Vsum:res) + for(size_t i = 0; i < vecR.size();i++) res += conj(vecR[i]) * std::complex(vecL[i], 0.); + return res; + } + + /** + * @brief Simple inner product routine for two Eigen::VectorXcd + * + * @param [in] const Eigen::VectorXcd& vecR + * @param [in] const Eigen::VectorXcd& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, const Eigen::VectorXcd& vecL){ + //SIMPLE INNER PRODUCT ROUTINE + return vecR.dot(vecL); + } + + /** + * @brief Simple inner product routine for two Eigen::VectorXd + * + * @param [in] const Eigen::VectorXd& vecR + * @param [in] const Eigen::VectorXd& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + inline double MyInnProd(const Eigen::VectorXd& vecR, const Eigen::VectorXd& vecL){ + //SIMPLE INNER PRODUCT ROUTINE + return vecR.dot(vecL); + } +}// namespace macis diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp new file mode 100644 index 00000000..0e819459 --- /dev/null +++ b/include/macis/gf/lanczos.hpp @@ -0,0 +1,555 @@ +/** + * @brief Implements simple one-band Lanczos method + * to compute the lowest eigenvalue of a given + * Hamiltonian. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +#pragma once +#include "macis/gf/eigsolver.hpp" +#include "macis/gf/inn_prods.hpp" +#include +#include +#include +#include +#include + +namespace macis +{ + + struct LanczosSettings { + + size_t itermax = 1000; + double Lantol = 1.E-8; + double E0tol = 1.E-8; + bool print = false; + }; + + /** + * @brief Wrapper class for Eigen::MatrixXd, to be used in + * the Lanczos code. Just needs to implement a matrix- + * vector product dot, and a function rows() to return the + * nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + class eigMatDOp + { + private: + const eigMatD *mat; + public: + /** + * @brief Constructor, takes Eigen::MatrixXd and keeps + * pointer to it. + * + * @param [in] const Eigen::MatrixXd &A: Matrix to wrap. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + eigMatDOp(const eigMatD &A){mat = &A;} + /** + * @brief Simple matrix-vector product. + * + * @param [in] const Eigen::VectorXd &vec: Input vector. + * + * @returns Eigen::VectorXd: A * vec. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + VectorXd dot(const VectorXd &vec) const {return (*mat) * vec;} + /** + * @brief Returns nr. of rows in the wrapped matrix. + * + * @returns int: Nr. of rows. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + int64_t rows() const {return mat->rows();} + }; + + /** + * @brief Wrapper class for Eigen::SparseMatrix, to be used in + * the Lanczos code. Just needs to implement a matrix- + * vector product dot, and a function rows() to return the + * nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + class SpMatDOp + { + private: + const SpMatD *mat; + public: + /** + * @brief Constructor, takes Eigen::SparseMatrix and keeps + * pointer to it. + * + * @param [in] const Eigen::SparseMatrix &A: Matrix to wrap. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + SpMatDOp(const SpMatD &A){mat = &A;} + /** + * @brief Simple matrix-vector product. + * + * @param [in] const Eigen::VectorXd &vec: Input vector. + * + * @returns Eigen::VectorXd: A * vec. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + VectorXd dot(const VectorXd &vec) const {return (*mat) * vec;} + /** + * @brief Returns nr. of rows in the wrapped matrix. + * + * @returns int: Nr. of rows. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + int64_t rows() const {return mat->rows();} + }; + + /** + * @brief Wrapper class for sparsexx::dist_sparse_matrix, to be used in + * the Lanczos code. Just needs to implement a matrix- + * vector product dot, and a function rows() to return the + * nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 13/06/2021 + */ + class SparsexDistSpMatOp + { + private: + const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix > *mat; + sparsexx::spblas::spmv_info spmv_info; + public: + /** + * @brief Constructor, takes sparsexx::dist_sparse_matrix< sparsexx::csr_matrix and keeps + * pointer to it. + * + * @param [in] const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix &A: Matrix to wrap. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + SparsexDistSpMatOp(const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix > &A) + { + mat = &A; + spmv_info = sparsexx::spblas::generate_spmv_comm_info( A ); + } + /** + * @brief Simple matrix-vector product. + * + * @param [in] const Eigen::VectorXd &vec: Input vector. + * + * @returns Eigen::VectorXd: A * vec. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + VectorXd dot(const VectorXd &vec) const + { + std::vector vin( &vec[0], vec.data()+vec.cols()*vec.rows()); + std::vector vout(vec.size(), 0.); + sparsexx::spblas::pgespmv( 1., *mat, vin.data(), + 0., vout.data(), spmv_info ); + Eigen::VectorXd vec_out = Eigen::Map(vout.data(), vout.size()); + return vec_out; + } + /** + * @brief Returns nr. of rows in the wrapped matrix. + * + * @returns int: Nr. of rows. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + int64_t rows() const {return mat->m();} + }; + + /** + * @brief Simple single band Lanczos implementation. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! + * @param [in] int64_t nLanIts: Maximal number of iterations. + * @param [out] std::vector &alphas: Diagonal of the tri-diagonal H. + * @param [out] std::vector &betas: Off-diagonal of the tri-diagonal H. + * @param [in] double tol: Lanczos tolerance. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + template + void MyLanczos(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, std::vector &alphas, std::vector &betas, double tol) + { + //LANCZOS ROUTINE USING TEMPLATED MATRIX + //CLASS. ONLY NEEDS TO PROVIDE A MATRIX + //VECTOR PRODUCT. + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + alphas.clear(); + betas.clear(); + + alphas.resize(nLanIts, 0.); + betas.resize(nLanIts+1, 0.); + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1, itermax = nLanIts; + + nlan++; + qold = start_vec / normpsi; + + qnew = H.dot(qold); + alphas[0] = MyInnProd(qold, qnew); + qnew -= alphas[0] * qold; + betas[0] = normpsi; + betas[1] = sqrt(MyInnProd(qnew, qnew)); + if(abs(betas[1]) <= tol) itermax = 1; + for(size_t iter = 1; iter < itermax; iter++){ + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas[iter] = MyInnProd(qold, qnew); + qnew -= alphas[iter] * qold; + betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + + if(abs(betas[iter + 1]) <= tol){ + itermax = iter; + std::cout << "EXIT BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; + break; + } + } + } + + /** + * @brief Single band Lanczos implementation, with backprojection to + * evaluate eigenvector in the original basis. A previous Lanczos + * to determine the ground state in the Krylov basis has to be performed + * first. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! + * @param [in] int64_t nLanIts: Maximal number of iterations. + * @param [in] Eigen::VectorXd &vec_P: Eigenvector in the Krylov basis. + * @param [out] Eigen::VectorXd &vec_BP: Eigenvector in the original basis. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + template + void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, VectorXd &vec_P, VectorXd &vec_BP) + { + //REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS + //CALCULATION. + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + + std::vector alphas(nLanIts, 0.); + std::vector betas(nLanIts+1, 0.); + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1, itermax = nLanIts; + + vec_BP = VectorXd::Zero(n); + + nlan++; + qold = start_vec / normpsi; + vec_BP = vec_P(0) * qold; + + qnew = H.dot(qold); + alphas[0] = MyInnProd(qold, qnew); + qnew -= alphas[0] * qold; + betas[0] = normpsi; + betas[1] = sqrt(MyInnProd(qnew, qnew)); + for(size_t iter = 1; iter < itermax; iter++){ + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + vec_BP += vec_P(iter) * qold; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas[iter] = MyInnProd(qold, qnew); + qnew -= alphas[iter] * qold; + betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + } + alphas.clear(); + betas.clear(); + } + + /** + * @brief Determine ground state of Hamiltonian using Lanczos, returns + * the ground state vector in the Krylov basis. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0_Lan: Eigenvector in the Krylov basis. + * @param [in] LanczosSettings &settings: Input structure with Lanczos parameters. + * + * @returns int: Required nr. of Lanczos iterations. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + template + int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, VectorXd &psi0_Lan, const LanczosSettings &settings) + { + //COMPUTE LOWEST EIGENVALUE OF MATRIX H + //USING LANCZOS. RETURNS EIGENVECTOR IN + //THE BASIS OF KRYLOV VECTORS + auto w = std::setw(15); + double Lantol = settings.Lantol; + double E0tol = settings.E0tol; + bool print = settings.print; + size_t itermax = settings.itermax; + + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + VectorXd eigvals; + eigMatD eigvecs; + std::vector alphas, betas; + double currE0, prevE0; + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1; + + nlan++; + qold = start_vec / normpsi; + + qnew = H.dot(qold); + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[0] * qold; + betas.push_back(normpsi); + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + prevE0 = alphas[0]; + + if(print) + { + std::cout << w << "Lanczos diagonalization:" << std::endl; + std::ostringstream header; + header << w << "Iter." << w << "Alpha" << w << "Beta" << w << "E0" << w << "dE"; + std::cout << header.str() << std::endl; + std::cout << w << std::string(header.str().length(), '-') << std::endl; + std::cout << w << 1 << w << std::scientific << std::setprecision(5) << alphas[0] << w << betas[1] << w << prevE0 << w << "***" << std::endl; + } + + if(abs(betas[1]) <= Lantol){ + itermax = 1; + currE0 = alphas[0]; + } + for(size_t iter = 1; iter < itermax; iter++){ + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[iter] * qold; + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + //GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX + Hste_v(alphas, betas, eigvals, eigvecs); + currE0 = eigvals(0); + if(print) + std::cout << w << iter+1 << w << std::scientific << std::setprecision(5) << alphas[iter] << w << betas[iter+1] << w << currE0 << w << abs(currE0 - prevE0) << std::endl; + + if(abs(betas[iter + 1]) <= Lantol){ + itermax = iter+1; + if(print) + std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; + break; + } + if(abs(currE0 - prevE0) <= E0tol){ + itermax = iter+1; + if(print) + std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT ITERATION " << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; + break; + } + prevE0 = currE0; + } + + if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1 && abs(betas[itermax]) > Lantol ) + { + std::ostringstream oss; + oss << "Unable to achieve the desired accuracy of " << std::scientific << E0tol << " in Lanczos after " << itermax << " iterations!!"; + throw (oss.str()); + } + + E0 = currE0; + if(itermax == 1) + { + psi0_Lan = VectorXd::Ones(1); + } + else + { + psi0_Lan = eigvecs.col(0); + } + return itermax; + } + + /** + * @brief Determine ground state of Hamiltonian using Lanczos, returns + * the ground state vector in the original basis. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. + * @param [in] const LanczosSettings &settings: Input structure with Lanczos parameters. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + template + void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, VectorXd &psi0, const LanczosSettings &settings) + { + //COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR + //OF MATRIX H USING LANCZOS. + double Lantol = settings.Lantol; + double E0tol = settings.E0tol; + bool print = settings.print; + size_t itermax = settings.itermax; + + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + VectorXd eigvals; + eigMatD eigvecs; + std::vector kry_vecs; + std::vector alphas, betas; + double currE0, prevE0; + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1; + + nlan++; + qold = start_vec / normpsi; + kry_vecs.push_back(qold); + + qnew = H.dot(qold); + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[0] * qold; + betas.push_back(normpsi); + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + prevE0 = alphas[0]; + + if(abs(betas[1]) <= Lantol){ + itermax = 1; + currE0 = alphas[0]; + } + for(size_t iter = 1; iter < itermax; iter++){ + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + kry_vecs.push_back(qold); + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[iter] * qold; + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + //GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX + Hste_v(alphas, betas, eigvals, eigvecs); + currE0 = eigvals(0); + + if(abs(betas[iter + 1]) <= Lantol){ + itermax = iter; + if(print) + std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; + break; + } + if(abs(currE0 - prevE0) <= E0tol){ + itermax = iter; + if(print) + std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT ITERATION " << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; + break; + } + prevE0 = currE0; + } + + if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1 ) + { + std::ostringstream oss; + oss << "Unable to achieve the desired accuracy of " << std::scientific << E0tol << " in Lanczos after " << itermax << " iterations!!"; + throw (oss.str()); + } + + E0 = currE0; + psi0 = VectorXd::Zero(n); + if(kry_vecs.size() == 1) + { + psi0 = kry_vecs[0]; + } + else + { + for(int64_t i = 0; i < kry_vecs.size(); i++) + psi0 += eigvecs.col(0)(i) * kry_vecs[i]; + } + } + + /** + * @brief Computes ground state of Hamiltonian and corresponding + * eigenvector using Lanczos. + * + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. + * @param [in] const LanczosSettings &settings: Input structure with Lanczos parameters. + * @param [in] bool superCI: Determines starting guess for Lanczos. If true + * we start from [1,0,0,0,...] vector, otherwise from [1,1,1,...]. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + template + void GetGS(const MatOp &H, double &E0, VectorXd &psi0, const LanczosSettings &settings, bool isHF = false) + { + //Computes the lowest eigenvalue and corresponding + //eigenvector from the dense matrix H by using Lanczos. + + int64_t n = H.rows(); + //Initial vector. We choose (1,0,0,0,...)t + //for HF, Otherwhise (1,1,1,1,...)t + VectorXd start_psi = isHF ? VectorXd::Zero(n) : VectorXd::Ones(n); + start_psi(0) = 1.; + //Determine lowest eigenvalue for the given + //tolerance. + VectorXd psi0_Lan; + int64_t nLanIts = GetGSEn_Lanczos(start_psi, H, E0, psi0_Lan, settings); + //Reconstruct the eigenvector + MyLanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); + start_psi = psi0; + GetGSEnVec_Lanczos(start_psi, H, E0, psi0, settings); + } + +}// namespace macis diff --git a/src/macis/CMakeLists.txt b/src/macis/CMakeLists.txt index 862df2ce..c7a3495d 100644 --- a/src/macis/CMakeLists.txt +++ b/src/macis/CMakeLists.txt @@ -15,6 +15,9 @@ add_library( macis orbital_rotation_utilities.cxx orbital_hessian.cxx orbital_steps.cxx + gf/eigsolver.cxx + gf/bandlan.cxx + gf/gf.cxx ) target_include_directories( macis PUBLIC diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx new file mode 100644 index 00000000..94e7cb4b --- /dev/null +++ b/src/macis/gf/bandlan.cxx @@ -0,0 +1,484 @@ +#include "macis/gf/bandlan.hpp" +#include + +inline bool is_file (const std::string& name) { + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + +namespace macis +{ + bool QRdecomp(std::vector > &Q, std::vector > &R) + { + //CALL LAPACK'S QR DECOMPOSITION ROUTINES. + //INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE RECTANGULAR, + // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF ROWS. + //OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT + // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. + // return : TRUE FOR SUCCESS, FALSE OTHERWISE + + R.clear(); + //PREPARE VARIABLES TO CALL LAPACK + int M = Q.size(), N = Q[0].size(); + assert(M >= N); + int LDA = M, INFO = 0, LWORK; + double *A, *TAU, *WORK; + + //INITIALIZE A + A = new double[M * N]; + for(int i = 0; i < M; i++){ + for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; + Q[i].clear(); + } + //INITIALIZE TAU, AND PERFORM WORKSPACE QUERY + TAU = new double[N]; + WORK = new double[N]; + LWORK = -1; + + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + //NOW, PERFORM ACTUAL QR DECOMPOSITION + WORK = new double[LWORK]; + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO << std::endl; + return false; + } + //SAVE THE R MATRIX + R.resize(N); + for(int i = 0; i < N; i++){ + R[i].resize(N); + std::fill(R[i].begin(), R[i].end(), 0.); + for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; + } + + //NOW, COMPUTE THE ACTUAL Q MATRIX + int K = N; + //FIRST, PERFORM WORKSPACE QUERY + LWORK = -1; + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + WORK = new double[LWORK]; + //NOW, COMPUTE ACTUAL Q + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] TAU; + delete[] WORK; + //SAVE THE Q MATRIX + for(int i = 0; i < M; i++){ + Q[i].resize(N); + for(int j = 0; j < N; j++) Q[i][j] = A[i + j * M]; + } + delete[] A; + + return true; + + } + + bool QRdecomp_tr(std::vector > &Q, std::vector > &R) + { + //CALL LAPACK'S QR DECOMPOSITION ROUTINES. + //INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE RECTANGULAR, + // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF ROWS. + //OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT + // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. + // return : TRUE FOR SUCCESS, FALSE OTHERWISE + + R.clear(); + //PREPARE VARIABLES TO CALL LAPACK + int M = Q[0].size(), N = Q.size(); + assert(M >= N); + int LDA = M, INFO = 0, LWORK; + double *A, *TAU, *WORK; + + //INITIALIZE A + A = new double[M * N]; + for(int i = 0; i < M; i++){ + for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; + } + + //INITIALIZE TAU, AND PERFORM WORKSPACE QUERY + TAU = new double[N]; + WORK = new double[N]; + LWORK = -1; + + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + //NOW, PERFORM ACTUAL QR DECOMPOSITION + WORK = new double[LWORK]; + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO << std::endl; + return false; + } + //SAVE THE R MATRIX + R.resize(N); + for(int i = 0; i < N; i++){ + R[i].resize(N); + std::fill(R[i].begin(), R[i].end(), 0.); + for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; + } + + //NOW, COMPUTE THE ACTUAL Q MATRIX + int K = N; + //FIRST, PERFORM WORKSPACE QUERY + LWORK = -1; + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + WORK = new double[LWORK]; + //NOW, COMPUTE ACTUAL Q + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] TAU; + delete[] WORK; + //SAVE THE Q MATRIX + for(int i = 0; i < M; i++){ + for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; + } + delete[] A; + + return true; + + } + + bool GetEigsys(std::vector > & mat, std::vector &eigvals, std::vector > & eigvecs) + { + //COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC MATRIX mat BY CALLING LAPACK. + //WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. + //FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES AND + //EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs RESPECTIVELY. THE MATRIX mat IS + //ERASED DURING COMPUTATION + eigvals.clear(); eigvecs.clear(); + //PREPARE VARIABLES FOR LAPACK + char UPLO = 'U', COMPZ = 'V'; + int N = mat.size(), LDA = mat.size(), LWORK = -1, INFO; + double *A, *D, *E, *TAU, *WORK; + + //INITIALIZE A + A = new double[N * N]; + for(int i = 0; i < N; i++){ + for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; + mat[i].clear(); + } + mat.clear(); + //ALLOCATE REST OF THE MEMORY + D = new double[N]; + E = new double[N-1]; + TAU = new double[N-1]; + WORK = new double[N]; + + //TRANSFORM THE MATRIX TO TRIDIAGONAL FORM + //FIRST, PERFORM MEMORY QUERY + dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dsytrd_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + //NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM + dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dsytrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " << INFO << std::endl; + return false; + } + + //COMPUTE THE TRANSFORMATION MATRIX, NECESSARY TO COMPUTE EIGENVECTORS + //FIRST, PERFORM MEMORY QUERY + LWORK = -1; + dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgtr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; + return false; + } + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + //NOW, COMPUTE THE TRANSFORMATION MATRIX. IT WILL BE STORED IN A + dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dorgtr_ COMPUTING TRANSFORMATION MATRIX!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] TAU; + + //FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! + delete[] WORK; + WORK = new double[2 * N - 2]; + dsteqr_(&COMPZ, &N, D, E, A, &LDA, WORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] WORK; + delete[] E; + + //NOW, STORE THE EIGENVALUES AND EIGENVECTORS + eigvals.resize(N); + for(int i = 0; i < N; i++) eigvals[i] = D[i]; + delete[] D; + eigvecs.resize(N); + for(int i = 0; i < N; i++){ + eigvecs[i].resize(N); + for(int j = 0; j < N; j++) eigvecs[i][j] = A[j + i * N]; + } + delete[] A; + + return true; + + } + + bool GetEigsysBand(std::vector > & mat, int nSupDiag, std::vector &eigvals, std::vector > & eigvecs) + { + //COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC BAND MATRIX mat BY CALLING LAPACK. + //WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. + //FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES AND + //EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs RESPECTIVELY. THE MATRIX mat IS + //ERASED DURING COMPUTATION + eigvals.clear(); eigvecs.clear(); + //PREPARE VARIABLES FOR LAPACK + char UPLO = 'U', VECT = 'V', COMPZ = 'V'; + int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1, LWORK = -1, INFO; + double *AB, *D, *E, *Q, *WORK; + + //INITIALIZE A + AB = new double[(nSupDiag + 1) * N]; + for(int j = 0; j < N; j++){ + for(int i = std::max(0,j-nSupDiag); i <= j; i++) AB[nSupDiag + i - j + j * (nSupDiag+1)] = mat[i][j]; + } + mat.clear(); + //ALLOCATE REST OF THE MEMORY + Q = new double[N * N]; + D = new double[N]; + E = new double[N-1]; + WORK = new double[N]; + + //TRANSFORM THE MATRIX TO TRIDIAGONAL FORM + //NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM + dsbtrd_(&VECT, &UPLO, &N, &nSupDiag, AB, &LDAB, D, E, Q, &LDQ, WORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dsbtrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] AB; + + //FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! + delete[] WORK; + WORK = new double[2 * N - 2]; + dsteqr_(&COMPZ, &N, D, E, Q, &LDQ, WORK, &INFO); + if(INFO != 0){ + std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! ERROR CODE: " << INFO << std::endl; + return false; + } + delete[] WORK; + delete[] E; + + //NOW, STORE THE EIGENVALUES AND EIGENVECTORS + eigvals.resize(N); + for(int i = 0; i < N; i++) eigvals[i] = D[i]; + delete[] D; + eigvecs.resize(N); + for(int i = 0; i < N; i++){ + eigvecs[i].resize(N); + for(int j = 0; j < N; j++) eigvecs[i][j] = Q[j + i * N]; + } + delete[] Q; + + return true; + + } + + void BandResolvent( + const sparsexx::dist_sparse_matrix > &H, + std::vector > &vecs, + const std::vector > &ws, + std::vector > > > &res, + int nLanIts, + double E0, + bool ispart, + bool print, + bool saveGFmats ) + { + //COMPUTES THE RESOLVENT (ws - H)^-1 IN MATRIX FORM FOR THE "BASIS" GIVEN BY THE + //vecs VECTORS AND THE FREQUENCY GRID IN ws. USES THE BAND LANCZOS ALGORITHM. IT + //GETS STORED IN res. + res.clear(); + std::cout << "RESOLVENT ROUTINE: "; + res.resize(ws.size(), std::vector > >(vecs.size(), std::vector >(vecs.size(), std::complex(0.,0.)) )); + int n = vecs.size(); + + + //FIRST, COMPUTE QR DECOMPOSITION OF THE "BASIS" VECTORS vecs, NECESSARY FOR + //LANCZOS + std::vector > R; + std::cout << "QR DECOMPOSITION ..."; + bool worked = QRdecomp_tr(vecs, R); + if(not worked) + { + std::cout << "QR DECOMPOSITION FAILED!!" << std::endl; + return; + } + std::cout << "DONE! "; + + if(print){ + std::ofstream ofile("QRresVecs.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF QR DECOMPOSITION: " << std::endl; + ofile << " New Vectors: " << std::endl; + for(int i = 0; i < vecs[0].size(); i++){ + for(int j = 0; j < vecs.size(); j++) ofile << std::scientific << vecs[j][i] << " "; + ofile << std::endl; + } + ofile.close(); + ofile.clear(); + ofile.open("QRresRmat.dat", std::ios::out); + ofile << " R Matrix: " << std::endl; + for(int i = 0; i < R.size(); i++){ + for(int j = 0; j < R[i].size(); j++) ofile << std::scientific << R[i][j] << " "; + ofile << std::endl; + } + ofile.close(); + } + + //NEXT, COMPUTE THE BAND LANCZOS + std::vector > bandH; + std::cout << "BAND LANCZOS ..."; + MyBandLan(H, vecs, bandH, nLanIts, 1.E-6, print); + std::cout << "DONE! "; + if(print){ + std::ofstream ofile("BLH.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF BAND LANCZOS: " << std::endl; + ofile << " bandH Matrix: " << std::endl; + for(int i = 0; i < bandH.size(); i++){ + for(int j = 0; j < bandH[i].size(); j++) ofile << std::scientific << bandH[i][j] << " "; + ofile << std::endl; + } + ofile.close(); + } + + if(n == 1) + { + //ONLY ONE BAND. DIAGONAL GREEN'S FUNCTION ELEMENT. + //COMPUTE THROUGH CONTINUED FRACTION. + std::cout << "COMPUTING GF AS CONTINUED FRACTION..."; + std::vector alphas(bandH.size(), 0.), betas(bandH.size(), 0.); + for(int i = 0; i < bandH.size(); i++) + alphas[i] = ispart ? E0 - bandH[i][i] : bandH[i][i] - E0; + for(int i = 0; i < bandH.size()-1; i++) + betas[i+1] = ispart ? -bandH[i][i+1] : bandH[i][i+1]; + betas[0] = R[0][0]; + #pragma omp parallel for + for(int indx_w = 0; indx_w < ws.size(); indx_w++){ + res[indx_w][0][0] = betas.back() * betas.back() / (ws[indx_w] + alphas.back()); + for(int i = betas.size() - 2; i >= 0; i--) res[indx_w][0][0] = betas[i] * betas[i] / (ws[indx_w] + alphas[i] - res[indx_w][0][0]); + } + } + else + { + //NEXT, COMPUTE THE EIGENVALUES AND EIGENVECTORS OF THE BAND DIAGONAL KRYLOV + //HAMILTONIAN + std::vector eigvals; + std::vector > eigvecs; + std::cout << "COMPUTING EIGENVALES ..."; + if( ispart ) + for( int rr = 0; rr < bandH.size(); rr++ ) + { + bandH[rr][rr] = E0 - bandH[rr][rr]; + for( int cc = rr+1; cc < bandH.size(); cc++ ) + { + bandH[rr][cc] = -bandH[rr][cc]; + bandH[cc][rr] = -bandH[cc][rr]; + } + } + else + for( int rr = 0; rr < bandH.size(); rr++ ) + bandH[rr][rr] = bandH[rr][rr] - E0; + + GetEigsysBand(bandH, std::min(size_t(n), bandH.size() - 1), eigvals, eigvecs); + if(print){ + std::ofstream ofile("BLEigs.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF EIGENVALUE CALCULATION: " << std::endl; + ofile << " Eigvals: ["; + for(int i = 0; i < eigvals.size(); i++) ofile << std::scientific << eigvals[i] << ", "; + ofile << std::endl; + ofile << "Eigvecs: " << std::endl; + for(int i = 0; i < eigvecs.size(); i++){ + for(int j = 0; j < eigvecs[i].size(); j++) ofile << std::scientific << eigvecs[i][j] << " "; + ofile << std::endl; + } + ofile.close(); + } + std::cout << "DONE! "; + //FINALLY, COMPUTE S-MATRIX AND RESOLVENT + std::vector > S(nLanIts, std::vector(n, 0.)); + std::cout << " COMPUTING S MATRIX ..."; + for(int i_lan = 0; i_lan < nLanIts; i_lan++){ + for(int j_n = 0; j_n < n; j_n++){ + for(int l = 0; l < n; l++) S[i_lan][j_n] += eigvecs[i_lan][l] * R[l][j_n]; + } + } + if( saveGFmats ) + { + std::cout << "WRITING S MATRIX AND BAND-LANCZOS EIGENVALUES TO FILE!" << std::endl; + std::string fprefix = ispart ? "particle" : "hole"; + std::ofstream ofile( fprefix + "_S.mat", std::ios::out ); + ofile.precision( dbl::max_digits10 ); + for( int i_lan = 0; i_lan < nLanIts; i_lan++) + { + for( int k = 0; k < n; k++ ) + ofile << std::scientific << S[i_lan][k] << " "; + ofile << std::endl; + } + ofile.close(); + ofile.open( fprefix + "_BLevals.dat", std::ios::out); + ofile.precision( dbl::max_digits10 ); + for( int i_lan = 0; i_lan < nLanIts; i_lan++ ) + ofile << std::scientific << eigvals[i_lan] << std::endl; + ofile.close(); + + } + std::cout << "DONE! COMPUTING RESOLVENT ..."; + #pragma omp parallel for + for(int iw = 0; iw < ws.size(); iw++){ + for(int k = 0; k < n; k++){ + for(int l = 0; l < n; l++){ + for(int i_lan = 0; i_lan < nLanIts; i_lan++){ + res[iw][k][l] += S[i_lan][k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan][l]; + } + } + } + } + } + std::cout << "DONE!" << std::endl; + } + +}// namespace macis diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx new file mode 100644 index 00000000..4f2b70eb --- /dev/null +++ b/src/macis/gf/eigsolver.cxx @@ -0,0 +1,100 @@ +#include "macis/gf/eigsolver.hpp" + +/***Written by Carlos Mejuto Zaera***/ + +namespace macis +{ + + void Hste_v(const std::vector &alphas, const std::vector &betas, VectorXd &eigvals, eigMatD &eigvecs){ + /* + * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A TRIDIAGONAL, SYMMETRIC MATRIX A USING LAPACK. + */ + eigvals.resize(alphas.size()); + eigvecs.resize(alphas.size(), alphas.size()); + //INITIALIZE VARIABLES + char JOBZ = 'I'; // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX + int N = alphas.size(), LDZ = N, INFO; // SIZES + double *D, *E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS + double *WORK, *Z; // WORKSPACE AND EIGENVECTORS + //INITIALIZE MATRIX + D = new double[N]; + for(int64_t i = 0; i < N; i++) + D[i] = alphas[i]; + E = new double[N-1]; + for(int64_t i = 1; i < N; i++) + E[i-1] = betas[i]; + //ALLOCATE MEMORY + WORK = new double[2*N -2]; + Z = new double[N * LDZ]; + + //ACTUAL EIGENVALUE CALCULATION + dsteqr_(&JOBZ, &N, D, E, Z, &LDZ, WORK, &INFO); + if(INFO != 0){ + if(INFO < 0) + throw ("In dsteqr_, the " + std::to_string(-1 * INFO) + "-th argument had an illegal value"); + if(INFO > 0) + throw ("dsteqr_ the algorithm has failed to find all the eigenvalues in a total of " + std::to_string(30*N) + " iterations"); + } + delete[] WORK; + delete[] E; + //SAVE EIGENVECTORS + for(int i = 0; i < N; i++){ + for(int j = 0; j < N; j++) eigvecs(i,j) = Z[i+ j * N]; + } + delete[] Z; + //SAVE EIGENVALUES + for(int i = 0; i < N; i++) eigvals(i) = D[i]; + + delete[] D; + } + + void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs){ + /* + * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING LAPACK. + */ + eigvals.resize(H.rows()); + eigvecs.resize(H.rows(), H.rows()); + //INITIALIZE VARIABLES + char JOBZ = 'V', UPLO = 'U'; // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS STORED IN THE UPPER TRIANGLE + int N = H.rows(), LWORK = -1, LDA = N, INFO; // SIZES + double *A, *WORK; // MATRIX AND WORKSPACE + double *W; // EIGENVALUES AND WORKSPACE + //INITIALIZE MATRIX + A = new double[N * N]; + for(int i = 0; i < N; i++){ + for(int j = 0; j < N; j++) + A[i + j * N] = H(i,j); + } + //ALLOCATE MEMORY + WORK = new double[2*N + 1]; + W = new double[N]; + + //MEMORY QUERY + dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); + if(INFO != 0) + throw ("ERROR IN dsyev_ MEMORY QUERY!! ERROR CODE: " + std::to_string(INFO)); + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + //ACTUAL EIGENVALUE CALCULATION + dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); + if(INFO != 0){ + if(INFO < 0) + throw("ERROR IN dsyev_! The " + std::to_string(-1 * INFO) + "-th argument had an illegal value"); + throw("ERROR IN dsyev_! Algorithm failed to converge! " + std::to_string(INFO) + " off-diagonal elements of an intermediate tridiagonal form did not converge to zero"); + } + delete[] WORK; + //SAVE EIGENVECTORS + for(int i = 0; i < N; i++){ + for(int j = 0; j < N; j++) + eigvecs(i,N - 1 - j) = A[i+ j * N]; + } + delete[] A; + //SAVE EIGENVALUES + for(int i = 0; i < N; i++) + eigvals(N - 1 - i) = W[i]; + + delete[] W; + } + +}// namespace macis diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx new file mode 100644 index 00000000..8339d3fa --- /dev/null +++ b/src/macis/gf/gf.cxx @@ -0,0 +1,52 @@ +#include "macis/gf/gf.hpp" + +namespace macis +{ + void write_GF( const std::vector > > > &GF, const std::vector > &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part ) + { + + size_t nfreqs = ws.size(); + + if(GF_orbs.size() > 1) + { + + std::string fname = is_part ? + "LanGFMatrix_ADD.dat" + : "LanGFMatrix_SUB.dat"; + std::ofstream ofile( fname ); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++){ + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; + for(int jjj = 0; jjj < GF[iii].size(); jjj++){ + for(int lll = 0; lll < GF[iii][jjj].size(); lll++)ofile << std::scientific << real(GF[iii][jjj][lll]) << " " << imag(GF[iii][jjj][lll]) << " "; + } + ofile << std::endl; + } + ofile.close(); + + std::string fname2 = is_part ? + "GFMatrix_OrbitalIndices_ADD.dat" + : "GFMatrix_OrbitalIndices_SUB.dat"; + std::ofstream ofile2( fname2 ); + for(int iii = 0; iii < GF_orbs.size(); iii++) + { + if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) + continue; + ofile2 << GF_orbs[iii] << std::endl; + } + ofile2.close(); + } + else + { + std::string fname = is_part ? + "LanGF_ADD_" + : "LanGF_SUB_"; + fname += std::to_string(GF_orbs[0]+1) + "_" + std::to_string(GF_orbs[0]+1) + ".dat"; + std::ofstream ofile( fname ); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " << real(GF[iii][0][0]) << " " << imag(GF[iii][0][0]) << std::endl; + ofile.close(); + } + } + +}// namespace macis diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 2cd6b778..37091d52 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -314,6 +315,67 @@ int main(int argc, char** argv) { } } + // Testing GF + bool testGF = false; + OPT_KEYWORD("CI.GF", testGF, bool); + if( testGF ) + { + // Generate determinant list + auto dets = macis::generate_hilbert_space(n_active, nalpha, nbeta); + // Generate the Hamiltonian Generator + generator_t ham_gen( + macis::matrix_span(T_active.data(),n_active,n_active), + macis::rank4_span(V_active.data(),n_active,n_active,n_active, + n_active) + ); + + // Generate frequency grid + double wmin = -8.; + double wmax = 8.; + size_t nws = 1001; + double eta = 0.1; + std::complex w0( wmin, eta ); + std::complex wf( wmax, eta ); + std::vector > ws( nws, std::complex(0.,0.) ); + for( int i = 0; i < nws; i++ ) + ws[i] = w0 + (wf - w0) / double(nws - 1) * double(i); + + // MCSCF Settings + macis::GFSettings gf_settings; + OPT_KEYWORD("GF.NORBS" , gf_settings.norbs, size_t); + OPT_KEYWORD("GF.TRUNC_SIZE" , gf_settings.trunc_size, size_t); + OPT_KEYWORD("GF.TOT_SD" , gf_settings.tot_SD, int); + OPT_KEYWORD("GF.GFSEEDTHRES", gf_settings.GFseedThres, double ); + OPT_KEYWORD("GF.ASTHRES" , gf_settings.asThres, double); + OPT_KEYWORD("GF.USE_BANDLAN", gf_settings.use_bandLan, bool); + OPT_KEYWORD("GF.NLANITS" , gf_settings.nLanIts, int); + OPT_KEYWORD("GF.WRITE" , gf_settings.writeGF, bool); + OPT_KEYWORD("GF.PRINT" , gf_settings.print, bool); + OPT_KEYWORD("GF.SAVEGFMATS" , gf_settings.saveGFmats, bool); + gf_settings.GF_orbs_basis = std::vector(n_active,0); + for( int i = 0; i < n_active; i++ ) + gf_settings.GF_orbs_basis[i] = i; + gf_settings.GF_orbs_comp = std::vector(2,0); + for( int i = 0; i < 2; i++ ) + gf_settings.GF_orbs_comp[i] = i; + gf_settings.is_up_basis = std::vector(n_active, true); + gf_settings.is_up_comp = std::vector(2, true); + + // GF vector + std::vector > > > GF( 1, std::vector > >(1, std::vector >(nws, std::complex(0.,0.) ) ) ); + + // Occupation numbers + std::vector occs( n_active, 1. ); + + // GS vector + Eigen::VectorXd psi0 = Eigen::Map( C_local.data(), C_local.size() ); + + // Evaluate particle GF + macis::RunGFCalc( GF, psi0, ham_gen, dets, E0, true, ws, occs, gf_settings ); + // Evaluate hole GF + macis::RunGFCalc( GF, psi0, ham_gen, dets, E0, false, ws, occs, gf_settings ); + } + } else { // Generate the Hamiltonian Generator From dbea9ae5fabc7ebeab02b47d9e088a0f35028383 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Fri, 2 Jun 2023 16:39:52 +0200 Subject: [PATCH 02/35] Filling in the doxygen docu for the GF-relevant routines. --- include/macis/gf/gf.hpp | 32 +++++++++++++ include/macis/sd_operations.hpp | 84 +++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 8 deletions(-) diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index e4a670c7..714c9097 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -51,6 +51,19 @@ namespace macis bool saveGFmats = false; }; + /** + * @brief Gets fermionic sign incurred by inserting an electron of spin + * up in a given orbital to a given determinant. + * + * @param[in] const std::bitset &st: Determinant to which we are adding + * an electron. + * @param[in] size_t orb: Index of the orbital where we are adding the electron. + * + * @returns double: Fermionic sign of the operation. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template inline double GetInsertionUpSign( const std::bitset &st, size_t orb ) { @@ -58,6 +71,19 @@ namespace macis return ((st & mask).count() % 2 == 1 ? -1. : 1.); } + /** + * @brief Gets fermionic sign incurred by inserting an electron of spin + * down in a given orbital to a given determinant. + * + * @param[in] const std::bitset &st: Determinant to which we are adding + * an electron. + * @param[in] size_t orb: Index of the orbital where we are adding the electron. + * + * @returns double: Fermionic sign of the operation. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template inline double GetInsertionDoSign( const std::bitset &st, size_t orb ) { @@ -135,6 +161,12 @@ namespace macis } } + /** + * @brief Class for comparing two determinants, to use in sorting routines. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template class BitSetComparator { public: diff --git a/include/macis/sd_operations.hpp b/include/macis/sd_operations.hpp index 7c8a4c7f..4d45e2f6 100644 --- a/include/macis/sd_operations.hpp +++ b/include/macis/sd_operations.hpp @@ -100,16 +100,17 @@ void bitset_to_occ_vir( size_t norb, std::bitset state, } /** - * @brief Generate the list of (un)occupied orbitals for a paricular state. + * @brief Generate the list of (un)occupied orbitals for a paricular state, + * but considering only a subset of active orbitals. * * TODO: Test this function * * @tparam N Number of bits for the total bit string of the state * @param[in] norb Number of orbitals used to describe the state (<= `N`) * @param[in] state The state from which to determine orbital occupations. - * @param[out] occ List of occupied orbitals in `state` - * @param[out] vir List of unoccupied orbitals in `state` - * @param[in] as_orbs TODO:???? + * @param[out] occ List of occupied active orbitals in `state` + * @param[out] vir List of unoccupied active orbitals in `state` + * @param[in] as_orbs: Orbital indices for the active orbitals to consider.. */ template void bitset_to_occ_vir_as( size_t norb, std::bitset state, @@ -213,7 +214,23 @@ void generate_singles_doubles( size_t norb, std::bitset state, -// TODO: Test this function +/** + * @brief Generates single excitations for a given spin involving only the orbitals + * defined in the active space as_orbs. + * + * TODO: Test this function + * + * @param[in] size_t norb: Nr. of orbitals in the system. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, + * includes only one of the spin species. + * @param[out] std::vector >& singles: Vector storing the singly + * excited determinants from state, considering the active space. + * @param[in] const std::vector as_orbs: Vector with the indices of the active + * orbitals. Only excitations involving these orbitals will be formed. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template void generate_singles_as( size_t norb, std::bitset state, std::vector>& singles, const std::vector& as_orbs ) { @@ -226,7 +243,25 @@ void generate_singles_as( size_t norb, std::bitset state, } -// TODO: Test this function +/** + * @brief Generates single and double excitations for a given spin involving only the orbitals + * defined in the active space as_orbs. + * + * TODO: Test this function + * + * @param[in] size_t norb: Nr. of orbitals in the system. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, + * includes only one of the spin species. + * @param[out] std::vector >& singles: Vector storing the singly + * excited determinants from state, considering the active space. + * @param[out] std::vector >& doubles: Vector storing the doubly + * excited determinants from state, considering the active space. + * @param[in] const std::vector as_orbs: Vector with the indices of the active + * orbitals. Only excitations involving these orbitals will be formed. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template void generate_singles_doubles_as( size_t norb, std::bitset state, std::vector>& singles, std::vector>& doubles, @@ -241,7 +276,22 @@ void generate_singles_doubles_as( size_t norb, std::bitset state, } -// TODO: Test this function +/** + * @brief Generates single excitations for both spins involving only the orbitals + * defined in the active space as_orbs. + * + * TODO: Test this function + * + * @param[in] size_t norb: Nr. of orbitals in the system. + * @param[in] std::bitsetstate : Slater determinant for which to compute the excitations. + * @param[out] std::vector >& singles: Vector storing the singly + * excited determinants from state, considering the active space. + * @param[in] const std::vector as_orbs: Vector with the indices of the active + * orbitals. Only excitations involving these orbitals will be formed. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template void generate_singles_spin_as( size_t norb, std::bitset state, std::vector>& singles, const std::vector as_orbs ) { @@ -277,7 +327,25 @@ void generate_singles_spin_as( size_t norb, std::bitset state, } -// TODO: Test this function +/** + * @brief Generates single and double excitations for both spins involving only the orbitals + * defined in the active space as_orbs. + * + * TODO: Test this function + * + * @param[in] size_t norb: Nr. of orbitals in the system. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, + * includes only one of the spin species. + * @param[out] std::vector >& singles: Vector storing the singly + * excited determinants from state, considering the active space. + * @param[out] std::vector >& doubles: Vector storing the doubly + * excited determinants from state, considering the active space. + * @param[in] const std::vector as_orbs: Vector with the indices of the active + * orbitals. Only excitations involving these orbitals will be formed. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ template void generate_singles_doubles_spin_as( size_t norb, std::bitset state, std::vector>& singles, std::vector>& doubles, From 88353d3c539774da99dac788c45fb9cdb8526c1d Mon Sep 17 00:00:00 2001 From: "license[bot]" Date: Fri, 2 Jun 2023 16:00:12 +0000 Subject: [PATCH 03/35] Committing license headers --- include/macis/gf/bandlan.hpp | 8 ++++++++ include/macis/gf/eigsolver.hpp | 8 ++++++++ include/macis/gf/gf.hpp | 8 ++++++++ include/macis/gf/inn_prods.hpp | 8 ++++++++ include/macis/gf/lanczos.hpp | 8 ++++++++ src/macis/gf/bandlan.cxx | 8 ++++++++ src/macis/gf/eigsolver.cxx | 8 ++++++++ src/macis/gf/gf.cxx | 8 ++++++++ 8 files changed, 64 insertions(+) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 80a186b3..39a0612f 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -1,3 +1,11 @@ +/* + * 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++ * diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index 8e5e9005..b6cdd99a 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -1,3 +1,11 @@ +/* + * 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 diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 714c9097..274fcab0 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -1,3 +1,11 @@ +/* + * 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 + */ + /** * @brief Collection of routines to compute Green's functions * within ED or CI-based approaches. By this, we mean diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp index a5dfa3b8..f3e721d6 100644 --- a/include/macis/gf/inn_prods.hpp +++ b/include/macis/gf/inn_prods.hpp @@ -1,3 +1,11 @@ +/* + * 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 inn_prods.h++ * diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index 0e819459..0506a727 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -1,3 +1,11 @@ +/* + * 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 + */ + /** * @brief Implements simple one-band Lanczos method * to compute the lowest eigenvalue of a given diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 94e7cb4b..6588c1e6 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -1,3 +1,11 @@ +/* + * 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 + */ + #include "macis/gf/bandlan.hpp" #include diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index 4f2b70eb..8a2a0e2c 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -1,3 +1,11 @@ +/* + * 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 + */ + #include "macis/gf/eigsolver.hpp" /***Written by Carlos Mejuto Zaera***/ diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 8339d3fa..b241f3a7 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -1,3 +1,11 @@ +/* + * 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 + */ + #include "macis/gf/gf.hpp" namespace macis From 90c234a7caee0b059323db2ac62b8aad4a87944e Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Fri, 2 Jun 2023 18:46:37 +0000 Subject: [PATCH 04/35] Committing clang-format changes --- include/macis/gf/bandlan.hpp | 340 +++--- include/macis/gf/eigsolver.hpp | 86 +- include/macis/gf/gf.hpp | 1216 +++++++++++---------- include/macis/gf/inn_prods.hpp | 193 ++-- include/macis/gf/lanczos.hpp | 992 ++++++++--------- include/macis/sd_operations.hpp | 53 +- src/macis/gf/bandlan.cxx | 936 ++++++++-------- src/macis/gf/eigsolver.cxx | 191 ++-- src/macis/gf/gf.cxx | 88 +- src/sparsexx/examples/attic/test_norm.cxx | 2 +- tests/standalone_driver.cxx | 131 ++- 11 files changed, 2175 insertions(+), 2053 deletions(-) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 39a0612f..170dbedd 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -16,171 +16,209 @@ */ #pragma once #include -#include +#include + #include +#include #include #include -#include -#include -#include #include +#include #include -#include #include +#include +#include + #include "macis/gf/inn_prods.hpp" -typedef std::numeric_limits< double > dbl; +typedef std::numeric_limits dbl; -namespace macis -{ - - extern "C" { - extern int dgeqrf_(int*, int*, double*, int*, double*, double*, int*, int*); - extern int dorgqr_(int*, int*, int*, double*, int*, double*, double*, int*, int*); - extern int dsbtrd_(char*, char*, int*, int*, double*, int*, double*, double*, double*, int*, double*, int*); - extern int dsytrd_(char*, int*, double*, int*, double*, double*, double*, double*, int*, int*); - extern int dorgtr_(char*, int*, double*, int*, double*, double*, int*, int*); - extern int dsteqr_(char*, int*, double*, double*, double*, int*, double*, int*); - } - - bool QRdecomp(std::vector > &Q, std::vector > &R); - - bool QRdecomp_tr(std::vector > &Q, std::vector > &R); - - bool GetEigsys(std::vector > & mat, std::vector &eigvals, std::vector > & eigvecs); +namespace macis { - bool GetEigsysBand( std::vector > &mat, int nSupDiag, std::vector &eigvals, std::vector > &eigvecs ); +extern "C" { +extern int dgeqrf_(int *, int *, double *, int *, double *, double *, int *, + int *); +extern int dorgqr_(int *, int *, int *, double *, int *, double *, double *, + int *, int *); +extern int dsbtrd_(char *, char *, int *, int *, double *, int *, double *, + double *, double *, int *, double *, int *); +extern int dsytrd_(char *, int *, double *, int *, double *, double *, double *, + double *, int *, int *); +extern int dorgtr_(char *, int *, double *, int *, double *, double *, int *, + int *); +extern int dsteqr_(char *, int *, double *, double *, double *, int *, double *, + int *); +} - /** - * @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 &H: Hamiltonian oprator. Just needs to implement a matrix vector product. - * @param[in] std::vector > &qs: Initial set of vetors to perform the band Lanczos on. Deleted on exit. - * @param[in] std::vector > &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 - void MyBandLan( - const sparsexx::dist_sparse_matrix > &H, - std::vector > &qs, - std::vector > &bandH, - int & nLanIts, - 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(nLanIts, 0.)); - - int nbands = qs.size(); - auto spmv_info = sparsexx::spblas::generate_spmv_comm_info( H ); - //MAKE SPACE FOR 2 * nbands VECTORS - qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); - std::vector temp(qs[0].size(), 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++) ofile << std::scientific << qs[i][el] << std::endl; - ofile.close(); - } +bool QRdecomp(std::vector > &Q, + std::vector > &R); + +bool QRdecomp_tr(std::vector > &Q, + std::vector > &R); + +bool GetEigsys(std::vector > &mat, + std::vector &eigvals, + std::vector > &eigvecs); + +bool GetEigsysBand(std::vector > &mat, int nSupDiag, + std::vector &eigvals, + std::vector > &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 &H: Hamiltonian + * oprator. Just needs to implement a matrix vector product. + * @param[in] std::vector > &qs: Initial set of vetors to + * perform the band Lanczos on. Deleted on exit. + * @param[in] std::vector > &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 +void MyBandLan( + const sparsexx::dist_sparse_matrix > + &H, + std::vector > &qs, std::vector > &bandH, + int &nLanIts, 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(nLanIts, 0.)); + + int nbands = qs.size(); + auto spmv_info = sparsexx::spblas::generate_spmv_comm_info(H); + // MAKE SPACE FOR 2 * nbands VECTORS + qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); + std::vector temp(qs[0].size(), 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++) + ofile << std::scientific << qs[i][el] << 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 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 - sparsexx::spblas::pgespmv( 1., H, qs[band_indx_i].data(), - 0., temp.data(), spmv_info ); - 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]; - } - 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[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]; - } - 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++) qs[true_indx[it+nbands]][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++) qs[true_indx[it+nbands]][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++) ofile << std::scientific << qs[true_indx[it+nbands]][el] << 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 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 + sparsexx::spblas::pgespmv(1., H, qs[band_indx_i].data(), 0., temp.data(), + spmv_info); + 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]; + } + 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[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]; + } + 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++) + qs[true_indx[it + nbands]][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++) + qs[true_indx[it + nbands]][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++) + ofile << std::scientific << qs[true_indx[it + nbands]][el] + << std::endl; + ofile.close(); } - next_indx = (next_indx + 1 >= 2 * nbands) ? 0 : next_indx + 1; } + 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 > &H: Hamiltonian operator. - * @param[in] std::vector > &vecs: Vectors for which to compute the resolvent matrix elements. - * @param[in] std::vector > &ws: Frequency grid over which to evaluate the resolvent. - * @param[out] std::vector > > > &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 > &H, - std::vector > &vecs, - const std::vector > &ws, + 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 > &H: Hamiltonian operator. + * @param[in] std::vector > &vecs: Vectors for which to + * compute the resolvent matrix elements. + * @param[in] std::vector > &ws: Frequency grid over which + * to evaluate the resolvent. + * @param[out] std::vector > > > + * &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 > + &H, + std::vector > &vecs, + const std::vector > &ws, std::vector > > > &res, - int nLanIts, - double E0, - bool ispart, - bool print = false, - bool saveGFmats = false ); - -}// namespace macis + int nLanIts, double E0, bool ispart, bool print = false, + bool saveGFmats = false); + +} // namespace macis diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index b6cdd99a..d0e6db20 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -18,45 +18,47 @@ #include #include -namespace macis -{ - - using namespace Eigen; - - typedef MatrixXd eigMatD; - typedef SparseMatrix SpMatD; - - extern "C" { - extern int dsteqr_(char*, int*, double*, double*, double*, int*, double*, int*); - extern int dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*); - } - - /** - * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric matrix - * using Lapack. - * - * @param [in] const std::vector &alphas: Diagonal of the matrix. - * @param [in] const std::vector &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 &alphas, const std::vector &betas, VectorXd &eigvals, eigMatD &eigvecs); - - /** - * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric matrix - * using Lapack. - * - * @param [in] const std::vector &alphas: Diagonal of the matrix. - * @param [in] const std::vector &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, VectorXd &eigvals, eigMatD &eigvecs); - -}// namespace macis +namespace macis { + +using namespace Eigen; + +typedef MatrixXd eigMatD; +typedef SparseMatrix SpMatD; + +extern "C" { +extern int dsteqr_(char *, int *, double *, double *, double *, int *, double *, + int *); +extern int dsyev_(char *, char *, int *, double *, int *, double *, double *, + int *, int *); +} + +/** + * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric + * matrix using Lapack. + * + * @param [in] const std::vector &alphas: Diagonal of the matrix. + * @param [in] const std::vector &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 &alphas, const std::vector &betas, + VectorXd &eigvals, eigMatD &eigvecs); + +/** + * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric + * matrix using Lapack. + * + * @param [in] const std::vector &alphas: Diagonal of the matrix. + * @param [in] const std::vector &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, VectorXd &eigvals, eigMatD &eigvecs); + +} // namespace macis diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 274fcab0..588dccbd 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -11,634 +11,662 @@ * within ED or CI-based approaches. By this, we mean * any approximated approach where the wave function for * which we want to compute the Green's function is written - * as a list of determinants. + * as a list of determinants. * * @author Carlos Mejuto Zaera * @date 25/04/2022 */ #pragma once +#include #include +#include #include #include -#include -#include -#include #include -#include "macis/gf/lanczos.hpp" +#include + +#include "macis/csr_hamiltonian.hpp" #include "macis/gf/bandlan.hpp" -#include "macis/sd_operations.hpp" +#include "macis/gf/lanczos.hpp" #include "macis/hamiltonian_generator.hpp" -#include "macis/csr_hamiltonian.hpp" +#include "macis/sd_operations.hpp" #if __has_include() - #define MACIS_USE_BOOST_SORT - #include +#define MACIS_USE_BOOST_SORT +#include #endif -namespace macis -{ - - using namespace Eigen; - - typedef std::numeric_limits< double > dbl; - typedef std::chrono::high_resolution_clock Clock; - - struct GFSettings{ - size_t norbs = 0; - size_t trunc_size = 0; - int tot_SD = 1; - double GFseedThres = 1.E-4; - double asThres = 1.E-4; - bool use_bandLan = true; - std::vector GF_orbs_basis = std::vector(0); - std::vector GF_orbs_comp = std::vector(0); - std::vector is_up_basis = std::vector(0); - std::vector is_up_comp = std::vector(0); - int nLanIts = 1000; - bool writeGF = false; - bool print = false; - bool saveGFmats = false; - }; - - /** - * @brief Gets fermionic sign incurred by inserting an electron of spin - * up in a given orbital to a given determinant. - * - * @param[in] const std::bitset &st: Determinant to which we are adding - * an electron. - * @param[in] size_t orb: Index of the orbital where we are adding the electron. - * - * @returns double: Fermionic sign of the operation. - * - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ - template - inline double GetInsertionUpSign( const std::bitset &st, size_t orb ) - { - std::bitset mask = full_mask( orb ); - return ((st & mask).count() % 2 == 1 ? -1. : 1.); +namespace macis { + +using namespace Eigen; + +typedef std::numeric_limits dbl; +typedef std::chrono::high_resolution_clock Clock; + +struct GFSettings { + size_t norbs = 0; + size_t trunc_size = 0; + int tot_SD = 1; + double GFseedThres = 1.E-4; + double asThres = 1.E-4; + bool use_bandLan = true; + std::vector GF_orbs_basis = std::vector(0); + std::vector GF_orbs_comp = std::vector(0); + std::vector is_up_basis = std::vector(0); + std::vector is_up_comp = std::vector(0); + int nLanIts = 1000; + bool writeGF = false; + bool print = false; + bool saveGFmats = false; +}; + +/** + * @brief Gets fermionic sign incurred by inserting an electron of spin + * up in a given orbital to a given determinant. + * + * @param[in] const std::bitset &st: Determinant to which we are adding + * an electron. + * @param[in] size_t orb: Index of the orbital where we are adding the electron. + * + * @returns double: Fermionic sign of the operation. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ +template +inline double GetInsertionUpSign(const std::bitset &st, size_t orb) { + std::bitset mask = full_mask(orb); + return ((st & mask).count() % 2 == 1 ? -1. : 1.); +} + +/** + * @brief Gets fermionic sign incurred by inserting an electron of spin + * down in a given orbital to a given determinant. + * + * @param[in] const std::bitset &st: Determinant to which we are adding + * an electron. + * @param[in] size_t orb: Index of the orbital where we are adding the electron. + * + * @returns double: Fermionic sign of the operation. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ +template +inline double GetInsertionDoSign(const std::bitset &st, size_t orb) { + std::bitset mask = full_mask(orb + nbits / 2); + return ((st & mask).count() % 2 == 1 ? -1. : 1.); +} + +/** + * @brief Routine to compute single diagonal Green's function element. + * Essentially, evaluates the resolvent + * G(w) = + * using one-band Lanczos and continuous fraction representation. + * + * @param [in] const VectorXd &state_0: Reference state, for which to evaluate + * the resolvent. + * @param [in] const MatOp &H: Matrix operator representing the effective + * Hamiltonian. + * @param [in] const std::vector > &freqs: Frequency grid + * over which to evaluate the resolvent. + * @param [inout] std::vector > &gf: On successful exit, + * green's function along the frequency grid. + * @param [in] int nLanIts: Max. number of Lanczos iterations. + * @param [in] bool saveABtofile: If true, save the alpha and beta parameters + * from the Lanczos calculation to file. + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ +template +void GF_Diag(const VectorXd &state_0, const MatOp &H, + const std::vector> &freqs, + std::vector> &gf, double E0, bool ispart, + int nLanIts = 1000, bool saveABtofile = false, + std::string fpref = "") { + // FIRST, WE HAVE TO COMPUTE THE LANCZOS alphas AND betas + double tol = 1.E-6; + std::vector alphas, betas; + + MyLanczos(state_0, H, nLanIts, alphas, betas, tol); + + int kry_size = 0; + for(int i = 1; i < nLanIts; i++) { + if(abs(betas[i]) <= tol) break; + kry_size++; } - /** - * @brief Gets fermionic sign incurred by inserting an electron of spin - * down in a given orbital to a given determinant. - * - * @param[in] const std::bitset &st: Determinant to which we are adding - * an electron. - * @param[in] size_t orb: Index of the orbital where we are adding the electron. - * - * @returns double: Fermionic sign of the operation. - * - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ - template - inline double GetInsertionDoSign( const std::bitset &st, size_t orb ) - { - std::bitset mask = full_mask( orb + nbits/2 ); - return ((st & mask).count() % 2 == 1 ? -1. : 1.); + double sign = ispart ? -1. : 1.; + + if(saveABtofile) { + std::ofstream ofile(fpref + "alphas.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + for(int i = 0; i <= kry_size; i++) + ofile << std::scientific << alphas[i] << std::endl; + ofile.close(); + ofile.open(fpref + "betas.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + for(int i = 0; i <= kry_size; i++) + ofile << std::scientific << betas[i] << std::endl; + ofile.close(); } - /** - * @brief Routine to compute single diagonal Green's function element. - * Essentially, evaluates the resolvent - * G(w) = - * using one-band Lanczos and continuous fraction representation. - * - * @param [in] const VectorXd &state_0: Reference state, for which to evaluate - * the resolvent. - * @param [in] const MatOp &H: Matrix operator representing the effective - * Hamiltonian. - * @param [in] const std::vector > &freqs: Frequency grid over which to evaluate the - * resolvent. - * @param [inout] std::vector > &gf: On successful exit, green's function along the - * frequency grid. - * @param [in] int nLanIts: Max. number of Lanczos iterations. - * @param [in] bool saveABtofile: If true, save the alpha and beta parameters - * from the Lanczos calculation to file. - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ - template - void GF_Diag( - const VectorXd &state_0, - const MatOp &H, - const std::vector > &freqs, - std::vector > &gf, - double E0, - bool ispart, - int nLanIts = 1000, - bool saveABtofile = false, - std::string fpref = ""){ - - //FIRST, WE HAVE TO COMPUTE THE LANCZOS alphas AND betas - double tol = 1.E-6; - std::vector alphas, betas; - - - MyLanczos(state_0, H, nLanIts, alphas, betas, tol); - - int kry_size = 0; - for(int i = 1; i < nLanIts; i++){ - if(abs(betas[i]) <= tol) break; - kry_size++; - } - - double sign = ispart ? -1. : 1.; - - if( saveABtofile ) - { - std::ofstream ofile( fpref + "alphas.dat", std::ios::out); - ofile.precision( dbl::max_digits10 ); - for(int i = 0; i <= kry_size; i++) ofile << std::scientific << alphas[i] << std::endl; - ofile.close(); - ofile.open(fpref + "betas.dat", std::ios::out); - ofile.precision( dbl::max_digits10 ); - for(int i = 0; i <= kry_size; i++) ofile << std::scientific << betas[i] << std::endl; - ofile.close(); - } - - //FINALLY, WE CAN COMPUTE THE GREEN'S FUNCTION - gf.clear(); - gf.resize(freqs.size(), std::complex(0.,0.)); - - #pragma omp parallel for - for (int indx_w = 0; indx_w < freqs.size(); indx_w++){ - gf[indx_w] = betas[kry_size] * betas[kry_size] / (freqs[indx_w] + sign * ( alphas[kry_size] - E0 ) ); - for(int i = kry_size - 1; i >= 0; i--) gf[indx_w] = betas[i] * betas[i] / (freqs[indx_w] + sign * ( alphas[i] - E0 ) - gf[indx_w]); //SINCE I CHOSE betas[0] = normpsi^2 + // FINALLY, WE CAN COMPUTE THE GREEN'S FUNCTION + gf.clear(); + gf.resize(freqs.size(), std::complex(0., 0.)); + +#pragma omp parallel for + for(int indx_w = 0; indx_w < freqs.size(); indx_w++) { + gf[indx_w] = betas[kry_size] * betas[kry_size] / + (freqs[indx_w] + sign * (alphas[kry_size] - E0)); + for(int i = kry_size - 1; i >= 0; i--) + gf[indx_w] = betas[i] * betas[i] / + (freqs[indx_w] + sign * (alphas[i] - E0) - + gf[indx_w]); // SINCE I CHOSE betas[0] = normpsi^2 + } +} + +/** + * @brief Class for comparing two determinants, to use in sorting routines. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ +template +class BitSetComparator { + public: + bool operator()(const std::bitset &c1, + const std::bitset &c2) const { + return bitset_less(c1, c2); + } +}; + +/** + * @brief Routine to build basis to compute the basis for Green's function + * calculation on the state |wfn> considering orbital orb. Templated + * to allow for differente slater determinant implementations (thinking + * beyond ED). + * + * @tparam class DetType: Slater determiant type. Should implement functions to + * check for orbital occupation, returning state bitstring and finding single + * excitations accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second + * quatization, should allow for basic bit operations, and being an index in a + * dictionary. + * + * @param [in] int orb: Orbital index for the Green's function basis. + * @param [in] bool sp_up: If true, the orbital is spin up, otherwise it's spin + * down. + * @param [in] bool is_part: If true, compute GF basis for particle sector + * (particle addition), otherwise compute it for hole sector (particle removal). + * @param [in] const VectorXd: Coefficient of the wave function describing the + * state whose Green's function we are computing. + * @param [in] const std::vector &old_basis: Basis of determinants + * describing the wave function wfn. + * @param [out] std::vector &new_basis: On return, the built basis for + * the Green's function calculation. + * @param [in] const std::vector &occs: Occupation numbers of all + * orbitals. Used to define active spaces. + * @param [in] const GFSettings &settings: Includes input parameters, in + * particular: o) double asThres: Threshold for the occupation numbers to define + * the active space. If 0+asThres <= occ[i] <= 2 - asThres, then the orbital i + * is added into the active space. o) double GFseedThreshold: Threshold to + * determine from which determinants to get excitations in the basis + * construction. o) int tot_SD: Number of layers of single excitations to build + * the basis. o) size_t trunc_size: Max. size for the Green's function basis. + * + * @author Carlos Mejuto Zaera + * @date 28/01/2022 + */ +template +void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, + const std::vector> &old_basis, + std::vector> &new_basis, + const std::vector &occs, + const GFSettings &settings) { + // CARLOS: BUILDS BASIS FOR THE ADD SPACE NEEDED TO DESCRIBE THE DIAGONAL + // PARTICLE GF ELEMENT OF ORBITAL orb. + + size_t norbs = settings.norbs; + size_t trunc_size = settings.trunc_size; + int tot_SD = settings.tot_SD; + double GFseedThreshold = settings.GFseedThres; + double asThres = settings.asThres; + + std::cout << "COMPUTING GF SPACE IN *" << (is_part ? "PARTICLE" : "HOLE") + << "* SECTOR FOR ORBITAL " << orb << ", WITH SPIN *" + << (sp_up ? "UP" : "DOWN") << "*" << std::endl; + + time_t loop1 = time(NULL); + auto loop1C = Clock::now(); + size_t ndets = old_basis.size(); + size_t cgf = -1; + size_t sporb = sp_up ? orb : orb + nbits / 2; + std::bitset uni_string; + std::vector> founddets; + founddets.reserve(trunc_size); + std::map, size_t, BitSetComparator> founddet_pos, + basedet_pos; + typename std::map, size_t, + BitSetComparator>::iterator it; + // ACTIVE SPACE + std::vector as_orbs; + for(size_t i = 0; i < occs.size(); i++) { + if(occs[i] >= asThres && occs[i] <= (1. - asThres)) as_orbs.push_back(i); + } + std::cout << "ACTIVE SPACE: ["; + for(int iii = 0; iii < as_orbs.size(); iii++) + std::cout << as_orbs[iii] << ", "; + std::cout << "]" << std::endl; + + // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS + for(size_t iii = 0; iii < ndets; iii++) basedet_pos[old_basis[iii]] = iii; + + // LOOP OVER ALL STATES IN THE BASIS AND BUILD THE BASIS + for(size_t iii = 0; iii < ndets; iii++) { + size_t norb1 = orb; + // CHECK WHETHER IT CORRESPONDS TO this GF: a_i^+|wfn> OR a_i|wfn> + bool ingf = false; + if(is_part && !old_basis[iii][sporb]) // PARTICLE + ingf = true; + else if(!is_part && old_basis[iii][sporb]) // HOLE + ingf = true; + if(ingf) { + // YES, ADD TO LIST + std::bitset temp = old_basis[iii]; + temp.flip(sporb); + it = founddet_pos.find(temp); + if(it == founddet_pos.end()) { + cgf++; + founddet_pos[temp] = cgf; + founddets.push_back(temp); + } } - } - - /** - * @brief Class for comparing two determinants, to use in sorting routines. - * - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ - template - class BitSetComparator { - public: - bool operator()(const std::bitset& c1, const std::bitset& c2) const - { - return bitset_less( c1, c2 ); + } + + // IF NO STATE FOUND, THIS BASIS IS EMPTY + if(cgf + 1 == 0) { + new_basis.resize(cgf + 1); + return; + } + // NOW, ADD SINGLE-DOUBLES. THIS AMOUNTS TO ADDING THE + // SINGLE EXCITATIONS ON TOP OF FOUNDDET + std::cout << "BEFORE ADDING SINGLE-DOUBLES, cgf = " << cgf << std::endl; + size_t orig_cgf = cgf; + + std::cout << "Nr. OF STATES: " << cgf + 1 << std::endl; + + size_t norb = orb; + VectorXd b = Eigen::VectorXd::Zero(cgf + 1); + // COMPUTE VECTOR b IN THE NEW BASIS + for(size_t ndet = 0; ndet < cgf + 1; ndet++) { + // CHECK, CAN ndet COME FROM ai^+|GS> / ai|wfn> WITH THE ORBITAL *orb? + bool fromwfn = false; + if(is_part && founddets[ndet][sporb]) + fromwfn = true; + else if(!is_part && !founddets[ndet][sporb]) + fromwfn = true; + if(fromwfn) { + // YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE DETERMINANT + // SPACE + std::bitset temp = founddets[ndet]; + temp.flip(sporb); + it = basedet_pos.find(temp); + if(it != basedet_pos.end()) { + // IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE + // THUS, IT CONTRIBUTES TO wfns1 + double sign = sp_up ? GetInsertionUpSign(temp, orb) + : GetInsertionDoSign(temp, orb); + double fac = wfn(it->second); + b(ndet) += fac * sign; } - }; - - /** - * @brief Routine to build basis to compute the basis for Green's function - * calculation on the state |wfn> considering orbital orb. Templated - * to allow for differente slater determinant implementations (thinking - * beyond ED). - * - * @tparam class DetType: Slater determiant type. Should implement functions to check - * for orbital occupation, returning state bitstring and finding single excitations - * accounting for active space structure. - * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, - * should allow for basic bit operations, and being an index in a dictionary. - * - * @param [in] int orb: Orbital index for the Green's function basis. - * @param [in] bool sp_up: If true, the orbital is spin up, otherwise it's spin - * down. - * @param [in] bool is_part: If true, compute GF basis for particle sector (particle addition), - * otherwise compute it for hole sector (particle removal). - * @param [in] const VectorXd: Coefficient of the wave function describing the - * state whose Green's function we are computing. - * @param [in] const std::vector &old_basis: Basis of determinants describing the - * wave function wfn. - * @param [out] std::vector &new_basis: On return, the built basis for the Green's - * function calculation. - * @param [in] const std::vector &occs: Occupation numbers of all orbitals. Used to define - * active spaces. - * @param [in] const GFSettings &settings: Includes input parameters, in particular: - * o) double asThres: Threshold for the occupation numbers to define the - * active space. If 0+asThres <= occ[i] <= 2 - asThres, then the orbital - * i is added into the active space. - * o) double GFseedThreshold: Threshold to determine from which determinants to get - * excitations in the basis construction. - * o) int tot_SD: Number of layers of single excitations to build the basis. - * o) size_t trunc_size: Max. size for the Green's function basis. - * - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ - template - void get_GF_basis_AS_1El( - int orb, - bool sp_up, - bool is_part, - const VectorXd &wfn, - const std::vector > &old_basis, - std::vector > &new_basis, - const std::vector &occs, - const GFSettings &settings) - { - //CARLOS: BUILDS BASIS FOR THE ADD SPACE NEEDED TO DESCRIBE THE DIAGONAL PARTICLE - //GF ELEMENT OF ORBITAL orb. - - size_t norbs = settings.norbs; - size_t trunc_size = settings.trunc_size; - int tot_SD = settings.tot_SD; - double GFseedThreshold = settings.GFseedThres; - double asThres = settings.asThres; - - std::cout << "COMPUTING GF SPACE IN *" << (is_part? "PARTICLE" : "HOLE") << "* SECTOR FOR ORBITAL " << orb << ", WITH SPIN *" << (sp_up ? "UP" : "DOWN") << "*" << std::endl; - - time_t loop1 = time(NULL); - auto loop1C = Clock::now(); - size_t ndets = old_basis.size(); - size_t cgf = -1; - size_t sporb = sp_up ? orb : orb + nbits / 2; - std::bitset uni_string; - std::vector > founddets; - founddets.reserve(trunc_size); - std::map, size_t, BitSetComparator > founddet_pos, basedet_pos; - typename std::map, size_t, BitSetComparator >::iterator it; - //ACTIVE SPACE - std::vector as_orbs; - for(size_t i = 0; i < occs.size(); i++){ - if(occs[i] >= asThres && occs[i] <= (1. - asThres)) as_orbs.push_back(i); } - std::cout << "ACTIVE SPACE: ["; - for(int iii = 0; iii < as_orbs.size(); iii++) std::cout << as_orbs[iii] << ", "; - std::cout << "]" << std::endl; - - //INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - for(size_t iii = 0; iii < ndets; iii++) - basedet_pos[old_basis[iii]] = iii; - - //LOOP OVER ALL STATES IN THE BASIS AND BUILD THE BASIS - for(size_t iii = 0; iii < ndets; iii++) - { - size_t norb1 = orb; - //CHECK WHETHER IT CORRESPONDS TO this GF: a_i^+|wfn> OR a_i|wfn> - bool ingf = false; - if( is_part && !old_basis[iii][sporb]) // PARTICLE - ingf = true; - else if( !is_part && old_basis[iii][sporb]) // HOLE - ingf = true; - if( ingf ) - { - //YES, ADD TO LIST - std::bitset temp = old_basis[iii]; - temp.flip(sporb); - it = founddet_pos.find(temp); - if(it == founddet_pos.end()) - { + } + + std::cout << "GOING TO ITERATIVELY ADD SINGLES AND DOUBLES!" << std::endl; + std::cout << "--BEFORE ADDING SINGLE-DOUBLES, nterms = " << cgf + 1 + << std::endl; + size_t orig_nterms = cgf + 1; + + int startSD = 0, endSD = orig_nterms - 1, GFseed = 0; + for(int nSD = 1; nSD <= tot_SD && cgf <= trunc_size; nSD++) { + for(int iii = startSD; iii <= endSD && cgf <= trunc_size; iii++) { + if(nSD == 1) + if(abs(b(iii)) < GFseedThreshold) + continue; // FROM THE ORIGINAL SET, ONLY CONSIDER THE MOST IMPORTANT + // ONES + // GET SINGLES + GFseed += (nSD == 1) ? 1 : 0; + std::vector> tdets; + generate_singles_spin_as(norbs, founddets[iii], tdets, as_orbs); + + for(size_t jjj = 0; jjj < tdets.size(); jjj++) { + it = founddet_pos.find(tdets[jjj]); + if(it == + founddet_pos.end()) { // FOR ZERO STATES ONLY, ADD: and matches > 0 cgf++; - founddet_pos[temp] = cgf; - founddets.push_back(temp); + founddet_pos[tdets[jjj]] = cgf; + founddets.push_back(tdets[jjj]); } } } - - //IF NO STATE FOUND, THIS BASIS IS EMPTY - if(cgf+1 == 0) - { - new_basis.resize(cgf+1); - return; - } - //NOW, ADD SINGLE-DOUBLES. THIS AMOUNTS TO ADDING THE - //SINGLE EXCITATIONS ON TOP OF FOUNDDET - std::cout << "BEFORE ADDING SINGLE-DOUBLES, cgf = " << cgf << std::endl; - size_t orig_cgf = cgf; - - std::cout << "Nr. OF STATES: " << cgf+1 << std::endl; - - size_t norb = orb; - VectorXd b = Eigen::VectorXd::Zero(cgf+1); - //COMPUTE VECTOR b IN THE NEW BASIS - for(size_t ndet = 0; ndet < cgf+1; ndet++) - { - //CHECK, CAN ndet COME FROM ai^+|GS> / ai|wfn> WITH THE ORBITAL *orb? - bool fromwfn = false; - if( is_part && founddets[ndet][sporb]) - fromwfn = true; - else if ( !is_part && !founddets[ndet][sporb] ) - fromwfn = true; - if( fromwfn ) - { - //YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE DETERMINANT SPACE - std::bitset temp = founddets[ndet]; + startSD = endSD + 1; + endSD = cgf; + } + std::cout << "--AFTER CUTTING BY: " << GFseedThreshold + << ", GF-SPACE WITH GF SEED: " << GFseed + << ", WE HAVE STATES: " << cgf + 1 << std::endl; + + // NOW THAT WE FOUND THE BASIS, JUST STORE IT + new_basis.resize(cgf + 1); + new_basis.assign(founddets.begin(), founddets.end()); +} + +/** + * @brief Routine to prepare the wave functions for the Lanczos computation of + * the Green's function (be it Band Lanczos or regular Lanczos). + * + * @tparam class DetType: Slater determiant type. Should implement functions to + * check for orbital occupation, returning state bitstring and finding single + * excitations accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second + * quatization, should allow for basic bit operations, and being an index in a + * dictionary. + * + * @param [in] const VectorXd &base_wfn: Wave function from which to compute the + * Green's function. + * @param [in] const std::vector &GF_orbs: Orbital indices for which to + * compute the GF. + * @param [in] const std::vector &is_up: Flags regarding the spin of each + * orbital. True means spin up, false means spin down. + * @param [in] const std::vector &base_dets: Vector of the Slater + * determinants in the basis. + * @param [in] const std::vector &GF_gets: Vector of the Slater + * determinants in the GF basis. + * @param [in] bool is_part: Flag to determine GF sector. For true, we are in + * the particle sector. For false we are in the hole sector. + * @param [out] std::vector& todelete: On return, contains a list of the + * orbitals for which the Green's function vector ai/ai+|base_wfn> vanishes, and + * hence is eliminated from the list of wave functions. + * @param [in] double zero_thresh: Threshold to decide whether a computed vector + * is zero or not, judging by the magnitude of the norm. + * + * @author Carlos Mejuto Zaera + * @date 01/02/2022 + */ +template +std::vector> BuildWfn4Lanczos( + const VectorXd &base_wfn, const std::vector &GF_orbs, + const std::vector &is_up, + const std::vector> &base_dets, + const std::vector> &GF_dets, bool is_part, + std::vector &todelete, double zero_thresh = 1.E-7) { + // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS + std::map, size_t, BitSetComparator> base_dets_pos; + for(size_t iii = 0; iii < base_dets.size(); iii++) + base_dets_pos[base_dets[iii]] = iii; + + // PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS + size_t nterms = GF_dets.size(); + std::vector> wfns(GF_orbs.size(), + std::vector(nterms, 0.)); + for(size_t iorb = 0; iorb < GF_orbs.size(); iorb++) { + int orb = GF_orbs[iorb]; + bool sp_up = is_up[iorb]; + // int sporb = sp_up ? orb : orb + Norbs; + int sporb = sp_up ? orb : orb + nbits / 2; + // BUILD THE WAVEFUNCTION FOR ORBITAL orb + for(size_t ndet = 0; ndet < nterms; ndet++) { + // CHECK, CAN ndet COME FROM ai^+|GS> *OR* ai|GS> WITH THE ORBITAL orb? + bool in_gf = false; + if(is_part && GF_dets[ndet][sporb]) // PARTICLE + in_gf = true; + else if(!is_part && !GF_dets[ndet][sporb]) // HOLE + in_gf = true; + if(in_gf) { + // YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE + // DETERMINANT SPACE + std::bitset temp(GF_dets[ndet]); temp.flip(sporb); - it = basedet_pos.find(temp); - if(it != basedet_pos.end()){ - //IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE - //THUS, IT CONTRIBUTES TO wfns1 - double sign = sp_up ? GetInsertionUpSign( temp, orb ) : GetInsertionDoSign( temp, orb ); - double fac = wfn(it->second); - b(ndet) += fac * sign; + typename std::map, size_t, + BitSetComparator>::const_iterator it = + base_dets_pos.find(temp); + if(it != base_dets_pos.end()) { + // IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE + // THUS, IT CONTRIBUTES TO wfns1 + double sign = sp_up ? GetInsertionUpSign(temp, orb) + : GetInsertionDoSign(temp, orb); + double fac = base_wfn(it->second); + wfns[iorb][ndet] += fac * sign; } } } - - std::cout << "GOING TO ITERATIVELY ADD SINGLES AND DOUBLES!" << std::endl; - std::cout << "--BEFORE ADDING SINGLE-DOUBLES, nterms = " << cgf+1 << std::endl; - size_t orig_nterms = cgf+1; - - int startSD = 0, endSD = orig_nterms-1, GFseed = 0; - for(int nSD = 1; nSD <= tot_SD && cgf <= trunc_size; nSD++){ - for(int iii = startSD; iii <= endSD && cgf <= trunc_size; iii++){ - if(nSD == 1) if(abs(b(iii)) < GFseedThreshold) continue; //FROM THE ORIGINAL SET, ONLY CONSIDER THE MOST IMPORTANT ONES - //GET SINGLES - GFseed += (nSD == 1) ? 1 : 0; - std::vector > tdets; - generate_singles_spin_as( norbs, founddets[iii], tdets, as_orbs ); - - for(size_t jjj = 0; jjj < tdets.size(); jjj++){ - it = founddet_pos.find(tdets[jjj]); - if(it == founddet_pos.end()){ // FOR ZERO STATES ONLY, ADD: and matches > 0 - cgf++; - founddet_pos[tdets[jjj]] = cgf; - founddets.push_back(tdets[jjj]); - } - } - } - startSD = endSD + 1; - endSD = cgf; - } - std::cout << "--AFTER CUTTING BY: " << GFseedThreshold << ", GF-SPACE WITH GF SEED: " << GFseed << ", WE HAVE STATES: " << cgf+1 << std::endl; - - //NOW THAT WE FOUND THE BASIS, JUST STORE IT - new_basis.resize(cgf+1); - new_basis.assign(founddets.begin(), founddets.end()); } - /** - * @brief Routine to prepare the wave functions for the Lanczos computation of the Green's function (be it - * Band Lanczos or regular Lanczos). - * - * @tparam class DetType: Slater determiant type. Should implement functions to check - * for orbital occupation, returning state bitstring and finding single excitations - * accounting for active space structure. - * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, - * should allow for basic bit operations, and being an index in a dictionary. - * - * @param [in] const VectorXd &base_wfn: Wave function from which to compute the Green's function. - * @param [in] const std::vector &GF_orbs: Orbital indices for which to compute the GF. - * @param [in] const std::vector &is_up: Flags regarding the spin of each orbital. True means - * spin up, false means spin down. - * @param [in] const std::vector &base_dets: Vector of the Slater determinants in the basis. - * @param [in] const std::vector &GF_gets: Vector of the Slater determinants in the GF basis. - * @param [in] bool is_part: Flag to determine GF sector. For true, we are in the particle sector. For - * false we are in the hole sector. - * @param [out] std::vector& todelete: On return, contains a list of the orbitals for which the - * Green's function vector ai/ai+|base_wfn> vanishes, and hence is - * eliminated from the list of wave functions. - * @param [in] double zero_thresh: Threshold to decide whether a computed vector is zero or not, judging by - * the magnitude of the norm. - * - * @author Carlos Mejuto Zaera - * @date 01/02/2022 - */ - template - std::vector> BuildWfn4Lanczos( - const VectorXd &base_wfn, - const std::vector &GF_orbs, - const std::vector &is_up, - const std::vector > &base_dets, - const std::vector > &GF_dets, - bool is_part, - std::vector &todelete, - double zero_thresh = 1.E-7 ) - { - //INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - std::map, size_t, BitSetComparator > base_dets_pos; - for(size_t iii = 0; iii < base_dets.size(); iii++) - base_dets_pos[base_dets[iii]] = iii; - - //PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS - size_t nterms = GF_dets.size(); - std::vector> wfns(GF_orbs.size(), std::vector(nterms,0.)); - for(size_t iorb = 0; iorb < GF_orbs.size(); iorb++){ - int orb = GF_orbs[iorb]; - bool sp_up = is_up[iorb]; - //int sporb = sp_up ? orb : orb + Norbs; - int sporb = sp_up ? orb : orb + nbits/2; - //BUILD THE WAVEFUNCTION FOR ORBITAL orb - for(size_t ndet = 0; ndet < nterms; ndet++){ - //CHECK, CAN ndet COME FROM ai^+|GS> *OR* ai|GS> WITH THE ORBITAL orb? - bool in_gf = false; - if( is_part && GF_dets[ndet][sporb]) // PARTICLE - in_gf = true; - else if( !is_part && !GF_dets[ndet][sporb] ) // HOLE - in_gf = true; - if( in_gf ) - { - //YES, CHECK WHETHER THE GENERATING STATE COMES FROM THE BASE DETERMINANT SPACE - std::bitset temp( GF_dets[ndet] ); - temp.flip(sporb); - typename std::map, size_t, BitSetComparator >::const_iterator it = base_dets_pos.find(temp); - if(it != base_dets_pos.end()){ - //IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE - //THUS, IT CONTRIBUTES TO wfns1 - double sign = sp_up ? GetInsertionUpSign( temp, orb ) : GetInsertionDoSign( temp, orb ); - double fac = base_wfn(it->second); - wfns[iorb][ndet] += fac * sign; - } - } - } - } + // CHECK WHETHER ANY OF THE VECTORS IS EXACTLY ZERO. IF SO, TAKE IT OUT! + todelete.clear(); + for(int orb_indx = 0; orb_indx < GF_orbs.size(); orb_indx++) { + double st_nrm = 0.; +#pragma omp declare reduction(Vsum:double \ + : omp_out = omp_out + omp_in) \ + initializer(omp_priv = 0.) +#pragma omp parallel for reduction(Vsum : st_nrm) + for(size_t iii = 0; iii < nterms; iii++) + st_nrm += wfns[orb_indx][iii] * wfns[orb_indx][iii]; + if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); + } + for(int i = 0; i < todelete.size(); i++) + wfns.erase(wfns.begin() + todelete[i] - i); + std::cout << "ORBITALS WITH NO CORRESPONING ADD-VECTOR: ["; + for(int i = 0; i < todelete.size(); i++) std::cout << todelete[i] << ", "; + std::cout << "]" << std::endl; - //CHECK WHETHER ANY OF THE VECTORS IS EXACTLY ZERO. IF SO, TAKE IT OUT! - todelete.clear(); - for(int orb_indx = 0; orb_indx < GF_orbs.size(); orb_indx++){ - double st_nrm = 0.; - #pragma omp declare reduction \ - (Vsum:double:omp_out=omp_out+omp_in)\ - initializer(omp_priv=0.) - #pragma omp parallel for reduction (Vsum:st_nrm) - for(size_t iii = 0; iii < nterms; iii++) st_nrm += wfns[orb_indx][iii] * wfns[orb_indx][iii]; - if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); - } - for(int i = 0; i < todelete.size(); i++) wfns.erase(wfns.begin() + todelete[i] - i); - std::cout << "ORBITALS WITH NO CORRESPONING ADD-VECTOR: ["; - for(int i = 0; i < todelete.size(); i++) std::cout << todelete[i] << ", "; - std::cout << "]" << std::endl; - - return wfns; + return wfns; +} + +/** + * @brief Routine to write Green's function to file. It stores the frequency + * grid together with the full GF matrix. Also, in case of a multi-orbitla GF, + * it stores the orbital indices in a separate file. + * + * @param [in] const std::vector > + * > > &GF: GF to store. Written as GF[freq-axis][orb1][orb2]. + * @param [in] const std::vector > &ws: Frequency grid. + * @param [in] const std::vector &GF_orbs: Orbital indices for the Green's + * function, as requested originally in the GF computation. Some of them may not + * have been actually used, if the corresponding ai/ai+|wfn0> states were zero. + * @param [in] const std::vector &todelete: List of deleted orbital indices + * in the case just described. + * @param [in] const bool is_part: Flag to label GF file depending on whether it + * is a particle GF (True), or a hole GF (False). + * + * @author Carlos Mejuto Zaera + * @date 02/02/2022 + */ +void write_GF( + const std::vector>>> &GF, + const std::vector> &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part); + +/** + * @brief Routine to run Green's function calculation at zero temperature from + * some input ref. wave function. Allows for choosing to compute particle/hole + * GF, using normal/band Lanczos, and simplifying the calculation by virtue of + * exploiting some active space structure. + * + * @tparam class DetType: Slater determiant type. Should implement functions to + * check for orbital occupation, returning state bitstring and finding single + * excitations accounting for active space structure. + * @tparam DetStateType: State bitstring type. Encodes fermionic state in second + * quatization, should allow for basic bit operations, and being an index in a + * dictionary. + * + * @param [out] std::vector > > >: + * On output, contains the computed Green's function, in format + * GF[freq.][orb1][orb2]. + * @param [in] const VectorXd &wfn0: Reference wave function from which to + * compute the GF. + * @param [in] const FermionHamil &H: Fermionic Hamiltonian defining the system. + * @param [in] const std::vector &base_dets: Basis of Slater + * determinants for the description of wfn0. + * @param [in] const double energ: Energy of reference state wfn0. + * @param [in] const bool is_part: Flag to determine GF sector. For true, we are + * in the particle sector. Otherwise, we are in the hole sector. + * @param [in] const std::vector > &ws: Frequency grid over + * which to compute the Green's function. + * @param [in] const std::vector &occs: Occupation numbers for each + * orbital. + * @param [in] const GFSettings &settings: Structure with various parameters for + * Green's function calculation. + * + * @author Carlos Mejuto Zaera + * @date 01/02/2022 + */ +template +void RunGFCalc(std::vector>>> &GF, + const VectorXd &wfn0, HamiltonianGenerator &Hgen, + const std::vector> &base_dets, + const double energ, const bool is_part, + const std::vector> &ws, + const std::vector &occs, const GFSettings &settings) { + // READ INPUT + const size_t trunc_size = settings.trunc_size; + const int tot_SD = settings.tot_SD; + const double GFseedThreshold = settings.GFseedThres; + const double asThres = settings.asThres; + const bool use_bandLan = settings.use_bandLan; + const std::vector GF_orbs_basis = settings.GF_orbs_basis; + const std::vector GF_orbs_comp = settings.GF_orbs_comp; + const std::vector is_up_basis = settings.is_up_basis; + const std::vector is_up_comp = settings.is_up_comp; + + double h_el_tol = 1.E-6; + int nLanIts = settings.nLanIts; + bool print = settings.print; + bool writeGF = settings.writeGF; + bool saveGFmats = settings.saveGFmats; + + time_t loop1 = time(NULL), loop2 = time(NULL); + auto loop1C = Clock::now(), loop2C = Clock::now(); + size_t ndets = base_dets.size(); + + // FIRST, BUILD THE BASIS SEQUENTIALLY BY FORMING THE BASES OF EACH ORBITAL + // AND ADDING THEM TOGETHER + std::vector> gf_dets, gf_dets_tmp; + for(size_t iorb = 0; iorb < GF_orbs_basis.size(); iorb++) { + get_GF_basis_AS_1El(GF_orbs_basis[iorb], is_up_basis[iorb], + is_part, wfn0, base_dets, gf_dets_tmp, + occs, settings); + gf_dets.insert(gf_dets.end(), gf_dets_tmp.begin(), gf_dets_tmp.end()); + + gf_dets_tmp.clear(); + + auto comparator = [](const auto &x, const auto &y) { + return bitset_less(x, y); + }; +#ifdef MACIS_USE_BOOST_SORT + boost::sort::pdqsort_branchless +#else + std::sort +#endif + (gf_dets.begin(), gf_dets.end(), comparator); + + typename std::vector>::iterator b_it = + std::unique(gf_dets.begin(), gf_dets.end()); + gf_dets.resize(std::distance(gf_dets.begin(), b_it)); + std::cout << "---> BASIS HAS NOW: " << gf_dets.size() + << " ELMENTS!! BY ORBITAL " << iorb + 1 << "/" + << GF_orbs_basis.size() << std::endl; } - /** - * @brief Routine to write Green's function to file. It stores the frequency grid together with - * the full GF matrix. Also, in case of a multi-orbitla GF, it stores the orbital - * indices in a separate file. - * - * @param [in] const std::vector > > > &GF: - * GF to store. Written as GF[freq-axis][orb1][orb2]. - * @param [in] const std::vector > &ws: Frequency grid. - * @param [in] const std::vector &GF_orbs: Orbital indices for the Green's function, as requested - * originally in the GF computation. Some of them may not have been actually - * used, if the corresponding ai/ai+|wfn0> states were zero. - * @param [in] const std::vector &todelete: List of deleted orbital indices in the case just described. - * @param [in] const bool is_part: Flag to label GF file depending on whether it is a particle - * GF (True), or a hole GF (False). - * - * @author Carlos Mejuto Zaera - * @date 02/02/2022 - */ - void write_GF( const std::vector > > > &GF, const std::vector > &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part ); - - /** - * @brief Routine to run Green's function calculation at zero temperature from some input ref. wave function. - * Allows for choosing to compute particle/hole GF, using normal/band Lanczos, - * and simplifying the calculation by virtue of exploiting some active space structure. - * - * @tparam class DetType: Slater determiant type. Should implement functions to check - * for orbital occupation, returning state bitstring and finding single excitations - * accounting for active space structure. - * @tparam DetStateType: State bitstring type. Encodes fermionic state in second quatization, - * should allow for basic bit operations, and being an index in a dictionary. - * - * @param [out] std::vector > > >: On output, - * contains the computed Green's function, in format GF[freq.][orb1][orb2]. - * @param [in] const VectorXd &wfn0: Reference wave function from which to compute the GF. - * @param [in] const FermionHamil &H: Fermionic Hamiltonian defining the system. - * @param [in] const std::vector &base_dets: Basis of Slater determinants for the - * description of wfn0. - * @param [in] const double energ: Energy of reference state wfn0. - * @param [in] const bool is_part: Flag to determine GF sector. For true, we are in - * the particle sector. Otherwise, we are in the hole sector. - * @param [in] const std::vector > &ws: Frequency grid over which to compute the Green's function. - * @param [in] const std::vector &occs: Occupation numbers for each orbital. - * @param [in] const GFSettings &settings: Structure with various parameters for Green's function calculation. - * - * @author Carlos Mejuto Zaera - * @date 01/02/2022 - */ - template - void RunGFCalc( - std::vector > > > &GF, - const VectorXd &wfn0, - HamiltonianGenerator &Hgen, - const std::vector > &base_dets, - const double energ, - const bool is_part, - const std::vector >& ws, - const std::vector & occs, - const GFSettings &settings) - { - - // READ INPUT - const size_t trunc_size = settings.trunc_size; - const int tot_SD = settings.tot_SD; - const double GFseedThreshold = settings.GFseedThres; - const double asThres = settings.asThres; - const bool use_bandLan = settings.use_bandLan; - const std::vector GF_orbs_basis = settings.GF_orbs_basis; - const std::vector GF_orbs_comp = settings.GF_orbs_comp; - const std::vector is_up_basis = settings.is_up_basis; - const std::vector is_up_comp = settings.is_up_comp; - - double h_el_tol = 1.E-6; - int nLanIts = settings.nLanIts; - bool print = settings.print; - bool writeGF = settings.writeGF; - bool saveGFmats = settings.saveGFmats; - - time_t loop1 = time(NULL), loop2 = time(NULL); - auto loop1C = Clock::now(), loop2C = Clock::now(); - size_t ndets = base_dets.size(); - - //FIRST, BUILD THE BASIS SEQUENTIALLY BY FORMING THE BASES OF EACH ORBITAL AND - //ADDING THEM TOGETHER - std::vector > gf_dets, gf_dets_tmp; - for(size_t iorb = 0; iorb < GF_orbs_basis.size(); iorb++){ - get_GF_basis_AS_1El( GF_orbs_basis[iorb], is_up_basis[iorb], is_part, wfn0, base_dets, - gf_dets_tmp, occs, settings ); - gf_dets.insert( gf_dets.end(), gf_dets_tmp.begin(), - gf_dets_tmp.end() ); - - gf_dets_tmp.clear(); - - auto comparator = [](const auto& x, const auto& y) { - return bitset_less(x, y); - }; - #ifdef MACIS_USE_BOOST_SORT - boost::sort::pdqsort_branchless - #else - std::sort - #endif - ( gf_dets.begin(), gf_dets.end(), comparator); - - typename std::vector >::iterator b_it = std::unique(gf_dets.begin(), gf_dets.end()); - gf_dets.resize(std::distance(gf_dets.begin(), b_it)); - std::cout << "---> BASIS HAS NOW: " << gf_dets.size() << " ELMENTS!! BY ORBITAL " << iorb + 1 << "/" << GF_orbs_basis.size() << std::endl; + size_t nterms = gf_dets.size(); + std::cout << "---> FINAL ADD BASIS HAS " << nterms << " ELEMENTS" + << std::endl; + + loop1 = time(NULL); + loop1C = Clock::now(); + auto hamil = make_dist_csr_hamiltonian( + MPI_COMM_WORLD, gf_dets.begin(), gf_dets.end(), Hgen, h_el_tol); + loop2 = time(NULL); + loop2C = Clock::now(); + std::cout << std::setprecision(3) << "Building " + << (is_part ? "*PARTICLE*" : "*HOLE*") << " Hamiltonian: " + << double(std::chrono::duration_cast( + loop2C - loop1C) + .count()) / + 1000 + << std::endl; + // NOW, PERFORM THE BAND LANCZOS ON THE TRUNCATED SPACE + // WE ALREADY BUILT THE HAMILTONIANS + + if(nterms < nLanIts) nLanIts = nterms; + + // PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS + std::vector todelete; + std::vector> wfns = BuildWfn4Lanczos( + wfn0, GF_orbs_comp, is_up_comp, base_dets, gf_dets, is_part, todelete); + + // //ACTUALLY COMPUTE THE GF! + time_t GF_loop1 = time(NULL); + auto GF_loop1C = Clock::now(); + + if(use_bandLan) { + BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, print, + saveGFmats); + } else { + // DO SIMPLE LANCZOS FOR ALL GF ELEMENTS + SparsexDistSpMatOp hamil_wrap(hamil); + GF.resize(ws.size(), + std::vector>>( + wfns.size(), std::vector>( + wfns.size(), std::complex(0., 0.)))); + for(int i = 0; i < wfns.size(); i++) { + std::vector> tGF; + // DIAGONAL ELEMENT + std::cout << "DOING ELEMENT (" << i << ", " << i << ")" << std::endl; + VectorXd twfn = + Eigen::Map(wfns[i].data(), nterms); + std::string fpref_basis = is_part ? "particle" : "hole"; + std::string fpref = + fpref_basis + "_" + std::to_string(i) + "_" + std::to_string(i); + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, + nLanIts, saveGFmats, fpref); + for(int iw = 0; iw < ws.size(); iw++) GF[iw][i][i] = tGF[iw]; + for(int j = i + 1; j < wfns.size(); j++) { + // OFF DIAGONAL ELEMENTS + std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; + for(size_t iii = 0; iii < nterms; iii++) + twfn(iii) = wfns[i][iii] + wfns[j][iii]; + fpref = fpref_basis + "_" + std::to_string(i) + "_" + + std::to_string(j) + "_a"; + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, + nLanIts, saveGFmats, fpref); + for(int iw = 0; iw < ws.size(); iw++) GF[iw][i][j] += 0.25 * tGF[iw]; + for(size_t iii = 0; iii < nterms; iii++) + twfn(iii) = wfns[i][iii] - wfns[j][iii]; + fpref = fpref_basis + "_" + std::to_string(i) + "_" + + std::to_string(j) + "_b"; + GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, + nLanIts); + for(int iw = 0; iw < ws.size(); iw++) { + GF[iw][i][j] -= 0.25 * tGF[iw]; + GF[iw][j][i] = GF[iw][i][j]; + } + } } - - size_t nterms = gf_dets.size(); - std::cout << "---> FINAL ADD BASIS HAS " << nterms << " ELEMENTS" << std::endl; - - loop1 = time(NULL); - loop1C = Clock::now(); - auto hamil = make_dist_csr_hamiltonian( MPI_COMM_WORLD, gf_dets.begin(), - gf_dets.end(), Hgen, h_el_tol ); - loop2 = time(NULL); - loop2C = Clock::now(); - std::cout << std::setprecision(3)<<"Building " << (is_part ? "*PARTICLE*" : "*HOLE*") << " Hamiltonian: " << double(std::chrono::duration_cast(loop2C - loop1C).count())/1000 << std::endl; - //NOW, PERFORM THE BAND LANCZOS ON THE TRUNCATED SPACE - //WE ALREADY BUILT THE HAMILTONIANS - - if(nterms < nLanIts) - nLanIts = nterms; - - //PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS - std::vector todelete; - std::vector> wfns = BuildWfn4Lanczos( wfn0, GF_orbs_comp, is_up_comp, - base_dets, gf_dets, is_part, todelete ); - - // //ACTUALLY COMPUTE THE GF! - time_t GF_loop1 = time(NULL); - auto GF_loop1C = Clock::now(); - - if( use_bandLan ) - { - BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, print, saveGFmats); - } - else - { - //DO SIMPLE LANCZOS FOR ALL GF ELEMENTS - SparsexDistSpMatOp hamil_wrap( hamil ); - GF.resize(ws.size(), std::vector > >(wfns.size(), std::vector >(wfns.size(), std::complex(0.,0.)) )); - for(int i = 0; i < wfns.size(); i++) - { - std::vector > tGF; - //DIAGONAL ELEMENT - std::cout << "DOING ELEMENT (" << i << ", " << i << ")" << std::endl; - VectorXd twfn = Eigen::Map(wfns[i].data(), nterms); - std::string fpref_basis = is_part ? "particle" : "hole"; - std::string fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( i ); - GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); - for(int iw = 0; iw < ws.size(); iw++) - GF[iw][i][i] = tGF[iw]; - for(int j = i+1; j < wfns.size(); j++) - { - //OFF DIAGONAL ELEMENTS - std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; - for(size_t iii = 0; iii < nterms; iii++) - twfn(iii) = wfns[i][iii] + wfns[j][iii]; - fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( j ) + "_a"; - GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); - for(int iw = 0; iw < ws.size(); iw++) - GF[iw][i][j] += 0.25 * tGF[iw]; - for(size_t iii = 0; iii < nterms; iii++) - twfn(iii) = wfns[i][iii] - wfns[j][iii]; - fpref = fpref_basis + "_" + std::to_string( i ) + "_" + std::to_string( j ) + "_b"; - GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts); - for(int iw = 0; iw < ws.size(); iw++) - { - GF[iw][i][j] -= 0.25 * tGF[iw]; - GF[iw][j][i] = GF[iw][i][j]; - } - } - } - } - - time_t GF_loop2 = time(NULL); - auto GF_loop2C = Clock::now(); - std::cout << std::setprecision(3)<<"Computing GF with " << (use_bandLan ? " *Band Lanczos*" : "*Regular Lanczos*") << double(std::chrono::duration_cast(GF_loop2C - GF_loop1C).count())/1000 << std::endl; - - if( writeGF ) - write_GF( GF, ws, GF_orbs_comp, todelete, is_part ); } -}// namespace macis + time_t GF_loop2 = time(NULL); + auto GF_loop2C = Clock::now(); + std::cout << std::setprecision(3) << "Computing GF with " + << (use_bandLan ? " *Band Lanczos*" : "*Regular Lanczos*") + << double(std::chrono::duration_cast( + GF_loop2C - GF_loop1C) + .count()) / + 1000 + << std::endl; + + if(writeGF) write_GF(GF, ws, GF_orbs_comp, todelete, is_part); +} + +} // namespace macis diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp index f3e721d6..a5bb00ad 100644 --- a/include/macis/gf/inn_prods.hpp +++ b/include/macis/gf/inn_prods.hpp @@ -10,7 +10,7 @@ * @file inn_prods.h++ * * @brief Inner product routines between vectors. - * + * * @author Carlos Mejuto Zaera * @date 02/06/2023 */ @@ -19,98 +19,107 @@ #include #include -namespace macis -{ - /** - * @brief Simple inner product routine between two std::vector - * - * @param [in] const std::vecotr& vecR - * @param [in] const std::vecotr& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - inline double MyInnProd(const std::vector& vecR, const std::vector& vecL){ - //SIMPLE INNER PRODUCT ROUTINE - double res = 0.; - #pragma omp declare reduction \ - (Vsum:double:omp_out=omp_out+omp_in)\ - initializer(omp_priv=0.) - #pragma omp parallel for reduction (Vsum:res) - for(size_t i = 0; i < vecR.size();i++) res += vecR[i] * vecL[i]; - return res; - } - - /** - * @brief Simple inner product routine between two std::vector > - * - * @param [in] const std::vecotr >& vecR - * @param [in] const std::vecotr >& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - inline std::complex MyInnProd(const std::vector >& vecR, const std::vector >& vecL){ - //SIMPLE INNER PRODUCT ROUTINE - std::complex res(0.,0.); - #pragma omp declare reduction \ +namespace macis { +/** + * @brief Simple inner product routine between two std::vector + * + * @param [in] const std::vecotr& vecR + * @param [in] const std::vecotr& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +inline double MyInnProd(const std::vector& vecR, + const std::vector& vecL) { + // SIMPLE INNER PRODUCT ROUTINE + double res = 0.; +#pragma omp declare reduction(Vsum:double \ + : omp_out = omp_out + omp_in) \ + initializer(omp_priv = 0.) +#pragma omp parallel for reduction(Vsum : res) + for(size_t i = 0; i < vecR.size(); i++) res += vecR[i] * vecL[i]; + return res; +} + +/** + * @brief Simple inner product routine between two + * std::vector > + * + * @param [in] const std::vecotr >& vecR + * @param [in] const std::vecotr >& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +inline std::complex MyInnProd( + const std::vector >& vecR, + const std::vector >& vecL) { + // SIMPLE INNER PRODUCT ROUTINE + std::complex res(0., 0.); +#pragma omp declare reduction \ (Vsum:std::complex:omp_out=omp_out+omp_in)\ initializer(omp_priv=std::complex(0.,0.)) - #pragma omp parallel for reduction (Vsum:res) - for(size_t i = 0; i < vecR.size();i++) res += conj(vecR[i]) * vecL[i]; - return res; - } - - /** - * @brief Simple inner product routine between std::vector and std::vector > - * - * @param [in] const std::vecotr >& vecR - * @param [in] const std::vecotr& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - inline std::complex MyInnProd(const std::vector >& vecR, const std::vector& vecL){ - //SIMPLE INNER PRODUCT ROUTINE - std::complex res(0.,0.); - #pragma omp declare reduction \ +#pragma omp parallel for reduction(Vsum : res) + for(size_t i = 0; i < vecR.size(); i++) res += conj(vecR[i]) * vecL[i]; + return res; +} + +/** + * @brief Simple inner product routine between std::vector and + * std::vector > + * + * @param [in] const std::vecotr >& vecR + * @param [in] const std::vecotr& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +inline std::complex MyInnProd( + const std::vector >& vecR, + const std::vector& vecL) { + // SIMPLE INNER PRODUCT ROUTINE + std::complex res(0., 0.); +#pragma omp declare reduction \ (Vsum:std::complex:omp_out=omp_out+omp_in)\ initializer(omp_priv=std::complex(0.,0.)) - #pragma omp parallel for reduction (Vsum:res) - for(size_t i = 0; i < vecR.size();i++) res += conj(vecR[i]) * std::complex(vecL[i], 0.); - return res; - } - - /** - * @brief Simple inner product routine for two Eigen::VectorXcd - * - * @param [in] const Eigen::VectorXcd& vecR - * @param [in] const Eigen::VectorXcd& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, const Eigen::VectorXcd& vecL){ - //SIMPLE INNER PRODUCT ROUTINE - return vecR.dot(vecL); - } - - /** - * @brief Simple inner product routine for two Eigen::VectorXd - * - * @param [in] const Eigen::VectorXd& vecR - * @param [in] const Eigen::VectorXd& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - inline double MyInnProd(const Eigen::VectorXd& vecR, const Eigen::VectorXd& vecL){ - //SIMPLE INNER PRODUCT ROUTINE - return vecR.dot(vecL); - } -}// namespace macis +#pragma omp parallel for reduction(Vsum : res) + for(size_t i = 0; i < vecR.size(); i++) + res += conj(vecR[i]) * std::complex(vecL[i], 0.); + return res; +} + +/** + * @brief Simple inner product routine for two Eigen::VectorXcd + * + * @param [in] const Eigen::VectorXcd& vecR + * @param [in] const Eigen::VectorXcd& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, + const Eigen::VectorXcd& vecL) { + // SIMPLE INNER PRODUCT ROUTINE + return vecR.dot(vecL); +} + +/** + * @brief Simple inner product routine for two Eigen::VectorXd + * + * @param [in] const Eigen::VectorXd& vecR + * @param [in] const Eigen::VectorXd& vecL + * @return Inner product + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +inline double MyInnProd(const Eigen::VectorXd& vecR, + const Eigen::VectorXd& vecL) { + // SIMPLE INNER PRODUCT ROUTINE + return vecR.dot(vecL); +} +} // namespace macis diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index 0506a727..c184b966 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -15,549 +15,563 @@ * @date 05/04/2021 */ #pragma once -#include "macis/gf/eigsolver.hpp" -#include "macis/gf/inn_prods.hpp" -#include +#include + +#include #include -#include #include -#include +#include -namespace macis -{ +#include "macis/gf/eigsolver.hpp" +#include "macis/gf/inn_prods.hpp" - struct LanczosSettings { +namespace macis { - size_t itermax = 1000; - double Lantol = 1.E-8; - double E0tol = 1.E-8; - bool print = false; - }; +struct LanczosSettings { + size_t itermax = 1000; + double Lantol = 1.E-8; + double E0tol = 1.E-8; + bool print = false; +}; +/** + * @brief Wrapper class for Eigen::MatrixXd, to be used in + * the Lanczos code. Just needs to implement a matrix- + * vector product dot, and a function rows() to return the + * nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +class eigMatDOp { + private: + const eigMatD *mat; + + public: /** - * @brief Wrapper class for Eigen::MatrixXd, to be used in - * the Lanczos code. Just needs to implement a matrix- - * vector product dot, and a function rows() to return the - * nr. of rows in the matrix. + * @brief Constructor, takes Eigen::MatrixXd and keeps + * pointer to it. + * + * @param [in] const Eigen::MatrixXd &A: Matrix to wrap. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - class eigMatDOp - { - private: - const eigMatD *mat; - public: - /** - * @brief Constructor, takes Eigen::MatrixXd and keeps - * pointer to it. - * - * @param [in] const Eigen::MatrixXd &A: Matrix to wrap. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - eigMatDOp(const eigMatD &A){mat = &A;} - /** - * @brief Simple matrix-vector product. - * - * @param [in] const Eigen::VectorXd &vec: Input vector. - * - * @returns Eigen::VectorXd: A * vec. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - VectorXd dot(const VectorXd &vec) const {return (*mat) * vec;} - /** - * @brief Returns nr. of rows in the wrapped matrix. - * - * @returns int: Nr. of rows. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - int64_t rows() const {return mat->rows();} - }; - + eigMatDOp(const eigMatD &A) { mat = &A; } /** - * @brief Wrapper class for Eigen::SparseMatrix, to be used in - * the Lanczos code. Just needs to implement a matrix- - * vector product dot, and a function rows() to return the - * nr. of rows in the matrix. + * @brief Simple matrix-vector product. + * + * @param [in] const Eigen::VectorXd &vec: Input vector. + * + * @returns Eigen::VectorXd: A * vec. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - class SpMatDOp - { - private: - const SpMatD *mat; - public: - /** - * @brief Constructor, takes Eigen::SparseMatrix and keeps - * pointer to it. - * - * @param [in] const Eigen::SparseMatrix &A: Matrix to wrap. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - SpMatDOp(const SpMatD &A){mat = &A;} - /** - * @brief Simple matrix-vector product. - * - * @param [in] const Eigen::VectorXd &vec: Input vector. - * - * @returns Eigen::VectorXd: A * vec. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - VectorXd dot(const VectorXd &vec) const {return (*mat) * vec;} - /** - * @brief Returns nr. of rows in the wrapped matrix. - * - * @returns int: Nr. of rows. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - int64_t rows() const {return mat->rows();} - }; - + VectorXd dot(const VectorXd &vec) const { return (*mat) * vec; } /** - * @brief Wrapper class for sparsexx::dist_sparse_matrix, to be used in - * the Lanczos code. Just needs to implement a matrix- - * vector product dot, and a function rows() to return the - * nr. of rows in the matrix. + * @brief Returns nr. of rows in the wrapped matrix. + * + * @returns int: Nr. of rows. * * @author Carlos Mejuto Zaera - * @date 13/06/2021 + * @date 05/04/2021 */ - class SparsexDistSpMatOp - { - private: - const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix > *mat; - sparsexx::spblas::spmv_info spmv_info; - public: - /** - * @brief Constructor, takes sparsexx::dist_sparse_matrix< sparsexx::csr_matrix and keeps - * pointer to it. - * - * @param [in] const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix &A: Matrix to wrap. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - SparsexDistSpMatOp(const sparsexx::dist_sparse_matrix< sparsexx::csr_matrix > &A) - { - mat = &A; - spmv_info = sparsexx::spblas::generate_spmv_comm_info( A ); - } - /** - * @brief Simple matrix-vector product. - * - * @param [in] const Eigen::VectorXd &vec: Input vector. - * - * @returns Eigen::VectorXd: A * vec. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - VectorXd dot(const VectorXd &vec) const - { - std::vector vin( &vec[0], vec.data()+vec.cols()*vec.rows()); - std::vector vout(vec.size(), 0.); - sparsexx::spblas::pgespmv( 1., *mat, vin.data(), - 0., vout.data(), spmv_info ); - Eigen::VectorXd vec_out = Eigen::Map(vout.data(), vout.size()); - return vec_out; - } - /** - * @brief Returns nr. of rows in the wrapped matrix. - * - * @returns int: Nr. of rows. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - int64_t rows() const {return mat->m();} - }; - + int64_t rows() const { return mat->rows(); } +}; + +/** + * @brief Wrapper class for Eigen::SparseMatrix, to be + * used in the Lanczos code. Just needs to implement a matrix- vector product + * dot, and a function rows() to return the nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +class SpMatDOp { + private: + const SpMatD *mat; + + public: /** - * @brief Simple single band Lanczos implementation. + * @brief Constructor, takes Eigen::SparseMatrix and + * keeps pointer to it. * - * @param [in] const Eigen::VectorXd &start_vec: Starting vector. - * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! - * @param [in] int64_t nLanIts: Maximal number of iterations. - * @param [out] std::vector &alphas: Diagonal of the tri-diagonal H. - * @param [out] std::vector &betas: Off-diagonal of the tri-diagonal H. - * @param [in] double tol: Lanczos tolerance. + * @param [in] const Eigen::SparseMatrix &A: Matrix + * to wrap. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - template - void MyLanczos(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, std::vector &alphas, std::vector &betas, double tol) - { - //LANCZOS ROUTINE USING TEMPLATED MATRIX - //CLASS. ONLY NEEDS TO PROVIDE A MATRIX - //VECTOR PRODUCT. - int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - alphas.clear(); - betas.clear(); - - alphas.resize(nLanIts, 0.); - betas.resize(nLanIts+1, 0.); - - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); - int64_t nlan = -1, itermax = nLanIts; - - nlan++; - qold = start_vec / normpsi; - - qnew = H.dot(qold); - alphas[0] = MyInnProd(qold, qnew); - qnew -= alphas[0] * qold; - betas[0] = normpsi; - betas[1] = sqrt(MyInnProd(qnew, qnew)); - if(abs(betas[1]) <= tol) itermax = 1; - for(size_t iter = 1; iter < itermax; iter++){ - nlan++; - qtemp = qold; - qold = qnew / betas[iter]; - qnew = -betas[iter] * qtemp; - - qtemp = H.dot(qold); - - qnew += qtemp; - alphas[iter] = MyInnProd(qold, qnew); - qnew -= alphas[iter] * qold; - betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); - - if(abs(betas[iter + 1]) <= tol){ - itermax = iter; - std::cout << "EXIT BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; - break; - } - } - } - + SpMatDOp(const SpMatD &A) { mat = &A; } + /** + * @brief Simple matrix-vector product. + * + * @param [in] const Eigen::VectorXd &vec: Input vector. + * + * @returns Eigen::VectorXd: A * vec. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + VectorXd dot(const VectorXd &vec) const { return (*mat) * vec; } /** - * @brief Single band Lanczos implementation, with backprojection to - * evaluate eigenvector in the original basis. A previous Lanczos - * to determine the ground state in the Krylov basis has to be performed - * first. + * @brief Returns nr. of rows in the wrapped matrix. * - * @param [in] const Eigen::VectorXd &start_vec: Starting vector. - * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! - * @param [in] int64_t nLanIts: Maximal number of iterations. - * @param [in] Eigen::VectorXd &vec_P: Eigenvector in the Krylov basis. - * @param [out] Eigen::VectorXd &vec_BP: Eigenvector in the original basis. + * @returns int: Nr. of rows. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - template - void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, VectorXd &vec_P, VectorXd &vec_BP) - { - //REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS - //CALCULATION. - int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - - std::vector alphas(nLanIts, 0.); - std::vector betas(nLanIts+1, 0.); - - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); - int64_t nlan = -1, itermax = nLanIts; - - vec_BP = VectorXd::Zero(n); - - nlan++; - qold = start_vec / normpsi; - vec_BP = vec_P(0) * qold; - - qnew = H.dot(qold); - alphas[0] = MyInnProd(qold, qnew); - qnew -= alphas[0] * qold; - betas[0] = normpsi; - betas[1] = sqrt(MyInnProd(qnew, qnew)); - for(size_t iter = 1; iter < itermax; iter++){ - nlan++; - qtemp = qold; - qold = qnew / betas[iter]; - vec_BP += vec_P(iter) * qold; - qnew = -betas[iter] * qtemp; - - qtemp = H.dot(qold); - - qnew += qtemp; - alphas[iter] = MyInnProd(qold, qnew); - qnew -= alphas[iter] * qold; - betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); - } - alphas.clear(); - betas.clear(); + int64_t rows() const { return mat->rows(); } +}; + +/** + * @brief Wrapper class for + * sparsexx::dist_sparse_matrix, to be + * used in the Lanczos code. Just needs to implement a matrix- vector product + * dot, and a function rows() to return the nr. of rows in the matrix. + * + * @author Carlos Mejuto Zaera + * @date 13/06/2021 + */ +class SparsexDistSpMatOp { + private: + const sparsexx::dist_sparse_matrix > + *mat; + sparsexx::spblas::spmv_info spmv_info; + + public: + /** + * @brief Constructor, takes sparsexx::dist_sparse_matrix< + * sparsexx::csr_matrix and keeps pointer to it. + * + * @param [in] const sparsexx::dist_sparse_matrix< + * sparsexx::csr_matrix &A: Matrix to wrap. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ + SparsexDistSpMatOp( + const sparsexx::dist_sparse_matrix > + &A) { + mat = &A; + spmv_info = sparsexx::spblas::generate_spmv_comm_info(A); } - /** - * @brief Determine ground state of Hamiltonian using Lanczos, returns - * the ground state vector in the Krylov basis. + * @brief Simple matrix-vector product. * - * @param [in] const Eigen::VectorXd &start_vec: Starting vector. - * @param [in] const MatOp &H: Wrapped Hamiltonian. - * @param [out] double &E0: Ground state energy. - * @param [out] Eigen::VectorXd &psi0_Lan: Eigenvector in the Krylov basis. - * @param [in] LanczosSettings &settings: Input structure with Lanczos parameters. + * @param [in] const Eigen::VectorXd &vec: Input vector. * - * @returns int: Required nr. of Lanczos iterations. + * @returns Eigen::VectorXd: A * vec. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - template - int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, VectorXd &psi0_Lan, const LanczosSettings &settings) - { - //COMPUTE LOWEST EIGENVALUE OF MATRIX H - //USING LANCZOS. RETURNS EIGENVECTOR IN - //THE BASIS OF KRYLOV VECTORS - auto w = std::setw(15); - double Lantol = settings.Lantol; - double E0tol = settings.E0tol; - bool print = settings.print; - size_t itermax = settings.itermax; - - int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - VectorXd eigvals; - eigMatD eigvecs; - std::vector alphas, betas; - double currE0, prevE0; - - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); - int64_t nlan = -1; - - nlan++; - qold = start_vec / normpsi; - - qnew = H.dot(qold); - alphas.push_back(MyInnProd(qold, qnew)); - qnew -= alphas[0] * qold; - betas.push_back(normpsi); - betas.push_back(sqrt(MyInnProd(qnew, qnew))); - prevE0 = alphas[0]; - - if(print) - { - std::cout << w << "Lanczos diagonalization:" << std::endl; - std::ostringstream header; - header << w << "Iter." << w << "Alpha" << w << "Beta" << w << "E0" << w << "dE"; - std::cout << header.str() << std::endl; - std::cout << w << std::string(header.str().length(), '-') << std::endl; - std::cout << w << 1 << w << std::scientific << std::setprecision(5) << alphas[0] << w << betas[1] << w << prevE0 << w << "***" << std::endl; - } - - if(abs(betas[1]) <= Lantol){ - itermax = 1; - currE0 = alphas[0]; - } - for(size_t iter = 1; iter < itermax; iter++){ - nlan++; - qtemp = qold; - qold = qnew / betas[iter]; - qnew = -betas[iter] * qtemp; - - qtemp = H.dot(qold); - - qnew += qtemp; - alphas.push_back(MyInnProd(qold, qnew)); - qnew -= alphas[iter] * qold; - betas.push_back(sqrt(MyInnProd(qnew, qnew))); - //GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX - Hste_v(alphas, betas, eigvals, eigvecs); - currE0 = eigvals(0); - if(print) - std::cout << w << iter+1 << w << std::scientific << std::setprecision(5) << alphas[iter] << w << betas[iter+1] << w << currE0 << w << abs(currE0 - prevE0) << std::endl; - - if(abs(betas[iter + 1]) <= Lantol){ - itermax = iter+1; - if(print) - std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; - break; - } - if(abs(currE0 - prevE0) <= E0tol){ - itermax = iter+1; - if(print) - std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT ITERATION " << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; - break; - } - prevE0 = currE0; - } - - if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1 && abs(betas[itermax]) > Lantol ) - { - std::ostringstream oss; - oss << "Unable to achieve the desired accuracy of " << std::scientific << E0tol << " in Lanczos after " << itermax << " iterations!!"; - throw (oss.str()); - } - - E0 = currE0; - if(itermax == 1) - { - psi0_Lan = VectorXd::Ones(1); - } - else - { - psi0_Lan = eigvecs.col(0); - } - return itermax; + VectorXd dot(const VectorXd &vec) const { + std::vector vin(&vec[0], vec.data() + vec.cols() * vec.rows()); + std::vector vout(vec.size(), 0.); + sparsexx::spblas::pgespmv(1., *mat, vin.data(), 0., vout.data(), spmv_info); + Eigen::VectorXd vec_out = + Eigen::Map(vout.data(), vout.size()); + return vec_out; } - /** - * @brief Determine ground state of Hamiltonian using Lanczos, returns - * the ground state vector in the original basis. + * @brief Returns nr. of rows in the wrapped matrix. * - * @param [in] const Eigen::VectorXd &start_vec: Starting vector. - * @param [in] const MatOp &H: Wrapped Hamiltonian. - * @param [out] double &E0: Ground state energy. - * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. - * @param [in] const LanczosSettings &settings: Input structure with Lanczos parameters. + * @returns int: Nr. of rows. * * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - template - void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, VectorXd &psi0, const LanczosSettings &settings) - { - //COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR - //OF MATRIX H USING LANCZOS. - double Lantol = settings.Lantol; - double E0tol = settings.E0tol; - bool print = settings.print; - size_t itermax = settings.itermax; - - int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - VectorXd eigvals; - eigMatD eigvecs; - std::vector kry_vecs; - std::vector alphas, betas; - double currE0, prevE0; - - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); - int64_t nlan = -1; - + int64_t rows() const { return mat->m(); } +}; + +/** + * @brief Simple single band Lanczos implementation. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! + * @param [in] int64_t nLanIts: Maximal number of iterations. + * @param [out] std::vector &alphas: Diagonal of the tri-diagonal H. + * @param [out] std::vector &betas: Off-diagonal of the tri-diagonal H. + * @param [in] double tol: Lanczos tolerance. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +template +void MyLanczos(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, + std::vector &alphas, std::vector &betas, + double tol) { + // LANCZOS ROUTINE USING TEMPLATED MATRIX + // CLASS. ONLY NEEDS TO PROVIDE A MATRIX + // VECTOR PRODUCT. + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + alphas.clear(); + betas.clear(); + + alphas.resize(nLanIts, 0.); + betas.resize(nLanIts + 1, 0.); + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1, itermax = nLanIts; + + nlan++; + qold = start_vec / normpsi; + + qnew = H.dot(qold); + alphas[0] = MyInnProd(qold, qnew); + qnew -= alphas[0] * qold; + betas[0] = normpsi; + betas[1] = sqrt(MyInnProd(qnew, qnew)); + if(abs(betas[1]) <= tol) itermax = 1; + for(size_t iter = 1; iter < itermax; iter++) { nlan++; - qold = start_vec / normpsi; - kry_vecs.push_back(qold); - - qnew = H.dot(qold); + qtemp = qold; + qold = qnew / betas[iter]; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas[iter] = MyInnProd(qold, qnew); + qnew -= alphas[iter] * qold; + betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + + if(abs(betas[iter + 1]) <= tol) { + itermax = iter; + std::cout << "EXIT BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter + << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; + break; + } + } +} + +/** + * @brief Single band Lanczos implementation, with backprojection to + * evaluate eigenvector in the original basis. A previous Lanczos + * to determine the ground state in the Krylov basis has to be performed + * first. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Matrix. Has to be Hermitian! + * @param [in] int64_t nLanIts: Maximal number of iterations. + * @param [in] Eigen::VectorXd &vec_P: Eigenvector in the Krylov basis. + * @param [out] Eigen::VectorXd &vec_BP: Eigenvector in the original basis. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +template +void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, + int64_t nLanIts, VectorXd &vec_P, VectorXd &vec_BP) { + // REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS + // CALCULATION. + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + + std::vector alphas(nLanIts, 0.); + std::vector betas(nLanIts + 1, 0.); + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1, itermax = nLanIts; + + vec_BP = VectorXd::Zero(n); + + nlan++; + qold = start_vec / normpsi; + vec_BP = vec_P(0) * qold; + + qnew = H.dot(qold); + alphas[0] = MyInnProd(qold, qnew); + qnew -= alphas[0] * qold; + betas[0] = normpsi; + betas[1] = sqrt(MyInnProd(qnew, qnew)); + for(size_t iter = 1; iter < itermax; iter++) { + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + vec_BP += vec_P(iter) * qold; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas[iter] = MyInnProd(qold, qnew); + qnew -= alphas[iter] * qold; + betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + } + alphas.clear(); + betas.clear(); +} + +/** + * @brief Determine ground state of Hamiltonian using Lanczos, returns + * the ground state vector in the Krylov basis. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0_Lan: Eigenvector in the Krylov basis. + * @param [in] LanczosSettings &settings: Input structure with Lanczos + * parameters. + * + * @returns int: Required nr. of Lanczos iterations. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +template +int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, + VectorXd &psi0_Lan, const LanczosSettings &settings) { + // COMPUTE LOWEST EIGENVALUE OF MATRIX H + // USING LANCZOS. RETURNS EIGENVECTOR IN + // THE BASIS OF KRYLOV VECTORS + auto w = std::setw(15); + double Lantol = settings.Lantol; + double E0tol = settings.E0tol; + bool print = settings.print; + size_t itermax = settings.itermax; + + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + VectorXd eigvals; + eigMatD eigvecs; + std::vector alphas, betas; + double currE0, prevE0; + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1; + + nlan++; + qold = start_vec / normpsi; + + qnew = H.dot(qold); + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[0] * qold; + betas.push_back(normpsi); + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + prevE0 = alphas[0]; + + if(print) { + std::cout << w << "Lanczos diagonalization:" << std::endl; + std::ostringstream header; + header << w << "Iter." << w << "Alpha" << w << "Beta" << w << "E0" << w + << "dE"; + std::cout << header.str() << std::endl; + std::cout << w << std::string(header.str().length(), '-') << std::endl; + std::cout << w << 1 << w << std::scientific << std::setprecision(5) + << alphas[0] << w << betas[1] << w << prevE0 << w << "***" + << std::endl; + } + + if(abs(betas[1]) <= Lantol) { + itermax = 1; + currE0 = alphas[0]; + } + for(size_t iter = 1; iter < itermax; iter++) { + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; alphas.push_back(MyInnProd(qold, qnew)); - qnew -= alphas[0] * qold; - betas.push_back(normpsi); + qnew -= alphas[iter] * qold; betas.push_back(sqrt(MyInnProd(qnew, qnew))); - prevE0 = alphas[0]; - - if(abs(betas[1]) <= Lantol){ - itermax = 1; - currE0 = alphas[0]; - } - for(size_t iter = 1; iter < itermax; iter++){ - nlan++; - qtemp = qold; - qold = qnew / betas[iter]; - kry_vecs.push_back(qold); - qnew = -betas[iter] * qtemp; - - qtemp = H.dot(qold); - - qnew += qtemp; - alphas.push_back(MyInnProd(qold, qnew)); - qnew -= alphas[iter] * qold; - betas.push_back(sqrt(MyInnProd(qnew, qnew))); - //GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX - Hste_v(alphas, betas, eigvals, eigvecs); - currE0 = eigvals(0); - - if(abs(betas[iter + 1]) <= Lantol){ - itermax = iter; - if(print) - std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " << iter << ", betas[iter + 1] = " << betas[iter + 1] << std::endl; - break; - } - if(abs(currE0 - prevE0) <= E0tol){ - itermax = iter; - if(print) - std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT ITERATION " << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; - break; - } - prevE0 = currE0; + // GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX + Hste_v(alphas, betas, eigvals, eigvecs); + currE0 = eigvals(0); + if(print) + std::cout << w << iter + 1 << w << std::scientific << std::setprecision(5) + << alphas[iter] << w << betas[iter + 1] << w << currE0 << w + << abs(currE0 - prevE0) << std::endl; + + if(abs(betas[iter + 1]) <= Lantol) { + itermax = iter + 1; + if(print) + std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " + << iter << ", betas[iter + 1] = " << betas[iter + 1] + << std::endl; + break; } - - if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1 ) - { - std::ostringstream oss; - oss << "Unable to achieve the desired accuracy of " << std::scientific << E0tol << " in Lanczos after " << itermax << " iterations!!"; - throw (oss.str()); + if(abs(currE0 - prevE0) <= E0tol) { + itermax = iter + 1; + if(print) + std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT " + "ITERATION " + << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; + break; } - - E0 = currE0; - psi0 = VectorXd::Zero(n); - if(kry_vecs.size() == 1) - { - psi0 = kry_vecs[0]; + prevE0 = currE0; + } + + if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1 && + abs(betas[itermax]) > Lantol) { + std::ostringstream oss; + oss << "Unable to achieve the desired accuracy of " << std::scientific + << E0tol << " in Lanczos after " << itermax << " iterations!!"; + throw(oss.str()); + } + + E0 = currE0; + if(itermax == 1) { + psi0_Lan = VectorXd::Ones(1); + } else { + psi0_Lan = eigvecs.col(0); + } + return itermax; +} + +/** + * @brief Determine ground state of Hamiltonian using Lanczos, returns + * the ground state vector in the original basis. + * + * @param [in] const Eigen::VectorXd &start_vec: Starting vector. + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. + * @param [in] const LanczosSettings &settings: Input structure with Lanczos + * parameters. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +template +void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, + VectorXd &psi0, const LanczosSettings &settings) { + // COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR + // OF MATRIX H USING LANCZOS. + double Lantol = settings.Lantol; + double E0tol = settings.E0tol; + bool print = settings.print; + size_t itermax = settings.itermax; + + int64_t n = start_vec.rows(); + VectorXd qold = VectorXd::Zero(n); + VectorXd qtemp = VectorXd::Zero(n); + VectorXd qnew = VectorXd::Zero(n); + VectorXd eigvals; + eigMatD eigvecs; + std::vector kry_vecs; + std::vector alphas, betas; + double currE0, prevE0; + + double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + int64_t nlan = -1; + + nlan++; + qold = start_vec / normpsi; + kry_vecs.push_back(qold); + + qnew = H.dot(qold); + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[0] * qold; + betas.push_back(normpsi); + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + prevE0 = alphas[0]; + + if(abs(betas[1]) <= Lantol) { + itermax = 1; + currE0 = alphas[0]; + } + for(size_t iter = 1; iter < itermax; iter++) { + nlan++; + qtemp = qold; + qold = qnew / betas[iter]; + kry_vecs.push_back(qold); + qnew = -betas[iter] * qtemp; + + qtemp = H.dot(qold); + + qnew += qtemp; + alphas.push_back(MyInnProd(qold, qnew)); + qnew -= alphas[iter] * qold; + betas.push_back(sqrt(MyInnProd(qnew, qnew))); + // GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX + Hste_v(alphas, betas, eigvals, eigvecs); + currE0 = eigvals(0); + + if(abs(betas[iter + 1]) <= Lantol) { + itermax = iter; + if(print) + std::cout << "EXIT LANCZOS BECAUSE BETA IS TOO SMALL!! AT ITERATION " + << iter << ", betas[iter + 1] = " << betas[iter + 1] + << std::endl; + break; } - else - { - for(int64_t i = 0; i < kry_vecs.size(); i++) - psi0 += eigvecs.col(0)(i) * kry_vecs[i]; + if(abs(currE0 - prevE0) <= E0tol) { + itermax = iter; + if(print) + std::cout << "EXIT LANCZOS BECAUSE ENERGY ACCURACY WAS OBTAINED!! AT " + "ITERATION " + << iter << ", dE = " << abs(currE0 - prevE0) << std::endl; + break; } + prevE0 = currE0; } - - /** - * @brief Computes ground state of Hamiltonian and corresponding - * eigenvector using Lanczos. - * - * @param [in] const MatOp &H: Wrapped Hamiltonian. - * @param [out] double &E0: Ground state energy. - * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. - * @param [in] const LanczosSettings &settings: Input structure with Lanczos parameters. - * @param [in] bool superCI: Determines starting guess for Lanczos. If true - * we start from [1,0,0,0,...] vector, otherwise from [1,1,1,...]. - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ - template - void GetGS(const MatOp &H, double &E0, VectorXd &psi0, const LanczosSettings &settings, bool isHF = false) - { - //Computes the lowest eigenvalue and corresponding - //eigenvector from the dense matrix H by using Lanczos. - - int64_t n = H.rows(); - //Initial vector. We choose (1,0,0,0,...)t - //for HF, Otherwhise (1,1,1,1,...)t - VectorXd start_psi = isHF ? VectorXd::Zero(n) : VectorXd::Ones(n); - start_psi(0) = 1.; - //Determine lowest eigenvalue for the given - //tolerance. - VectorXd psi0_Lan; - int64_t nLanIts = GetGSEn_Lanczos(start_psi, H, E0, psi0_Lan, settings); - //Reconstruct the eigenvector - MyLanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); - start_psi = psi0; - GetGSEnVec_Lanczos(start_psi, H, E0, psi0, settings); + + if(abs(prevE0 - currE0) > E0tol && nlan == itermax - 1) { + std::ostringstream oss; + oss << "Unable to achieve the desired accuracy of " << std::scientific + << E0tol << " in Lanczos after " << itermax << " iterations!!"; + throw(oss.str()); } -}// namespace macis + E0 = currE0; + psi0 = VectorXd::Zero(n); + if(kry_vecs.size() == 1) { + psi0 = kry_vecs[0]; + } else { + for(int64_t i = 0; i < kry_vecs.size(); i++) + psi0 += eigvecs.col(0)(i) * kry_vecs[i]; + } +} + +/** + * @brief Computes ground state of Hamiltonian and corresponding + * eigenvector using Lanczos. + * + * @param [in] const MatOp &H: Wrapped Hamiltonian. + * @param [out] double &E0: Ground state energy. + * @param [out] Eigen::VectorXd &psi0: Ground state eigenvector. + * @param [in] const LanczosSettings &settings: Input structure with Lanczos + * parameters. + * @param [in] bool superCI: Determines starting guess for Lanczos. If true + * we start from [1,0,0,0,...] vector, otherwise from [1,1,1,...]. + * + * @author Carlos Mejuto Zaera + * @date 05/04/2021 + */ +template +void GetGS(const MatOp &H, double &E0, VectorXd &psi0, + const LanczosSettings &settings, bool isHF = false) { + // Computes the lowest eigenvalue and corresponding + // eigenvector from the dense matrix H by using Lanczos. + + int64_t n = H.rows(); + // Initial vector. We choose (1,0,0,0,...)t + // for HF, Otherwhise (1,1,1,1,...)t + VectorXd start_psi = isHF ? VectorXd::Zero(n) : VectorXd::Ones(n); + start_psi(0) = 1.; + // Determine lowest eigenvalue for the given + // tolerance. + VectorXd psi0_Lan; + int64_t nLanIts = GetGSEn_Lanczos(start_psi, H, E0, psi0_Lan, settings); + // Reconstruct the eigenvector + MyLanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); + start_psi = psi0; + GetGSEnVec_Lanczos(start_psi, H, E0, psi0, settings); +} + +} // namespace macis diff --git a/include/macis/sd_operations.hpp b/include/macis/sd_operations.hpp index 6de30cec..7c889134 100644 --- a/include/macis/sd_operations.hpp +++ b/include/macis/sd_operations.hpp @@ -199,21 +199,20 @@ void generate_singles_doubles(size_t norb, std::bitset state, append_doubles(state, occ_orbs, vir_orbs, doubles); } - - /** - * @brief Generates single excitations for a given spin involving only the orbitals - * defined in the active space as_orbs. + * @brief Generates single excitations for a given spin involving only the + * orbitals defined in the active space as_orbs. * * TODO: Test this function * * @param[in] size_t norb: Nr. of orbitals in the system. - * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, - * includes only one of the spin species. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute + * the excitations, includes only one of the spin species. * @param[out] std::vector >& singles: Vector storing the singly * excited determinants from state, considering the active space. - * @param[in] const std::vector as_orbs: Vector with the indices of the active - * orbitals. Only excitations involving these orbitals will be formed. + * @param[in] const std::vector as_orbs: Vector with the indices of + * the active orbitals. Only excitations involving these orbitals will be + * formed. * * @author Carlos Mejuto Zaera * @date 28/01/2022 @@ -230,20 +229,21 @@ void generate_singles_as(size_t norb, std::bitset state, } /** - * @brief Generates single and double excitations for a given spin involving only the orbitals - * defined in the active space as_orbs. + * @brief Generates single and double excitations for a given spin involving + * only the orbitals defined in the active space as_orbs. * * TODO: Test this function * * @param[in] size_t norb: Nr. of orbitals in the system. - * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, - * includes only one of the spin species. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute + * the excitations, includes only one of the spin species. * @param[out] std::vector >& singles: Vector storing the singly * excited determinants from state, considering the active space. * @param[out] std::vector >& doubles: Vector storing the doubly * excited determinants from state, considering the active space. - * @param[in] const std::vector as_orbs: Vector with the indices of the active - * orbitals. Only excitations involving these orbitals will be formed. + * @param[in] const std::vector as_orbs: Vector with the indices of + * the active orbitals. Only excitations involving these orbitals will be + * formed. * * @author Carlos Mejuto Zaera * @date 28/01/2022 @@ -263,17 +263,19 @@ void generate_singles_doubles_as(size_t norb, std::bitset state, } /** - * @brief Generates single excitations for both spins involving only the orbitals - * defined in the active space as_orbs. + * @brief Generates single excitations for both spins involving only the + * orbitals defined in the active space as_orbs. * * TODO: Test this function * * @param[in] size_t norb: Nr. of orbitals in the system. - * @param[in] std::bitsetstate : Slater determinant for which to compute the excitations. + * @param[in] std::bitsetstate : Slater determinant for which to compute the + * excitations. * @param[out] std::vector >& singles: Vector storing the singly * excited determinants from state, considering the active space. - * @param[in] const std::vector as_orbs: Vector with the indices of the active - * orbitals. Only excitations involving these orbitals will be formed. + * @param[in] const std::vector as_orbs: Vector with the indices of + * the active orbitals. Only excitations involving these orbitals will be + * formed. * * @author Carlos Mejuto Zaera * @date 28/01/2022 @@ -313,20 +315,21 @@ void generate_singles_spin_as(size_t norb, std::bitset state, } /** - * @brief Generates single and double excitations for both spins involving only the orbitals - * defined in the active space as_orbs. + * @brief Generates single and double excitations for both spins involving only + * the orbitals defined in the active space as_orbs. * * TODO: Test this function * * @param[in] size_t norb: Nr. of orbitals in the system. - * @param[in] std::bitsetstate : Half Slater determinant for which to compute the excitations, - * includes only one of the spin species. + * @param[in] std::bitsetstate : Half Slater determinant for which to compute + * the excitations, includes only one of the spin species. * @param[out] std::vector >& singles: Vector storing the singly * excited determinants from state, considering the active space. * @param[out] std::vector >& doubles: Vector storing the doubly * excited determinants from state, considering the active space. - * @param[in] const std::vector as_orbs: Vector with the indices of the active - * orbitals. Only excitations involving these orbitals will be formed. + * @param[in] const std::vector as_orbs: Vector with the indices of + * the active orbitals. Only excitations involving these orbitals will be + * formed. * * @author Carlos Mejuto Zaera * @date 28/01/2022 diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 6588c1e6..a1d323fa 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -7,486 +7,512 @@ */ #include "macis/gf/bandlan.hpp" + #include -inline bool is_file (const std::string& name) { +inline bool is_file(const std::string &name) { struct stat buffer; - return (stat (name.c_str(), &buffer) == 0); + return (stat(name.c_str(), &buffer) == 0); } -namespace macis -{ - bool QRdecomp(std::vector > &Q, std::vector > &R) - { - //CALL LAPACK'S QR DECOMPOSITION ROUTINES. - //INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE RECTANGULAR, - // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF ROWS. - //OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT - // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. - // return : TRUE FOR SUCCESS, FALSE OTHERWISE - - R.clear(); - //PREPARE VARIABLES TO CALL LAPACK - int M = Q.size(), N = Q[0].size(); - assert(M >= N); - int LDA = M, INFO = 0, LWORK; - double *A, *TAU, *WORK; - - //INITIALIZE A - A = new double[M * N]; - for(int i = 0; i < M; i++){ - for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; - Q[i].clear(); - } - //INITIALIZE TAU, AND PERFORM WORKSPACE QUERY - TAU = new double[N]; - WORK = new double[N]; - LWORK = -1; - - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - //NOW, PERFORM ACTUAL QR DECOMPOSITION - WORK = new double[LWORK]; - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO << std::endl; - return false; - } - //SAVE THE R MATRIX - R.resize(N); - for(int i = 0; i < N; i++){ - R[i].resize(N); - std::fill(R[i].begin(), R[i].end(), 0.); - for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; - } - - //NOW, COMPUTE THE ACTUAL Q MATRIX - int K = N; - //FIRST, PERFORM WORKSPACE QUERY - LWORK = -1; - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - WORK = new double[LWORK]; - //NOW, COMPUTE ACTUAL Q - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO << std::endl; - return false; - } - delete[] TAU; - delete[] WORK; - //SAVE THE Q MATRIX - for(int i = 0; i < M; i++){ - Q[i].resize(N); - for(int j = 0; j < N; j++) Q[i][j] = A[i + j * M]; - } - delete[] A; - - return true; - +namespace macis { +bool QRdecomp(std::vector > &Q, + std::vector > &R) { + // CALL LAPACK'S QR DECOMPOSITION ROUTINES. + // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE + // RECTANGULAR, + // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF + // ROWS. + // OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT + // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. + // return : TRUE FOR SUCCESS, FALSE OTHERWISE + + R.clear(); + // PREPARE VARIABLES TO CALL LAPACK + int M = Q.size(), N = Q[0].size(); + assert(M >= N); + int LDA = M, INFO = 0, LWORK; + double *A, *TAU, *WORK; + + // INITIALIZE A + A = new double[M * N]; + for(int i = 0; i < M; i++) { + for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; + Q[i].clear(); } - - bool QRdecomp_tr(std::vector > &Q, std::vector > &R) - { - //CALL LAPACK'S QR DECOMPOSITION ROUTINES. - //INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE RECTANGULAR, - // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF ROWS. - //OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT - // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. - // return : TRUE FOR SUCCESS, FALSE OTHERWISE - - R.clear(); - //PREPARE VARIABLES TO CALL LAPACK - int M = Q[0].size(), N = Q.size(); - assert(M >= N); - int LDA = M, INFO = 0, LWORK; - double *A, *TAU, *WORK; - - //INITIALIZE A - A = new double[M * N]; - for(int i = 0; i < M; i++){ - for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; - } - - //INITIALIZE TAU, AND PERFORM WORKSPACE QUERY - TAU = new double[N]; - WORK = new double[N]; - LWORK = -1; - - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - //NOW, PERFORM ACTUAL QR DECOMPOSITION - WORK = new double[LWORK]; - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO << std::endl; - return false; - } - //SAVE THE R MATRIX - R.resize(N); - for(int i = 0; i < N; i++){ - R[i].resize(N); - std::fill(R[i].begin(), R[i].end(), 0.); - for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; - } - - //NOW, COMPUTE THE ACTUAL Q MATRIX - int K = N; - //FIRST, PERFORM WORKSPACE QUERY - LWORK = -1; - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - WORK = new double[LWORK]; - //NOW, COMPUTE ACTUAL Q - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO << std::endl; - return false; - } - delete[] TAU; - delete[] WORK; - //SAVE THE Q MATRIX - for(int i = 0; i < M; i++){ - for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; - } - delete[] A; - - return true; - + // INITIALIZE TAU, AND PERFORM WORKSPACE QUERY + TAU = new double[N]; + WORK = new double[N]; + LWORK = -1; + + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; } - - bool GetEigsys(std::vector > & mat, std::vector &eigvals, std::vector > & eigvecs) - { - //COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC MATRIX mat BY CALLING LAPACK. - //WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. - //FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES AND - //EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs RESPECTIVELY. THE MATRIX mat IS - //ERASED DURING COMPUTATION - eigvals.clear(); eigvecs.clear(); - //PREPARE VARIABLES FOR LAPACK - char UPLO = 'U', COMPZ = 'V'; - int N = mat.size(), LDA = mat.size(), LWORK = -1, INFO; - double *A, *D, *E, *TAU, *WORK; - - //INITIALIZE A - A = new double[N * N]; - for(int i = 0; i < N; i++){ - for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; - mat[i].clear(); - } - mat.clear(); - //ALLOCATE REST OF THE MEMORY - D = new double[N]; - E = new double[N-1]; - TAU = new double[N-1]; - WORK = new double[N]; - - //TRANSFORM THE MATRIX TO TRIDIAGONAL FORM - //FIRST, PERFORM MEMORY QUERY - dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dsytrd_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; - //NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM - dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dsytrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " << INFO << std::endl; - return false; - } - - //COMPUTE THE TRANSFORMATION MATRIX, NECESSARY TO COMPUTE EIGENVECTORS - //FIRST, PERFORM MEMORY QUERY - LWORK = -1; - dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgtr_ MEMORY QUERY!! ERROR CODE: " << INFO << std::endl; - return false; - } - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; - //NOW, COMPUTE THE TRANSFORMATION MATRIX. IT WILL BE STORED IN A - dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dorgtr_ COMPUTING TRANSFORMATION MATRIX!! ERROR CODE: " << INFO << std::endl; - return false; - } - delete[] TAU; - - //FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! - delete[] WORK; - WORK = new double[2 * N - 2]; - dsteqr_(&COMPZ, &N, D, E, A, &LDA, WORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! ERROR CODE: " << INFO << std::endl; - return false; - } - delete[] WORK; - delete[] E; - - //NOW, STORE THE EIGENVALUES AND EIGENVECTORS - eigvals.resize(N); - for(int i = 0; i < N; i++) eigvals[i] = D[i]; - delete[] D; - eigvecs.resize(N); - for(int i = 0; i < N; i++){ - eigvecs[i].resize(N); - for(int j = 0; j < N; j++) eigvecs[i][j] = A[j + i * N]; - } - delete[] A; - - return true; - + LWORK = int(WORK[0]); + delete[] WORK; + // NOW, PERFORM ACTUAL QR DECOMPOSITION + WORK = new double[LWORK]; + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO + << std::endl; + return false; } - - bool GetEigsysBand(std::vector > & mat, int nSupDiag, std::vector &eigvals, std::vector > & eigvecs) - { - //COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC BAND MATRIX mat BY CALLING LAPACK. - //WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. - //FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES AND - //EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs RESPECTIVELY. THE MATRIX mat IS - //ERASED DURING COMPUTATION - eigvals.clear(); eigvecs.clear(); - //PREPARE VARIABLES FOR LAPACK - char UPLO = 'U', VECT = 'V', COMPZ = 'V'; - int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1, LWORK = -1, INFO; - double *AB, *D, *E, *Q, *WORK; - - //INITIALIZE A - AB = new double[(nSupDiag + 1) * N]; - for(int j = 0; j < N; j++){ - for(int i = std::max(0,j-nSupDiag); i <= j; i++) AB[nSupDiag + i - j + j * (nSupDiag+1)] = mat[i][j]; - } - mat.clear(); - //ALLOCATE REST OF THE MEMORY - Q = new double[N * N]; - D = new double[N]; - E = new double[N-1]; - WORK = new double[N]; - - //TRANSFORM THE MATRIX TO TRIDIAGONAL FORM - //NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM - dsbtrd_(&VECT, &UPLO, &N, &nSupDiag, AB, &LDAB, D, E, Q, &LDQ, WORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dsbtrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " << INFO << std::endl; - return false; + // SAVE THE R MATRIX + R.resize(N); + for(int i = 0; i < N; i++) { + R[i].resize(N); + std::fill(R[i].begin(), R[i].end(), 0.); + for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; + } + + // NOW, COMPUTE THE ACTUAL Q MATRIX + int K = N; + // FIRST, PERFORM WORKSPACE QUERY + LWORK = -1; + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + WORK = new double[LWORK]; + // NOW, COMPUTE ACTUAL Q + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO + << std::endl; + return false; + } + delete[] TAU; + delete[] WORK; + // SAVE THE Q MATRIX + for(int i = 0; i < M; i++) { + Q[i].resize(N); + for(int j = 0; j < N; j++) Q[i][j] = A[i + j * M]; + } + delete[] A; + + return true; +} + +bool QRdecomp_tr(std::vector > &Q, + std::vector > &R) { + // CALL LAPACK'S QR DECOMPOSITION ROUTINES. + // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE + // RECTANGULAR, + // THE NUMBER OF COLUMNS WILL BE ALWAYS LESS THAN THE NUMBER OF + // ROWS. + // OUTPUT: Q: Q MATRIX FROM THE DECOMPOSITION, OVERWRITES INPUT + // R: R MATRIX FROM THE DECOMPOSITION. UPPER DIAGONAL, SQUARE. + // return : TRUE FOR SUCCESS, FALSE OTHERWISE + + R.clear(); + // PREPARE VARIABLES TO CALL LAPACK + int M = Q[0].size(), N = Q.size(); + assert(M >= N); + int LDA = M, INFO = 0, LWORK; + double *A, *TAU, *WORK; + + // INITIALIZE A + A = new double[M * N]; + for(int i = 0; i < M; i++) { + for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; + } + + // INITIALIZE TAU, AND PERFORM WORKSPACE QUERY + TAU = new double[N]; + WORK = new double[N]; + LWORK = -1; + + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + // NOW, PERFORM ACTUAL QR DECOMPOSITION + WORK = new double[LWORK]; + dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO + << std::endl; + return false; + } + // SAVE THE R MATRIX + R.resize(N); + for(int i = 0; i < N; i++) { + R[i].resize(N); + std::fill(R[i].begin(), R[i].end(), 0.); + for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; + } + + // NOW, COMPUTE THE ACTUAL Q MATRIX + int K = N; + // FIRST, PERFORM WORKSPACE QUERY + LWORK = -1; + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; + } + LWORK = int(WORK[0]); + delete[] WORK; + WORK = new double[LWORK]; + // NOW, COMPUTE ACTUAL Q + dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO + << std::endl; + return false; + } + delete[] TAU; + delete[] WORK; + // SAVE THE Q MATRIX + for(int i = 0; i < M; i++) { + for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; + } + delete[] A; + + return true; +} + +bool GetEigsys(std::vector > &mat, + std::vector &eigvals, + std::vector > &eigvecs) { + // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC MATRIX mat BY + // CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. FIRST, + // IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES + // AND EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs RESPECTIVELY. THE + // MATRIX mat IS ERASED DURING COMPUTATION + eigvals.clear(); + eigvecs.clear(); + // PREPARE VARIABLES FOR LAPACK + char UPLO = 'U', COMPZ = 'V'; + int N = mat.size(), LDA = mat.size(), LWORK = -1, INFO; + double *A, *D, *E, *TAU, *WORK; + + // INITIALIZE A + A = new double[N * N]; + for(int i = 0; i < N; i++) { + for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; + mat[i].clear(); + } + mat.clear(); + // ALLOCATE REST OF THE MEMORY + D = new double[N]; + E = new double[N - 1]; + TAU = new double[N - 1]; + WORK = new double[N]; + + // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM + // FIRST, PERFORM MEMORY QUERY + dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dsytrd_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; + } + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM + dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout + << "ERROR IN dsytrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " + << INFO << std::endl; + return false; + } + + // COMPUTE THE TRANSFORMATION MATRIX, NECESSARY TO COMPUTE EIGENVECTORS + // FIRST, PERFORM MEMORY QUERY + LWORK = -1; + dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dorgtr_ MEMORY QUERY!! ERROR CODE: " << INFO + << std::endl; + return false; + } + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + // NOW, COMPUTE THE TRANSFORMATION MATRIX. IT WILL BE STORED IN A + dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); + if(INFO != 0) { + std::cout + << "ERROR IN dorgtr_ COMPUTING TRANSFORMATION MATRIX!! ERROR CODE: " + << INFO << std::endl; + return false; + } + delete[] TAU; + + // FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! + delete[] WORK; + WORK = new double[2 * N - 2]; + dsteqr_(&COMPZ, &N, D, E, A, &LDA, WORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! " + "ERROR CODE: " + << INFO << std::endl; + return false; + } + delete[] WORK; + delete[] E; + + // NOW, STORE THE EIGENVALUES AND EIGENVECTORS + eigvals.resize(N); + for(int i = 0; i < N; i++) eigvals[i] = D[i]; + delete[] D; + eigvecs.resize(N); + for(int i = 0; i < N; i++) { + eigvecs[i].resize(N); + for(int j = 0; j < N; j++) eigvecs[i][j] = A[j + i * N]; + } + delete[] A; + + return true; +} + +bool GetEigsysBand(std::vector > &mat, int nSupDiag, + std::vector &eigvals, + std::vector > &eigvecs) { + // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC BAND MATRIX mat + // BY CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. + // FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE + // EIGENVALUES AND EIGENVECTORS. THESE ARE STORED IN eigvals AND eigvecs + // RESPECTIVELY. THE MATRIX mat IS ERASED DURING COMPUTATION + eigvals.clear(); + eigvecs.clear(); + // PREPARE VARIABLES FOR LAPACK + char UPLO = 'U', VECT = 'V', COMPZ = 'V'; + int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1, LWORK = -1, INFO; + double *AB, *D, *E, *Q, *WORK; + + // INITIALIZE A + AB = new double[(nSupDiag + 1) * N]; + for(int j = 0; j < N; j++) { + for(int i = std::max(0, j - nSupDiag); i <= j; i++) + AB[nSupDiag + i - j + j * (nSupDiag + 1)] = mat[i][j]; + } + mat.clear(); + // ALLOCATE REST OF THE MEMORY + Q = new double[N * N]; + D = new double[N]; + E = new double[N - 1]; + WORK = new double[N]; + + // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM + // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM + dsbtrd_(&VECT, &UPLO, &N, &nSupDiag, AB, &LDAB, D, E, Q, &LDQ, WORK, &INFO); + if(INFO != 0) { + std::cout + << "ERROR IN dsbtrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " + << INFO << std::endl; + return false; + } + delete[] AB; + + // FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! + delete[] WORK; + WORK = new double[2 * N - 2]; + dsteqr_(&COMPZ, &N, D, E, Q, &LDQ, WORK, &INFO); + if(INFO != 0) { + std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! " + "ERROR CODE: " + << INFO << std::endl; + return false; + } + delete[] WORK; + delete[] E; + + // NOW, STORE THE EIGENVALUES AND EIGENVECTORS + eigvals.resize(N); + for(int i = 0; i < N; i++) eigvals[i] = D[i]; + delete[] D; + eigvecs.resize(N); + for(int i = 0; i < N; i++) { + eigvecs[i].resize(N); + for(int j = 0; j < N; j++) eigvecs[i][j] = Q[j + i * N]; + } + delete[] Q; + + return true; +} + +void BandResolvent( + const sparsexx::dist_sparse_matrix > + &H, + std::vector > &vecs, + const std::vector > &ws, + std::vector > > > &res, + int nLanIts, double E0, bool ispart, bool print, bool saveGFmats) { + // COMPUTES THE RESOLVENT (ws - H)^-1 IN MATRIX FORM FOR THE "BASIS" GIVEN BY + // THE vecs VECTORS AND THE FREQUENCY GRID IN ws. USES THE BAND LANCZOS + // ALGORITHM. IT GETS STORED IN res. + res.clear(); + std::cout << "RESOLVENT ROUTINE: "; + res.resize(ws.size(), + std::vector > >( + vecs.size(), std::vector >( + vecs.size(), std::complex(0., 0.)))); + int n = vecs.size(); + + // FIRST, COMPUTE QR DECOMPOSITION OF THE "BASIS" VECTORS vecs, NECESSARY FOR + // LANCZOS + std::vector > R; + std::cout << "QR DECOMPOSITION ..."; + bool worked = QRdecomp_tr(vecs, R); + if(not worked) { + std::cout << "QR DECOMPOSITION FAILED!!" << std::endl; + return; + } + std::cout << "DONE! "; + + if(print) { + std::ofstream ofile("QRresVecs.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF QR DECOMPOSITION: " << std::endl; + ofile << " New Vectors: " << std::endl; + for(int i = 0; i < vecs[0].size(); i++) { + for(int j = 0; j < vecs.size(); j++) + ofile << std::scientific << vecs[j][i] << " "; + ofile << std::endl; } - delete[] AB; - - //FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! - delete[] WORK; - WORK = new double[2 * N - 2]; - dsteqr_(&COMPZ, &N, D, E, Q, &LDQ, WORK, &INFO); - if(INFO != 0){ - std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! ERROR CODE: " << INFO << std::endl; - return false; + ofile.close(); + ofile.clear(); + ofile.open("QRresRmat.dat", std::ios::out); + ofile << " R Matrix: " << std::endl; + for(int i = 0; i < R.size(); i++) { + for(int j = 0; j < R[i].size(); j++) + ofile << std::scientific << R[i][j] << " "; + ofile << std::endl; } - delete[] WORK; - delete[] E; - - //NOW, STORE THE EIGENVALUES AND EIGENVECTORS - eigvals.resize(N); - for(int i = 0; i < N; i++) eigvals[i] = D[i]; - delete[] D; - eigvecs.resize(N); - for(int i = 0; i < N; i++){ - eigvecs[i].resize(N); - for(int j = 0; j < N; j++) eigvecs[i][j] = Q[j + i * N]; + ofile.close(); + } + + // NEXT, COMPUTE THE BAND LANCZOS + std::vector > bandH; + std::cout << "BAND LANCZOS ..."; + MyBandLan(H, vecs, bandH, nLanIts, 1.E-6, print); + std::cout << "DONE! "; + if(print) { + std::ofstream ofile("BLH.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF BAND LANCZOS: " << std::endl; + ofile << " bandH Matrix: " << std::endl; + for(int i = 0; i < bandH.size(); i++) { + for(int j = 0; j < bandH[i].size(); j++) + ofile << std::scientific << bandH[i][j] << " "; + ofile << std::endl; } - delete[] Q; - - return true; - + ofile.close(); } - - void BandResolvent( - const sparsexx::dist_sparse_matrix > &H, - std::vector > &vecs, - const std::vector > &ws, - std::vector > > > &res, - int nLanIts, - double E0, - bool ispart, - bool print, - bool saveGFmats ) - { - //COMPUTES THE RESOLVENT (ws - H)^-1 IN MATRIX FORM FOR THE "BASIS" GIVEN BY THE - //vecs VECTORS AND THE FREQUENCY GRID IN ws. USES THE BAND LANCZOS ALGORITHM. IT - //GETS STORED IN res. - res.clear(); - std::cout << "RESOLVENT ROUTINE: "; - res.resize(ws.size(), std::vector > >(vecs.size(), std::vector >(vecs.size(), std::complex(0.,0.)) )); - int n = vecs.size(); - - - //FIRST, COMPUTE QR DECOMPOSITION OF THE "BASIS" VECTORS vecs, NECESSARY FOR - //LANCZOS - std::vector > R; - std::cout << "QR DECOMPOSITION ..."; - bool worked = QRdecomp_tr(vecs, R); - if(not worked) - { - std::cout << "QR DECOMPOSITION FAILED!!" << std::endl; - return; + + if(n == 1) { + // ONLY ONE BAND. DIAGONAL GREEN'S FUNCTION ELEMENT. + // COMPUTE THROUGH CONTINUED FRACTION. + std::cout << "COMPUTING GF AS CONTINUED FRACTION..."; + std::vector alphas(bandH.size(), 0.), betas(bandH.size(), 0.); + for(int i = 0; i < bandH.size(); i++) + alphas[i] = ispart ? E0 - bandH[i][i] : bandH[i][i] - E0; + for(int i = 0; i < bandH.size() - 1; i++) + betas[i + 1] = ispart ? -bandH[i][i + 1] : bandH[i][i + 1]; + betas[0] = R[0][0]; +#pragma omp parallel for + for(int indx_w = 0; indx_w < ws.size(); indx_w++) { + res[indx_w][0][0] = + betas.back() * betas.back() / (ws[indx_w] + alphas.back()); + for(int i = betas.size() - 2; i >= 0; i--) + res[indx_w][0][0] = + betas[i] * betas[i] / (ws[indx_w] + alphas[i] - res[indx_w][0][0]); } - std::cout << "DONE! "; - - if(print){ - std::ofstream ofile("QRresVecs.dat", std::ios::out); - ofile.precision(dbl::max_digits10); - ofile << "RESULT OF QR DECOMPOSITION: " << std::endl; - ofile << " New Vectors: " << std::endl; - for(int i = 0; i < vecs[0].size(); i++){ - for(int j = 0; j < vecs.size(); j++) ofile << std::scientific << vecs[j][i] << " "; - ofile << std::endl; + } else { + // NEXT, COMPUTE THE EIGENVALUES AND EIGENVECTORS OF THE BAND DIAGONAL + // KRYLOV HAMILTONIAN + std::vector eigvals; + std::vector > eigvecs; + std::cout << "COMPUTING EIGENVALES ..."; + if(ispart) + for(int rr = 0; rr < bandH.size(); rr++) { + bandH[rr][rr] = E0 - bandH[rr][rr]; + for(int cc = rr + 1; cc < bandH.size(); cc++) { + bandH[rr][cc] = -bandH[rr][cc]; + bandH[cc][rr] = -bandH[cc][rr]; + } } - ofile.close(); - ofile.clear(); - ofile.open("QRresRmat.dat", std::ios::out); - ofile << " R Matrix: " << std::endl; - for(int i = 0; i < R.size(); i++){ - for(int j = 0; j < R[i].size(); j++) ofile << std::scientific << R[i][j] << " "; + else + for(int rr = 0; rr < bandH.size(); rr++) + bandH[rr][rr] = bandH[rr][rr] - E0; + + GetEigsysBand(bandH, std::min(size_t(n), bandH.size() - 1), eigvals, + eigvecs); + if(print) { + std::ofstream ofile("BLEigs.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + ofile << "RESULT OF EIGENVALUE CALCULATION: " << std::endl; + ofile << " Eigvals: ["; + for(int i = 0; i < eigvals.size(); i++) + ofile << std::scientific << eigvals[i] << ", "; + ofile << std::endl; + ofile << "Eigvecs: " << std::endl; + for(int i = 0; i < eigvecs.size(); i++) { + for(int j = 0; j < eigvecs[i].size(); j++) + ofile << std::scientific << eigvecs[i][j] << " "; ofile << std::endl; } ofile.close(); } - - //NEXT, COMPUTE THE BAND LANCZOS - std::vector > bandH; - std::cout << "BAND LANCZOS ..."; - MyBandLan(H, vecs, bandH, nLanIts, 1.E-6, print); std::cout << "DONE! "; - if(print){ - std::ofstream ofile("BLH.dat", std::ios::out); - ofile.precision(dbl::max_digits10); - ofile << "RESULT OF BAND LANCZOS: " << std::endl; - ofile << " bandH Matrix: " << std::endl; - for(int i = 0; i < bandH.size(); i++){ - for(int j = 0; j < bandH[i].size(); j++) ofile << std::scientific << bandH[i][j] << " "; - ofile << std::endl; - } - ofile.close(); - } - - if(n == 1) - { - //ONLY ONE BAND. DIAGONAL GREEN'S FUNCTION ELEMENT. - //COMPUTE THROUGH CONTINUED FRACTION. - std::cout << "COMPUTING GF AS CONTINUED FRACTION..."; - std::vector alphas(bandH.size(), 0.), betas(bandH.size(), 0.); - for(int i = 0; i < bandH.size(); i++) - alphas[i] = ispart ? E0 - bandH[i][i] : bandH[i][i] - E0; - for(int i = 0; i < bandH.size()-1; i++) - betas[i+1] = ispart ? -bandH[i][i+1] : bandH[i][i+1]; - betas[0] = R[0][0]; - #pragma omp parallel for - for(int indx_w = 0; indx_w < ws.size(); indx_w++){ - res[indx_w][0][0] = betas.back() * betas.back() / (ws[indx_w] + alphas.back()); - for(int i = betas.size() - 2; i >= 0; i--) res[indx_w][0][0] = betas[i] * betas[i] / (ws[indx_w] + alphas[i] - res[indx_w][0][0]); + // FINALLY, COMPUTE S-MATRIX AND RESOLVENT + std::vector > S(nLanIts, std::vector(n, 0.)); + std::cout << " COMPUTING S MATRIX ..."; + for(int i_lan = 0; i_lan < nLanIts; i_lan++) { + for(int j_n = 0; j_n < n; j_n++) { + for(int l = 0; l < n; l++) + S[i_lan][j_n] += eigvecs[i_lan][l] * R[l][j_n]; } } - else - { - //NEXT, COMPUTE THE EIGENVALUES AND EIGENVECTORS OF THE BAND DIAGONAL KRYLOV - //HAMILTONIAN - std::vector eigvals; - std::vector > eigvecs; - std::cout << "COMPUTING EIGENVALES ..."; - if( ispart ) - for( int rr = 0; rr < bandH.size(); rr++ ) - { - bandH[rr][rr] = E0 - bandH[rr][rr]; - for( int cc = rr+1; cc < bandH.size(); cc++ ) - { - bandH[rr][cc] = -bandH[rr][cc]; - bandH[cc][rr] = -bandH[cc][rr]; - } - } - else - for( int rr = 0; rr < bandH.size(); rr++ ) - bandH[rr][rr] = bandH[rr][rr] - E0; - - GetEigsysBand(bandH, std::min(size_t(n), bandH.size() - 1), eigvals, eigvecs); - if(print){ - std::ofstream ofile("BLEigs.dat", std::ios::out); - ofile.precision(dbl::max_digits10); - ofile << "RESULT OF EIGENVALUE CALCULATION: " << std::endl; - ofile << " Eigvals: ["; - for(int i = 0; i < eigvals.size(); i++) ofile << std::scientific << eigvals[i] << ", "; + if(saveGFmats) { + std::cout << "WRITING S MATRIX AND BAND-LANCZOS EIGENVALUES TO FILE!" + << std::endl; + std::string fprefix = ispart ? "particle" : "hole"; + std::ofstream ofile(fprefix + "_S.mat", std::ios::out); + ofile.precision(dbl::max_digits10); + for(int i_lan = 0; i_lan < nLanIts; i_lan++) { + for(int k = 0; k < n; k++) + ofile << std::scientific << S[i_lan][k] << " "; ofile << std::endl; - ofile << "Eigvecs: " << std::endl; - for(int i = 0; i < eigvecs.size(); i++){ - for(int j = 0; j < eigvecs[i].size(); j++) ofile << std::scientific << eigvecs[i][j] << " "; - ofile << std::endl; - } - ofile.close(); - } - std::cout << "DONE! "; - //FINALLY, COMPUTE S-MATRIX AND RESOLVENT - std::vector > S(nLanIts, std::vector(n, 0.)); - std::cout << " COMPUTING S MATRIX ..."; - for(int i_lan = 0; i_lan < nLanIts; i_lan++){ - for(int j_n = 0; j_n < n; j_n++){ - for(int l = 0; l < n; l++) S[i_lan][j_n] += eigvecs[i_lan][l] * R[l][j_n]; - } - } - if( saveGFmats ) - { - std::cout << "WRITING S MATRIX AND BAND-LANCZOS EIGENVALUES TO FILE!" << std::endl; - std::string fprefix = ispart ? "particle" : "hole"; - std::ofstream ofile( fprefix + "_S.mat", std::ios::out ); - ofile.precision( dbl::max_digits10 ); - for( int i_lan = 0; i_lan < nLanIts; i_lan++) - { - for( int k = 0; k < n; k++ ) - ofile << std::scientific << S[i_lan][k] << " "; - ofile << std::endl; - } - ofile.close(); - ofile.open( fprefix + "_BLevals.dat", std::ios::out); - ofile.precision( dbl::max_digits10 ); - for( int i_lan = 0; i_lan < nLanIts; i_lan++ ) - ofile << std::scientific << eigvals[i_lan] << std::endl; - ofile.close(); - } - std::cout << "DONE! COMPUTING RESOLVENT ..."; - #pragma omp parallel for - for(int iw = 0; iw < ws.size(); iw++){ - for(int k = 0; k < n; k++){ - for(int l = 0; l < n; l++){ - for(int i_lan = 0; i_lan < nLanIts; i_lan++){ - res[iw][k][l] += S[i_lan][k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan][l]; - } + ofile.close(); + ofile.open(fprefix + "_BLevals.dat", std::ios::out); + ofile.precision(dbl::max_digits10); + for(int i_lan = 0; i_lan < nLanIts; i_lan++) + ofile << std::scientific << eigvals[i_lan] << std::endl; + ofile.close(); + } + std::cout << "DONE! COMPUTING RESOLVENT ..."; +#pragma omp parallel for + for(int iw = 0; iw < ws.size(); iw++) { + for(int k = 0; k < n; k++) { + for(int l = 0; l < n; l++) { + for(int i_lan = 0; i_lan < nLanIts; i_lan++) { + res[iw][k][l] += + S[i_lan][k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan][l]; } } } } - std::cout << "DONE!" << std::endl; } - -}// namespace macis + std::cout << "DONE!" << std::endl; +} + +} // namespace macis diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index 8a2a0e2c..4eb42f5b 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -10,99 +10,106 @@ /***Written by Carlos Mejuto Zaera***/ -namespace macis -{ +namespace macis { - void Hste_v(const std::vector &alphas, const std::vector &betas, VectorXd &eigvals, eigMatD &eigvecs){ - /* - * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A TRIDIAGONAL, SYMMETRIC MATRIX A USING LAPACK. - */ - eigvals.resize(alphas.size()); - eigvecs.resize(alphas.size(), alphas.size()); - //INITIALIZE VARIABLES - char JOBZ = 'I'; // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX - int N = alphas.size(), LDZ = N, INFO; // SIZES - double *D, *E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS - double *WORK, *Z; // WORKSPACE AND EIGENVECTORS - //INITIALIZE MATRIX - D = new double[N]; - for(int64_t i = 0; i < N; i++) - D[i] = alphas[i]; - E = new double[N-1]; - for(int64_t i = 1; i < N; i++) - E[i-1] = betas[i]; - //ALLOCATE MEMORY - WORK = new double[2*N -2]; - Z = new double[N * LDZ]; - - //ACTUAL EIGENVALUE CALCULATION - dsteqr_(&JOBZ, &N, D, E, Z, &LDZ, WORK, &INFO); - if(INFO != 0){ - if(INFO < 0) - throw ("In dsteqr_, the " + std::to_string(-1 * INFO) + "-th argument had an illegal value"); - if(INFO > 0) - throw ("dsteqr_ the algorithm has failed to find all the eigenvalues in a total of " + std::to_string(30*N) + " iterations"); - } - delete[] WORK; - delete[] E; - //SAVE EIGENVECTORS - for(int i = 0; i < N; i++){ - for(int j = 0; j < N; j++) eigvecs(i,j) = Z[i+ j * N]; - } - delete[] Z; - //SAVE EIGENVALUES - for(int i = 0; i < N; i++) eigvals(i) = D[i]; - - delete[] D; +void Hste_v(const std::vector &alphas, const std::vector &betas, + VectorXd &eigvals, eigMatD &eigvecs) { + /* + * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A TRIDIAGONAL, SYMMETRIC + * MATRIX A USING LAPACK. + */ + eigvals.resize(alphas.size()); + eigvecs.resize(alphas.size(), alphas.size()); + // INITIALIZE VARIABLES + char JOBZ = + 'I'; // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX + int N = alphas.size(), LDZ = N, INFO; // SIZES + double *D, *E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS + double *WORK, *Z; // WORKSPACE AND EIGENVECTORS + // INITIALIZE MATRIX + D = new double[N]; + for(int64_t i = 0; i < N; i++) D[i] = alphas[i]; + E = new double[N - 1]; + for(int64_t i = 1; i < N; i++) E[i - 1] = betas[i]; + // ALLOCATE MEMORY + WORK = new double[2 * N - 2]; + Z = new double[N * LDZ]; + + // ACTUAL EIGENVALUE CALCULATION + dsteqr_(&JOBZ, &N, D, E, Z, &LDZ, WORK, &INFO); + if(INFO != 0) { + if(INFO < 0) + throw("In dsteqr_, the " + std::to_string(-1 * INFO) + + "-th argument had an illegal value"); + if(INFO > 0) + throw( + "dsteqr_ the algorithm has failed to find all the eigenvalues in a " + "total of " + + std::to_string(30 * N) + " iterations"); + } + delete[] WORK; + delete[] E; + // SAVE EIGENVECTORS + for(int i = 0; i < N; i++) { + for(int j = 0; j < N; j++) eigvecs(i, j) = Z[i + j * N]; + } + delete[] Z; + // SAVE EIGENVALUES + for(int i = 0; i < N; i++) eigvals(i) = D[i]; + + delete[] D; +} + +void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs) { + /* + * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING + * LAPACK. + */ + eigvals.resize(H.rows()); + eigvecs.resize(H.rows(), H.rows()); + // INITIALIZE VARIABLES + char JOBZ = 'V', UPLO = 'U'; // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS + // STORED IN THE UPPER TRIANGLE + int N = H.rows(), LWORK = -1, LDA = N, INFO; // SIZES + double *A, *WORK; // MATRIX AND WORKSPACE + double *W; // EIGENVALUES AND WORKSPACE + // INITIALIZE MATRIX + A = new double[N * N]; + for(int i = 0; i < N; i++) { + for(int j = 0; j < N; j++) A[i + j * N] = H(i, j); + } + // ALLOCATE MEMORY + WORK = new double[2 * N + 1]; + W = new double[N]; + + // MEMORY QUERY + dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); + if(INFO != 0) + throw("ERROR IN dsyev_ MEMORY QUERY!! ERROR CODE: " + std::to_string(INFO)); + LWORK = WORK[0]; + delete[] WORK; + WORK = new double[LWORK]; + // ACTUAL EIGENVALUE CALCULATION + dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); + if(INFO != 0) { + if(INFO < 0) + throw("ERROR IN dsyev_! The " + std::to_string(-1 * INFO) + + "-th argument had an illegal value"); + throw("ERROR IN dsyev_! Algorithm failed to converge! " + + std::to_string(INFO) + + " off-diagonal elements of an intermediate tridiagonal form did not " + "converge to zero"); } - - void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs){ - /* - * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING LAPACK. - */ - eigvals.resize(H.rows()); - eigvecs.resize(H.rows(), H.rows()); - //INITIALIZE VARIABLES - char JOBZ = 'V', UPLO = 'U'; // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS STORED IN THE UPPER TRIANGLE - int N = H.rows(), LWORK = -1, LDA = N, INFO; // SIZES - double *A, *WORK; // MATRIX AND WORKSPACE - double *W; // EIGENVALUES AND WORKSPACE - //INITIALIZE MATRIX - A = new double[N * N]; - for(int i = 0; i < N; i++){ - for(int j = 0; j < N; j++) - A[i + j * N] = H(i,j); - } - //ALLOCATE MEMORY - WORK = new double[2*N + 1]; - W = new double[N]; - - //MEMORY QUERY - dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); - if(INFO != 0) - throw ("ERROR IN dsyev_ MEMORY QUERY!! ERROR CODE: " + std::to_string(INFO)); - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; - //ACTUAL EIGENVALUE CALCULATION - dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); - if(INFO != 0){ - if(INFO < 0) - throw("ERROR IN dsyev_! The " + std::to_string(-1 * INFO) + "-th argument had an illegal value"); - throw("ERROR IN dsyev_! Algorithm failed to converge! " + std::to_string(INFO) + " off-diagonal elements of an intermediate tridiagonal form did not converge to zero"); - } - delete[] WORK; - //SAVE EIGENVECTORS - for(int i = 0; i < N; i++){ - for(int j = 0; j < N; j++) - eigvecs(i,N - 1 - j) = A[i+ j * N]; - } - delete[] A; - //SAVE EIGENVALUES - for(int i = 0; i < N; i++) - eigvals(N - 1 - i) = W[i]; - - delete[] W; + delete[] WORK; + // SAVE EIGENVECTORS + for(int i = 0; i < N; i++) { + for(int j = 0; j < N; j++) eigvecs(i, N - 1 - j) = A[i + j * N]; } + delete[] A; + // SAVE EIGENVALUES + for(int i = 0; i < N; i++) eigvals(N - 1 - i) = W[i]; + + delete[] W; +} -}// namespace macis +} // namespace macis diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index b241f3a7..093a506f 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -8,53 +8,49 @@ #include "macis/gf/gf.hpp" -namespace macis -{ - void write_GF( const std::vector > > > &GF, const std::vector > &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part ) - { +namespace macis { +void write_GF( + const std::vector > > > &GF, + const std::vector > &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part) { + size_t nfreqs = ws.size(); - size_t nfreqs = ws.size(); + if(GF_orbs.size() > 1) { + std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) { + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; + for(int jjj = 0; jjj < GF[iii].size(); jjj++) { + for(int lll = 0; lll < GF[iii][jjj].size(); lll++) + ofile << std::scientific << real(GF[iii][jjj][lll]) << " " + << imag(GF[iii][jjj][lll]) << " "; + } + ofile << std::endl; + } + ofile.close(); - if(GF_orbs.size() > 1) - { - - std::string fname = is_part ? - "LanGFMatrix_ADD.dat" - : "LanGFMatrix_SUB.dat"; - std::ofstream ofile( fname ); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++){ - ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; - for(int jjj = 0; jjj < GF[iii].size(); jjj++){ - for(int lll = 0; lll < GF[iii][jjj].size(); lll++)ofile << std::scientific << real(GF[iii][jjj][lll]) << " " << imag(GF[iii][jjj][lll]) << " "; - } - ofile << std::endl; - } - ofile.close(); - - std::string fname2 = is_part ? - "GFMatrix_OrbitalIndices_ADD.dat" - : "GFMatrix_OrbitalIndices_SUB.dat"; - std::ofstream ofile2( fname2 ); - for(int iii = 0; iii < GF_orbs.size(); iii++) - { - if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) - continue; - ofile2 << GF_orbs[iii] << std::endl; - } - ofile2.close(); - } - else - { - std::string fname = is_part ? - "LanGF_ADD_" - : "LanGF_SUB_"; - fname += std::to_string(GF_orbs[0]+1) + "_" + std::to_string(GF_orbs[0]+1) + ".dat"; - std::ofstream ofile( fname ); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++) ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " << real(GF[iii][0][0]) << " " << imag(GF[iii][0][0]) << std::endl; - ofile.close(); - } + std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" + : "GFMatrix_OrbitalIndices_SUB.dat"; + std::ofstream ofile2(fname2); + for(int iii = 0; iii < GF_orbs.size(); iii++) { + if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) + continue; + ofile2 << GF_orbs[iii] << std::endl; + } + ofile2.close(); + } else { + std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; + fname += std::to_string(GF_orbs[0] + 1) + "_" + + std::to_string(GF_orbs[0] + 1) + ".dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " + << real(GF[iii][0][0]) << " " << imag(GF[iii][0][0]) << std::endl; + ofile.close(); } +} -}// namespace macis +} // namespace macis diff --git a/src/sparsexx/examples/attic/test_norm.cxx b/src/sparsexx/examples/attic/test_norm.cxx index 09d19628..d31017ba 100644 --- a/src/sparsexx/examples/attic/test_norm.cxx +++ b/src/sparsexx/examples/attic/test_norm.cxx @@ -178,7 +178,7 @@ int main(int argc, char** argv) { // } //// sparsexx::spblas::gespmbv( K, 1., A, V.data(), N, 0., AV_serial.data(), - ///N ); + /// N ); auto pspbmv_dur = time_op([&]() { sparsexx::spblas::pgespmbv_grv(K, 1., dist_B, V.data(), N, 0., diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 2093cbc4..56bd0eef 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -304,71 +304,70 @@ int main(int argc, char** argv) { } } - - // Testing GF - bool testGF = false; - OPT_KEYWORD("CI.GF", testGF, bool); - if( testGF ) - { - // Generate determinant list - auto dets = macis::generate_hilbert_space(n_active, nalpha, nbeta); - // Generate the Hamiltonian Generator - generator_t ham_gen( - macis::matrix_span(T_active.data(),n_active,n_active), - macis::rank4_span(V_active.data(),n_active,n_active,n_active, - n_active) - ); - - // Generate frequency grid - double wmin = -8.; - double wmax = 8.; - size_t nws = 1001; - double eta = 0.1; - std::complex w0( wmin, eta ); - std::complex wf( wmax, eta ); - std::vector > ws( nws, std::complex(0.,0.) ); - for( int i = 0; i < nws; i++ ) - ws[i] = w0 + (wf - w0) / double(nws - 1) * double(i); - - // MCSCF Settings - macis::GFSettings gf_settings; - OPT_KEYWORD("GF.NORBS" , gf_settings.norbs, size_t); - OPT_KEYWORD("GF.TRUNC_SIZE" , gf_settings.trunc_size, size_t); - OPT_KEYWORD("GF.TOT_SD" , gf_settings.tot_SD, int); - OPT_KEYWORD("GF.GFSEEDTHRES", gf_settings.GFseedThres, double ); - OPT_KEYWORD("GF.ASTHRES" , gf_settings.asThres, double); - OPT_KEYWORD("GF.USE_BANDLAN", gf_settings.use_bandLan, bool); - OPT_KEYWORD("GF.NLANITS" , gf_settings.nLanIts, int); - OPT_KEYWORD("GF.WRITE" , gf_settings.writeGF, bool); - OPT_KEYWORD("GF.PRINT" , gf_settings.print, bool); - OPT_KEYWORD("GF.SAVEGFMATS" , gf_settings.saveGFmats, bool); - gf_settings.GF_orbs_basis = std::vector(n_active,0); - for( int i = 0; i < n_active; i++ ) - gf_settings.GF_orbs_basis[i] = i; - gf_settings.GF_orbs_comp = std::vector(2,0); - for( int i = 0; i < 2; i++ ) - gf_settings.GF_orbs_comp[i] = i; - gf_settings.is_up_basis = std::vector(n_active, true); - gf_settings.is_up_comp = std::vector(2, true); - - // GF vector - std::vector > > > GF( 1, std::vector > >(1, std::vector >(nws, std::complex(0.,0.) ) ) ); - - // Occupation numbers - std::vector occs( n_active, 1. ); - - // GS vector - Eigen::VectorXd psi0 = Eigen::Map( C_local.data(), C_local.size() ); - - // Evaluate particle GF - macis::RunGFCalc( GF, psi0, ham_gen, dets, E0, true, ws, occs, gf_settings ); - // Evaluate hole GF - macis::RunGFCalc( GF, psi0, ham_gen, dets, E0, false, ws, occs, gf_settings ); - } - - - - + // Testing GF + bool testGF = false; + OPT_KEYWORD("CI.GF", testGF, bool); + if(testGF) { + // Generate determinant list + auto dets = macis::generate_hilbert_space( + n_active, nalpha, nbeta); + // Generate the Hamiltonian Generator + generator_t ham_gen( + macis::matrix_span(T_active.data(), n_active, n_active), + macis::rank4_span(V_active.data(), n_active, n_active, + n_active, n_active)); + + // Generate frequency grid + double wmin = -8.; + double wmax = 8.; + size_t nws = 1001; + double eta = 0.1; + std::complex w0(wmin, eta); + std::complex wf(wmax, eta); + std::vector> ws(nws, + std::complex(0., 0.)); + for(int i = 0; i < nws; i++) + ws[i] = w0 + (wf - w0) / double(nws - 1) * double(i); + + // MCSCF Settings + macis::GFSettings gf_settings; + OPT_KEYWORD("GF.NORBS", gf_settings.norbs, size_t); + OPT_KEYWORD("GF.TRUNC_SIZE", gf_settings.trunc_size, size_t); + OPT_KEYWORD("GF.TOT_SD", gf_settings.tot_SD, int); + OPT_KEYWORD("GF.GFSEEDTHRES", gf_settings.GFseedThres, double); + OPT_KEYWORD("GF.ASTHRES", gf_settings.asThres, double); + OPT_KEYWORD("GF.USE_BANDLAN", gf_settings.use_bandLan, bool); + OPT_KEYWORD("GF.NLANITS", gf_settings.nLanIts, int); + OPT_KEYWORD("GF.WRITE", gf_settings.writeGF, bool); + OPT_KEYWORD("GF.PRINT", gf_settings.print, bool); + OPT_KEYWORD("GF.SAVEGFMATS", gf_settings.saveGFmats, bool); + gf_settings.GF_orbs_basis = std::vector(n_active, 0); + for(int i = 0; i < n_active; i++) gf_settings.GF_orbs_basis[i] = i; + gf_settings.GF_orbs_comp = std::vector(2, 0); + for(int i = 0; i < 2; i++) gf_settings.GF_orbs_comp[i] = i; + gf_settings.is_up_basis = std::vector(n_active, true); + gf_settings.is_up_comp = std::vector(2, true); + + // GF vector + std::vector>>> GF( + 1, std::vector>>( + 1, std::vector>( + nws, std::complex(0., 0.)))); + + // Occupation numbers + std::vector occs(n_active, 1.); + + // GS vector + Eigen::VectorXd psi0 = Eigen::Map( + C_local.data(), C_local.size()); + + // Evaluate particle GF + macis::RunGFCalc(GF, psi0, ham_gen, dets, E0, true, ws, + occs, gf_settings); + // Evaluate hole GF + macis::RunGFCalc(GF, psi0, ham_gen, dets, E0, false, ws, + occs, gf_settings); + } } else { // Generate the Hamiltonian Generator From 2f9d5ee694b891d8c34d28ce963c0b30b33ecd45 Mon Sep 17 00:00:00 2001 From: David Williams-Young Date: Fri, 2 Jun 2023 12:04:47 -0700 Subject: [PATCH 05/35] Remove extra omp.h inclusion --- include/macis/gf/lanczos.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index c184b966..b722c5e8 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -15,7 +15,6 @@ * @date 05/04/2021 */ #pragma once -#include #include #include From e23c5376250f1395c2472ad43288ee1e7950ded0 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Fri, 2 Jun 2023 19:20:59 +0000 Subject: [PATCH 06/35] Committing clang-format changes --- include/macis/gf/bandlan.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 170dbedd..d2f848d0 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -95,7 +95,7 @@ void MyBandLan( // 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 + // ITERATIONS! THE qs VECTOR IS ERASED AT THE END OF THE CALCULATION bandH.clear(); bandH.resize(nLanIts, std::vector(nLanIts, 0.)); From 2ffd1e2bd5504c38caa8338043c1d19ea948efd0 Mon Sep 17 00:00:00 2001 From: CarlosMejZ Date: Mon, 5 Jun 2023 17:12:43 +0200 Subject: [PATCH 07/35] Applied review comments from pull request, started reformulating the Band Lanczos routines to use matrices which are guaranteed contiguous in memory. --- include/macis/gf/bandlan.hpp | 134 ++++++++++++++----- include/macis/gf/eigsolver.hpp | 18 +-- include/macis/gf/gf.hpp | 25 +--- include/macis/gf/inn_prods.hpp | 34 +---- src/macis/gf/bandlan.cxx | 226 ++++++--------------------------- src/macis/gf/eigsolver.cxx | 79 ++++-------- src/macis/gf/gf.cxx | 3 - 7 files changed, 179 insertions(+), 340 deletions(-) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index d2f848d0..b96a7641 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -30,36 +30,91 @@ #include #include "macis/gf/inn_prods.hpp" +#include "macis/solvers/davidson.hpp" typedef std::numeric_limits dbl; namespace macis { -extern "C" { -extern int dgeqrf_(int *, int *, double *, int *, double *, double *, int *, - int *); -extern int dorgqr_(int *, int *, int *, double *, int *, double *, double *, - int *, int *); -extern int dsbtrd_(char *, char *, int *, int *, double *, int *, double *, - double *, double *, int *, double *, int *); -extern int dsytrd_(char *, int *, double *, int *, double *, double *, double *, - double *, int *, int *); -extern int dorgtr_(char *, int *, double *, int *, double *, double *, int *, - int *); -extern int dsteqr_(char *, int *, double *, double *, double *, int *, double *, - int *); -} - +/** + * @ 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 > &Q: On input, + * matrix for which to evaluate the QR decomposition. + * On output, Q-matrix. + * @param[out] std::vector > &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 > &Q, std::vector > &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 > &Q: On input, + * matrix for which to evaluate the QR decomposition. + * On output, Q-matrix. + * @param[out] std::vector > &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 > &Q, std::vector > &R); +/** + * @brief Wrapper to LAPACK routine to evaluate the eigenvectors + * and eigenvalues of the symmetric matrix mat. + * + * @param[inout] std::vector > &mat: Matrix for + * which to compute the eigenvalues/vectors. Erased + * during computation. + * @param[out] std::vector &eigvals: Eigenvalues, sorted from smallest + * to largest. + * @param[out] std::vector > &eigvecs: Eigenvectors, + * stored as row vectors. + * + * @returns bool: Error code from LAPACK. + * + * @author Carlos Mejuto Zaera + * @date 25/04/2022 + */ bool GetEigsys(std::vector > &mat, std::vector &eigvals, std::vector > &eigvecs); +/** + * @brief Wrapper to LAPACK routine to evaluate the eigenvectors + * and eigenvalues of the symmetric band matrix mat. + * + * @param[inout] std::vector > &mat: Matrix for + * which to compute the eigenvalues/vectors. Erased + * during computation. + * @param[in] int nSupDiag: Nr. of bands. + * @param[out] std::vector &eigvals: Eigenvalues, sorted from smallest + * to largest. + * @param[out] std::vector > &eigvecs: Eigenvectors, + * stored as row vectors. + * + * @returns bool: Error code from LAPACK. + * + * @author Carlos Mejuto Zaera + * @date 25/04/2022 + */ bool GetEigsysBand(std::vector > &mat, int nSupDiag, std::vector &eigvals, std::vector > &eigvecs); @@ -85,12 +140,12 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, * @author Carlos Mejuto Zaera * @date 25/04/2022 */ -template +template void MyBandLan( - const sparsexx::dist_sparse_matrix > - &H, - std::vector > &qs, std::vector > &bandH, - int &nLanIts, double thres = 1.E-6, bool print = false) { + const Functor &H, + //std::vector > &qs, std::vector > &bandH, + std::vector &qs, std::vector > &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 @@ -99,18 +154,20 @@ void MyBandLan( bandH.clear(); bandH.resize(nLanIts, std::vector(nLanIts, 0.)); - int nbands = qs.size(); - auto spmv_info = sparsexx::spblas::generate_spmv_comm_info(H); // MAKE SPACE FOR 2 * nbands VECTORS - qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); - std::vector temp(qs[0].size(), 0.); + //qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); + qs.resize( 2 * nbands * N ); + //std::vector temp(qs[0].size(), 0.); + std::vector 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++) - ofile << std::scientific << qs[i][el] << std::endl; + //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(); } } @@ -125,8 +182,8 @@ void MyBandLan( 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 - sparsexx::spblas::pgespmv(1., H, qs[band_indx_i].data(), 0., temp.data(), - spmv_info); + //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); @@ -140,15 +197,18 @@ void MyBandLan( 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[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] = 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[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] = @@ -166,20 +226,24 @@ void MyBandLan( break; #pragma omp parallel for for(size_t coeff = 0; coeff < temp.size(); coeff++) - qs[true_indx[it + nbands]][coeff] = 0.; + //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++) - qs[true_indx[it + nbands]][coeff] = + //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++) - ofile << std::scientific << qs[true_indx[it + nbands]][el] + //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(); } diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index d0e6db20..32478ef0 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -17,20 +17,14 @@ #pragma once #include #include +#include namespace macis { -using namespace Eigen; -typedef MatrixXd eigMatD; -typedef SparseMatrix SpMatD; - -extern "C" { -extern int dsteqr_(char *, int *, double *, double *, double *, int *, double *, - int *); -extern int dsyev_(char *, char *, int *, double *, int *, double *, double *, - int *, int *); -} +typedef Eigen::VectorXd VectorXd; +typedef Eigen::MatrixXd eigMatD; +typedef Eigen::SparseMatrix SpMatD; /** * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric @@ -45,7 +39,7 @@ extern int dsyev_(char *, char *, int *, double *, int *, double *, double *, * @date 05/04/2021 */ void Hste_v(const std::vector &alphas, const std::vector &betas, - VectorXd &eigvals, eigMatD &eigvecs); + Eigen::VectorXd &eigvals, eigMatD &eigvecs); /** * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric @@ -59,6 +53,6 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, * @author Carlos Mejuto Zaera * @date 05/04/2021 */ -void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs); +void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs); } // namespace macis diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 588dccbd..619629a1 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -37,7 +37,7 @@ namespace macis { -using namespace Eigen; +typedef Eigen::VectorXd VectorXd; typedef std::numeric_limits dbl; typedef std::chrono::high_resolution_clock Clock; @@ -165,21 +165,6 @@ void GF_Diag(const VectorXd &state_0, const MatOp &H, } } -/** - * @brief Class for comparing two determinants, to use in sorting routines. - * - * @author Carlos Mejuto Zaera - * @date 28/01/2022 - */ -template -class BitSetComparator { - public: - bool operator()(const std::bitset &c1, - const std::bitset &c2) const { - return bitset_less(c1, c2); - } -}; - /** * @brief Routine to build basis to compute the basis for Green's function * calculation on the state |wfn> considering orbital orb. Templated @@ -244,10 +229,10 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, std::bitset uni_string; std::vector> founddets; founddets.reserve(trunc_size); - std::map, size_t, BitSetComparator> founddet_pos, + std::map, size_t, bitset_less_comparator> founddet_pos, basedet_pos; typename std::map, size_t, - BitSetComparator>::iterator it; + bitset_less_comparator>::iterator it; // ACTIVE SPACE std::vector as_orbs; for(size_t i = 0; i < occs.size(); i++) { @@ -401,7 +386,7 @@ std::vector> BuildWfn4Lanczos( const std::vector> &GF_dets, bool is_part, std::vector &todelete, double zero_thresh = 1.E-7) { // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - std::map, size_t, BitSetComparator> base_dets_pos; + std::map, size_t, bitset_less_comparator> base_dets_pos; for(size_t iii = 0; iii < base_dets.size(); iii++) base_dets_pos[base_dets[iii]] = iii; @@ -428,7 +413,7 @@ std::vector> BuildWfn4Lanczos( std::bitset temp(GF_dets[ndet]); temp.flip(sporb); typename std::map, size_t, - BitSetComparator>::const_iterator it = + bitset_less_comparator>::const_iterator it = base_dets_pos.find(temp); if(it != base_dets_pos.end()) { // IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp index a5bb00ad..837207ab 100644 --- a/include/macis/gf/inn_prods.hpp +++ b/include/macis/gf/inn_prods.hpp @@ -32,14 +32,7 @@ namespace macis { */ inline double MyInnProd(const std::vector& vecR, const std::vector& vecL) { - // SIMPLE INNER PRODUCT ROUTINE - double res = 0.; -#pragma omp declare reduction(Vsum:double \ - : omp_out = omp_out + omp_in) \ - initializer(omp_priv = 0.) -#pragma omp parallel for reduction(Vsum : res) - for(size_t i = 0; i < vecR.size(); i++) res += vecR[i] * vecL[i]; - return res; + return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); } /** @@ -56,14 +49,7 @@ inline double MyInnProd(const std::vector& vecR, inline std::complex MyInnProd( const std::vector >& vecR, const std::vector >& vecL) { - // SIMPLE INNER PRODUCT ROUTINE - std::complex res(0., 0.); -#pragma omp declare reduction \ - (Vsum:std::complex:omp_out=omp_out+omp_in)\ - initializer(omp_priv=std::complex(0.,0.)) -#pragma omp parallel for reduction(Vsum : res) - for(size_t i = 0; i < vecR.size(); i++) res += conj(vecR[i]) * vecL[i]; - return res; + return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); } /** @@ -80,15 +66,7 @@ inline std::complex MyInnProd( inline std::complex MyInnProd( const std::vector >& vecR, const std::vector& vecL) { - // SIMPLE INNER PRODUCT ROUTINE - std::complex res(0., 0.); -#pragma omp declare reduction \ - (Vsum:std::complex:omp_out=omp_out+omp_in)\ - initializer(omp_priv=std::complex(0.,0.)) -#pragma omp parallel for reduction(Vsum : res) - for(size_t i = 0; i < vecR.size(); i++) - res += conj(vecR[i]) * std::complex(vecL[i], 0.); - return res; + return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); } /** @@ -103,8 +81,7 @@ inline std::complex MyInnProd( */ inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, const Eigen::VectorXcd& vecL) { - // SIMPLE INNER PRODUCT ROUTINE - return vecR.dot(vecL); + return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); } /** @@ -119,7 +96,6 @@ inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, */ inline double MyInnProd(const Eigen::VectorXd& vecR, const Eigen::VectorXd& vecL) { - // SIMPLE INNER PRODUCT ROUTINE - return vecR.dot(vecL); + return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); } } // namespace macis diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index a1d323fa..e928c38b 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -31,36 +31,18 @@ bool QRdecomp(std::vector > &Q, // PREPARE VARIABLES TO CALL LAPACK int M = Q.size(), N = Q[0].size(); assert(M >= N); - int LDA = M, INFO = 0, LWORK; - double *A, *TAU, *WORK; + int LDA = M, INFO = 0; + std::vector A, TAU; // INITIALIZE A - A = new double[M * N]; + A.resize( M * N, 0.); for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; Q[i].clear(); } - // INITIALIZE TAU, AND PERFORM WORKSPACE QUERY - TAU = new double[N]; - WORK = new double[N]; - LWORK = -1; - - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - // NOW, PERFORM ACTUAL QR DECOMPOSITION - WORK = new double[LWORK]; - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO - << std::endl; - return false; - } + // INITIALIZE TAU, AND COMPUTE R MATRIX + TAU.resize( N ); + lapack::geqrf( M, N, A.data(), LDA, TAU.data() ); // SAVE THE R MATRIX R.resize(N); for(int i = 0; i < N; i++) { @@ -71,32 +53,12 @@ bool QRdecomp(std::vector > &Q, // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; - // FIRST, PERFORM WORKSPACE QUERY - LWORK = -1; - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - WORK = new double[LWORK]; - // NOW, COMPUTE ACTUAL Q - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO - << std::endl; - return false; - } - delete[] TAU; - delete[] WORK; + lapack::orgqr( M, N, K, A.data(), LDA, TAU.data() ); // SAVE THE Q MATRIX for(int i = 0; i < M; i++) { Q[i].resize(N); for(int j = 0; j < N; j++) Q[i][j] = A[i + j * M]; } - delete[] A; return true; } @@ -116,36 +78,18 @@ bool QRdecomp_tr(std::vector > &Q, // PREPARE VARIABLES TO CALL LAPACK int M = Q[0].size(), N = Q.size(); assert(M >= N); - int LDA = M, INFO = 0, LWORK; - double *A, *TAU, *WORK; + int LDA = M, INFO = 0; + std::vector A, TAU; // INITIALIZE A - A = new double[M * N]; + A.resize( M * N ); for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; } - // INITIALIZE TAU, AND PERFORM WORKSPACE QUERY - TAU = new double[N]; - WORK = new double[N]; - LWORK = -1; - - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dgeqrf_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - // NOW, PERFORM ACTUAL QR DECOMPOSITION - WORK = new double[LWORK]; - dgeqrf_(&M, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dgeqrf_ QR DECOMPOSITION!! ERROR CODE: " << INFO - << std::endl; - return false; - } + // INITIALIZE TAU, AND EVALUATE R MATRIX + TAU.resize( N ); + lapack::geqrf( M, N, A.data(), LDA, TAU.data() ); // SAVE THE R MATRIX R.resize(N); for(int i = 0; i < N; i++) { @@ -156,31 +100,11 @@ bool QRdecomp_tr(std::vector > &Q, // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; - // FIRST, PERFORM WORKSPACE QUERY - LWORK = -1; - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dorgqr_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = int(WORK[0]); - delete[] WORK; - WORK = new double[LWORK]; - // NOW, COMPUTE ACTUAL Q - dorgqr_(&M, &N, &K, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dorgqr_ COMPUTATION OF Q!! ERROR CODE: " << INFO - << std::endl; - return false; - } - delete[] TAU; - delete[] WORK; + lapack::orgqr( M, N, K, A.data(), LDA, TAU.data() ); // SAVE THE Q MATRIX for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; } - delete[] A; return true; } @@ -196,88 +120,30 @@ bool GetEigsys(std::vector > &mat, eigvals.clear(); eigvecs.clear(); // PREPARE VARIABLES FOR LAPACK - char UPLO = 'U', COMPZ = 'V'; - int N = mat.size(), LDA = mat.size(), LWORK = -1, INFO; - double *A, *D, *E, *TAU, *WORK; + lapack::Uplo UPLO = lapack::Uplo::Upper; + lapack::Job JOBZ = lapack::Job::Vec; + int N = mat.size(), LDA = mat.size(); + std::vector A, D; // INITIALIZE A - A = new double[N * N]; + A.resize( N * N ); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; mat[i].clear(); } mat.clear(); // ALLOCATE REST OF THE MEMORY - D = new double[N]; - E = new double[N - 1]; - TAU = new double[N - 1]; - WORK = new double[N]; - - // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM - // FIRST, PERFORM MEMORY QUERY - dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dsytrd_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; - // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM - dsytrd_(&UPLO, &N, A, &LDA, D, E, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout - << "ERROR IN dsytrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " - << INFO << std::endl; - return false; - } - - // COMPUTE THE TRANSFORMATION MATRIX, NECESSARY TO COMPUTE EIGENVECTORS - // FIRST, PERFORM MEMORY QUERY - LWORK = -1; - dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dorgtr_ MEMORY QUERY!! ERROR CODE: " << INFO - << std::endl; - return false; - } - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; - // NOW, COMPUTE THE TRANSFORMATION MATRIX. IT WILL BE STORED IN A - dorgtr_(&UPLO, &N, A, &LDA, TAU, WORK, &LWORK, &INFO); - if(INFO != 0) { - std::cout - << "ERROR IN dorgtr_ COMPUTING TRANSFORMATION MATRIX!! ERROR CODE: " - << INFO << std::endl; - return false; - } - delete[] TAU; - - // FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! - delete[] WORK; - WORK = new double[2 * N - 2]; - dsteqr_(&COMPZ, &N, D, E, A, &LDA, WORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! " - "ERROR CODE: " - << INFO << std::endl; - return false; - } - delete[] WORK; - delete[] E; + D.resize( N ); + lapack::heev_2stage( JOBZ, UPLO, N, A.data(), LDA, D.data()); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS eigvals.resize(N); for(int i = 0; i < N; i++) eigvals[i] = D[i]; - delete[] D; eigvecs.resize(N); for(int i = 0; i < N; i++) { eigvecs[i].resize(N); for(int j = 0; j < N; j++) eigvecs[i][j] = A[j + i * N]; } - delete[] A; return true; } @@ -293,57 +159,41 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, eigvals.clear(); eigvecs.clear(); // PREPARE VARIABLES FOR LAPACK - char UPLO = 'U', VECT = 'V', COMPZ = 'V'; - int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1, LWORK = -1, INFO; - double *AB, *D, *E, *Q, *WORK; + lapack::Uplo UPLO = lapack::Uplo::Upper; + lapack::Job VECT = lapack::Job::Vec; + lapack::Job COMPZ = lapack::Job::Vec; + int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1; + std::vector AB, D, E, Q; // INITIALIZE A - AB = new double[(nSupDiag + 1) * N]; + AB.resize( (nSupDiag + 1) * N ); for(int j = 0; j < N; j++) { for(int i = std::max(0, j - nSupDiag); i <= j; i++) AB[nSupDiag + i - j + j * (nSupDiag + 1)] = mat[i][j]; } mat.clear(); // ALLOCATE REST OF THE MEMORY - Q = new double[N * N]; - D = new double[N]; - E = new double[N - 1]; - WORK = new double[N]; + Q.resize( N * N ); + D.resize( N ); + E.resize( N - 1 ); // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM - dsbtrd_(&VECT, &UPLO, &N, &nSupDiag, AB, &LDAB, D, E, Q, &LDQ, WORK, &INFO); - if(INFO != 0) { - std::cout - << "ERROR IN dsbtrd_ COMPUTING THE TRIDIAGONAL MATRIX!! ERROR CODE: " - << INFO << std::endl; - return false; - } - delete[] AB; + lapack::sbtrd( VECT, UPLO, N, nSupDiag, AB.data(), LDAB, D.data(), E.data(), Q.data(), LDQ ); + AB.clear(); // FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! - delete[] WORK; - WORK = new double[2 * N - 2]; - dsteqr_(&COMPZ, &N, D, E, Q, &LDQ, WORK, &INFO); - if(INFO != 0) { - std::cout << "ERROR IN dsteqr_ COMPUTING EIGENVECTORS AND EIGENVALUES!! " - "ERROR CODE: " - << INFO << std::endl; - return false; - } - delete[] WORK; - delete[] E; + lapack::steqr( COMPZ, N, D.data(), E.data(), Q.data(), LDQ ); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS eigvals.resize(N); for(int i = 0; i < N; i++) eigvals[i] = D[i]; - delete[] D; + D.clear(); eigvecs.resize(N); for(int i = 0; i < N; i++) { eigvecs[i].resize(N); for(int j = 0; j < N; j++) eigvecs[i][j] = Q[j + i * N]; } - delete[] Q; return true; } @@ -402,7 +252,13 @@ void BandResolvent( // NEXT, COMPUTE THE BAND LANCZOS std::vector > bandH; std::cout << "BAND LANCZOS ..."; - MyBandLan(H, vecs, bandH, nLanIts, 1.E-6, print); + SparseMatrixOperator Hop(H); + int nbands = vecs.size(); + std::vector qs( vecs.size() * n, 0. ); + for( int i = 0; i < vecs.size(); i++ ) + for( int j = 0; j < n; j++ ) + qs[j + n * i] = vecs[i][j]; + MyBandLan(Hop, qs, bandH, nLanIts, nbands, n, 1.E-6, print); std::cout << "DONE! "; if(print) { std::ofstream ofile("BLH.dat", std::ios::out); diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index 4eb42f5b..8a94be82 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -13,7 +13,7 @@ namespace macis { void Hste_v(const std::vector &alphas, const std::vector &betas, - VectorXd &eigvals, eigMatD &eigvecs) { + Eigen::VectorXd &eigvals, eigMatD &eigvecs) { /* * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A TRIDIAGONAL, SYMMETRIC * MATRIX A USING LAPACK. @@ -21,46 +21,31 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, eigvals.resize(alphas.size()); eigvecs.resize(alphas.size(), alphas.size()); // INITIALIZE VARIABLES - char JOBZ = - 'I'; // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX - int N = alphas.size(), LDZ = N, INFO; // SIZES - double *D, *E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS - double *WORK, *Z; // WORKSPACE AND EIGENVECTORS + // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX + lapack::Job JOBZ = lapack::Job::Vec; + int N = alphas.size(), LDZ = N; // SIZES + std::vector D, E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS + std::vector Z; // EIGENVECTORS // INITIALIZE MATRIX - D = new double[N]; + D.resize( N ); for(int64_t i = 0; i < N; i++) D[i] = alphas[i]; - E = new double[N - 1]; + E.resize( N - 1 ); for(int64_t i = 1; i < N; i++) E[i - 1] = betas[i]; // ALLOCATE MEMORY - WORK = new double[2 * N - 2]; - Z = new double[N * LDZ]; + Z.resize( N * LDZ ); // ACTUAL EIGENVALUE CALCULATION - dsteqr_(&JOBZ, &N, D, E, Z, &LDZ, WORK, &INFO); - if(INFO != 0) { - if(INFO < 0) - throw("In dsteqr_, the " + std::to_string(-1 * INFO) + - "-th argument had an illegal value"); - if(INFO > 0) - throw( - "dsteqr_ the algorithm has failed to find all the eigenvalues in a " - "total of " + - std::to_string(30 * N) + " iterations"); - } - delete[] WORK; - delete[] E; + lapack::steqr( JOBZ, N, D.data(), E.data(), Z.data(), LDZ); // SAVE EIGENVECTORS for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) eigvecs(i, j) = Z[i + j * N]; } - delete[] Z; + Z.clear(); // SAVE EIGENVALUES for(int i = 0; i < N; i++) eigvals(i) = D[i]; - - delete[] D; } -void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs) { +void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs) { /* * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING * LAPACK. @@ -68,48 +53,30 @@ void Hsyev(const eigMatD &H, VectorXd &eigvals, eigMatD &eigvecs) { eigvals.resize(H.rows()); eigvecs.resize(H.rows(), H.rows()); // INITIALIZE VARIABLES - char JOBZ = 'V', UPLO = 'U'; // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS - // STORED IN THE UPPER TRIANGLE - int N = H.rows(), LWORK = -1, LDA = N, INFO; // SIZES - double *A, *WORK; // MATRIX AND WORKSPACE - double *W; // EIGENVALUES AND WORKSPACE + // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS + // STORED IN THE UPPER TRIANGLE + lapack::Job JOBZ = lapack::Job::Vec; + lapack::Uplo UPLO = lapack::Uplo::Upper; + int N = H.rows(), LDA = N; // SIZES + std::vector A; // MATRIX AND WORKSPACE + std::vector W; // EIGENVALUES AND WORKSPACE // INITIALIZE MATRIX - A = new double[N * N]; + A.resize( N * N ); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) A[i + j * N] = H(i, j); } // ALLOCATE MEMORY - WORK = new double[2 * N + 1]; - W = new double[N]; + W.resize( N ); - // MEMORY QUERY - dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); - if(INFO != 0) - throw("ERROR IN dsyev_ MEMORY QUERY!! ERROR CODE: " + std::to_string(INFO)); - LWORK = WORK[0]; - delete[] WORK; - WORK = new double[LWORK]; // ACTUAL EIGENVALUE CALCULATION - dsyev_(&JOBZ, &UPLO, &N, A, &LDA, W, WORK, &LWORK, &INFO); - if(INFO != 0) { - if(INFO < 0) - throw("ERROR IN dsyev_! The " + std::to_string(-1 * INFO) + - "-th argument had an illegal value"); - throw("ERROR IN dsyev_! Algorithm failed to converge! " + - std::to_string(INFO) + - " off-diagonal elements of an intermediate tridiagonal form did not " - "converge to zero"); - } - delete[] WORK; + lapack::syev( JOBZ, UPLO, N, A.data(), LDA, W.data() ); // SAVE EIGENVECTORS for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) eigvecs(i, N - 1 - j) = A[i + j * N]; } - delete[] A; + A.clear(); // SAVE EIGENVALUES for(int i = 0; i < N; i++) eigvals(N - 1 - i) = W[i]; - - delete[] W; } } // namespace macis diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 093a506f..359317ac 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -29,7 +29,6 @@ void write_GF( } ofile << std::endl; } - ofile.close(); std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" : "GFMatrix_OrbitalIndices_SUB.dat"; @@ -39,7 +38,6 @@ void write_GF( continue; ofile2 << GF_orbs[iii] << std::endl; } - ofile2.close(); } else { std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; fname += std::to_string(GF_orbs[0] + 1) + "_" + @@ -49,7 +47,6 @@ void write_GF( for(int iii = 0; iii < nfreqs; iii++) ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " << real(GF[iii][0][0]) << " " << imag(GF[iii][0][0]) << std::endl; - ofile.close(); } } From 91e506ba7450c165669c061209db9e2eff9424e6 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Mon, 5 Jun 2023 15:13:31 +0000 Subject: [PATCH 08/35] Committing clang-format changes --- include/macis/gf/bandlan.hpp | 54 ++++++++++++++++++---------------- include/macis/gf/eigsolver.hpp | 1 - include/macis/gf/gf.hpp | 7 +++-- include/macis/gf/inn_prods.hpp | 10 +++---- src/macis/gf/bandlan.cxx | 48 +++++++++++++++--------------- src/macis/gf/eigsolver.cxx | 22 +++++++------- 6 files changed, 73 insertions(+), 69 deletions(-) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index b96a7641..8ef70d62 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -41,8 +41,8 @@ namespace macis { * 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 > &Q: On input, + * + * @param[inout] std::vector > &Q: On input, * matrix for which to evaluate the QR decomposition. * On output, Q-matrix. * @param[out] std::vector > &R: On output, R @@ -61,8 +61,8 @@ bool QRdecomp(std::vector > &Q, * 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 > &Q: On input, + * + * @param[inout] std::vector > &Q: On input, * matrix for which to evaluate the QR decomposition. * On output, Q-matrix. * @param[out] std::vector > &R: On output, R @@ -141,11 +141,12 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, * @date 25/04/2022 */ template -void MyBandLan( - const Functor &H, - //std::vector > &qs, std::vector > &bandH, - std::vector &qs, std::vector > &bandH, - int &nLanIts, int nbands, int N, double thres = 1.E-6, bool print = false) { +void MyBandLan(const Functor &H, + // std::vector > &qs, + // std::vector > &bandH, + std::vector &qs, std::vector > &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 @@ -155,18 +156,18 @@ void MyBandLan( bandH.resize(nLanIts, std::vector(nLanIts, 0.)); // MAKE SPACE FOR 2 * nbands VECTORS - //qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); - qs.resize( 2 * nbands * N ); - //std::vector temp(qs[0].size(), 0.); + // qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); + qs.resize(2 * nbands * N); + // std::vector temp(qs[0].size(), 0.); std::vector 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 < qs[i].size(); el++) for(size_t el = 0; el < N; el++) - //ofile << std::scientific << qs[i][el] << std::endl; + // ofile << std::scientific << qs[i][el] << std::endl; ofile << std::scientific << qs[el + i * N] << std::endl; ofile.close(); } @@ -182,8 +183,10 @@ void MyBandLan( 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 - //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 ); + // 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); @@ -197,17 +200,18 @@ void MyBandLan( 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]; + // 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[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[band_indx_j][coeff]; temp[coeff] -= bandH[it - 1][jt - 1] * qs[N * band_indx_j + coeff]; } if(it + nbands <= nLanIts) { @@ -226,23 +230,23 @@ void MyBandLan( break; #pragma omp parallel for for(size_t coeff = 0; coeff < temp.size(); coeff++) - //qs[true_indx[it + nbands]][coeff] = 0.; + // 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++) - //qs[true_indx[it + nbands]][coeff] = + // 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 < 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]][el] ofile << std::scientific << qs[true_indx[it + nbands] * N + el] << std::endl; ofile.close(); diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index 32478ef0..66b2e204 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -21,7 +21,6 @@ namespace macis { - typedef Eigen::VectorXd VectorXd; typedef Eigen::MatrixXd eigMatD; typedef Eigen::SparseMatrix SpMatD; diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 619629a1..0665827c 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -229,8 +229,8 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, std::bitset uni_string; std::vector> founddets; founddets.reserve(trunc_size); - std::map, size_t, bitset_less_comparator> founddet_pos, - basedet_pos; + std::map, size_t, bitset_less_comparator> + founddet_pos, basedet_pos; typename std::map, size_t, bitset_less_comparator>::iterator it; // ACTIVE SPACE @@ -386,7 +386,8 @@ std::vector> BuildWfn4Lanczos( const std::vector> &GF_dets, bool is_part, std::vector &todelete, double zero_thresh = 1.E-7) { // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - std::map, size_t, bitset_less_comparator> base_dets_pos; + std::map, size_t, bitset_less_comparator> + base_dets_pos; for(size_t iii = 0; iii < base_dets.size(); iii++) base_dets_pos[base_dets[iii]] = iii; diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp index 837207ab..411ad186 100644 --- a/include/macis/gf/inn_prods.hpp +++ b/include/macis/gf/inn_prods.hpp @@ -32,7 +32,7 @@ namespace macis { */ inline double MyInnProd(const std::vector& vecR, const std::vector& vecL) { - return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); + return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); } /** @@ -49,7 +49,7 @@ inline double MyInnProd(const std::vector& vecR, inline std::complex MyInnProd( const std::vector >& vecR, const std::vector >& vecL) { - return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); + return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); } /** @@ -66,7 +66,7 @@ inline std::complex MyInnProd( inline std::complex MyInnProd( const std::vector >& vecR, const std::vector& vecL) { - return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); + return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); } /** @@ -81,7 +81,7 @@ inline std::complex MyInnProd( */ inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, const Eigen::VectorXcd& vecL) { - return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); + return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); } /** @@ -96,6 +96,6 @@ inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, */ inline double MyInnProd(const Eigen::VectorXd& vecR, const Eigen::VectorXd& vecL) { - return blas::dot( vecR.size(), vecR.data(), 1, vecL.data(), 1 ); + return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); } } // namespace macis diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index e928c38b..508eb5a9 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -35,14 +35,14 @@ bool QRdecomp(std::vector > &Q, std::vector A, TAU; // INITIALIZE A - A.resize( M * N, 0.); + A.resize(M * N, 0.); for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; Q[i].clear(); } - // INITIALIZE TAU, AND COMPUTE R MATRIX - TAU.resize( N ); - lapack::geqrf( M, N, A.data(), LDA, TAU.data() ); + // INITIALIZE TAU, AND COMPUTE R MATRIX + TAU.resize(N); + lapack::geqrf(M, N, A.data(), LDA, TAU.data()); // SAVE THE R MATRIX R.resize(N); for(int i = 0; i < N; i++) { @@ -53,7 +53,7 @@ bool QRdecomp(std::vector > &Q, // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; - lapack::orgqr( M, N, K, A.data(), LDA, TAU.data() ); + lapack::orgqr(M, N, K, A.data(), LDA, TAU.data()); // SAVE THE Q MATRIX for(int i = 0; i < M; i++) { Q[i].resize(N); @@ -82,14 +82,14 @@ bool QRdecomp_tr(std::vector > &Q, std::vector A, TAU; // INITIALIZE A - A.resize( M * N ); + A.resize(M * N); for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; } // INITIALIZE TAU, AND EVALUATE R MATRIX - TAU.resize( N ); - lapack::geqrf( M, N, A.data(), LDA, TAU.data() ); + TAU.resize(N); + lapack::geqrf(M, N, A.data(), LDA, TAU.data()); // SAVE THE R MATRIX R.resize(N); for(int i = 0; i < N; i++) { @@ -100,7 +100,7 @@ bool QRdecomp_tr(std::vector > &Q, // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; - lapack::orgqr( M, N, K, A.data(), LDA, TAU.data() ); + lapack::orgqr(M, N, K, A.data(), LDA, TAU.data()); // SAVE THE Q MATRIX for(int i = 0; i < M; i++) { for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; @@ -121,20 +121,20 @@ bool GetEigsys(std::vector > &mat, eigvecs.clear(); // PREPARE VARIABLES FOR LAPACK lapack::Uplo UPLO = lapack::Uplo::Upper; - lapack::Job JOBZ = lapack::Job::Vec; + lapack::Job JOBZ = lapack::Job::Vec; int N = mat.size(), LDA = mat.size(); std::vector A, D; // INITIALIZE A - A.resize( N * N ); + A.resize(N * N); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; mat[i].clear(); } mat.clear(); // ALLOCATE REST OF THE MEMORY - D.resize( N ); - lapack::heev_2stage( JOBZ, UPLO, N, A.data(), LDA, D.data()); + D.resize(N); + lapack::heev_2stage(JOBZ, UPLO, N, A.data(), LDA, D.data()); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS eigvals.resize(N); @@ -160,30 +160,31 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, eigvecs.clear(); // PREPARE VARIABLES FOR LAPACK lapack::Uplo UPLO = lapack::Uplo::Upper; - lapack::Job VECT = lapack::Job::Vec; + lapack::Job VECT = lapack::Job::Vec; lapack::Job COMPZ = lapack::Job::Vec; int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1; std::vector AB, D, E, Q; // INITIALIZE A - AB.resize( (nSupDiag + 1) * N ); + AB.resize((nSupDiag + 1) * N); for(int j = 0; j < N; j++) { for(int i = std::max(0, j - nSupDiag); i <= j; i++) AB[nSupDiag + i - j + j * (nSupDiag + 1)] = mat[i][j]; } mat.clear(); // ALLOCATE REST OF THE MEMORY - Q.resize( N * N ); - D.resize( N ); - E.resize( N - 1 ); + Q.resize(N * N); + D.resize(N); + E.resize(N - 1); // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM - lapack::sbtrd( VECT, UPLO, N, nSupDiag, AB.data(), LDAB, D.data(), E.data(), Q.data(), LDQ ); + lapack::sbtrd(VECT, UPLO, N, nSupDiag, AB.data(), LDAB, D.data(), E.data(), + Q.data(), LDQ); AB.clear(); // FINALLY, COMPUTE THE EIGENVALUES AND EIGENVECTORS! - lapack::steqr( COMPZ, N, D.data(), E.data(), Q.data(), LDQ ); + lapack::steqr(COMPZ, N, D.data(), E.data(), Q.data(), LDQ); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS eigvals.resize(N); @@ -254,10 +255,9 @@ void BandResolvent( std::cout << "BAND LANCZOS ..."; SparseMatrixOperator Hop(H); int nbands = vecs.size(); - std::vector qs( vecs.size() * n, 0. ); - for( int i = 0; i < vecs.size(); i++ ) - for( int j = 0; j < n; j++ ) - qs[j + n * i] = vecs[i][j]; + std::vector qs(vecs.size() * n, 0.); + for(int i = 0; i < vecs.size(); i++) + for(int j = 0; j < n; j++) qs[j + n * i] = vecs[i][j]; MyBandLan(Hop, qs, bandH, nLanIts, nbands, n, 1.E-6, print); std::cout << "DONE! "; if(print) { diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index 8a94be82..ca29277a 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -23,19 +23,19 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, // INITIALIZE VARIABLES // COMPUTE EIGENVALUES AND EIGENVECTORS OF THE TRIDIAGONAL MATRIX lapack::Job JOBZ = lapack::Job::Vec; - int N = alphas.size(), LDZ = N; // SIZES - std::vector D, E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS - std::vector Z; // EIGENVECTORS + int N = alphas.size(), LDZ = N; // SIZES + std::vector D, E; // DIAGONAL AND SUB-DIAGONAL ELEMENTS + std::vector Z; // EIGENVECTORS // INITIALIZE MATRIX - D.resize( N ); + D.resize(N); for(int64_t i = 0; i < N; i++) D[i] = alphas[i]; - E.resize( N - 1 ); + E.resize(N - 1); for(int64_t i = 1; i < N; i++) E[i - 1] = betas[i]; // ALLOCATE MEMORY - Z.resize( N * LDZ ); + Z.resize(N * LDZ); // ACTUAL EIGENVALUE CALCULATION - lapack::steqr( JOBZ, N, D.data(), E.data(), Z.data(), LDZ); + lapack::steqr(JOBZ, N, D.data(), E.data(), Z.data(), LDZ); // SAVE EIGENVECTORS for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) eigvecs(i, j) = Z[i + j * N]; @@ -55,21 +55,21 @@ void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs) { // INITIALIZE VARIABLES // COMPUTE EIGENVALUES AND EIGENVECTORS, H IS // STORED IN THE UPPER TRIANGLE - lapack::Job JOBZ = lapack::Job::Vec; + lapack::Job JOBZ = lapack::Job::Vec; lapack::Uplo UPLO = lapack::Uplo::Upper; int N = H.rows(), LDA = N; // SIZES std::vector A; // MATRIX AND WORKSPACE std::vector W; // EIGENVALUES AND WORKSPACE // INITIALIZE MATRIX - A.resize( N * N ); + A.resize(N * N); for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) A[i + j * N] = H(i, j); } // ALLOCATE MEMORY - W.resize( N ); + W.resize(N); // ACTUAL EIGENVALUE CALCULATION - lapack::syev( JOBZ, UPLO, N, A.data(), LDA, W.data() ); + lapack::syev(JOBZ, UPLO, N, A.data(), LDA, W.data()); // SAVE EIGENVECTORS for(int i = 0; i < N; i++) { for(int j = 0; j < N; j++) eigvecs(i, N - 1 - j) = A[i + j * N]; From 5175a96907195fac413bc85c8dc5a5aeb38e743e Mon Sep 17 00:00:00 2001 From: David Williams-Young Date: Wed, 7 Jun 2023 08:56:32 -0700 Subject: [PATCH 09/35] Added Hubbard Hamiltonian generator + UT --- include/macis/model/hubbard.hpp | 13 +++++++++ src/macis/CMakeLists.txt | 1 + src/macis/model/hubbard.cxx | 29 ++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/hubbard.cxx | 48 +++++++++++++++++++++++++++++++++ 5 files changed, 92 insertions(+) create mode 100644 include/macis/model/hubbard.hpp create mode 100644 src/macis/model/hubbard.cxx create mode 100644 tests/hubbard.cxx diff --git a/include/macis/model/hubbard.hpp b/include/macis/model/hubbard.hpp new file mode 100644 index 00000000..32ee3d71 --- /dev/null +++ b/include/macis/model/hubbard.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace macis { + +/** + * @brief Generate Hamiltonian Data for 1D Hubbard + */ +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, + std::vector& V); + +} diff --git a/src/macis/CMakeLists.txt b/src/macis/CMakeLists.txt index 862df2ce..dd65d431 100644 --- a/src/macis/CMakeLists.txt +++ b/src/macis/CMakeLists.txt @@ -15,6 +15,7 @@ add_library( macis orbital_rotation_utilities.cxx orbital_hessian.cxx orbital_steps.cxx + model/hubbard.cxx ) target_include_directories( macis PUBLIC diff --git a/src/macis/model/hubbard.cxx b/src/macis/model/hubbard.cxx new file mode 100644 index 00000000..528349b0 --- /dev/null +++ b/src/macis/model/hubbard.cxx @@ -0,0 +1,29 @@ +#include + +namespace macis { + +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, + std::vector& V) { + + + T.resize(nsites * nsites); + V.resize(nsites * nsites * nsites * nsites); + + + for(size_t p = 0; p < nsites; ++p) { + // Half-filling Chemical Potential + T[p * (nsites+1)] = -U/2; + + // On-Site Interaction + V[p * (nsites*nsites*nsites + nsites*nsites + nsites + 1)] = U; + + // Hopping + if(p < nsites-1) { + T[p + (p+1)*nsites] = -t; + T[(p+1) + p*nsites] = -t; + } + } + +} + +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9d613244..73694653 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable( macis_test mcscf.cxx asci.cxx dist_quickselect.cxx + hubbard.cxx ) target_link_libraries( macis_test PUBLIC macis Catch2::Catch2 ) target_include_directories( macis_test PUBLIC ${PROJECT_BINARY_DIR}/tests ) diff --git a/tests/hubbard.cxx b/tests/hubbard.cxx new file mode 100644 index 00000000..2f142ab5 --- /dev/null +++ b/tests/hubbard.cxx @@ -0,0 +1,48 @@ + + +#include +#include +#include + +#include + +#include "ut_common.hpp" + +TEST_CASE("Hubbard") { + ROOT_ONLY(MPI_COMM_WORLD); + + const size_t nsites = 4; + const size_t nsites2 = nsites*nsites; + const size_t nsites3 = nsites2*nsites; + const double t = 1.0, U = 4.0; + std::vector T,V; + + SECTION("1D") { + macis::hubbard_1d( nsites, t, U, T, V ); + + // Check two-body term + for(int p = 0; p < nsites; ++p) + for(int q = 0; q < nsites; ++q) + for(int r = 0; r < nsites; ++r) + for(int s = 0; s < nsites; ++s) { + const auto mat_el = V[p + nsites*q + nsites2*r + nsites3*s]; + if(p==q and p==r and p==s) + REQUIRE(mat_el == U); + else + REQUIRE(mat_el == 0.0); + } + + // Check 1-body term + for(int p = 0; p < nsites; ++p) + for(int q = 0; q < nsites; ++q) { + const auto mat_el = T[p + q*nsites]; + if(p == q) + REQUIRE(mat_el == Approx(-U/2)); + else if( std::abs(p-q) == 1 ) + REQUIRE(mat_el == -t); + else + REQUIRE(mat_el == 0.0); + } + } + +} From ebb7ef4d4ee3f92b3b0d23260cfd5cef3ee87f12 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Wed, 7 Jun 2023 15:57:12 +0000 Subject: [PATCH 10/35] Committing clang-format changes --- include/macis/model/hubbard.hpp | 6 ++--- src/macis/model/hubbard.cxx | 18 +++++-------- tests/hubbard.cxx | 47 ++++++++++++++++----------------- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/include/macis/model/hubbard.hpp b/include/macis/model/hubbard.hpp index 32ee3d71..4fd849db 100644 --- a/include/macis/model/hubbard.hpp +++ b/include/macis/model/hubbard.hpp @@ -4,10 +4,10 @@ namespace macis { -/** +/** * @brief Generate Hamiltonian Data for 1D Hubbard */ -void hubbard_1d(size_t nsites, double t, double U, std::vector& T, +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, std::vector& V); -} +} // namespace macis diff --git a/src/macis/model/hubbard.cxx b/src/macis/model/hubbard.cxx index 528349b0..cdbfa2d6 100644 --- a/src/macis/model/hubbard.cxx +++ b/src/macis/model/hubbard.cxx @@ -2,28 +2,24 @@ namespace macis { -void hubbard_1d(size_t nsites, double t, double U, std::vector& T, +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, std::vector& V) { - - T.resize(nsites * nsites); V.resize(nsites * nsites * nsites * nsites); - for(size_t p = 0; p < nsites; ++p) { // Half-filling Chemical Potential - T[p * (nsites+1)] = -U/2; + T[p * (nsites + 1)] = -U / 2; // On-Site Interaction - V[p * (nsites*nsites*nsites + nsites*nsites + nsites + 1)] = U; + V[p * (nsites * nsites * nsites + nsites * nsites + nsites + 1)] = U; // Hopping - if(p < nsites-1) { - T[p + (p+1)*nsites] = -t; - T[(p+1) + p*nsites] = -t; + if(p < nsites - 1) { + T[p + (p + 1) * nsites] = -t; + T[(p + 1) + p * nsites] = -t; } } - } -} +} // namespace macis diff --git a/tests/hubbard.cxx b/tests/hubbard.cxx index 2f142ab5..1f62f1a9 100644 --- a/tests/hubbard.cxx +++ b/tests/hubbard.cxx @@ -1,9 +1,9 @@ -#include #include #include +#include #include #include "ut_common.hpp" @@ -12,37 +12,36 @@ TEST_CASE("Hubbard") { ROOT_ONLY(MPI_COMM_WORLD); const size_t nsites = 4; - const size_t nsites2 = nsites*nsites; - const size_t nsites3 = nsites2*nsites; + const size_t nsites2 = nsites * nsites; + const size_t nsites3 = nsites2 * nsites; const double t = 1.0, U = 4.0; - std::vector T,V; + std::vector T, V; SECTION("1D") { - macis::hubbard_1d( nsites, t, U, T, V ); + macis::hubbard_1d(nsites, t, U, T, V); // Check two-body term for(int p = 0; p < nsites; ++p) - for(int q = 0; q < nsites; ++q) - for(int r = 0; r < nsites; ++r) - for(int s = 0; s < nsites; ++s) { - const auto mat_el = V[p + nsites*q + nsites2*r + nsites3*s]; - if(p==q and p==r and p==s) - REQUIRE(mat_el == U); - else - REQUIRE(mat_el == 0.0); - } + for(int q = 0; q < nsites; ++q) + for(int r = 0; r < nsites; ++r) + for(int s = 0; s < nsites; ++s) { + const auto mat_el = V[p + nsites * q + nsites2 * r + nsites3 * s]; + if(p == q and p == r and p == s) + REQUIRE(mat_el == U); + else + REQUIRE(mat_el == 0.0); + } // Check 1-body term for(int p = 0; p < nsites; ++p) - for(int q = 0; q < nsites; ++q) { - const auto mat_el = T[p + q*nsites]; - if(p == q) - REQUIRE(mat_el == Approx(-U/2)); - else if( std::abs(p-q) == 1 ) - REQUIRE(mat_el == -t); - else - REQUIRE(mat_el == 0.0); - } + for(int q = 0; q < nsites; ++q) { + const auto mat_el = T[p + q * nsites]; + if(p == q) + REQUIRE(mat_el == Approx(-U / 2)); + else if(std::abs(p - q) == 1) + REQUIRE(mat_el == -t); + else + REQUIRE(mat_el == 0.0); + } } - } From 84b219da94e3bd76dafac1199b408682e86b8e15 Mon Sep 17 00:00:00 2001 From: "license[bot]" Date: Wed, 7 Jun 2023 15:57:53 +0000 Subject: [PATCH 11/35] Committing license headers --- include/macis/model/hubbard.hpp | 8 ++++++++ src/macis/model/hubbard.cxx | 8 ++++++++ tests/hubbard.cxx | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/include/macis/model/hubbard.hpp b/include/macis/model/hubbard.hpp index 4fd849db..f03f03bb 100644 --- a/include/macis/model/hubbard.hpp +++ b/include/macis/model/hubbard.hpp @@ -1,3 +1,11 @@ +/* + * 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 + */ + #pragma once #include diff --git a/src/macis/model/hubbard.cxx b/src/macis/model/hubbard.cxx index cdbfa2d6..44f62824 100644 --- a/src/macis/model/hubbard.cxx +++ b/src/macis/model/hubbard.cxx @@ -1,3 +1,11 @@ +/* + * 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 + */ + #include namespace macis { diff --git a/tests/hubbard.cxx b/tests/hubbard.cxx index 1f62f1a9..de01a4bd 100644 --- a/tests/hubbard.cxx +++ b/tests/hubbard.cxx @@ -1,3 +1,11 @@ +/* + * 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 + */ + #include From 65f56b3e3b4389a0a11c75a5d9d71ac0337d5612 Mon Sep 17 00:00:00 2001 From: David Williams-Young Date: Tue, 13 Jun 2023 10:02:42 -0700 Subject: [PATCH 12/35] Add PBC --- include/macis/model/hubbard.hpp | 5 +++-- src/macis/model/hubbard.cxx | 11 +++++++++-- tests/hubbard.cxx | 20 ++++++++++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/include/macis/model/hubbard.hpp b/include/macis/model/hubbard.hpp index f03f03bb..6c723ab3 100644 --- a/include/macis/model/hubbard.hpp +++ b/include/macis/model/hubbard.hpp @@ -15,7 +15,8 @@ namespace macis { /** * @brief Generate Hamiltonian Data for 1D Hubbard */ -void hubbard_1d(size_t nsites, double t, double U, std::vector& T, - std::vector& V); +void hubbard_1d(size_t nsites, double t, double U, + std::vector& T, std::vector& V, + bool pbc = false); } // namespace macis diff --git a/src/macis/model/hubbard.cxx b/src/macis/model/hubbard.cxx index 44f62824..0d508af2 100644 --- a/src/macis/model/hubbard.cxx +++ b/src/macis/model/hubbard.cxx @@ -10,8 +10,9 @@ namespace macis { -void hubbard_1d(size_t nsites, double t, double U, std::vector& T, - std::vector& V) { +void hubbard_1d(size_t nsites, double t, double U, + std::vector& T, std::vector& V, + bool pbc) { T.resize(nsites * nsites); V.resize(nsites * nsites * nsites * nsites); @@ -28,6 +29,12 @@ void hubbard_1d(size_t nsites, double t, double U, std::vector& T, T[(p + 1) + p * nsites] = -t; } } + + // PBC for 1-D + if(pbc) { + T[ (nsites-1) ] = -t; + T[ (nsites-1) * nsites] = -t; + } } } // namespace macis diff --git a/tests/hubbard.cxx b/tests/hubbard.cxx index de01a4bd..05bf24c5 100644 --- a/tests/hubbard.cxx +++ b/tests/hubbard.cxx @@ -26,7 +26,18 @@ TEST_CASE("Hubbard") { std::vector T, V; SECTION("1D") { - macis::hubbard_1d(nsites, t, U, T, V); + + bool pbc; + + SECTION("No PBC") { + pbc = false; + } + + SECTION("PBC") { + pbc = true; + } + + macis::hubbard_1d(nsites, t, U, T, V, pbc); // Check two-body term for(int p = 0; p < nsites; ++p) @@ -48,7 +59,12 @@ TEST_CASE("Hubbard") { REQUIRE(mat_el == Approx(-U / 2)); else if(std::abs(p - q) == 1) REQUIRE(mat_el == -t); - else + else if(pbc) { + if( (p == 0 and q == nsites-1) or (p == nsites-1 and q == 0) ) + REQUIRE(mat_el == -t); + else + REQUIRE(mat_el == 0.0); + } else REQUIRE(mat_el == 0.0); } } From e0ef7715cd790f1d67266cf7f47245406b8ccdc9 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Tue, 13 Jun 2023 17:03:22 +0000 Subject: [PATCH 13/35] Committing clang-format changes --- include/macis/model/hubbard.hpp | 5 ++--- src/macis/model/hubbard.cxx | 9 ++++----- tests/hubbard.cxx | 13 +++---------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/include/macis/model/hubbard.hpp b/include/macis/model/hubbard.hpp index 6c723ab3..5e80fd0f 100644 --- a/include/macis/model/hubbard.hpp +++ b/include/macis/model/hubbard.hpp @@ -15,8 +15,7 @@ namespace macis { /** * @brief Generate Hamiltonian Data for 1D Hubbard */ -void hubbard_1d(size_t nsites, double t, double U, - std::vector& T, std::vector& V, - bool pbc = false); +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, + std::vector& V, bool pbc = false); } // namespace macis diff --git a/src/macis/model/hubbard.cxx b/src/macis/model/hubbard.cxx index 0d508af2..5e74b0d3 100644 --- a/src/macis/model/hubbard.cxx +++ b/src/macis/model/hubbard.cxx @@ -10,9 +10,8 @@ namespace macis { -void hubbard_1d(size_t nsites, double t, double U, - std::vector& T, std::vector& V, - bool pbc) { +void hubbard_1d(size_t nsites, double t, double U, std::vector& T, + std::vector& V, bool pbc) { T.resize(nsites * nsites); V.resize(nsites * nsites * nsites * nsites); @@ -32,8 +31,8 @@ void hubbard_1d(size_t nsites, double t, double U, // PBC for 1-D if(pbc) { - T[ (nsites-1) ] = -t; - T[ (nsites-1) * nsites] = -t; + T[(nsites - 1)] = -t; + T[(nsites - 1) * nsites] = -t; } } diff --git a/tests/hubbard.cxx b/tests/hubbard.cxx index 05bf24c5..6f3d3553 100644 --- a/tests/hubbard.cxx +++ b/tests/hubbard.cxx @@ -6,8 +6,6 @@ * See LICENSE.txt for details */ - - #include #include @@ -26,16 +24,11 @@ TEST_CASE("Hubbard") { std::vector T, V; SECTION("1D") { - bool pbc; - SECTION("No PBC") { - pbc = false; - } + SECTION("No PBC") { pbc = false; } - SECTION("PBC") { - pbc = true; - } + SECTION("PBC") { pbc = true; } macis::hubbard_1d(nsites, t, U, T, V, pbc); @@ -60,7 +53,7 @@ TEST_CASE("Hubbard") { else if(std::abs(p - q) == 1) REQUIRE(mat_el == -t); else if(pbc) { - if( (p == 0 and q == nsites-1) or (p == nsites-1 and q == 0) ) + if((p == 0 and q == nsites - 1) or (p == nsites - 1 and q == 0)) REQUIRE(mat_el == -t); else REQUIRE(mat_el == 0.0); From 302feefa0841dca9ef7c4334f42607f8516777ea Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Thu, 15 Jun 2023 16:09:55 +0200 Subject: [PATCH 14/35] Implemented suggestions for GF routines. Most importantly, vectorized all matrices to avoid using vector data types. --- include/macis/bitset_operations.hpp | 2 + include/macis/gf/bandlan.hpp | 107 ++++++------- include/macis/gf/eigsolver.hpp | 8 +- include/macis/gf/gf.hpp | 98 ++++++------ include/macis/gf/lanczos.hpp | 74 ++++----- src/macis/gf/bandlan.cxx | 233 ++++++++++++---------------- src/macis/gf/eigsolver.cxx | 4 +- src/macis/gf/gf.cxx | 14 +- tests/standalone_driver.cxx | 7 +- 9 files changed, 255 insertions(+), 292 deletions(-) diff --git a/include/macis/bitset_operations.hpp b/include/macis/bitset_operations.hpp index e0f5ec27..44acbb0e 100644 --- a/include/macis/bitset_operations.hpp +++ b/include/macis/bitset_operations.hpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include namespace macis { diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 8ef70d62..ccd842eb 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -32,8 +32,6 @@ #include "macis/gf/inn_prods.hpp" #include "macis/solvers/davidson.hpp" -typedef std::numeric_limits dbl; - namespace macis { /** @@ -42,19 +40,23 @@ namespace macis { * Q matrices, which are returned. Here, the input * matrix has more rows than columns. * - * @param[inout] std::vector > &Q: On input, + * @param[inout] std::vector &Q: On input, * matrix for which to evaluate the QR decomposition. * On output, Q-matrix. - * @param[out] std::vector > &R: On output, R + * @param[out] std::vector &R: On output, R * matrix in the QR decomposition. + * @param[in] int Qrows: Nr. of rows in matrix Q. + * @param[in] int Qcols: Nr. of cols in matrix Q. * * @returns bool: Error code from LAPACK routines. * * @author Carlos Mejuto-Zaera * @date 25/04/2022 */ -bool QRdecomp(std::vector > &Q, - std::vector > &R); +bool QRdecomp(std::vector &Q, + std::vector &R, + int Qrows, + int Qcols); /** * @ brief Wrapper for QR decomposition in LAPACK, basically @@ -62,62 +64,70 @@ bool QRdecomp(std::vector > &Q, * Q matrices, which are returned. Here, the input * matrix has more columns than rows. * - * @param[inout] std::vector > &Q: On input, + * @param[inout] std::vector &Q: On input, * matrix for which to evaluate the QR decomposition. * On output, Q-matrix. - * @param[out] std::vector > &R: On output, R + * @param[out] std::vector &R: On output, R * matrix in the QR decomposition. + * @param[in] int Qrows: Nr. of rows in Q. + * @param[in] int Qcols: Nr. of cols in Q. * * @returns bool: Error code from LAPACK routines. * * @author Carlos Mejuto-Zaera * @date 25/04/2022 */ -bool QRdecomp_tr(std::vector > &Q, - std::vector > &R); +bool QRdecomp_tr(std::vector &Q, + std::vector &R, + int Qrows, + int Qcols); /** * @brief Wrapper to LAPACK routine to evaluate the eigenvectors * and eigenvalues of the symmetric matrix mat. * - * @param[inout] std::vector > &mat: Matrix for + * @param[inout] std::vector &mat: Matrix for * which to compute the eigenvalues/vectors. Erased * during computation. * @param[out] std::vector &eigvals: Eigenvalues, sorted from smallest * to largest. - * @param[out] std::vector > &eigvecs: Eigenvectors, + * @param[out] std::vector &eigvecs: Eigenvectors, * stored as row vectors. + * @param[in] int matsize: Nr. of rows/columns of the square matrix mat. * * @returns bool: Error code from LAPACK. * * @author Carlos Mejuto Zaera * @date 25/04/2022 */ -bool GetEigsys(std::vector > &mat, +bool GetEigsys(std::vector &mat, std::vector &eigvals, - std::vector > &eigvecs); + std::vector &eigvecs, + int matsize); /** * @brief Wrapper to LAPACK routine to evaluate the eigenvectors * and eigenvalues of the symmetric band matrix mat. * - * @param[inout] std::vector > &mat: Matrix for + * @param[inout] std::vector &mat: Matrix for * which to compute the eigenvalues/vectors. Erased * during computation. * @param[in] int nSupDiag: Nr. of bands. * @param[out] std::vector &eigvals: Eigenvalues, sorted from smallest * to largest. - * @param[out] std::vector > &eigvecs: Eigenvectors, + * @param[out] std::vector &eigvecs: Eigenvectors, * stored as row vectors. + * @param[in] int matsize: Nr. of rows/cols of the square matrix mat. * * @returns bool: Error code from LAPACK. * * @author Carlos Mejuto Zaera * @date 25/04/2022 */ -bool GetEigsysBand(std::vector > &mat, int nSupDiag, +bool GetEigsysBand(std::vector &mat, int nSupDiag, std::vector &eigvals, - std::vector > &eigvecs); + std::vector &eigvecs, + int matsize); /** * @brief Perform a band Lanczos calculation on the Hamiltonian operator H, @@ -128,11 +138,11 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, * * @param[in] const sparseexx::csr_matrix &H: Hamiltonian * oprator. Just needs to implement a matrix vector product. - * @param[in] std::vector > &qs: Initial set of vetors to + * @param[in] std::vector &qs: Initial set of vetors to * perform the band Lanczos on. Deleted on exit. - * @param[in] std::vector > &bandH: On exit, band-diagonal + * @param[in] std::vector &bandH: On exit, band-diagonal * Hamiltonian approximation. - * @param[in] int &nLanIts: Number of Lanczos iterations to perform. + * @param[inout] 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. @@ -142,9 +152,7 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, */ template void MyBandLan(const Functor &H, - // std::vector > &qs, - // std::vector > &bandH, - std::vector &qs, std::vector > &bandH, + std::vector &qs, std::vector &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 @@ -152,22 +160,19 @@ void MyBandLan(const Functor &H, // 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 + using dbl = std::numeric_limits; bandH.clear(); - bandH.resize(nLanIts, std::vector(nLanIts, 0.)); + bandH.resize(nLanIts * nLanIts, 0.); // MAKE SPACE FOR 2 * nbands VECTORS - // qs.resize(2 * nbands, std::vector(qs[0].size(), 0.)); qs.resize(2 * nbands * N); - // std::vector temp(qs[0].size(), 0.); std::vector 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(); } @@ -183,8 +188,6 @@ void MyBandLan(const Functor &H, 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 - // 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) { @@ -200,53 +203,45 @@ void MyBandLan(const Functor &H, 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]; + temp[coeff] -= bandH[(it - 1) * nLanIts + 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] = + bandH[(it - 1) * nLanIts + 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]; + bandH[(jt - 1) * nLanIts + it - 1] = bandH[(it - 1 ) * nLanIts + 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]; + temp[coeff] -= bandH[(it - 1 ) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; } if(it + nbands <= nLanIts) { - bandH[it - 1][it + nbands - 1] = + bandH[(it - 1 ) * nLanIts + it + nbands - 1] = std::sqrt(std::real(MyInnProd(temp, temp))); - bandH[it + nbands - 1][it - 1] = bandH[it - 1][it + nbands - 1]; + bandH[(it + nbands - 1 ) * nLanIts + it - 1] = bandH[(it - 1 ) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; - if(std::abs(bandH[it - 1][it + nbands - 1]) < thres) { + if(std::abs(bandH[(it - 1 ) * nLanIts + it + nbands - 1]) < thres) { std::cout << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " - << bandH[it - 1][it + nbands - 1] + << bandH[(it - 1 ) * nLanIts + 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); + bandH.resize(nLanIts * nLanIts); break; #pragma omp parallel for for(size_t coeff = 0; coeff < temp.size(); coeff++) - // 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++) - // qs[true_indx[it + nbands]][coeff] = qs[true_indx[it + nbands] * N + coeff] = - temp[coeff] / bandH[it - 1][it + nbands - 1]; + temp[coeff] / bandH[(it - 1 ) * nLanIts + 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(); @@ -265,11 +260,11 @@ void MyBandLan(const Functor &H, * * @param[in] const sparsex::dist_sparse_matrix > &H: Hamiltonian operator. - * @param[in] std::vector > &vecs: Vectors for which to - * compute the resolvent matrix elements. + * @param[in] std::vector &vecs: Vectors for which to + * compute the resolvent matrix elements in format res[freq.][iorb1 * norbs + iorb2]. * @param[in] std::vector > &ws: Frequency grid over which * to evaluate the resolvent. - * @param[out] std::vector > > > + * @param[out] std::vector > > * &res: On exit, resolvent elements. * @param[in] int nLanIts: Max number of iterations. * @param[in] double E0: Ground state energy, for shifting the resolvent. @@ -283,10 +278,10 @@ void MyBandLan(const Functor &H, void BandResolvent( const sparsexx::dist_sparse_matrix > &H, - std::vector > &vecs, + std::vector &vecs, const std::vector > &ws, - std::vector > > > &res, - int nLanIts, double E0, bool ispart, bool print = false, - bool saveGFmats = false); + std::vector > > &res, + int nLanIts, double E0, bool ispart, int nvecs, + int len_vec, bool print = false, bool saveGFmats = false); } // namespace macis diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index 66b2e204..6d569117 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -21,10 +21,6 @@ namespace macis { -typedef Eigen::VectorXd VectorXd; -typedef Eigen::MatrixXd eigMatD; -typedef Eigen::SparseMatrix SpMatD; - /** * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric * matrix using Lapack. @@ -38,7 +34,7 @@ typedef Eigen::SparseMatrix SpMatD; * @date 05/04/2021 */ void Hste_v(const std::vector &alphas, const std::vector &betas, - Eigen::VectorXd &eigvals, eigMatD &eigvecs); + Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs); /** * @brief Computes the eigenvalues and eigenvectors of a tridiagonal, symmetric @@ -52,6 +48,6 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, * @author Carlos Mejuto Zaera * @date 05/04/2021 */ -void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs); +void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs); } // namespace macis diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 0665827c..430cde49 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -37,11 +37,6 @@ namespace macis { -typedef Eigen::VectorXd VectorXd; - -typedef std::numeric_limits dbl; -typedef std::chrono::high_resolution_clock Clock; - struct GFSettings { size_t norbs = 0; size_t trunc_size = 0; @@ -118,11 +113,12 @@ inline double GetInsertionDoSign(const std::bitset &st, size_t orb) { * @date 28/01/2022 */ template -void GF_Diag(const VectorXd &state_0, const MatOp &H, +void GF_Diag(const Eigen::VectorXd &state_0, const MatOp &H, const std::vector> &freqs, std::vector> &gf, double E0, bool ispart, int nLanIts = 1000, bool saveABtofile = false, std::string fpref = "") { + using dbl = std::numeric_limits; // FIRST, WE HAVE TO COMPUTE THE LANCZOS alphas AND betas double tol = 1.E-6; std::vector alphas, betas; @@ -203,13 +199,15 @@ void GF_Diag(const VectorXd &state_0, const MatOp &H, * @date 28/01/2022 */ template -void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, +void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const Eigen::VectorXd &wfn, const std::vector> &old_basis, std::vector> &new_basis, const std::vector &occs, const GFSettings &settings) { // CARLOS: BUILDS BASIS FOR THE ADD SPACE NEEDED TO DESCRIBE THE DIAGONAL // PARTICLE GF ELEMENT OF ORBITAL orb. + using bitset_map = std::map< std::bitset, size_t, bitset_less_comparator>; + using bitset_map_iterator = typename bitset_map::iterator; size_t norbs = settings.norbs; size_t trunc_size = settings.trunc_size; @@ -221,18 +219,14 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, << "* SECTOR FOR ORBITAL " << orb << ", WITH SPIN *" << (sp_up ? "UP" : "DOWN") << "*" << std::endl; - time_t loop1 = time(NULL); - auto loop1C = Clock::now(); size_t ndets = old_basis.size(); size_t cgf = -1; size_t sporb = sp_up ? orb : orb + nbits / 2; std::bitset uni_string; std::vector> founddets; founddets.reserve(trunc_size); - std::map, size_t, bitset_less_comparator> - founddet_pos, basedet_pos; - typename std::map, size_t, - bitset_less_comparator>::iterator it; + bitset_map founddet_pos, basedet_pos; + bitset_map_iterator it; // ACTIVE SPACE std::vector as_orbs; for(size_t i = 0; i < occs.size(); i++) { @@ -281,7 +275,7 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, std::cout << "Nr. OF STATES: " << cgf + 1 << std::endl; size_t norb = orb; - VectorXd b = Eigen::VectorXd::Zero(cgf + 1); + Eigen::VectorXd b = Eigen::VectorXd::Zero(cgf + 1); // COMPUTE VECTOR b IN THE NEW BASIS for(size_t ndet = 0; ndet < cgf + 1; ndet++) { // CHECK, CAN ndet COME FROM ai^+|GS> / ai|wfn> WITH THE ORBITAL *orb? @@ -379,26 +373,26 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const VectorXd &wfn, * @date 01/02/2022 */ template -std::vector> BuildWfn4Lanczos( - const VectorXd &base_wfn, const std::vector &GF_orbs, +auto BuildWfn4Lanczos( + const Eigen::VectorXd &base_wfn, const std::vector &GF_orbs, const std::vector &is_up, const std::vector> &base_dets, const std::vector> &GF_dets, bool is_part, std::vector &todelete, double zero_thresh = 1.E-7) { // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - std::map, size_t, bitset_less_comparator> - base_dets_pos; + using bitset_map = std::map< std::bitset, size_t, bitset_less_comparator>; + using bitset_map_iterator = typename bitset_map::const_iterator; + + bitset_map base_dets_pos; for(size_t iii = 0; iii < base_dets.size(); iii++) base_dets_pos[base_dets[iii]] = iii; // PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS size_t nterms = GF_dets.size(); - std::vector> wfns(GF_orbs.size(), - std::vector(nterms, 0.)); + std::vector wfns(GF_orbs.size() * nterms, 0.); for(size_t iorb = 0; iorb < GF_orbs.size(); iorb++) { int orb = GF_orbs[iorb]; bool sp_up = is_up[iorb]; - // int sporb = sp_up ? orb : orb + Norbs; int sporb = sp_up ? orb : orb + nbits / 2; // BUILD THE WAVEFUNCTION FOR ORBITAL orb for(size_t ndet = 0; ndet < nterms; ndet++) { @@ -413,16 +407,14 @@ std::vector> BuildWfn4Lanczos( // DETERMINANT SPACE std::bitset temp(GF_dets[ndet]); temp.flip(sporb); - typename std::map, size_t, - bitset_less_comparator>::const_iterator it = - base_dets_pos.find(temp); + bitset_map_iterator it = base_dets_pos.find(temp); if(it != base_dets_pos.end()) { // IT DOES COME INDEED FROM A DETERMINANT IN THE ORIGINAL GROUND STATE // THUS, IT CONTRIBUTES TO wfns1 double sign = sp_up ? GetInsertionUpSign(temp, orb) : GetInsertionDoSign(temp, orb); double fac = base_wfn(it->second); - wfns[iorb][ndet] += fac * sign; + wfns[iorb * nterms + ndet] += fac * sign; } } } @@ -437,16 +429,17 @@ std::vector> BuildWfn4Lanczos( initializer(omp_priv = 0.) #pragma omp parallel for reduction(Vsum : st_nrm) for(size_t iii = 0; iii < nterms; iii++) - st_nrm += wfns[orb_indx][iii] * wfns[orb_indx][iii]; + st_nrm += wfns[orb_indx * nterms + iii] * wfns[orb_indx * nterms + iii]; if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); } + int nvecs = GF_orbs.size() - todelete.size(); for(int i = 0; i < todelete.size(); i++) - wfns.erase(wfns.begin() + todelete[i] - i); + wfns.erase(wfns.begin() + (todelete[i] - i) * nterms, wfns.begin() + (todelete[i] - i + 1) * nterms); std::cout << "ORBITALS WITH NO CORRESPONING ADD-VECTOR: ["; for(int i = 0; i < todelete.size(); i++) std::cout << todelete[i] << ", "; std::cout << "]" << std::endl; - return wfns; + return std::tuple( wfns, nvecs ); } /** @@ -454,8 +447,8 @@ std::vector> BuildWfn4Lanczos( * grid together with the full GF matrix. Also, in case of a multi-orbitla GF, * it stores the orbital indices in a separate file. * - * @param [in] const std::vector > - * > > &GF: GF to store. Written as GF[freq-axis][orb1][orb2]. + * @param [in] const std::vector > + * > &GF: GF to store. Written as GF[freq-axis][orb1 * norbs + orb2]. * @param [in] const std::vector > &ws: Frequency grid. * @param [in] const std::vector &GF_orbs: Orbital indices for the Green's * function, as requested originally in the GF computation. Some of them may not @@ -469,7 +462,7 @@ std::vector> BuildWfn4Lanczos( * @date 02/02/2022 */ void write_GF( - const std::vector>>> &GF, + const std::vector>> &GF, const std::vector> &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part); @@ -487,10 +480,10 @@ void write_GF( * quatization, should allow for basic bit operations, and being an index in a * dictionary. * - * @param [out] std::vector > > >: + * @param [out] std::vector > >: * On output, contains the computed Green's function, in format - * GF[freq.][orb1][orb2]. - * @param [in] const VectorXd &wfn0: Reference wave function from which to + * GF[freq.][orb1 * norbs + orb2]. + * @param [in] const Eigen::VectorXd &wfn0: Reference wave function from which to * compute the GF. * @param [in] const FermionHamil &H: Fermionic Hamiltonian defining the system. * @param [in] const std::vector &base_dets: Basis of Slater @@ -509,12 +502,13 @@ void write_GF( * @date 01/02/2022 */ template -void RunGFCalc(std::vector>>> &GF, - const VectorXd &wfn0, HamiltonianGenerator &Hgen, +void RunGFCalc(std::vector>> &GF, + const Eigen::VectorXd &wfn0, HamiltonianGenerator &Hgen, const std::vector> &base_dets, const double energ, const bool is_part, const std::vector> &ws, const std::vector &occs, const GFSettings &settings) { + using Clock = std::chrono::high_resolution_clock; // READ INPUT const size_t trunc_size = settings.trunc_size; const int tot_SD = settings.tot_SD; @@ -589,7 +583,9 @@ void RunGFCalc(std::vector>>> &GF, // PREPARE THE WAVEFUNCTIONS FOR THE BAND LANCZOS std::vector todelete; - std::vector> wfns = BuildWfn4Lanczos( + std::vector wfns; + int nvecs; + std::tie( wfns, nvecs ) = BuildWfn4Lanczos( wfn0, GF_orbs_comp, is_up_comp, base_dets, gf_dets, is_part, todelete); // //ACTUALLY COMPUTE THE GF! @@ -597,46 +593,46 @@ void RunGFCalc(std::vector>>> &GF, auto GF_loop1C = Clock::now(); if(use_bandLan) { - BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, print, + BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, nvecs, nterms, print, saveGFmats); } else { // DO SIMPLE LANCZOS FOR ALL GF ELEMENTS SparsexDistSpMatOp hamil_wrap(hamil); + GF.clear(); GF.resize(ws.size(), - std::vector>>( - wfns.size(), std::vector>( - wfns.size(), std::complex(0., 0.)))); - for(int i = 0; i < wfns.size(); i++) { + std::vector>( + nvecs * nvecs, std::complex(0., 0.))); + for(int i = 0; i < nvecs; i++) { std::vector> tGF; // DIAGONAL ELEMENT std::cout << "DOING ELEMENT (" << i << ", " << i << ")" << std::endl; - VectorXd twfn = - Eigen::Map(wfns[i].data(), nterms); + Eigen::VectorXd twfn = + Eigen::Map(wfns.data() + nterms * i, nterms); std::string fpref_basis = is_part ? "particle" : "hole"; std::string fpref = fpref_basis + "_" + std::to_string(i) + "_" + std::to_string(i); GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); - for(int iw = 0; iw < ws.size(); iw++) GF[iw][i][i] = tGF[iw]; - for(int j = i + 1; j < wfns.size(); j++) { + for(int iw = 0; iw < ws.size(); iw++) GF[iw][i * nvecs + i] = tGF[iw]; + for(int j = i + 1; j < nvecs; j++) { // OFF DIAGONAL ELEMENTS std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; for(size_t iii = 0; iii < nterms; iii++) - twfn(iii) = wfns[i][iii] + wfns[j][iii]; + twfn(iii) = wfns[i * nterms + iii] + wfns[j * nterms + iii]; fpref = fpref_basis + "_" + std::to_string(i) + "_" + std::to_string(j) + "_a"; GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); - for(int iw = 0; iw < ws.size(); iw++) GF[iw][i][j] += 0.25 * tGF[iw]; + for(int iw = 0; iw < ws.size(); iw++) GF[iw][i * nvecs + j] += 0.25 * tGF[iw]; for(size_t iii = 0; iii < nterms; iii++) - twfn(iii) = wfns[i][iii] - wfns[j][iii]; + twfn(iii) = wfns[i * nterms + iii] - wfns[j * nterms + iii]; fpref = fpref_basis + "_" + std::to_string(i) + "_" + std::to_string(j) + "_b"; GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts); for(int iw = 0; iw < ws.size(); iw++) { - GF[iw][i][j] -= 0.25 * tGF[iw]; - GF[iw][j][i] = GF[iw][i][j]; + GF[iw][i * nvecs + j] -= 0.25 * tGF[iw]; + GF[iw][j * nvecs + i] = GF[iw][i * nvecs + j]; } } } diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index b722c5e8..d8bf7473 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -44,7 +44,7 @@ struct LanczosSettings { */ class eigMatDOp { private: - const eigMatD *mat; + const Eigen::MatrixXd *mat; public: /** @@ -56,7 +56,7 @@ class eigMatDOp { * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - eigMatDOp(const eigMatD &A) { mat = &A; } + eigMatDOp(const Eigen::MatrixXd &A) { mat = &A; } /** * @brief Simple matrix-vector product. * @@ -67,7 +67,7 @@ class eigMatDOp { * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - VectorXd dot(const VectorXd &vec) const { return (*mat) * vec; } + Eigen::VectorXd dot(const Eigen::VectorXd &vec) const { return (*mat) * vec; } /** * @brief Returns nr. of rows in the wrapped matrix. * @@ -89,7 +89,7 @@ class eigMatDOp { */ class SpMatDOp { private: - const SpMatD *mat; + const Eigen::SparseMatrix *mat; public: /** @@ -102,7 +102,7 @@ class SpMatDOp { * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - SpMatDOp(const SpMatD &A) { mat = &A; } + SpMatDOp(const Eigen::SparseMatrix &A) { mat = &A; } /** * @brief Simple matrix-vector product. * @@ -113,7 +113,7 @@ class SpMatDOp { * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - VectorXd dot(const VectorXd &vec) const { return (*mat) * vec; } + Eigen::VectorXd dot(const Eigen::VectorXd &vec) const { return (*mat) * vec; } /** * @brief Returns nr. of rows in the wrapped matrix. * @@ -167,7 +167,7 @@ class SparsexDistSpMatOp { * @author Carlos Mejuto Zaera * @date 05/04/2021 */ - VectorXd dot(const VectorXd &vec) const { + Eigen::VectorXd dot(const Eigen::VectorXd &vec) const { std::vector vin(&vec[0], vec.data() + vec.cols() * vec.rows()); std::vector vout(vec.size(), 0.); sparsexx::spblas::pgespmv(1., *mat, vin.data(), 0., vout.data(), spmv_info); @@ -200,16 +200,16 @@ class SparsexDistSpMatOp { * @date 05/04/2021 */ template -void MyLanczos(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, +void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, int64_t nLanIts, std::vector &alphas, std::vector &betas, double tol) { // LANCZOS ROUTINE USING TEMPLATED MATRIX // CLASS. ONLY NEEDS TO PROVIDE A MATRIX // VECTOR PRODUCT. int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); + Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qnew = Eigen::VectorXd::Zero(n); alphas.clear(); betas.clear(); @@ -266,14 +266,14 @@ void MyLanczos(const VectorXd &start_vec, const MatOp &H, int64_t nLanIts, * @date 05/04/2021 */ template -void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, - int64_t nLanIts, VectorXd &vec_P, VectorXd &vec_BP) { +void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, + int64_t nLanIts, Eigen::VectorXd &vec_P, Eigen::VectorXd &vec_BP) { // REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS // CALCULATION. int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); + Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qnew = Eigen::VectorXd::Zero(n); std::vector alphas(nLanIts, 0.); std::vector betas(nLanIts + 1, 0.); @@ -281,7 +281,7 @@ void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, double normpsi = sqrt(MyInnProd(start_vec, start_vec)); int64_t nlan = -1, itermax = nLanIts; - vec_BP = VectorXd::Zero(n); + vec_BP = Eigen::VectorXd::Zero(n); nlan++; qold = start_vec / normpsi; @@ -327,8 +327,8 @@ void MyLanczos_BackProj(const VectorXd &start_vec, const MatOp &H, * @date 05/04/2021 */ template -int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, - VectorXd &psi0_Lan, const LanczosSettings &settings) { +int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, double &E0, + Eigen::VectorXd &psi0_Lan, const LanczosSettings &settings) { // COMPUTE LOWEST EIGENVALUE OF MATRIX H // USING LANCZOS. RETURNS EIGENVECTOR IN // THE BASIS OF KRYLOV VECTORS @@ -339,11 +339,11 @@ int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, size_t itermax = settings.itermax; int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - VectorXd eigvals; - eigMatD eigvecs; + Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qnew = Eigen::VectorXd::Zero(n); + Eigen::VectorXd eigvals; + Eigen::MatrixXd eigvecs; std::vector alphas, betas; double currE0, prevE0; @@ -425,7 +425,7 @@ int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, E0 = currE0; if(itermax == 1) { - psi0_Lan = VectorXd::Ones(1); + psi0_Lan = Eigen::VectorXd::Ones(1); } else { psi0_Lan = eigvecs.col(0); } @@ -447,8 +447,8 @@ int64_t GetGSEn_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, * @date 05/04/2021 */ template -void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, - VectorXd &psi0, const LanczosSettings &settings) { +void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, double &E0, + Eigen::VectorXd &psi0, const LanczosSettings &settings) { // COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR // OF MATRIX H USING LANCZOS. double Lantol = settings.Lantol; @@ -457,12 +457,12 @@ void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, size_t itermax = settings.itermax; int64_t n = start_vec.rows(); - VectorXd qold = VectorXd::Zero(n); - VectorXd qtemp = VectorXd::Zero(n); - VectorXd qnew = VectorXd::Zero(n); - VectorXd eigvals; - eigMatD eigvecs; - std::vector kry_vecs; + Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); + Eigen::VectorXd qnew = Eigen::VectorXd::Zero(n); + Eigen::VectorXd eigvals; + Eigen::MatrixXd eigvecs; + std::vector kry_vecs; std::vector alphas, betas; double currE0, prevE0; @@ -528,7 +528,7 @@ void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, } E0 = currE0; - psi0 = VectorXd::Zero(n); + psi0 = Eigen::VectorXd::Zero(n); if(kry_vecs.size() == 1) { psi0 = kry_vecs[0]; } else { @@ -553,7 +553,7 @@ void GetGSEnVec_Lanczos(const VectorXd &start_vec, const MatOp &H, double &E0, * @date 05/04/2021 */ template -void GetGS(const MatOp &H, double &E0, VectorXd &psi0, +void GetGS(const MatOp &H, double &E0, Eigen::VectorXd &psi0, const LanczosSettings &settings, bool isHF = false) { // Computes the lowest eigenvalue and corresponding // eigenvector from the dense matrix H by using Lanczos. @@ -561,11 +561,11 @@ void GetGS(const MatOp &H, double &E0, VectorXd &psi0, int64_t n = H.rows(); // Initial vector. We choose (1,0,0,0,...)t // for HF, Otherwhise (1,1,1,1,...)t - VectorXd start_psi = isHF ? VectorXd::Zero(n) : VectorXd::Ones(n); + Eigen::VectorXd start_psi = isHF ? Eigen::VectorXd::Zero(n) : Eigen::VectorXd::Ones(n); start_psi(0) = 1.; // Determine lowest eigenvalue for the given // tolerance. - VectorXd psi0_Lan; + Eigen::VectorXd psi0_Lan; int64_t nLanIts = GetGSEn_Lanczos(start_psi, H, E0, psi0_Lan, settings); // Reconstruct the eigenvector MyLanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 508eb5a9..a76afc03 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -16,8 +16,10 @@ inline bool is_file(const std::string &name) { } namespace macis { -bool QRdecomp(std::vector > &Q, - std::vector > &R) { +bool QRdecomp(std::vector &Q, + std::vector &R, + int Qrows, + int Qcols) { // CALL LAPACK'S QR DECOMPOSITION ROUTINES. // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE // RECTANGULAR, @@ -29,42 +31,35 @@ bool QRdecomp(std::vector > &Q, R.clear(); // PREPARE VARIABLES TO CALL LAPACK - int M = Q.size(), N = Q[0].size(); + int M = Qrows, N = Qcols; assert(M >= N); int LDA = M, INFO = 0; - std::vector A, TAU; + std::vector A( M * N, 0. ), TAU( N, 0. ); // INITIALIZE A - A.resize(M * N, 0.); - for(int i = 0; i < M; i++) { - for(int j = 0; j < N; j++) A[i + j * M] = Q[i][j]; - Q[i].clear(); - } - // INITIALIZE TAU, AND COMPUTE R MATRIX - TAU.resize(N); + for(int i = 0; i < M; i++) + for(int j = 0; j < N; j++) A[i + j * M] = Q[i + j * M]; + // COMPUTE R MATRIX lapack::geqrf(M, N, A.data(), LDA, TAU.data()); // SAVE THE R MATRIX - R.resize(N); - for(int i = 0; i < N; i++) { - R[i].resize(N); - std::fill(R[i].begin(), R[i].end(), 0.); - for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; - } + R.resize(N * N); + for(int i = 0; i < N; i++) + for(int j = i; j < N; j++) R[i + j * N] = A[i + j * M]; // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; lapack::orgqr(M, N, K, A.data(), LDA, TAU.data()); // SAVE THE Q MATRIX - for(int i = 0; i < M; i++) { - Q[i].resize(N); - for(int j = 0; j < N; j++) Q[i][j] = A[i + j * M]; - } + for(int i = 0; i < M; i++) + for(int j = 0; j < N; j++) Q[i + j * M] = A[i + j * M]; return true; } -bool QRdecomp_tr(std::vector > &Q, - std::vector > &R) { +bool QRdecomp_tr(std::vector &Q, + std::vector &R, + int Qrows, + int Qcols) { // CALL LAPACK'S QR DECOMPOSITION ROUTINES. // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE // RECTANGULAR, @@ -76,42 +71,36 @@ bool QRdecomp_tr(std::vector > &Q, R.clear(); // PREPARE VARIABLES TO CALL LAPACK - int M = Q[0].size(), N = Q.size(); + int M = Qcols, N = Qrows; assert(M >= N); int LDA = M, INFO = 0; - std::vector A, TAU; + std::vector A( M * N, 0. ), TAU( N, 0. ); // INITIALIZE A - A.resize(M * N); - for(int i = 0; i < M; i++) { - for(int j = 0; j < N; j++) A[i + j * M] = Q[j][i]; - } + for(int i = 0; i < M; i++) + for(int j = 0; j < N; j++) A[i + j * M] = Q[i + j * M]; - // INITIALIZE TAU, AND EVALUATE R MATRIX - TAU.resize(N); + // EVALUATE R MATRIX lapack::geqrf(M, N, A.data(), LDA, TAU.data()); // SAVE THE R MATRIX - R.resize(N); - for(int i = 0; i < N; i++) { - R[i].resize(N); - std::fill(R[i].begin(), R[i].end(), 0.); - for(int j = i; j < N; j++) R[i][j] = A[i + j * M]; - } + R.resize(N * N); + for(int i = 0; i < N; i++) + for(int j = i; j < N; j++) R[i + j * N] = A[i + j * M]; // NOW, COMPUTE THE ACTUAL Q MATRIX int K = N; lapack::orgqr(M, N, K, A.data(), LDA, TAU.data()); // SAVE THE Q MATRIX - for(int i = 0; i < M; i++) { - for(int j = 0; j < N; j++) Q[j][i] = A[i + j * M]; - } + for(int i = 0; i < M; i++) + for(int j = 0; j < N; j++) Q[i + j * M] = A[i + j * M]; return true; } -bool GetEigsys(std::vector > &mat, +bool GetEigsys(std::vector &mat, std::vector &eigvals, - std::vector > &eigvecs) { + std::vector &eigvecs, + int matsize) { // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC MATRIX mat BY // CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. FIRST, // IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES @@ -122,35 +111,30 @@ bool GetEigsys(std::vector > &mat, // PREPARE VARIABLES FOR LAPACK lapack::Uplo UPLO = lapack::Uplo::Upper; lapack::Job JOBZ = lapack::Job::Vec; - int N = mat.size(), LDA = mat.size(); - std::vector A, D; + int N = matsize, LDA = matsize; + std::vector A( N * N, 0. ), D( N, 0. ); // INITIALIZE A - A.resize(N * N); - for(int i = 0; i < N; i++) { - for(int j = 0; j < N; j++) A[i + j * N] = mat[i][j]; - mat[i].clear(); - } + for(int i = 0; i < N; i++) + for(int j = 0; j < N; j++) A[i + j * N] = mat[i + j * N]; mat.clear(); - // ALLOCATE REST OF THE MEMORY - D.resize(N); + // COMPUTE EIGENVALUES AND EIGENVECTORS lapack::heev_2stage(JOBZ, UPLO, N, A.data(), LDA, D.data()); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS eigvals.resize(N); for(int i = 0; i < N; i++) eigvals[i] = D[i]; - eigvecs.resize(N); - for(int i = 0; i < N; i++) { - eigvecs[i].resize(N); - for(int j = 0; j < N; j++) eigvecs[i][j] = A[j + i * N]; - } + eigvecs.resize(N * N); + for(int i = 0; i < N; i++) + for(int j = 0; j < N; j++) eigvecs[i + j * N] = A[j + i * N]; return true; } -bool GetEigsysBand(std::vector > &mat, int nSupDiag, +bool GetEigsysBand(std::vector &mat, int nSupDiag, std::vector &eigvals, - std::vector > &eigvecs) { + std::vector &eigvecs, + int matsize) { // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC BAND MATRIX mat // BY CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. // FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE @@ -162,20 +146,15 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, lapack::Uplo UPLO = lapack::Uplo::Upper; lapack::Job VECT = lapack::Job::Vec; lapack::Job COMPZ = lapack::Job::Vec; - int N = mat.size(), LDQ = mat.size(), LDAB = nSupDiag + 1; - std::vector AB, D, E, Q; + int N = matsize, LDQ = matsize, LDAB = nSupDiag + 1; + std::vector AB( (nSupDiag + 1) * N, 0. ); + std::vector D( N, 0. ), E( N - 1, 0. ), Q( N * N, 0. ); // INITIALIZE A - AB.resize((nSupDiag + 1) * N); - for(int j = 0; j < N; j++) { + for(int j = 0; j < N; j++) for(int i = std::max(0, j - nSupDiag); i <= j; i++) - AB[nSupDiag + i - j + j * (nSupDiag + 1)] = mat[i][j]; - } + AB[nSupDiag + i - j + j * (nSupDiag + 1)] = mat[i + j * N]; mat.clear(); - // ALLOCATE REST OF THE MEMORY - Q.resize(N * N); - D.resize(N); - E.resize(N - 1); // TRANSFORM THE MATRIX TO TRIDIAGONAL FORM // NOW, TRANSFORM MATRIX TO TRIDIAGONAL FORM @@ -190,11 +169,9 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, eigvals.resize(N); for(int i = 0; i < N; i++) eigvals[i] = D[i]; D.clear(); - eigvecs.resize(N); - for(int i = 0; i < N; i++) { - eigvecs[i].resize(N); - for(int j = 0; j < N; j++) eigvecs[i][j] = Q[j + i * N]; - } + eigvecs.resize( N * N ); + for(int i = 0; i < N; i++) + for(int j = 0; j < N; j++) eigvecs[i + j * N] = Q[j + i * N]; return true; } @@ -202,26 +179,25 @@ bool GetEigsysBand(std::vector > &mat, int nSupDiag, void BandResolvent( const sparsexx::dist_sparse_matrix > &H, - std::vector > &vecs, + std::vector &vecs, const std::vector > &ws, - std::vector > > > &res, - int nLanIts, double E0, bool ispart, bool print, bool saveGFmats) { + std::vector > > &res, + int nLanIts, double E0, bool ispart, int nvecs, int len_vec, bool print, bool saveGFmats ) { // COMPUTES THE RESOLVENT (ws - H)^-1 IN MATRIX FORM FOR THE "BASIS" GIVEN BY // THE vecs VECTORS AND THE FREQUENCY GRID IN ws. USES THE BAND LANCZOS // ALGORITHM. IT GETS STORED IN res. + using dbl = std::numeric_limits; res.clear(); std::cout << "RESOLVENT ROUTINE: "; res.resize(ws.size(), - std::vector > >( - vecs.size(), std::vector >( - vecs.size(), std::complex(0., 0.)))); - int n = vecs.size(); + std::vector >( + nvecs * nvecs, std::complex(0., 0.))); // FIRST, COMPUTE QR DECOMPOSITION OF THE "BASIS" VECTORS vecs, NECESSARY FOR // LANCZOS - std::vector > R; + std::vector R; std::cout << "QR DECOMPOSITION ..."; - bool worked = QRdecomp_tr(vecs, R); + bool worked = QRdecomp_tr(vecs, R, nvecs, len_vec); if(not worked) { std::cout << "QR DECOMPOSITION FAILED!!" << std::endl; return; @@ -233,84 +209,81 @@ void BandResolvent( ofile.precision(dbl::max_digits10); ofile << "RESULT OF QR DECOMPOSITION: " << std::endl; ofile << " New Vectors: " << std::endl; - for(int i = 0; i < vecs[0].size(); i++) { - for(int j = 0; j < vecs.size(); j++) - ofile << std::scientific << vecs[j][i] << " "; + for(int i = 0; i < len_vec; i++) { + for(int j = 0; j < nvecs; j++) + ofile << std::scientific << vecs[j * len_vec + i] << " "; ofile << std::endl; } ofile.close(); ofile.clear(); ofile.open("QRresRmat.dat", std::ios::out); ofile << " R Matrix: " << std::endl; - for(int i = 0; i < R.size(); i++) { - for(int j = 0; j < R[i].size(); j++) - ofile << std::scientific << R[i][j] << " "; + for(int i = 0; i < nvecs; i++) { + for(int j = 0; j < nvecs; j++) + ofile << std::scientific << R[i + j * nvecs] << " "; ofile << std::endl; } ofile.close(); } // NEXT, COMPUTE THE BAND LANCZOS - std::vector > bandH; + std::vector bandH; std::cout << "BAND LANCZOS ..."; SparseMatrixOperator Hop(H); - int nbands = vecs.size(); - std::vector qs(vecs.size() * n, 0.); - for(int i = 0; i < vecs.size(); i++) - for(int j = 0; j < n; j++) qs[j + n * i] = vecs[i][j]; - MyBandLan(Hop, qs, bandH, nLanIts, nbands, n, 1.E-6, print); + int nbands = nvecs; + MyBandLan(Hop, vecs, bandH, nLanIts, nbands, nvecs, 1.E-6, print); std::cout << "DONE! "; if(print) { std::ofstream ofile("BLH.dat", std::ios::out); ofile.precision(dbl::max_digits10); ofile << "RESULT OF BAND LANCZOS: " << std::endl; ofile << " bandH Matrix: " << std::endl; - for(int i = 0; i < bandH.size(); i++) { - for(int j = 0; j < bandH[i].size(); j++) - ofile << std::scientific << bandH[i][j] << " "; + for(int i = 0; i < nLanIts; i++) { + for(int j = 0; j < nLanIts; j++) + ofile << std::scientific << bandH[i * nLanIts + j] << " "; ofile << std::endl; } ofile.close(); } - if(n == 1) { + if(nvecs == 1) { // ONLY ONE BAND. DIAGONAL GREEN'S FUNCTION ELEMENT. // COMPUTE THROUGH CONTINUED FRACTION. std::cout << "COMPUTING GF AS CONTINUED FRACTION..."; - std::vector alphas(bandH.size(), 0.), betas(bandH.size(), 0.); - for(int i = 0; i < bandH.size(); i++) - alphas[i] = ispart ? E0 - bandH[i][i] : bandH[i][i] - E0; - for(int i = 0; i < bandH.size() - 1; i++) - betas[i + 1] = ispart ? -bandH[i][i + 1] : bandH[i][i + 1]; - betas[0] = R[0][0]; + std::vector alphas(nLanIts, 0.), betas(nLanIts, 0.); + for(int i = 0; i < nLanIts; i++) + alphas[i] = ispart ? E0 - bandH[i * nLanIts + i] : bandH[i * nLanIts + i] - E0; + for(int i = 0; i < nLanIts - 1; i++) + betas[i + 1] = ispart ? -bandH[i * nLanIts + i + 1] : bandH[i * nLanIts + i + 1]; + betas[0] = R[0]; #pragma omp parallel for for(int indx_w = 0; indx_w < ws.size(); indx_w++) { - res[indx_w][0][0] = + res[indx_w][0] = betas.back() * betas.back() / (ws[indx_w] + alphas.back()); for(int i = betas.size() - 2; i >= 0; i--) - res[indx_w][0][0] = - betas[i] * betas[i] / (ws[indx_w] + alphas[i] - res[indx_w][0][0]); + res[indx_w][0] = + betas[i] * betas[i] / (ws[indx_w] + alphas[i] - res[indx_w][0]); } } else { // NEXT, COMPUTE THE EIGENVALUES AND EIGENVECTORS OF THE BAND DIAGONAL // KRYLOV HAMILTONIAN std::vector eigvals; - std::vector > eigvecs; + std::vector eigvecs; std::cout << "COMPUTING EIGENVALES ..."; if(ispart) - for(int rr = 0; rr < bandH.size(); rr++) { - bandH[rr][rr] = E0 - bandH[rr][rr]; - for(int cc = rr + 1; cc < bandH.size(); cc++) { - bandH[rr][cc] = -bandH[rr][cc]; - bandH[cc][rr] = -bandH[cc][rr]; + for(int rr = 0; rr < nLanIts; rr++) { + bandH[rr * nLanIts + rr] = E0 - bandH[rr * nLanIts + rr]; + for(int cc = rr + 1; cc < nLanIts; cc++) { + bandH[rr * nLanIts + cc] = -bandH[rr * nLanIts + cc]; + bandH[cc * nLanIts + rr] = -bandH[cc * nLanIts + rr]; } } else - for(int rr = 0; rr < bandH.size(); rr++) - bandH[rr][rr] = bandH[rr][rr] - E0; + for(int rr = 0; rr < nLanIts; rr++) + bandH[rr * nLanIts + rr] = bandH[rr * nLanIts + rr] - E0; - GetEigsysBand(bandH, std::min(size_t(n), bandH.size() - 1), eigvals, - eigvecs); + GetEigsysBand(bandH, std::min(size_t(nvecs), size_t(nLanIts - 1)), eigvals, + eigvecs, nLanIts); if(print) { std::ofstream ofile("BLEigs.dat", std::ios::out); ofile.precision(dbl::max_digits10); @@ -320,21 +293,21 @@ void BandResolvent( ofile << std::scientific << eigvals[i] << ", "; ofile << std::endl; ofile << "Eigvecs: " << std::endl; - for(int i = 0; i < eigvecs.size(); i++) { - for(int j = 0; j < eigvecs[i].size(); j++) - ofile << std::scientific << eigvecs[i][j] << " "; + for(int i = 0; i < nLanIts; i++) { + for(int j = 0; j < nLanIts; j++) + ofile << std::scientific << eigvecs[i + j * nLanIts] << " "; ofile << std::endl; } ofile.close(); } std::cout << "DONE! "; // FINALLY, COMPUTE S-MATRIX AND RESOLVENT - std::vector > S(nLanIts, std::vector(n, 0.)); + std::vector S(nLanIts * nvecs, 0.); std::cout << " COMPUTING S MATRIX ..."; for(int i_lan = 0; i_lan < nLanIts; i_lan++) { - for(int j_n = 0; j_n < n; j_n++) { - for(int l = 0; l < n; l++) - S[i_lan][j_n] += eigvecs[i_lan][l] * R[l][j_n]; + for(int j_n = 0; j_n < nvecs; j_n++) { + for(int l = 0; l < nvecs; l++) + S[i_lan * nvecs + j_n] += eigvecs[i_lan + l * nLanIts] * R[l + j_n * nvecs]; } } if(saveGFmats) { @@ -344,8 +317,8 @@ void BandResolvent( std::ofstream ofile(fprefix + "_S.mat", std::ios::out); ofile.precision(dbl::max_digits10); for(int i_lan = 0; i_lan < nLanIts; i_lan++) { - for(int k = 0; k < n; k++) - ofile << std::scientific << S[i_lan][k] << " "; + for(int k = 0; k < nvecs; k++) + ofile << std::scientific << S[i_lan * nvecs + k] << " "; ofile << std::endl; } ofile.close(); @@ -358,11 +331,11 @@ void BandResolvent( std::cout << "DONE! COMPUTING RESOLVENT ..."; #pragma omp parallel for for(int iw = 0; iw < ws.size(); iw++) { - for(int k = 0; k < n; k++) { - for(int l = 0; l < n; l++) { + for(int k = 0; k < nvecs; k++) { + for(int l = 0; l < nvecs; l++) { for(int i_lan = 0; i_lan < nLanIts; i_lan++) { - res[iw][k][l] += - S[i_lan][k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan][l]; + res[iw][k * nvecs + l] += + S[i_lan * nvecs + k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan * nvecs + l]; } } } diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index ca29277a..6bcb4caf 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -13,7 +13,7 @@ namespace macis { void Hste_v(const std::vector &alphas, const std::vector &betas, - Eigen::VectorXd &eigvals, eigMatD &eigvecs) { + Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs) { /* * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A TRIDIAGONAL, SYMMETRIC * MATRIX A USING LAPACK. @@ -45,7 +45,7 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, for(int i = 0; i < N; i++) eigvals(i) = D[i]; } -void Hsyev(const eigMatD &H, Eigen::VectorXd &eigvals, eigMatD &eigvecs) { +void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs) { /* * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING * LAPACK. diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 359317ac..2324f4cb 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -10,11 +10,13 @@ namespace macis { void write_GF( - const std::vector > > > &GF, + const std::vector > > &GF, const std::vector > &ws, const std::vector &GF_orbs, const std::vector &todelete, const bool is_part) { + using dbl = std::numeric_limits; size_t nfreqs = ws.size(); + int GFmat_size = GF_orbs.size() - todelete.size(); if(GF_orbs.size() > 1) { std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; @@ -22,10 +24,10 @@ void write_GF( ofile.precision(dbl::max_digits10); for(int iii = 0; iii < nfreqs; iii++) { ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; - for(int jjj = 0; jjj < GF[iii].size(); jjj++) { - for(int lll = 0; lll < GF[iii][jjj].size(); lll++) - ofile << std::scientific << real(GF[iii][jjj][lll]) << " " - << imag(GF[iii][jjj][lll]) << " "; + for(int jjj = 0; jjj < GFmat_size; jjj++) { + for(int lll = 0; lll < GFmat_size; lll++) + ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) << " " + << imag(GF[iii][jjj * GFmat_size + lll]) << " "; } ofile << std::endl; } @@ -46,7 +48,7 @@ void write_GF( ofile.precision(dbl::max_digits10); for(int iii = 0; iii < nfreqs; iii++) ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " - << real(GF[iii][0][0]) << " " << imag(GF[iii][0][0]) << std::endl; + << real(GF[iii][0]) << " " << imag(GF[iii][0]) << std::endl; } } diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 942b72a7..89bde9a9 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -353,10 +353,9 @@ int main(int argc, char** argv) { gf_settings.is_up_comp = std::vector(2, true); // GF vector - std::vector>>> GF( - 1, std::vector>>( - 1, std::vector>( - nws, std::complex(0., 0.)))); + std::vector>> GF( + nws, std::vector>( + 1, std::complex(0., 0.))); // Occupation numbers std::vector occs(n_active, 1.); From a806f13aba62129852d540ebf023133dee0f030f Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Thu, 15 Jun 2023 14:10:59 +0000 Subject: [PATCH 15/35] Committing clang-format changes --- include/macis/bitset_operations.hpp | 5 ++- include/macis/gf/bandlan.hpp | 61 ++++++++++++------------- include/macis/gf/eigsolver.hpp | 3 +- include/macis/gf/gf.hpp | 60 +++++++++++++------------ include/macis/gf/lanczos.hpp | 22 +++++---- src/macis/gf/bandlan.cxx | 70 ++++++++++++++--------------- src/macis/gf/eigsolver.cxx | 3 +- src/macis/gf/gf.cxx | 13 +++--- tests/standalone_driver.cxx | 2 +- 9 files changed, 120 insertions(+), 119 deletions(-) diff --git a/include/macis/bitset_operations.hpp b/include/macis/bitset_operations.hpp index 44acbb0e..e11b5f69 100644 --- a/include/macis/bitset_operations.hpp +++ b/include/macis/bitset_operations.hpp @@ -7,13 +7,14 @@ */ #pragma once +#include +#include + #include #include #include #include #include -#include -#include namespace macis { diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index ccd842eb..53e05ba2 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -53,10 +53,8 @@ namespace macis { * @author Carlos Mejuto-Zaera * @date 25/04/2022 */ -bool QRdecomp(std::vector &Q, - std::vector &R, - int Qrows, - int Qcols); +bool QRdecomp(std::vector &Q, std::vector &R, int Qrows, + int Qcols); /** * @ brief Wrapper for QR decomposition in LAPACK, basically @@ -77,10 +75,8 @@ bool QRdecomp(std::vector &Q, * @author Carlos Mejuto-Zaera * @date 25/04/2022 */ -bool QRdecomp_tr(std::vector &Q, - std::vector &R, - int Qrows, - int Qcols); +bool QRdecomp_tr(std::vector &Q, std::vector &R, int Qrows, + int Qcols); /** * @brief Wrapper to LAPACK routine to evaluate the eigenvectors @@ -100,10 +96,8 @@ bool QRdecomp_tr(std::vector &Q, * @author Carlos Mejuto Zaera * @date 25/04/2022 */ -bool GetEigsys(std::vector &mat, - std::vector &eigvals, - std::vector &eigvecs, - int matsize); +bool GetEigsys(std::vector &mat, std::vector &eigvals, + std::vector &eigvecs, int matsize); /** * @brief Wrapper to LAPACK routine to evaluate the eigenvectors @@ -125,9 +119,8 @@ bool GetEigsys(std::vector &mat, * @date 25/04/2022 */ bool GetEigsysBand(std::vector &mat, int nSupDiag, - std::vector &eigvals, - std::vector &eigvecs, - int matsize); + std::vector &eigvals, std::vector &eigvecs, + int matsize); /** * @brief Perform a band Lanczos calculation on the Hamiltonian operator H, @@ -151,10 +144,9 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, * @date 25/04/2022 */ template -void MyBandLan(const Functor &H, - std::vector &qs, std::vector &bandH, - int &nLanIts, int nbands, int N, double thres = 1.E-6, - bool print = false) { +void MyBandLan(const Functor &H, std::vector &qs, + std::vector &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 @@ -203,26 +195,29 @@ void MyBandLan(const Functor &H, 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) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; + temp[coeff] -= + bandH[(it - 1) * nLanIts + 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) * nLanIts + jt - 1] = blas::dot(N, temp.data(), 1, qs.data() + band_indx_j * N, 1); - bandH[(jt - 1) * nLanIts + it - 1] = bandH[(it - 1 ) * nLanIts + jt - 1]; + bandH[(jt - 1) * nLanIts + it - 1] = bandH[(it - 1) * nLanIts + jt - 1]; #pragma omp parallel for for(size_t coeff = 0; coeff < temp.size(); coeff++) - temp[coeff] -= bandH[(it - 1 ) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; + temp[coeff] -= + bandH[(it - 1) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; } if(it + nbands <= nLanIts) { - bandH[(it - 1 ) * nLanIts + it + nbands - 1] = + bandH[(it - 1) * nLanIts + it + nbands - 1] = std::sqrt(std::real(MyInnProd(temp, temp))); - bandH[(it + nbands - 1 ) * nLanIts + it - 1] = bandH[(it - 1 ) * nLanIts + it + nbands - 1]; + bandH[(it + nbands - 1) * nLanIts + it - 1] = + bandH[(it - 1) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; - if(std::abs(bandH[(it - 1 ) * nLanIts + it + nbands - 1]) < thres) { + if(std::abs(bandH[(it - 1) * nLanIts + it + nbands - 1]) < thres) { std::cout << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " - << bandH[(it - 1 ) * nLanIts + it + nbands - 1] + << bandH[(it - 1) * nLanIts + it + nbands - 1] << ", STOPPED AT ITERATION: " << it << std::endl; nLanIts = it; bandH.resize(nLanIts * nLanIts); @@ -236,7 +231,7 @@ void MyBandLan(const Functor &H, #pragma omp parallel for for(size_t coeff = 0; coeff < temp.size(); coeff++) qs[true_indx[it + nbands] * N + coeff] = - temp[coeff] / bandH[(it - 1 ) * nLanIts + it + nbands - 1]; + temp[coeff] / bandH[(it - 1) * nLanIts + it + nbands - 1]; if(print) { std::ofstream ofile("lanvec_" + std::to_string(it + nbands) + ".dat", std::ios::out); @@ -261,7 +256,8 @@ void MyBandLan(const Functor &H, * @param[in] const sparsex::dist_sparse_matrix > &H: Hamiltonian operator. * @param[in] std::vector &vecs: Vectors for which to - * compute the resolvent matrix elements in format res[freq.][iorb1 * norbs + iorb2]. + * compute the resolvent matrix elements in format res[freq.][iorb1 * norbs + + * iorb2]. * @param[in] std::vector > &ws: Frequency grid over which * to evaluate the resolvent. * @param[out] std::vector > > @@ -278,10 +274,9 @@ void MyBandLan(const Functor &H, void BandResolvent( const sparsexx::dist_sparse_matrix > &H, - std::vector &vecs, - const std::vector > &ws, - std::vector > > &res, - int nLanIts, double E0, bool ispart, int nvecs, - int len_vec, bool print = false, bool saveGFmats = false); + std::vector &vecs, const std::vector > &ws, + std::vector > > &res, int nLanIts, + double E0, bool ispart, int nvecs, int len_vec, bool print = false, + bool saveGFmats = false); } // namespace macis diff --git a/include/macis/gf/eigsolver.hpp b/include/macis/gf/eigsolver.hpp index 6d569117..295789fe 100644 --- a/include/macis/gf/eigsolver.hpp +++ b/include/macis/gf/eigsolver.hpp @@ -48,6 +48,7 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, * @author Carlos Mejuto Zaera * @date 05/04/2021 */ -void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs); +void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, + Eigen::MatrixXd &eigvecs); } // namespace macis diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 430cde49..09c35271 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -199,14 +199,16 @@ void GF_Diag(const Eigen::VectorXd &state_0, const MatOp &H, * @date 28/01/2022 */ template -void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const Eigen::VectorXd &wfn, +void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, + const Eigen::VectorXd &wfn, const std::vector> &old_basis, std::vector> &new_basis, const std::vector &occs, const GFSettings &settings) { // CARLOS: BUILDS BASIS FOR THE ADD SPACE NEEDED TO DESCRIBE THE DIAGONAL // PARTICLE GF ELEMENT OF ORBITAL orb. - using bitset_map = std::map< std::bitset, size_t, bitset_less_comparator>; + using bitset_map = + std::map, size_t, bitset_less_comparator>; using bitset_map_iterator = typename bitset_map::iterator; size_t norbs = settings.norbs; @@ -373,16 +375,18 @@ void get_GF_basis_AS_1El(int orb, bool sp_up, bool is_part, const Eigen::VectorX * @date 01/02/2022 */ template -auto BuildWfn4Lanczos( - const Eigen::VectorXd &base_wfn, const std::vector &GF_orbs, - const std::vector &is_up, - const std::vector> &base_dets, - const std::vector> &GF_dets, bool is_part, - std::vector &todelete, double zero_thresh = 1.E-7) { +auto BuildWfn4Lanczos(const Eigen::VectorXd &base_wfn, + const std::vector &GF_orbs, + const std::vector &is_up, + const std::vector> &base_dets, + const std::vector> &GF_dets, + bool is_part, std::vector &todelete, + double zero_thresh = 1.E-7) { // INITIALIZE THE DICTIONARY OF BASE DETERMINANTS - using bitset_map = std::map< std::bitset, size_t, bitset_less_comparator>; + using bitset_map = + std::map, size_t, bitset_less_comparator>; using bitset_map_iterator = typename bitset_map::const_iterator; - + bitset_map base_dets_pos; for(size_t iii = 0; iii < base_dets.size(); iii++) base_dets_pos[base_dets[iii]] = iii; @@ -434,12 +438,13 @@ auto BuildWfn4Lanczos( } int nvecs = GF_orbs.size() - todelete.size(); for(int i = 0; i < todelete.size(); i++) - wfns.erase(wfns.begin() + (todelete[i] - i) * nterms, wfns.begin() + (todelete[i] - i + 1) * nterms); + wfns.erase(wfns.begin() + (todelete[i] - i) * nterms, + wfns.begin() + (todelete[i] - i + 1) * nterms); std::cout << "ORBITALS WITH NO CORRESPONING ADD-VECTOR: ["; for(int i = 0; i < todelete.size(); i++) std::cout << todelete[i] << ", "; std::cout << "]" << std::endl; - return std::tuple( wfns, nvecs ); + return std::tuple(wfns, nvecs); } /** @@ -461,11 +466,10 @@ auto BuildWfn4Lanczos( * @author Carlos Mejuto Zaera * @date 02/02/2022 */ -void write_GF( - const std::vector>> &GF, - const std::vector> &ws, - const std::vector &GF_orbs, const std::vector &todelete, - const bool is_part); +void write_GF(const std::vector>> &GF, + const std::vector> &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part); /** * @brief Routine to run Green's function calculation at zero temperature from @@ -483,8 +487,8 @@ void write_GF( * @param [out] std::vector > >: * On output, contains the computed Green's function, in format * GF[freq.][orb1 * norbs + orb2]. - * @param [in] const Eigen::VectorXd &wfn0: Reference wave function from which to - * compute the GF. + * @param [in] const Eigen::VectorXd &wfn0: Reference wave function from which + * to compute the GF. * @param [in] const FermionHamil &H: Fermionic Hamiltonian defining the system. * @param [in] const std::vector &base_dets: Basis of Slater * determinants for the description of wfn0. @@ -585,7 +589,7 @@ void RunGFCalc(std::vector>> &GF, std::vector todelete; std::vector wfns; int nvecs; - std::tie( wfns, nvecs ) = BuildWfn4Lanczos( + std::tie(wfns, nvecs) = BuildWfn4Lanczos( wfn0, GF_orbs_comp, is_up_comp, base_dets, gf_dets, is_part, todelete); // //ACTUALLY COMPUTE THE GF! @@ -593,21 +597,20 @@ void RunGFCalc(std::vector>> &GF, auto GF_loop1C = Clock::now(); if(use_bandLan) { - BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, nvecs, nterms, print, - saveGFmats); + BandResolvent(hamil, wfns, ws, GF, nLanIts, energ, is_part, nvecs, nterms, + print, saveGFmats); } else { // DO SIMPLE LANCZOS FOR ALL GF ELEMENTS SparsexDistSpMatOp hamil_wrap(hamil); GF.clear(); - GF.resize(ws.size(), - std::vector>( - nvecs * nvecs, std::complex(0., 0.))); + GF.resize(ws.size(), std::vector>( + nvecs * nvecs, std::complex(0., 0.))); for(int i = 0; i < nvecs; i++) { std::vector> tGF; // DIAGONAL ELEMENT std::cout << "DOING ELEMENT (" << i << ", " << i << ")" << std::endl; - Eigen::VectorXd twfn = - Eigen::Map(wfns.data() + nterms * i, nterms); + Eigen::VectorXd twfn = Eigen::Map( + wfns.data() + nterms * i, nterms); std::string fpref_basis = is_part ? "particle" : "hole"; std::string fpref = fpref_basis + "_" + std::to_string(i) + "_" + std::to_string(i); @@ -623,7 +626,8 @@ void RunGFCalc(std::vector>> &GF, std::to_string(j) + "_a"; GF_Diag(twfn, hamil_wrap, ws, tGF, energ, is_part, nLanIts, saveGFmats, fpref); - for(int iw = 0; iw < ws.size(); iw++) GF[iw][i * nvecs + j] += 0.25 * tGF[iw]; + for(int iw = 0; iw < ws.size(); iw++) + GF[iw][i * nvecs + j] += 0.25 * tGF[iw]; for(size_t iii = 0; iii < nterms; iii++) twfn(iii) = wfns[i * nterms + iii] - wfns[j * nterms + iii]; fpref = fpref_basis + "_" + std::to_string(i) + "_" + diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index d8bf7473..b40bf5c4 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -200,9 +200,9 @@ class SparsexDistSpMatOp { * @date 05/04/2021 */ template -void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, int64_t nLanIts, - std::vector &alphas, std::vector &betas, - double tol) { +void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, + int64_t nLanIts, std::vector &alphas, + std::vector &betas, double tol) { // LANCZOS ROUTINE USING TEMPLATED MATRIX // CLASS. ONLY NEEDS TO PROVIDE A MATRIX // VECTOR PRODUCT. @@ -267,7 +267,8 @@ void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, int64_t nLanIts */ template void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, - int64_t nLanIts, Eigen::VectorXd &vec_P, Eigen::VectorXd &vec_BP) { + int64_t nLanIts, Eigen::VectorXd &vec_P, + Eigen::VectorXd &vec_BP) { // REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS // CALCULATION. int64_t n = start_vec.rows(); @@ -327,8 +328,9 @@ void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, * @date 05/04/2021 */ template -int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, double &E0, - Eigen::VectorXd &psi0_Lan, const LanczosSettings &settings) { +int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, + double &E0, Eigen::VectorXd &psi0_Lan, + const LanczosSettings &settings) { // COMPUTE LOWEST EIGENVALUE OF MATRIX H // USING LANCZOS. RETURNS EIGENVECTOR IN // THE BASIS OF KRYLOV VECTORS @@ -447,8 +449,9 @@ int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, double * @date 05/04/2021 */ template -void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, double &E0, - Eigen::VectorXd &psi0, const LanczosSettings &settings) { +void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, + double &E0, Eigen::VectorXd &psi0, + const LanczosSettings &settings) { // COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR // OF MATRIX H USING LANCZOS. double Lantol = settings.Lantol; @@ -561,7 +564,8 @@ void GetGS(const MatOp &H, double &E0, Eigen::VectorXd &psi0, int64_t n = H.rows(); // Initial vector. We choose (1,0,0,0,...)t // for HF, Otherwhise (1,1,1,1,...)t - Eigen::VectorXd start_psi = isHF ? Eigen::VectorXd::Zero(n) : Eigen::VectorXd::Ones(n); + Eigen::VectorXd start_psi = + isHF ? Eigen::VectorXd::Zero(n) : Eigen::VectorXd::Ones(n); start_psi(0) = 1.; // Determine lowest eigenvalue for the given // tolerance. diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index a76afc03..6580740f 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -16,10 +16,8 @@ inline bool is_file(const std::string &name) { } namespace macis { -bool QRdecomp(std::vector &Q, - std::vector &R, - int Qrows, - int Qcols) { +bool QRdecomp(std::vector &Q, std::vector &R, int Qrows, + int Qcols) { // CALL LAPACK'S QR DECOMPOSITION ROUTINES. // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE // RECTANGULAR, @@ -34,7 +32,7 @@ bool QRdecomp(std::vector &Q, int M = Qrows, N = Qcols; assert(M >= N); int LDA = M, INFO = 0; - std::vector A( M * N, 0. ), TAU( N, 0. ); + std::vector A(M * N, 0.), TAU(N, 0.); // INITIALIZE A for(int i = 0; i < M; i++) @@ -56,10 +54,8 @@ bool QRdecomp(std::vector &Q, return true; } -bool QRdecomp_tr(std::vector &Q, - std::vector &R, - int Qrows, - int Qcols) { +bool QRdecomp_tr(std::vector &Q, std::vector &R, int Qrows, + int Qcols) { // CALL LAPACK'S QR DECOMPOSITION ROUTINES. // INPUT: Q: INPUT MATRIX TO PERFORM A QR DECOMPOSITION FOR. MAY BE // RECTANGULAR, @@ -74,7 +70,7 @@ bool QRdecomp_tr(std::vector &Q, int M = Qcols, N = Qrows; assert(M >= N); int LDA = M, INFO = 0; - std::vector A( M * N, 0. ), TAU( N, 0. ); + std::vector A(M * N, 0.), TAU(N, 0.); // INITIALIZE A for(int i = 0; i < M; i++) @@ -91,16 +87,14 @@ bool QRdecomp_tr(std::vector &Q, int K = N; lapack::orgqr(M, N, K, A.data(), LDA, TAU.data()); // SAVE THE Q MATRIX - for(int i = 0; i < M; i++) + for(int i = 0; i < M; i++) for(int j = 0; j < N; j++) Q[i + j * M] = A[i + j * M]; return true; } -bool GetEigsys(std::vector &mat, - std::vector &eigvals, - std::vector &eigvecs, - int matsize) { +bool GetEigsys(std::vector &mat, std::vector &eigvals, + std::vector &eigvecs, int matsize) { // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC MATRIX mat BY // CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. FIRST, // IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE EIGENVALUES @@ -112,13 +106,13 @@ bool GetEigsys(std::vector &mat, lapack::Uplo UPLO = lapack::Uplo::Upper; lapack::Job JOBZ = lapack::Job::Vec; int N = matsize, LDA = matsize; - std::vector A( N * N, 0. ), D( N, 0. ); + std::vector A(N * N, 0.), D(N, 0.); // INITIALIZE A - for(int i = 0; i < N; i++) + for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) A[i + j * N] = mat[i + j * N]; mat.clear(); - // COMPUTE EIGENVALUES AND EIGENVECTORS + // COMPUTE EIGENVALUES AND EIGENVECTORS lapack::heev_2stage(JOBZ, UPLO, N, A.data(), LDA, D.data()); // NOW, STORE THE EIGENVALUES AND EIGENVECTORS @@ -132,9 +126,8 @@ bool GetEigsys(std::vector &mat, } bool GetEigsysBand(std::vector &mat, int nSupDiag, - std::vector &eigvals, - std::vector &eigvecs, - int matsize) { + std::vector &eigvals, std::vector &eigvecs, + int matsize) { // COMPUTES THE EIGENVALUES AND EIGENVECTORS OF THE SYMMETRIC BAND MATRIX mat // BY CALLING LAPACK. WE ASSUME THE UPPER TRIANGULAR PART OF A IS STORED. // FIRST, IT BRINGS THE MATRIX INTO TRIANGULAR FORM, THEN COMPUTES THE @@ -147,8 +140,8 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, lapack::Job VECT = lapack::Job::Vec; lapack::Job COMPZ = lapack::Job::Vec; int N = matsize, LDQ = matsize, LDAB = nSupDiag + 1; - std::vector AB( (nSupDiag + 1) * N, 0. ); - std::vector D( N, 0. ), E( N - 1, 0. ), Q( N * N, 0. ); + std::vector AB((nSupDiag + 1) * N, 0.); + std::vector D(N, 0.), E(N - 1, 0.), Q(N * N, 0.); // INITIALIZE A for(int j = 0; j < N; j++) @@ -169,8 +162,8 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, eigvals.resize(N); for(int i = 0; i < N; i++) eigvals[i] = D[i]; D.clear(); - eigvecs.resize( N * N ); - for(int i = 0; i < N; i++) + eigvecs.resize(N * N); + for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) eigvecs[i + j * N] = Q[j + i * N]; return true; @@ -179,19 +172,18 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, void BandResolvent( const sparsexx::dist_sparse_matrix > &H, - std::vector &vecs, - const std::vector > &ws, - std::vector > > &res, - int nLanIts, double E0, bool ispart, int nvecs, int len_vec, bool print, bool saveGFmats ) { + std::vector &vecs, const std::vector > &ws, + std::vector > > &res, int nLanIts, + double E0, bool ispart, int nvecs, int len_vec, bool print, + bool saveGFmats) { // COMPUTES THE RESOLVENT (ws - H)^-1 IN MATRIX FORM FOR THE "BASIS" GIVEN BY // THE vecs VECTORS AND THE FREQUENCY GRID IN ws. USES THE BAND LANCZOS // ALGORITHM. IT GETS STORED IN res. using dbl = std::numeric_limits; res.clear(); std::cout << "RESOLVENT ROUTINE: "; - res.resize(ws.size(), - std::vector >( - nvecs * nvecs, std::complex(0., 0.))); + res.resize(ws.size(), std::vector >( + nvecs * nvecs, std::complex(0., 0.))); // FIRST, COMPUTE QR DECOMPOSITION OF THE "BASIS" VECTORS vecs, NECESSARY FOR // LANCZOS @@ -252,9 +244,11 @@ void BandResolvent( std::cout << "COMPUTING GF AS CONTINUED FRACTION..."; std::vector alphas(nLanIts, 0.), betas(nLanIts, 0.); for(int i = 0; i < nLanIts; i++) - alphas[i] = ispart ? E0 - bandH[i * nLanIts + i] : bandH[i * nLanIts + i] - E0; + alphas[i] = + ispart ? E0 - bandH[i * nLanIts + i] : bandH[i * nLanIts + i] - E0; for(int i = 0; i < nLanIts - 1; i++) - betas[i + 1] = ispart ? -bandH[i * nLanIts + i + 1] : bandH[i * nLanIts + i + 1]; + betas[i + 1] = + ispart ? -bandH[i * nLanIts + i + 1] : bandH[i * nLanIts + i + 1]; betas[0] = R[0]; #pragma omp parallel for for(int indx_w = 0; indx_w < ws.size(); indx_w++) { @@ -307,7 +301,8 @@ void BandResolvent( for(int i_lan = 0; i_lan < nLanIts; i_lan++) { for(int j_n = 0; j_n < nvecs; j_n++) { for(int l = 0; l < nvecs; l++) - S[i_lan * nvecs + j_n] += eigvecs[i_lan + l * nLanIts] * R[l + j_n * nvecs]; + S[i_lan * nvecs + j_n] += + eigvecs[i_lan + l * nLanIts] * R[l + j_n * nvecs]; } } if(saveGFmats) { @@ -334,8 +329,9 @@ void BandResolvent( for(int k = 0; k < nvecs; k++) { for(int l = 0; l < nvecs; l++) { for(int i_lan = 0; i_lan < nLanIts; i_lan++) { - res[iw][k * nvecs + l] += - S[i_lan * nvecs + k] * 1. / (ws[iw] + eigvals[i_lan]) * S[i_lan * nvecs + l]; + res[iw][k * nvecs + l] += S[i_lan * nvecs + k] * 1. / + (ws[iw] + eigvals[i_lan]) * + S[i_lan * nvecs + l]; } } } diff --git a/src/macis/gf/eigsolver.cxx b/src/macis/gf/eigsolver.cxx index 6bcb4caf..30d7f9eb 100644 --- a/src/macis/gf/eigsolver.cxx +++ b/src/macis/gf/eigsolver.cxx @@ -45,7 +45,8 @@ void Hste_v(const std::vector &alphas, const std::vector &betas, for(int i = 0; i < N; i++) eigvals(i) = D[i]; } -void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, Eigen::MatrixXd &eigvecs) { +void Hsyev(const Eigen::MatrixXd &H, Eigen::VectorXd &eigvals, + Eigen::MatrixXd &eigvecs) { /* * COMPUTES THE EIGENVALUES AND EIGENVECTORS OF A SYMMETRIC MATRIX A USING * LAPACK. diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 2324f4cb..8dff6304 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -9,11 +9,10 @@ #include "macis/gf/gf.hpp" namespace macis { -void write_GF( - const std::vector > > &GF, - const std::vector > &ws, - const std::vector &GF_orbs, const std::vector &todelete, - const bool is_part) { +void write_GF(const std::vector > > &GF, + const std::vector > &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part) { using dbl = std::numeric_limits; size_t nfreqs = ws.size(); int GFmat_size = GF_orbs.size() - todelete.size(); @@ -26,8 +25,8 @@ void write_GF( ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; for(int jjj = 0; jjj < GFmat_size; jjj++) { for(int lll = 0; lll < GFmat_size; lll++) - ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) << " " - << imag(GF[iii][jjj * GFmat_size + lll]) << " "; + ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) + << " " << imag(GF[iii][jjj * GFmat_size + lll]) << " "; } ofile << std::endl; } diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 89bde9a9..63c5e57a 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -355,7 +355,7 @@ int main(int argc, char** argv) { // GF vector std::vector>> GF( nws, std::vector>( - 1, std::complex(0., 0.))); + 1, std::complex(0., 0.))); // Occupation numbers std::vector occs(n_active, 1.); From f02e8b07afa72bc3b2c91cff39041e05d25c47de Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Wed, 21 Jun 2023 10:08:39 +0200 Subject: [PATCH 16/35] Cleaned GF routines from omp pragmas, only one remaining to parallelize the evaluation of G[w] for each frequency in the single band case. Removed MyInnProd header, substituted by lambdas for blas::dot. --- include/macis/gf/bandlan.hpp | 35 +++++------- include/macis/gf/gf.hpp | 10 +--- include/macis/gf/inn_prods.hpp | 101 --------------------------------- include/macis/gf/lanczos.hpp | 99 +++++++++++++++++++++++--------- src/macis/gf/bandlan.cxx | 2 +- 5 files changed, 88 insertions(+), 159 deletions(-) delete mode 100644 include/macis/gf/inn_prods.hpp diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 53e05ba2..930db4df 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -29,7 +29,6 @@ #include #include -#include "macis/gf/inn_prods.hpp" #include "macis/solvers/davidson.hpp" namespace macis { @@ -144,9 +143,9 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, * @date 25/04/2022 */ template -void MyBandLan(const Functor &H, std::vector &qs, - std::vector &bandH, int &nLanIts, int nbands, int N, - double thres = 1.E-6, bool print = false) { +void BandLan(const Functor &H, std::vector &qs, + std::vector &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 @@ -156,6 +155,11 @@ void MyBandLan(const Functor &H, std::vector &qs, bandH.clear(); bandH.resize(nLanIts * nLanIts, 0.); + auto VecNorm = []( const std::vector &vec )->double + { + return std::sqrt(std::real(blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ))); + }; + // MAKE SPACE FOR 2 * nbands VECTORS qs.resize(2 * nbands * N); std::vector temp(N, 0.); @@ -193,24 +197,17 @@ void MyBandLan(const Functor &H, std::vector &qs, 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) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; + blas::axpy( N, -1. * bandH[(it-1) * nLanIts + jt - 1], qs.data() + N * band_indx_j, 1, temp.data(), 1 ); } for(int jt = it; jt <= std::min(it + nbands - 1, nLanIts); jt++) { int band_indx_j = true_indx[jt]; bandH[(it - 1) * nLanIts + jt - 1] = blas::dot(N, temp.data(), 1, qs.data() + band_indx_j * N, 1); bandH[(jt - 1) * nLanIts + it - 1] = bandH[(it - 1) * nLanIts + jt - 1]; -#pragma omp parallel for - for(size_t coeff = 0; coeff < temp.size(); coeff++) - temp[coeff] -= - bandH[(it - 1) * nLanIts + jt - 1] * qs[N * band_indx_j + coeff]; + blas::axpy( N, -1. * bandH[(it-1) * nLanIts + jt - 1], qs.data() + N * band_indx_j, 1, temp.data(), 1 ); } if(it + nbands <= nLanIts) { - bandH[(it - 1) * nLanIts + it + nbands - 1] = - std::sqrt(std::real(MyInnProd(temp, temp))); + bandH[(it - 1) * nLanIts + it + nbands - 1] = VecNorm( temp ); bandH[(it + nbands - 1) * nLanIts + it - 1] = bandH[(it - 1) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; @@ -222,16 +219,12 @@ void MyBandLan(const Functor &H, std::vector &qs, nLanIts = it; bandH.resize(nLanIts * nLanIts); break; -#pragma omp parallel for - for(size_t coeff = 0; coeff < temp.size(); coeff++) - qs[true_indx[it + nbands] * N + coeff] = 0.; + blas::scal( N, 0., qs.data() + true_indx[it + nbands] * N, 1 ); 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++) - qs[true_indx[it + nbands] * N + coeff] = - temp[coeff] / bandH[(it - 1) * nLanIts + it + nbands - 1]; + blas::copy( N, temp.data(), 1, qs.data() + true_indx[it + nbands] * N, 1 ); + blas::scal( N, 1. / bandH[(it-1) * nLanIts + it + nbands - 1], qs.data() + true_indx[it + nbands] * N, 1 ); if(print) { std::ofstream ofile("lanvec_" + std::to_string(it + nbands) + ".dat", std::ios::out); diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 09c35271..687bbcb3 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -123,7 +123,7 @@ void GF_Diag(const Eigen::VectorXd &state_0, const MatOp &H, double tol = 1.E-6; std::vector alphas, betas; - MyLanczos(state_0, H, nLanIts, alphas, betas, tol); + Lanczos(state_0, H, nLanIts, alphas, betas, tol); int kry_size = 0; for(int i = 1; i < nLanIts; i++) { @@ -427,13 +427,7 @@ auto BuildWfn4Lanczos(const Eigen::VectorXd &base_wfn, // CHECK WHETHER ANY OF THE VECTORS IS EXACTLY ZERO. IF SO, TAKE IT OUT! todelete.clear(); for(int orb_indx = 0; orb_indx < GF_orbs.size(); orb_indx++) { - double st_nrm = 0.; -#pragma omp declare reduction(Vsum:double \ - : omp_out = omp_out + omp_in) \ - initializer(omp_priv = 0.) -#pragma omp parallel for reduction(Vsum : st_nrm) - for(size_t iii = 0; iii < nterms; iii++) - st_nrm += wfns[orb_indx * nterms + iii] * wfns[orb_indx * nterms + iii]; + double st_nrm = blas::dot( nterms, wfns.data() + orb_indx * nterms, 1, wfns.data() + orb_indx * nterms, 1 ); if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); } int nvecs = GF_orbs.size() - todelete.size(); diff --git a/include/macis/gf/inn_prods.hpp b/include/macis/gf/inn_prods.hpp deleted file mode 100644 index 411ad186..00000000 --- a/include/macis/gf/inn_prods.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 inn_prods.h++ - * - * @brief Inner product routines between vectors. - * - * @author Carlos Mejuto Zaera - * @date 02/06/2023 - */ -#pragma once -#include -#include -#include - -namespace macis { -/** - * @brief Simple inner product routine between two std::vector - * - * @param [in] const std::vecotr& vecR - * @param [in] const std::vecotr& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ -inline double MyInnProd(const std::vector& vecR, - const std::vector& vecL) { - return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); -} - -/** - * @brief Simple inner product routine between two - * std::vector > - * - * @param [in] const std::vecotr >& vecR - * @param [in] const std::vecotr >& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ -inline std::complex MyInnProd( - const std::vector >& vecR, - const std::vector >& vecL) { - return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); -} - -/** - * @brief Simple inner product routine between std::vector and - * std::vector > - * - * @param [in] const std::vecotr >& vecR - * @param [in] const std::vecotr& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ -inline std::complex MyInnProd( - const std::vector >& vecR, - const std::vector& vecL) { - return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); -} - -/** - * @brief Simple inner product routine for two Eigen::VectorXcd - * - * @param [in] const Eigen::VectorXcd& vecR - * @param [in] const Eigen::VectorXcd& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ -inline std::complex MyInnProd(const Eigen::VectorXcd& vecR, - const Eigen::VectorXcd& vecL) { - return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); -} - -/** - * @brief Simple inner product routine for two Eigen::VectorXd - * - * @param [in] const Eigen::VectorXd& vecR - * @param [in] const Eigen::VectorXd& vecL - * @return Inner product - * - * @author Carlos Mejuto Zaera - * @date 05/04/2021 - */ -inline double MyInnProd(const Eigen::VectorXd& vecR, - const Eigen::VectorXd& vecL) { - return blas::dot(vecR.size(), vecR.data(), 1, vecL.data(), 1); -} -} // namespace macis diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index b40bf5c4..0f853c4a 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -22,7 +22,6 @@ #include #include "macis/gf/eigsolver.hpp" -#include "macis/gf/inn_prods.hpp" namespace macis { @@ -200,12 +199,23 @@ class SparsexDistSpMatOp { * @date 05/04/2021 */ template -void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, - int64_t nLanIts, std::vector &alphas, - std::vector &betas, double tol) { +void Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, + int64_t nLanIts, std::vector &alphas, + std::vector &betas, double tol) { // LANCZOS ROUTINE USING TEMPLATED MATRIX // CLASS. ONLY NEEDS TO PROVIDE A MATRIX // VECTOR PRODUCT. + // + // SOME LAMBDAS + auto VecNorm = []( const Eigen::VectorXd & vec )->double + { + return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + }; + auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double + { + return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + }; + // INITIALIZATIONS int64_t n = start_vec.rows(); Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); @@ -216,17 +226,17 @@ void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, alphas.resize(nLanIts, 0.); betas.resize(nLanIts + 1, 0.); - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + double normpsi = VecNorm(start_vec); int64_t nlan = -1, itermax = nLanIts; nlan++; qold = start_vec / normpsi; qnew = H.dot(qold); - alphas[0] = MyInnProd(qold, qnew); + alphas[0] = InnProd(qold, qnew); qnew -= alphas[0] * qold; betas[0] = normpsi; - betas[1] = sqrt(MyInnProd(qnew, qnew)); + betas[1] = VecNorm(qnew); if(abs(betas[1]) <= tol) itermax = 1; for(size_t iter = 1; iter < itermax; iter++) { nlan++; @@ -237,9 +247,9 @@ void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, qtemp = H.dot(qold); qnew += qtemp; - alphas[iter] = MyInnProd(qold, qnew); + alphas[iter] = InnProd(qold, qnew); qnew -= alphas[iter] * qold; - betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + betas[iter + 1] = VecNorm(qnew); if(abs(betas[iter + 1]) <= tol) { itermax = iter; @@ -266,11 +276,22 @@ void MyLanczos(const Eigen::VectorXd &start_vec, const MatOp &H, * @date 05/04/2021 */ template -void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, - int64_t nLanIts, Eigen::VectorXd &vec_P, - Eigen::VectorXd &vec_BP) { +void Lanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, + int64_t nLanIts, Eigen::VectorXd &vec_P, + Eigen::VectorXd &vec_BP) { // REBUILD THE EIGENVECTOR FROM A PREVIOUS LANZOS // CALCULATION. + // + // SOME LAMBDAS + auto VecNorm = []( const Eigen::VectorXd & vec )->double + { + return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + }; + auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double + { + return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + }; + // INITIALIZATIONS int64_t n = start_vec.rows(); Eigen::VectorXd qold = Eigen::VectorXd::Zero(n); Eigen::VectorXd qtemp = Eigen::VectorXd::Zero(n); @@ -279,7 +300,7 @@ void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, std::vector alphas(nLanIts, 0.); std::vector betas(nLanIts + 1, 0.); - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + double normpsi = VecNorm(start_vec); int64_t nlan = -1, itermax = nLanIts; vec_BP = Eigen::VectorXd::Zero(n); @@ -289,10 +310,10 @@ void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, vec_BP = vec_P(0) * qold; qnew = H.dot(qold); - alphas[0] = MyInnProd(qold, qnew); + alphas[0] = InnProd(qold, qnew); qnew -= alphas[0] * qold; betas[0] = normpsi; - betas[1] = sqrt(MyInnProd(qnew, qnew)); + betas[1] = VecNorm(qnew); for(size_t iter = 1; iter < itermax; iter++) { nlan++; qtemp = qold; @@ -303,9 +324,9 @@ void MyLanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, qtemp = H.dot(qold); qnew += qtemp; - alphas[iter] = MyInnProd(qold, qnew); + alphas[iter] = InnProd(qold, qnew); qnew -= alphas[iter] * qold; - betas[iter + 1] = sqrt(MyInnProd(qnew, qnew)); + betas[iter + 1] = VecNorm(qnew); } alphas.clear(); betas.clear(); @@ -334,6 +355,17 @@ int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, // COMPUTE LOWEST EIGENVALUE OF MATRIX H // USING LANCZOS. RETURNS EIGENVECTOR IN // THE BASIS OF KRYLOV VECTORS + // + // SOME LAMBDAS + auto VecNorm = []( const Eigen::VectorXd & vec )->double + { + return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + }; + auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double + { + return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + }; + // INITIALIZATIONS auto w = std::setw(15); double Lantol = settings.Lantol; double E0tol = settings.E0tol; @@ -349,17 +381,17 @@ int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, std::vector alphas, betas; double currE0, prevE0; - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + double normpsi = VecNorm(start_vec); int64_t nlan = -1; nlan++; qold = start_vec / normpsi; qnew = H.dot(qold); - alphas.push_back(MyInnProd(qold, qnew)); + alphas.push_back(InnProd(qold, qnew)); qnew -= alphas[0] * qold; betas.push_back(normpsi); - betas.push_back(sqrt(MyInnProd(qnew, qnew))); + betas.push_back(VecNorm(qnew)); prevE0 = alphas[0]; if(print) { @@ -387,9 +419,9 @@ int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, qtemp = H.dot(qold); qnew += qtemp; - alphas.push_back(MyInnProd(qold, qnew)); + alphas.push_back(InnProd(qold, qnew)); qnew -= alphas[iter] * qold; - betas.push_back(sqrt(MyInnProd(qnew, qnew))); + betas.push_back(VecNorm(qnew)); // GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX Hste_v(alphas, betas, eigvals, eigvecs); currE0 = eigvals(0); @@ -454,6 +486,17 @@ void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, const LanczosSettings &settings) { // COMPUTE LOWEST EIGENVALUE AND EIGENVECTOR // OF MATRIX H USING LANCZOS. + // + // SOME LAMBDAS + auto VecNorm = []( const Eigen::VectorXd & vec )->double + { + return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + }; + auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double + { + return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + }; + // INITIALIZATIONS double Lantol = settings.Lantol; double E0tol = settings.E0tol; bool print = settings.print; @@ -469,7 +512,7 @@ void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, std::vector alphas, betas; double currE0, prevE0; - double normpsi = sqrt(MyInnProd(start_vec, start_vec)); + double normpsi = VecNorm(start_vec); int64_t nlan = -1; nlan++; @@ -477,10 +520,10 @@ void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, kry_vecs.push_back(qold); qnew = H.dot(qold); - alphas.push_back(MyInnProd(qold, qnew)); + alphas.push_back(InnProd(qold, qnew)); qnew -= alphas[0] * qold; betas.push_back(normpsi); - betas.push_back(sqrt(MyInnProd(qnew, qnew))); + betas.push_back(VecNorm(qnew)); prevE0 = alphas[0]; if(abs(betas[1]) <= Lantol) { @@ -497,9 +540,9 @@ void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, qtemp = H.dot(qold); qnew += qtemp; - alphas.push_back(MyInnProd(qold, qnew)); + alphas.push_back(InnProd(qold, qnew)); qnew -= alphas[iter] * qold; - betas.push_back(sqrt(MyInnProd(qnew, qnew))); + betas.push_back(VecNorm(qnew)); // GET EIGENVALUES OF CURRENT TRI-DIAG MATRIX Hste_v(alphas, betas, eigvals, eigvecs); currE0 = eigvals(0); @@ -572,7 +615,7 @@ void GetGS(const MatOp &H, double &E0, Eigen::VectorXd &psi0, Eigen::VectorXd psi0_Lan; int64_t nLanIts = GetGSEn_Lanczos(start_psi, H, E0, psi0_Lan, settings); // Reconstruct the eigenvector - MyLanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); + Lanczos_BackProj(start_psi, H, nLanIts, psi0_Lan, psi0); start_psi = psi0; GetGSEnVec_Lanczos(start_psi, H, E0, psi0, settings); } diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 6580740f..d1a7dfef 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -223,7 +223,7 @@ void BandResolvent( std::cout << "BAND LANCZOS ..."; SparseMatrixOperator Hop(H); int nbands = nvecs; - MyBandLan(Hop, vecs, bandH, nLanIts, nbands, nvecs, 1.E-6, print); + BandLan(Hop, vecs, bandH, nLanIts, nbands, nvecs, 1.E-6, print); std::cout << "DONE! "; if(print) { std::ofstream ofile("BLH.dat", std::ios::out); From a08ebf0673af8b6d76d0e28b3ede016d58dd7fc9 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Wed, 21 Jun 2023 08:34:59 +0000 Subject: [PATCH 17/35] Committing clang-format changes --- include/macis/gf/bandlan.hpp | 28 +++++++++++--------- include/macis/gf/gf.hpp | 3 ++- include/macis/gf/lanczos.hpp | 50 +++++++++++++++++------------------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 930db4df..954a0f99 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -143,9 +143,9 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, * @date 25/04/2022 */ template -void BandLan(const Functor &H, std::vector &qs, - std::vector &bandH, int &nLanIts, int nbands, int N, - double thres = 1.E-6, bool print = false) { +void BandLan(const Functor &H, std::vector &qs, std::vector &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 @@ -155,9 +155,9 @@ void BandLan(const Functor &H, std::vector &qs, bandH.clear(); bandH.resize(nLanIts * nLanIts, 0.); - auto VecNorm = []( const std::vector &vec )->double - { - return std::sqrt(std::real(blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ))); + auto VecNorm = [](const std::vector &vec) -> double { + return std::sqrt( + std::real(blas::dot(vec.size(), vec.data(), 1, vec.data(), 1))); }; // MAKE SPACE FOR 2 * nbands VECTORS @@ -197,17 +197,19 @@ void BandLan(const Functor &H, std::vector &qs, for(int jt = std::max(1, it - nbands); jt <= std::min(it - 1, nLanIts); jt++) { int band_indx_j = true_indx[jt]; - blas::axpy( N, -1. * bandH[(it-1) * nLanIts + jt - 1], qs.data() + N * band_indx_j, 1, temp.data(), 1 ); + blas::axpy(N, -1. * bandH[(it - 1) * nLanIts + jt - 1], + qs.data() + N * band_indx_j, 1, temp.data(), 1); } for(int jt = it; jt <= std::min(it + nbands - 1, nLanIts); jt++) { int band_indx_j = true_indx[jt]; bandH[(it - 1) * nLanIts + jt - 1] = blas::dot(N, temp.data(), 1, qs.data() + band_indx_j * N, 1); bandH[(jt - 1) * nLanIts + it - 1] = bandH[(it - 1) * nLanIts + jt - 1]; - blas::axpy( N, -1. * bandH[(it-1) * nLanIts + jt - 1], qs.data() + N * band_indx_j, 1, temp.data(), 1 ); + blas::axpy(N, -1. * bandH[(it - 1) * nLanIts + jt - 1], + qs.data() + N * band_indx_j, 1, temp.data(), 1); } if(it + nbands <= nLanIts) { - bandH[(it - 1) * nLanIts + it + nbands - 1] = VecNorm( temp ); + bandH[(it - 1) * nLanIts + it + nbands - 1] = VecNorm(temp); bandH[(it + nbands - 1) * nLanIts + it - 1] = bandH[(it - 1) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; @@ -219,12 +221,14 @@ void BandLan(const Functor &H, std::vector &qs, nLanIts = it; bandH.resize(nLanIts * nLanIts); break; - blas::scal( N, 0., qs.data() + true_indx[it + nbands] * N, 1 ); + blas::scal(N, 0., qs.data() + true_indx[it + nbands] * N, 1); std::cout << "FOUND A ZERO VECTOR AT POSITION " << next_indx << std::endl; } else { - blas::copy( N, temp.data(), 1, qs.data() + true_indx[it + nbands] * N, 1 ); - blas::scal( N, 1. / bandH[(it-1) * nLanIts + it + nbands - 1], qs.data() + true_indx[it + nbands] * N, 1 ); + blas::copy(N, temp.data(), 1, qs.data() + true_indx[it + nbands] * N, + 1); + blas::scal(N, 1. / bandH[(it - 1) * nLanIts + it + nbands - 1], + qs.data() + true_indx[it + nbands] * N, 1); if(print) { std::ofstream ofile("lanvec_" + std::to_string(it + nbands) + ".dat", std::ios::out); diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 687bbcb3..6ed73b2c 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -427,7 +427,8 @@ auto BuildWfn4Lanczos(const Eigen::VectorXd &base_wfn, // CHECK WHETHER ANY OF THE VECTORS IS EXACTLY ZERO. IF SO, TAKE IT OUT! todelete.clear(); for(int orb_indx = 0; orb_indx < GF_orbs.size(); orb_indx++) { - double st_nrm = blas::dot( nterms, wfns.data() + orb_indx * nterms, 1, wfns.data() + orb_indx * nterms, 1 ); + double st_nrm = blas::dot(nterms, wfns.data() + orb_indx * nterms, 1, + wfns.data() + orb_indx * nterms, 1); if(abs(st_nrm) <= zero_thresh) todelete.push_back(orb_indx); } int nvecs = GF_orbs.size() - todelete.size(); diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index 0f853c4a..97677769 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -199,21 +199,20 @@ class SparsexDistSpMatOp { * @date 05/04/2021 */ template -void Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, - int64_t nLanIts, std::vector &alphas, - std::vector &betas, double tol) { +void Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, int64_t nLanIts, + std::vector &alphas, std::vector &betas, + double tol) { // LANCZOS ROUTINE USING TEMPLATED MATRIX // CLASS. ONLY NEEDS TO PROVIDE A MATRIX // VECTOR PRODUCT. // // SOME LAMBDAS - auto VecNorm = []( const Eigen::VectorXd & vec )->double - { - return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + auto VecNorm = [](const Eigen::VectorXd &vec) -> double { + return std::sqrt(blas::dot(vec.size(), vec.data(), 1, vec.data(), 1)); }; - auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double - { - return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + auto InnProd = [](const Eigen::VectorXd &Lvec, + const Eigen::VectorXd &Rvec) -> double { + return blas::dot(Lvec.size(), Lvec.data(), 1, Rvec.data(), 1); }; // INITIALIZATIONS int64_t n = start_vec.rows(); @@ -283,13 +282,12 @@ void Lanczos_BackProj(const Eigen::VectorXd &start_vec, const MatOp &H, // CALCULATION. // // SOME LAMBDAS - auto VecNorm = []( const Eigen::VectorXd & vec )->double - { - return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + auto VecNorm = [](const Eigen::VectorXd &vec) -> double { + return std::sqrt(blas::dot(vec.size(), vec.data(), 1, vec.data(), 1)); }; - auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double - { - return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + auto InnProd = [](const Eigen::VectorXd &Lvec, + const Eigen::VectorXd &Rvec) -> double { + return blas::dot(Lvec.size(), Lvec.data(), 1, Rvec.data(), 1); }; // INITIALIZATIONS int64_t n = start_vec.rows(); @@ -357,13 +355,12 @@ int64_t GetGSEn_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, // THE BASIS OF KRYLOV VECTORS // // SOME LAMBDAS - auto VecNorm = []( const Eigen::VectorXd & vec )->double - { - return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + auto VecNorm = [](const Eigen::VectorXd &vec) -> double { + return std::sqrt(blas::dot(vec.size(), vec.data(), 1, vec.data(), 1)); }; - auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double - { - return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + auto InnProd = [](const Eigen::VectorXd &Lvec, + const Eigen::VectorXd &Rvec) -> double { + return blas::dot(Lvec.size(), Lvec.data(), 1, Rvec.data(), 1); }; // INITIALIZATIONS auto w = std::setw(15); @@ -488,13 +485,12 @@ void GetGSEnVec_Lanczos(const Eigen::VectorXd &start_vec, const MatOp &H, // OF MATRIX H USING LANCZOS. // // SOME LAMBDAS - auto VecNorm = []( const Eigen::VectorXd & vec )->double - { - return std::sqrt( blas::dot( vec.size(), vec.data(), 1, vec.data(), 1 ) ); + auto VecNorm = [](const Eigen::VectorXd &vec) -> double { + return std::sqrt(blas::dot(vec.size(), vec.data(), 1, vec.data(), 1)); }; - auto InnProd = []( const Eigen::VectorXd &Lvec, const Eigen::VectorXd &Rvec )->double - { - return blas::dot( Lvec.size(), Lvec.data(), 1, Rvec.data(), 1 ); + auto InnProd = [](const Eigen::VectorXd &Lvec, + const Eigen::VectorXd &Rvec) -> double { + return blas::dot(Lvec.size(), Lvec.data(), 1, Rvec.data(), 1); }; // INITIALIZATIONS double Lantol = settings.Lantol; From 5baea2e8c118e0a57ebd718c84e38b87ff12ffd3 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Mon, 11 Sep 2023 15:46:33 +0200 Subject: [PATCH 18/35] BUG FIXED: Passing wrong vector length to Band Lanczos. Also, included core space determinants into the ASCI ranking (to allow for them to be substituted). --- include/macis/asci/determinant_search.hpp | 11 ++++++----- include/macis/asci/grow.hpp | 3 ++- include/macis/asci/iteration.hpp | 1 + include/macis/gf/bandlan.hpp | 14 +++++++------- src/macis/gf/bandlan.cxx | 2 +- tests/standalone_driver.cxx | 8 ++++---- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/macis/asci/determinant_search.hpp b/include/macis/asci/determinant_search.hpp index 7d66813c..c025469d 100644 --- a/include/macis/asci/determinant_search.hpp +++ b/include/macis/asci/determinant_search.hpp @@ -539,12 +539,13 @@ std::vector> asci_search( // and keep only the duplicate with positive coefficient. keep_only_largest_copy_asci_pairs(asci_pairs); - asci_pairs.erase(std::partition(asci_pairs.begin(), asci_pairs.end(), - [](const auto& p) { return p.rv < 0.0; }), - asci_pairs.end()); + //asci_pairs.erase(std::partition(asci_pairs.begin(), asci_pairs.end(), + // [](const auto& p) { return p.rv < 0.0; }), + // asci_pairs.end()); // Only do top-K on (ndets_max - ncdets) b/c CDETS will be added later - const size_t top_k_elements = ndets_max - ncdets; + //const size_t top_k_elements = ndets_max - ncdets; + const size_t top_k_elements = ndets_max; auto keep_large_en = clock_type::now(); duration_type keep_large_dur = keep_large_en - keep_large_st; @@ -650,7 +651,7 @@ std::vector> asci_search( [](auto x) { return x.state; }); // Insert the CDETS back in - new_dets.insert(new_dets.end(), cdets_begin, cdets_end); + //new_dets.insert(new_dets.end(), cdets_begin, cdets_end); new_dets.shrink_to_fit(); logger->info(" * New Dets Mem = {:.2e} GiB", to_gib(new_dets)); diff --git a/include/macis/asci/grow.hpp b/include/macis/asci/grow.hpp index f3f4260e..757f17a2 100644 --- a/include/macis/asci/grow.hpp +++ b/include/macis/asci/grow.hpp @@ -61,7 +61,8 @@ auto asci_grow(ASCISettings asci_settings, MCSCFSettings mcscf_settings, dur_t ai_dur = ai_en - ai_st; logger->trace(" * ASCI_ITER_DUR = {:.2e} ms", ai_dur.count()); if(ndets_new > wfn.size()) - throw std::runtime_error("Wavefunction didn't grow enough..."); + logger->info("Wavefunction didn't grow enough..."); + //throw std::runtime_error("Wavefunction didn't grow enough..."); logger->info(fmt_string, iter++, E, E - E0, wfn.size()); if(asci_settings.grow_with_rot and diff --git a/include/macis/asci/iteration.hpp b/include/macis/asci/iteration.hpp index aa6e271c..55a86eb2 100644 --- a/include/macis/asci/iteration.hpp +++ b/include/macis/asci/iteration.hpp @@ -64,6 +64,7 @@ auto asci_iter(ASCISettings asci_settings, MCSCFSettings mcscf_settings, X = std::move(X_local); // Serial #endif + if(wfn.size() > 1) reorder_ci_on_coeff(wfn, X); return std::make_tuple(E, wfn, X); } diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index 954a0f99..b03cefe3 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -214,13 +214,13 @@ void BandLan(const Functor &H, std::vector &qs, std::vector &bandH, bandH[(it - 1) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; if(std::abs(bandH[(it - 1) * nLanIts + it + nbands - 1]) < thres) { - std::cout - << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " - << bandH[(it - 1) * nLanIts + it + nbands - 1] - << ", STOPPED AT ITERATION: " << it << std::endl; - nLanIts = it; - bandH.resize(nLanIts * nLanIts); - break; + //std::cout + // << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " + // << bandH[(it - 1) * nLanIts + it + nbands - 1] + // << ", STOPPED AT ITERATION: " << it << std::endl; + //nLanIts = it; + //bandH.resize(nLanIts * nLanIts); + //break; blas::scal(N, 0., qs.data() + true_indx[it + nbands] * N, 1); std::cout << "FOUND A ZERO VECTOR AT POSITION " << next_indx << std::endl; diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index d1a7dfef..411f6363 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -223,7 +223,7 @@ void BandResolvent( std::cout << "BAND LANCZOS ..."; SparseMatrixOperator Hop(H); int nbands = nvecs; - BandLan(Hop, vecs, bandH, nLanIts, nbands, nvecs, 1.E-6, print); + BandLan(Hop, vecs, bandH, nLanIts, nbands, len_vec, 1.E-6, print); std::cout << "DONE! "; if(print) { std::ofstream ofile("BLH.dat", std::ios::out); diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 63c5e57a..4c27bb7f 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -347,15 +347,15 @@ int main(int argc, char** argv) { OPT_KEYWORD("GF.SAVEGFMATS", gf_settings.saveGFmats, bool); gf_settings.GF_orbs_basis = std::vector(n_active, 0); for(int i = 0; i < n_active; i++) gf_settings.GF_orbs_basis[i] = i; - gf_settings.GF_orbs_comp = std::vector(2, 0); - for(int i = 0; i < 2; i++) gf_settings.GF_orbs_comp[i] = i; + gf_settings.GF_orbs_comp = std::vector(n_active, 0); + for(int i = 0; i < n_active; i++) gf_settings.GF_orbs_comp[i] = i; gf_settings.is_up_basis = std::vector(n_active, true); - gf_settings.is_up_comp = std::vector(2, true); + gf_settings.is_up_comp = std::vector(n_active, true); // GF vector std::vector>> GF( nws, std::vector>( - 1, std::complex(0., 0.))); + n_active * n_active, std::complex(0., 0.))); // Occupation numbers std::vector occs(n_active, 1.); From 74702c274c646b9c7a6a94240a745686f8b7cbc4 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Mon, 11 Sep 2023 13:48:18 +0000 Subject: [PATCH 19/35] Committing clang-format changes --- include/macis/asci/determinant_search.hpp | 10 +++++----- include/macis/asci/grow.hpp | 2 +- include/macis/gf/bandlan.hpp | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/macis/asci/determinant_search.hpp b/include/macis/asci/determinant_search.hpp index c025469d..486aa557 100644 --- a/include/macis/asci/determinant_search.hpp +++ b/include/macis/asci/determinant_search.hpp @@ -539,12 +539,12 @@ std::vector> asci_search( // and keep only the duplicate with positive coefficient. keep_only_largest_copy_asci_pairs(asci_pairs); - //asci_pairs.erase(std::partition(asci_pairs.begin(), asci_pairs.end(), - // [](const auto& p) { return p.rv < 0.0; }), - // asci_pairs.end()); + // asci_pairs.erase(std::partition(asci_pairs.begin(), asci_pairs.end(), + // [](const auto& p) { return p.rv < 0.0; }), + // asci_pairs.end()); // Only do top-K on (ndets_max - ncdets) b/c CDETS will be added later - //const size_t top_k_elements = ndets_max - ncdets; + // const size_t top_k_elements = ndets_max - ncdets; const size_t top_k_elements = ndets_max; auto keep_large_en = clock_type::now(); @@ -651,7 +651,7 @@ std::vector> asci_search( [](auto x) { return x.state; }); // Insert the CDETS back in - //new_dets.insert(new_dets.end(), cdets_begin, cdets_end); + // new_dets.insert(new_dets.end(), cdets_begin, cdets_end); new_dets.shrink_to_fit(); logger->info(" * New Dets Mem = {:.2e} GiB", to_gib(new_dets)); diff --git a/include/macis/asci/grow.hpp b/include/macis/asci/grow.hpp index 757f17a2..5833fb39 100644 --- a/include/macis/asci/grow.hpp +++ b/include/macis/asci/grow.hpp @@ -62,7 +62,7 @@ auto asci_grow(ASCISettings asci_settings, MCSCFSettings mcscf_settings, logger->trace(" * ASCI_ITER_DUR = {:.2e} ms", ai_dur.count()); if(ndets_new > wfn.size()) logger->info("Wavefunction didn't grow enough..."); - //throw std::runtime_error("Wavefunction didn't grow enough..."); + // throw std::runtime_error("Wavefunction didn't grow enough..."); logger->info(fmt_string, iter++, E, E - E0, wfn.size()); if(asci_settings.grow_with_rot and diff --git a/include/macis/gf/bandlan.hpp b/include/macis/gf/bandlan.hpp index b03cefe3..c3603b13 100644 --- a/include/macis/gf/bandlan.hpp +++ b/include/macis/gf/bandlan.hpp @@ -214,13 +214,13 @@ void BandLan(const Functor &H, std::vector &qs, std::vector &bandH, bandH[(it - 1) * nLanIts + it + nbands - 1]; true_indx[it + nbands] = next_indx; if(std::abs(bandH[(it - 1) * nLanIts + it + nbands - 1]) < thres) { - //std::cout - // << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " - // << bandH[(it - 1) * nLanIts + it + nbands - 1] - // << ", STOPPED AT ITERATION: " << it << std::endl; - //nLanIts = it; - //bandH.resize(nLanIts * nLanIts); - //break; + // std::cout + // << "BAND LANCZOS STOPPED PREMATURELY DUE TO SMALL NORM! NAMELY " + // << bandH[(it - 1) * nLanIts + it + nbands - 1] + // << ", STOPPED AT ITERATION: " << it << std::endl; + // nLanIts = it; + // bandH.resize(nLanIts * nLanIts); + // break; blas::scal(N, 0., qs.data() + true_indx[it + nbands] * N, 1); std::cout << "FOUND A ZERO VECTOR AT POSITION " << next_indx << std::endl; From d56989c0cc112585ee58407b7db656f2348df387 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Tue, 19 Sep 2023 16:40:53 +0200 Subject: [PATCH 20/35] Included new HamiltonianGenerator, particularly efficient for impurity models. Test case added. --- include/macis/bitset_operations.hpp | 3 + include/macis/hamiltonian_generator.hpp | 2 +- .../macis/hamiltonian_generator/sd_build.hpp | 274 ++++++++++++++++++ include/macis/util/fcidump.hpp | 11 + src/macis/fcidump.cxx | 28 ++ tests/CMakeLists.txt | 1 + tests/ref_data/hubbard10.fci.dat | 38 +++ tests/sd_build.cxx | 115 ++++++++ tests/ut_common.hpp.in | 2 + 9 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 include/macis/hamiltonian_generator/sd_build.hpp create mode 100644 tests/ref_data/hubbard10.fci.dat create mode 100644 tests/sd_build.cxx diff --git a/include/macis/bitset_operations.hpp b/include/macis/bitset_operations.hpp index e0f5ec27..e11b5f69 100644 --- a/include/macis/bitset_operations.hpp +++ b/include/macis/bitset_operations.hpp @@ -7,6 +7,9 @@ */ #pragma once +#include +#include + #include #include #include diff --git a/include/macis/hamiltonian_generator.hpp b/include/macis/hamiltonian_generator.hpp index 9ef9583b..899f2586 100644 --- a/include/macis/hamiltonian_generator.hpp +++ b/include/macis/hamiltonian_generator.hpp @@ -183,7 +183,7 @@ class HamiltonianGenerator { void rotate_hamiltonian_ordm(const double* ordm); virtual void SetJustSingles(bool /*_js*/) {} - virtual bool GetJustSingles() { return false; } + virtual bool GetJustSingles() const { return false; } virtual size_t GetNimp() const { return N / 2; } }; diff --git a/include/macis/hamiltonian_generator/sd_build.hpp b/include/macis/hamiltonian_generator/sd_build.hpp new file mode 100644 index 00000000..b1170e79 --- /dev/null +++ b/include/macis/hamiltonian_generator/sd_build.hpp @@ -0,0 +1,274 @@ +/* + * 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 + */ + +#pragma once +#include +#include +#include +#include + +namespace macis { + +template< size_t N > +struct det_pos +{ + public: + std::bitset det; + uint32_t id; +}; + +template< size_t N > +bool operator<( const det_pos& a, const det_pos& b ) +{ return bitset_less( a.det, b.det ); } + +template +class SDBuildHamiltonianGenerator : public HamiltonianGenerator { + public: + using base_type = HamiltonianGenerator; + using full_det_t = typename base_type::full_det_t; + using spin_det_t = typename base_type::spin_det_t; + using full_det_iterator = typename base_type::full_det_iterator; + using matrix_span_t = typename base_type::matrix_span_t; + using rank4_span_t = typename base_type::rank4_span_t; + + template + using sparse_matrix_type = sparsexx::csr_matrix; + + protected: + size_t nimp, nimp2, nimp3; + + template + sparse_matrix_type make_csr_hamiltonian_block_( + full_det_iterator bra_begin, full_det_iterator bra_end, + full_det_iterator ket_begin, full_det_iterator ket_end, double H_thresh) { + const size_t nbra_dets = std::distance(bra_begin, bra_end); + const size_t nket_dets = std::distance(ket_begin, ket_end); + + std::vector colind, rowptr(nbra_dets + 1); + std::vector nzval; + + // List of impurity orbitals, assumed to be the first nimp. + std::vector imp_orbs(nimp, 0); + for( int ii = 0; ii < nimp; ii++) + imp_orbs[ii] = ii; + std::vector bra_occ_alpha, bra_occ_beta; + + std::set > kets; + for( full_det_iterator it = ket_begin; it != ket_end; it++ ) + { + det_pos a; + a.det = *it; + a.id = std::distance(ket_begin, it); + kets.insert( a ); + } + + rowptr[0] = 0; + + // Loop over bra determinants + for(size_t i = 0; i < nbra_dets; ++i) { + //if( (i%1000) == 0 ) std::cout << i << ", " << rowptr[i] << std::endl; + const auto bra = *(bra_begin + i); + + size_t nrow = 0; + if(bra.count()) { + // Separate out into alpha/beta components + spin_det_t bra_alpha = bitset_lo_word(bra); + spin_det_t bra_beta = bitset_hi_word(bra); + + // Get occupied indices + bits_to_indices(bra_alpha, bra_occ_alpha); + bits_to_indices(bra_beta , bra_occ_beta); + + // Get singles and doubles + // (Note that doubles only involve impurity orbitals) + std::vector excs, doubles; + if( just_singles ) + generate_singles_spin( this->norb_, bra, excs ); + else + { + std::vector singls; + generate_singles_spin( this->norb_, bra, excs ); + // This will store in singls sinles among impurity orbitals, which we + // have already taken into account. + generate_singles_doubles_spin_as( this->norb_, bra, singls, doubles, imp_orbs ); + excs.insert( excs.end(), doubles.begin(), doubles.end() ); + } + + // Diagonal term + full_det_t ex_diag = bra ^ bra; + spin_det_t exd_alpha = bitset_lo_word( ex_diag ); + spin_det_t exd_beta = bitset_hi_word( ex_diag ); + + // Compute Matrix Element + const auto h_eld = this->matrix_element_diag( bra_occ_alpha, bra_occ_beta ); + + if( std::abs(h_eld) > H_thresh ) { + nrow++; + colind.emplace_back(i); + nzval.emplace_back(h_eld); + } + + // Loop over ket determinants + for( const auto pos_ket : excs ) { + det_pos pos_ket2; pos_ket2.det = pos_ket; pos_ket2.id = 0; + auto it = kets.find( pos_ket2 ); + if( it != kets.end() ) { + int j = it->id; + spin_det_t ket_alpha = bitset_lo_word( pos_ket ); + spin_det_t ket_beta = bitset_hi_word( pos_ket ); + + full_det_t ex_total = bra ^ pos_ket; + + spin_det_t ex_alpha = bitset_lo_word( ex_total ); + spin_det_t ex_beta = bitset_hi_word( ex_total ); + + // Compute Matrix Element + const auto h_el = this->matrix_element( + bra_alpha, ket_alpha, ex_alpha, bra_beta, ket_beta, ex_beta, + bra_occ_alpha, bra_occ_beta ); + + if( std::abs(h_el) > H_thresh ) { + nrow++; + colind.emplace_back(j); + nzval.emplace_back(h_el); + } + + + } // Non-zero ket determinant + } // Loop over ket determinants + + } // Non-zero bra determinant + + rowptr[i + 1] = rowptr[i] + nrow; // Update rowptr + + } // Loop over bra determinants + + colind.shrink_to_fit(); + nzval.shrink_to_fit(); + + return sparse_matrix_type(nbra_dets, nket_dets, std::move(rowptr), + std::move(colind), std::move(nzval)); + } + + sparse_matrix_type make_csr_hamiltonian_block_32bit_( + full_det_iterator bra_begin, full_det_iterator bra_end, + full_det_iterator ket_begin, full_det_iterator ket_end, + double H_thresh) override { + return make_csr_hamiltonian_block_(bra_begin, bra_end, ket_begin, + ket_end, H_thresh); + } + + sparse_matrix_type make_csr_hamiltonian_block_64bit_( + full_det_iterator bra_begin, full_det_iterator bra_end, + full_det_iterator ket_begin, full_det_iterator ket_end, + double H_thresh) override { + return make_csr_hamiltonian_block_(bra_begin, bra_end, ket_begin, + ket_end, H_thresh); + } + + public: + void form_rdms(full_det_iterator bra_begin, full_det_iterator bra_end, + full_det_iterator ket_begin, full_det_iterator ket_end, + double *C, matrix_span_t ordm, rank4_span_t trdm) override { + const size_t nbra_dets = std::distance(bra_begin, bra_end); + const size_t nket_dets = std::distance(ket_begin, ket_end); + + std::vector bra_occ_alpha, bra_occ_beta; + + std::set > kets; + for( full_det_iterator it = ket_begin; it != ket_end; it++ ) + { + det_pos a; + a.det = *it; + a.id = std::distance(ket_begin, it); + kets.insert( a ); + } + + // Loop over bra determinants + for(size_t i = 0; i < nbra_dets; ++i) { + const auto bra = *(bra_begin + i); + // if( (i%1000) == 0 ) std::cout << i << std::endl; + if(bra.count()) { + // Separate out into alpha/beta components + spin_det_t bra_alpha = bitset_lo_word(bra); + spin_det_t bra_beta = bitset_hi_word(bra); + + // Get occupied indices + bits_to_indices(bra_alpha, bra_occ_alpha); + bits_to_indices(bra_beta, bra_occ_beta); + + // Get singles and doubles + std::vector excs; + if( trdm.data_handle() ){ + std::vector doubles; + generate_singles_doubles_spin( this->norb_, bra, excs, doubles ); + excs.insert( excs.end(), doubles.begin(), doubles.end() ); + } + else{ + generate_singles_spin( this->norb_, bra, excs ); + } + + // Diagonal term + full_det_t ex_diag = bra ^ bra; + spin_det_t exd_alpha = bitset_lo_word( ex_diag ); + spin_det_t exd_beta = bitset_hi_word( ex_diag ); + + // Compute Matrix Element + rdm_contributions( bra_alpha, bra_alpha, + exd_alpha, bra_beta, bra_beta, exd_beta, bra_occ_alpha, + bra_occ_beta, C[i] * C[i], ordm, trdm ); + + // Loop over excitations + for( const auto pos_ket : excs ) { + det_pos pos_ket2; pos_ket2.det = pos_ket; pos_ket2.id = 0; + auto it = kets.find( pos_ket2 ); + if( it != kets.end() ) { + int j = it->id; + spin_det_t ket_alpha = bitset_lo_word( pos_ket ); + spin_det_t ket_beta = bitset_hi_word( pos_ket ); + + full_det_t ex_total = bra ^ pos_ket; + int ex_lim = 2; + if(trdm.data_handle()) ex_lim = 4; + if( ex_total.count() <= ex_lim ) { + + spin_det_t ex_alpha = bitset_lo_word( ex_total ); + spin_det_t ex_beta = bitset_hi_word( ex_total ); + + const double val = C[i] * C[j]; + + // Compute Matrix Element + rdm_contributions( bra_alpha, ket_alpha, + ex_alpha, bra_beta, ket_beta, ex_beta, bra_occ_alpha, + bra_occ_beta, val, ordm, trdm ); + + } // Possible non-zero connection (Hamming distance) + + } // Non-zero ket determinant + } // Loop over ket determinants + + } // Non-zero bra determinant + } // Loop over bra determinants + } + + public: + + bool just_singles; + + template + SDBuildHamiltonianGenerator(Args &&...args) + : HamiltonianGenerator(std::forward(args)...), just_singles(false) + { SetNimp(this->norb_); } + + void SetJustSingles( bool _js ) override{ just_singles = _js; } + void SetNimp( size_t _n ){ nimp = _n; nimp2 = _n * _n; nimp3 = nimp2 * _n; } + size_t GetNimp() const override { return nimp; } + bool GetJustSingles( ) const override{ return just_singles; } +}; + +} // namespace macis diff --git a/include/macis/util/fcidump.hpp b/include/macis/util/fcidump.hpp index 41bb2a5c..6821f434 100644 --- a/include/macis/util/fcidump.hpp +++ b/include/macis/util/fcidump.hpp @@ -70,6 +70,17 @@ void read_fcidump_1body(std::string fname, col_major_span T); */ void read_fcidump_2body(std::string fname, col_major_span V); +/** + * @brief Check whether the 2-body contribution of the Hamiltonian is exclusively + * diagonal. + * + * @param[in] fname: Filename of FCIDUMP file + * + * @returns bool: Is the 2-body contribution to the Hamiltonian exclusively + * diagonal? + */ +bool is_2body_diagonal(std::string fname); + /** * @brief Write an FCIDUMP file from a 2-body hamiltonian * diff --git a/src/macis/fcidump.cxx b/src/macis/fcidump.cxx index bf1d7762..6af87371 100644 --- a/src/macis/fcidump.cxx +++ b/src/macis/fcidump.cxx @@ -181,6 +181,34 @@ void read_fcidump_2body(std::string fname, double* V, size_t LDV) { fname, KokkosEx::submdspan(V_map, sl, sl, sl, Kokkos::full_extent)); } +bool is_2body_diagonal(std::string fname) { + + auto norb = read_fcidump_norb(fname); + bool all_diag = true; + + std::ifstream file(fname); + std::string line; + while(std::getline(file, line)) { + auto tokens = split(line, " "); + if(tokens.size() != 5) continue; // not a valid FCIDUMP line + + auto [p, q, r, s, integral] = fcidump_line(tokens); + auto lc = line_classification(p, q, r, s); + if(lc == LineClassification::TwoBody) { + p--; + q--; + r--; + s--; + if(p != q || r != s) + { + all_diag = false; + break; + } + } + } + return all_diag; +} + void write_fcidump(std::string fname, size_t norb, const double* T, size_t LDT, const double* V, size_t LDV, double E_core) { auto logger = spdlog::basic_logger_mt("fcidump", fname); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3fd01966..1e539475 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable( macis_test fcidump.cxx read_wavefunction.cxx double_loop.cxx + sd_build.cxx csr_hamiltonian.cxx davidson.cxx transform.cxx diff --git a/tests/ref_data/hubbard10.fci.dat b/tests/ref_data/hubbard10.fci.dat new file mode 100644 index 00000000..aed59ff2 --- /dev/null +++ b/tests/ref_data/hubbard10.fci.dat @@ -0,0 +1,38 @@ +1 1 1 1 4. +2 2 2 2 4. +3 3 3 3 4. +4 4 4 4 4. +5 5 5 5 4. +6 6 6 6 4. +7 7 7 7 4. +8 8 8 8 4. +9 9 9 9 4. +10 10 10 10 4. +1 1 0 0 -2. +2 2 0 0 -2. +3 3 0 0 -2. +4 4 0 0 -2. +5 5 0 0 -2. +6 6 0 0 -2. +7 7 0 0 -2. +8 8 0 0 -2. +9 9 0 0 -2. +10 10 0 0 -2. +1 2 0 0 -1. +2 1 0 0 -1. +2 3 0 0 -1. +3 2 0 0 -1. +3 4 0 0 -1. +4 3 0 0 -1. +4 5 0 0 -1. +5 4 0 0 -1. +5 6 0 0 -1. +6 5 0 0 -1. +6 7 0 0 -1. +7 6 0 0 -1. +7 8 0 0 -1. +8 7 0 0 -1. +8 9 0 0 -1. +9 8 0 0 -1. +9 10 0 0 -1. +10 9 0 0 -1. diff --git a/tests/sd_build.cxx b/tests/sd_build.cxx new file mode 100644 index 00000000..0a8c95cb --- /dev/null +++ b/tests/sd_build.cxx @@ -0,0 +1,115 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ut_common.hpp" + +using macis::NumOrbital; +using macis::NumActive; +using macis::NumInactive; + +TEST_CASE("Single Double Build") { + ROOT_ONLY(MPI_COMM_WORLD); + + auto norb = macis::read_fcidump_norb(hubbard10_fcidump); + const auto norb2 = norb * norb; + const auto norb3 = norb2 * norb; + const size_t nocc = 10; + + std::vector T(norb * norb); + std::vector V(norb * norb * norb * norb); + auto E_core = macis::read_fcidump_core(hubbard10_fcidump); + macis::read_fcidump_1body(hubbard10_fcidump, T.data(), norb); + macis::read_fcidump_2body(hubbard10_fcidump, V.data(), norb); + bool just_singles = macis::is_2body_diagonal( hubbard10_fcidump ); + + using generator_type = macis::SDBuildHamiltonianGenerator<64>; + +#if 0 + generator_type ham_gen(norb, V.data(), T.data()); +#else + generator_type ham_gen( + macis::matrix_span(T.data(), norb, norb), + macis::rank4_span(V.data(), norb, norb, norb, norb)); + ham_gen.SetJustSingles(just_singles); +#endif + const auto hf_det = macis::canonical_hf_determinant<64>(nocc, nocc); + + std::vector eps(norb); + for(auto p = 0ul; p < norb; ++p) { + double tmp = 0.; + for(auto i = 0ul; i < nocc; ++i) { + tmp += 2. * V[p * (norb + 1) + i * (norb2 + norb3)] - + V[p * (1 + norb3) + i * (norb + norb2)]; + } + eps[p] = T[p * (norb + 1)] + tmp; + } + const auto EHF = ham_gen.matrix_element(hf_det, hf_det); + + SECTION("HF Energy") { REQUIRE(EHF + E_core == Approx(-0.00)); } + + SECTION("RDM") { + std::vector ordm(norb * norb, 0.0), trdm(norb3 * norb, 0.0); + std::vector> dets = { + macis::canonical_hf_determinant<64>(nocc, nocc)}; + + std::vector C = {1.}; + + ham_gen.form_rdms( + dets.begin(), dets.end(), dets.begin(), dets.end(), C.data(), + macis::matrix_span(ordm.data(), norb, norb), + macis::rank4_span(trdm.data(), norb, norb, norb, norb)); + + auto E_tmp = blas::dot(norb2, ordm.data(), 1, T.data(), 1) + + blas::dot(norb3 * norb, trdm.data(), 1, V.data(), 1); + REQUIRE(E_tmp == Approx(EHF)); + } + + SECTION("CI") { + size_t nalpha = 5; + size_t nbeta = 5; + size_t n_inactive = 0; + size_t n_active = 10; + size_t n_virtual = 0; + std::vector C_local; + std::vector active_ordm(n_active * n_active); + std::vector active_trdm; + macis::MCSCFSettings mcscf_settings; + mcscf_settings.ci_max_subspace = 100; + // Copy integrals into active subsets + std::vector T_active(n_active * n_active); + std::vector V_active(n_active * n_active * n_active * n_active); + + // Compute active-space Hamiltonian and inactive Fock matrix + std::vector F_inactive(norb2); + macis::active_hamiltonian(NumOrbital(norb), NumActive(n_active), + NumInactive(n_inactive), T.data(), norb, V.data(), + norb, F_inactive.data(), norb, T_active.data(), + n_active, V_active.data(), n_active); + auto E_inactive = macis::inactive_energy(NumInactive(n_inactive), T.data(), + norb, F_inactive.data(), norb); + auto dets = macis::generate_hilbert_space<64>(norb, nalpha, nbeta); + double E0 = + macis::selected_ci_diag(dets.begin(), dets.end(), ham_gen, mcscf_settings.ci_matel_tol, + mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, C_local, + MACIS_MPI_CODE(MPI_COMM_WORLD,) true); + E0 += E_inactive + E_core; + // Compute RDMs + ham_gen.form_rdms(dets.begin(), dets.end(), dets.begin(), dets.end(), + C_local.data(), macis::matrix_span(active_ordm.data(), norb, norb), + macis::rank4_span(active_trdm.data(), norb, norb, norb, norb)); + REQUIRE(E0 == Approx(-2.538061882041e+01)); + } +} diff --git a/tests/ut_common.hpp.in b/tests/ut_common.hpp.in index cb9cc085..ba5af02c 100644 --- a/tests/ut_common.hpp.in +++ b/tests/ut_common.hpp.in @@ -37,3 +37,5 @@ const std::string water_ccpvdz_nzval_fname = REF_DATA_PREFIX "/h2o.ccpvdz.cisd.nzval.bin"; const std::string ch4_wfn_fname = REF_DATA_PREFIX "/ch4.wfn.dat"; +const std::string hubbard10_fcidump = + REF_DATA_PREFIX "/hubbard10.fci.dat"; From 3d3277dbf436f0b68cac2796d1d0f774c7354adf Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Wed, 20 Sep 2023 07:47:27 +0000 Subject: [PATCH 21/35] Committing clang-format changes --- .../macis/hamiltonian_generator/sd_build.hpp | 200 +++++++++--------- include/macis/util/fcidump.hpp | 4 +- src/macis/fcidump.cxx | 10 +- tests/sd_build.cxx | 31 +-- 4 files changed, 124 insertions(+), 121 deletions(-) diff --git a/include/macis/hamiltonian_generator/sd_build.hpp b/include/macis/hamiltonian_generator/sd_build.hpp index b1170e79..37c8cf0f 100644 --- a/include/macis/hamiltonian_generator/sd_build.hpp +++ b/include/macis/hamiltonian_generator/sd_build.hpp @@ -14,17 +14,17 @@ namespace macis { -template< size_t N > -struct det_pos -{ - public: - std::bitset det; - uint32_t id; +template +struct det_pos { + public: + std::bitset det; + uint32_t id; }; -template< size_t N > -bool operator<( const det_pos& a, const det_pos& b ) -{ return bitset_less( a.det, b.det ); } +template +bool operator<(const det_pos& a, const det_pos& b) { + return bitset_less(a.det, b.det); +} template class SDBuildHamiltonianGenerator : public HamiltonianGenerator { @@ -54,94 +54,94 @@ class SDBuildHamiltonianGenerator : public HamiltonianGenerator { // List of impurity orbitals, assumed to be the first nimp. std::vector imp_orbs(nimp, 0); - for( int ii = 0; ii < nimp; ii++) - imp_orbs[ii] = ii; + for(int ii = 0; ii < nimp; ii++) imp_orbs[ii] = ii; std::vector bra_occ_alpha, bra_occ_beta; std::set > kets; - for( full_det_iterator it = ket_begin; it != ket_end; it++ ) - { + for(full_det_iterator it = ket_begin; it != ket_end; it++) { det_pos a; a.det = *it; - a.id = std::distance(ket_begin, it); - kets.insert( a ); + a.id = std::distance(ket_begin, it); + kets.insert(a); } rowptr[0] = 0; // Loop over bra determinants for(size_t i = 0; i < nbra_dets; ++i) { - //if( (i%1000) == 0 ) std::cout << i << ", " << rowptr[i] << std::endl; + // if( (i%1000) == 0 ) std::cout << i << ", " << rowptr[i] << std::endl; const auto bra = *(bra_begin + i); size_t nrow = 0; if(bra.count()) { // Separate out into alpha/beta components spin_det_t bra_alpha = bitset_lo_word(bra); - spin_det_t bra_beta = bitset_hi_word(bra); + spin_det_t bra_beta = bitset_hi_word(bra); // Get occupied indices bits_to_indices(bra_alpha, bra_occ_alpha); - bits_to_indices(bra_beta , bra_occ_beta); + bits_to_indices(bra_beta, bra_occ_beta); // Get singles and doubles // (Note that doubles only involve impurity orbitals) std::vector excs, doubles; - if( just_singles ) - generate_singles_spin( this->norb_, bra, excs ); - else - { + if(just_singles) + generate_singles_spin(this->norb_, bra, excs); + else { std::vector singls; - generate_singles_spin( this->norb_, bra, excs ); + generate_singles_spin(this->norb_, bra, excs); // This will store in singls sinles among impurity orbitals, which we - // have already taken into account. - generate_singles_doubles_spin_as( this->norb_, bra, singls, doubles, imp_orbs ); - excs.insert( excs.end(), doubles.begin(), doubles.end() ); + // have already taken into account. + generate_singles_doubles_spin_as(this->norb_, bra, singls, doubles, + imp_orbs); + excs.insert(excs.end(), doubles.begin(), doubles.end()); } // Diagonal term - full_det_t ex_diag = bra ^ bra; - spin_det_t exd_alpha = bitset_lo_word( ex_diag ); - spin_det_t exd_beta = bitset_hi_word( ex_diag ); + full_det_t ex_diag = bra ^ bra; + spin_det_t exd_alpha = bitset_lo_word(ex_diag); + spin_det_t exd_beta = bitset_hi_word(ex_diag); // Compute Matrix Element - const auto h_eld = this->matrix_element_diag( bra_occ_alpha, bra_occ_beta ); + const auto h_eld = + this->matrix_element_diag(bra_occ_alpha, bra_occ_beta); - if( std::abs(h_eld) > H_thresh ) { + if(std::abs(h_eld) > H_thresh) { nrow++; colind.emplace_back(i); nzval.emplace_back(h_eld); } // Loop over ket determinants - for( const auto pos_ket : excs ) { - det_pos pos_ket2; pos_ket2.det = pos_ket; pos_ket2.id = 0; - auto it = kets.find( pos_ket2 ); - if( it != kets.end() ) { + for(const auto pos_ket : excs) { + det_pos pos_ket2; + pos_ket2.det = pos_ket; + pos_ket2.id = 0; + auto it = kets.find(pos_ket2); + if(it != kets.end()) { int j = it->id; - spin_det_t ket_alpha = bitset_lo_word( pos_ket ); - spin_det_t ket_beta = bitset_hi_word( pos_ket ); + spin_det_t ket_alpha = bitset_lo_word(pos_ket); + spin_det_t ket_beta = bitset_hi_word(pos_ket); full_det_t ex_total = bra ^ pos_ket; - - spin_det_t ex_alpha = bitset_lo_word( ex_total ); - spin_det_t ex_beta = bitset_hi_word( ex_total ); + + spin_det_t ex_alpha = bitset_lo_word(ex_total); + spin_det_t ex_beta = bitset_hi_word(ex_total); // Compute Matrix Element - const auto h_el = this->matrix_element( - bra_alpha, ket_alpha, ex_alpha, bra_beta, ket_beta, ex_beta, - bra_occ_alpha, bra_occ_beta ); + const auto h_el = this->matrix_element( + bra_alpha, ket_alpha, ex_alpha, bra_beta, ket_beta, ex_beta, + bra_occ_alpha, bra_occ_beta); - if( std::abs(h_el) > H_thresh ) { + if(std::abs(h_el) > H_thresh) { nrow++; colind.emplace_back(j); nzval.emplace_back(h_el); } - - } // Non-zero ket determinant - } // Loop over ket determinants - + } // Non-zero ket determinant + } // Loop over ket determinants + } // Non-zero bra determinant rowptr[i + 1] = rowptr[i] + nrow; // Update rowptr @@ -174,19 +174,18 @@ class SDBuildHamiltonianGenerator : public HamiltonianGenerator { public: void form_rdms(full_det_iterator bra_begin, full_det_iterator bra_end, full_det_iterator ket_begin, full_det_iterator ket_end, - double *C, matrix_span_t ordm, rank4_span_t trdm) override { + double* C, matrix_span_t ordm, rank4_span_t trdm) override { const size_t nbra_dets = std::distance(bra_begin, bra_end); const size_t nket_dets = std::distance(ket_begin, ket_end); std::vector bra_occ_alpha, bra_occ_beta; std::set > kets; - for( full_det_iterator it = ket_begin; it != ket_end; it++ ) - { + for(full_det_iterator it = ket_begin; it != ket_end; it++) { det_pos a; a.det = *it; - a.id = std::distance(ket_begin, it); - kets.insert( a ); + a.id = std::distance(ket_begin, it); + kets.insert(a); } // Loop over bra determinants @@ -196,79 +195,84 @@ class SDBuildHamiltonianGenerator : public HamiltonianGenerator { if(bra.count()) { // Separate out into alpha/beta components spin_det_t bra_alpha = bitset_lo_word(bra); - spin_det_t bra_beta = bitset_hi_word(bra); + spin_det_t bra_beta = bitset_hi_word(bra); // Get occupied indices bits_to_indices(bra_alpha, bra_occ_alpha); bits_to_indices(bra_beta, bra_occ_beta); - + // Get singles and doubles std::vector excs; - if( trdm.data_handle() ){ + if(trdm.data_handle()) { std::vector doubles; - generate_singles_doubles_spin( this->norb_, bra, excs, doubles ); - excs.insert( excs.end(), doubles.begin(), doubles.end() ); - } - else{ - generate_singles_spin( this->norb_, bra, excs ); - } + generate_singles_doubles_spin(this->norb_, bra, excs, doubles); + excs.insert(excs.end(), doubles.begin(), doubles.end()); + } else { + generate_singles_spin(this->norb_, bra, excs); + } // Diagonal term - full_det_t ex_diag = bra ^ bra; - spin_det_t exd_alpha = bitset_lo_word( ex_diag ); - spin_det_t exd_beta = bitset_hi_word( ex_diag ); + full_det_t ex_diag = bra ^ bra; + spin_det_t exd_alpha = bitset_lo_word(ex_diag); + spin_det_t exd_beta = bitset_hi_word(ex_diag); // Compute Matrix Element - rdm_contributions( bra_alpha, bra_alpha, - exd_alpha, bra_beta, bra_beta, exd_beta, bra_occ_alpha, - bra_occ_beta, C[i] * C[i], ordm, trdm ); + rdm_contributions(bra_alpha, bra_alpha, exd_alpha, bra_beta, bra_beta, + exd_beta, bra_occ_alpha, bra_occ_beta, C[i] * C[i], + ordm, trdm); // Loop over excitations - for( const auto pos_ket : excs ) { - det_pos pos_ket2; pos_ket2.det = pos_ket; pos_ket2.id = 0; - auto it = kets.find( pos_ket2 ); - if( it != kets.end() ) { + for(const auto pos_ket : excs) { + det_pos pos_ket2; + pos_ket2.det = pos_ket; + pos_ket2.id = 0; + auto it = kets.find(pos_ket2); + if(it != kets.end()) { int j = it->id; - spin_det_t ket_alpha = bitset_lo_word( pos_ket ); - spin_det_t ket_beta = bitset_hi_word( pos_ket ); + spin_det_t ket_alpha = bitset_lo_word(pos_ket); + spin_det_t ket_beta = bitset_hi_word(pos_ket); full_det_t ex_total = bra ^ pos_ket; - int ex_lim = 2; - if(trdm.data_handle()) ex_lim = 4; - if( ex_total.count() <= ex_lim ) { - - spin_det_t ex_alpha = bitset_lo_word( ex_total ); - spin_det_t ex_beta = bitset_hi_word( ex_total ); + int ex_lim = 2; + if(trdm.data_handle()) ex_lim = 4; + if(ex_total.count() <= ex_lim) { + spin_det_t ex_alpha = bitset_lo_word(ex_total); + spin_det_t ex_beta = bitset_hi_word(ex_total); const double val = C[i] * C[j]; // Compute Matrix Element - rdm_contributions( bra_alpha, ket_alpha, - ex_alpha, bra_beta, ket_beta, ex_beta, bra_occ_alpha, - bra_occ_beta, val, ordm, trdm ); - - } // Possible non-zero connection (Hamming distance) - - } // Non-zero ket determinant - } // Loop over ket determinants - - } // Non-zero bra determinant - } // Loop over bra determinants + rdm_contributions(bra_alpha, ket_alpha, ex_alpha, bra_beta, + ket_beta, ex_beta, bra_occ_alpha, bra_occ_beta, + val, ordm, trdm); + + } // Possible non-zero connection (Hamming distance) + + } // Non-zero ket determinant + } // Loop over ket determinants + + } // Non-zero bra determinant + } // Loop over bra determinants } public: - bool just_singles; template - SDBuildHamiltonianGenerator(Args &&...args) - : HamiltonianGenerator(std::forward(args)...), just_singles(false) - { SetNimp(this->norb_); } + SDBuildHamiltonianGenerator(Args&&... args) + : HamiltonianGenerator(std::forward(args)...), + just_singles(false) { + SetNimp(this->norb_); + } - void SetJustSingles( bool _js ) override{ just_singles = _js; } - void SetNimp( size_t _n ){ nimp = _n; nimp2 = _n * _n; nimp3 = nimp2 * _n; } + void SetJustSingles(bool _js) override { just_singles = _js; } + void SetNimp(size_t _n) { + nimp = _n; + nimp2 = _n * _n; + nimp3 = nimp2 * _n; + } size_t GetNimp() const override { return nimp; } - bool GetJustSingles( ) const override{ return just_singles; } + bool GetJustSingles() const override { return just_singles; } }; } // namespace macis diff --git a/include/macis/util/fcidump.hpp b/include/macis/util/fcidump.hpp index 6821f434..823ef7c8 100644 --- a/include/macis/util/fcidump.hpp +++ b/include/macis/util/fcidump.hpp @@ -71,8 +71,8 @@ void read_fcidump_1body(std::string fname, col_major_span T); void read_fcidump_2body(std::string fname, col_major_span V); /** - * @brief Check whether the 2-body contribution of the Hamiltonian is exclusively - * diagonal. + * @brief Check whether the 2-body contribution of the Hamiltonian is + * exclusively diagonal. * * @param[in] fname: Filename of FCIDUMP file * diff --git a/src/macis/fcidump.cxx b/src/macis/fcidump.cxx index 6af87371..9870077c 100644 --- a/src/macis/fcidump.cxx +++ b/src/macis/fcidump.cxx @@ -182,8 +182,7 @@ void read_fcidump_2body(std::string fname, double* V, size_t LDV) { } bool is_2body_diagonal(std::string fname) { - - auto norb = read_fcidump_norb(fname); + auto norb = read_fcidump_norb(fname); bool all_diag = true; std::ifstream file(fname); @@ -199,10 +198,9 @@ bool is_2body_diagonal(std::string fname) { q--; r--; s--; - if(p != q || r != s) - { - all_diag = false; - break; + if(p != q || r != s) { + all_diag = false; + break; } } } diff --git a/tests/sd_build.cxx b/tests/sd_build.cxx index 0a8c95cb..9c2a0760 100644 --- a/tests/sd_build.cxx +++ b/tests/sd_build.cxx @@ -9,16 +9,16 @@ #include #include #include -#include -#include #include +#include #include +#include #include "ut_common.hpp" -using macis::NumOrbital; using macis::NumActive; using macis::NumInactive; +using macis::NumOrbital; TEST_CASE("Single Double Build") { ROOT_ONLY(MPI_COMM_WORLD); @@ -33,7 +33,7 @@ TEST_CASE("Single Double Build") { auto E_core = macis::read_fcidump_core(hubbard10_fcidump); macis::read_fcidump_1body(hubbard10_fcidump, T.data(), norb); macis::read_fcidump_2body(hubbard10_fcidump, V.data(), norb); - bool just_singles = macis::is_2body_diagonal( hubbard10_fcidump ); + bool just_singles = macis::is_2body_diagonal(hubbard10_fcidump); using generator_type = macis::SDBuildHamiltonianGenerator<64>; @@ -78,11 +78,11 @@ TEST_CASE("Single Double Build") { } SECTION("CI") { - size_t nalpha = 5; - size_t nbeta = 5; + size_t nalpha = 5; + size_t nbeta = 5; size_t n_inactive = 0; - size_t n_active = 10; - size_t n_virtual = 0; + size_t n_active = 10; + size_t n_virtual = 0; std::vector C_local; std::vector active_ordm(n_active * n_active); std::vector active_trdm; @@ -101,15 +101,16 @@ TEST_CASE("Single Double Build") { auto E_inactive = macis::inactive_energy(NumInactive(n_inactive), T.data(), norb, F_inactive.data(), norb); auto dets = macis::generate_hilbert_space<64>(norb, nalpha, nbeta); - double E0 = - macis::selected_ci_diag(dets.begin(), dets.end(), ham_gen, mcscf_settings.ci_matel_tol, - mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, C_local, - MACIS_MPI_CODE(MPI_COMM_WORLD,) true); + double E0 = macis::selected_ci_diag( + dets.begin(), dets.end(), ham_gen, mcscf_settings.ci_matel_tol, + mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, C_local, + MACIS_MPI_CODE(MPI_COMM_WORLD, ) true); E0 += E_inactive + E_core; // Compute RDMs - ham_gen.form_rdms(dets.begin(), dets.end(), dets.begin(), dets.end(), - C_local.data(), macis::matrix_span(active_ordm.data(), norb, norb), - macis::rank4_span(active_trdm.data(), norb, norb, norb, norb)); + ham_gen.form_rdms( + dets.begin(), dets.end(), dets.begin(), dets.end(), C_local.data(), + macis::matrix_span(active_ordm.data(), norb, norb), + macis::rank4_span(active_trdm.data(), norb, norb, norb, norb)); REQUIRE(E0 == Approx(-2.538061882041e+01)); } } From 41cc11691aea5f642e17db187504be64728c2afe Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Fri, 22 Sep 2023 10:19:50 +0200 Subject: [PATCH 22/35] Added option to read in vectors of ints and bools from input file, to be used in GF calculation. --- tests/ini_input.cxx | 42 +++++++++++++++++++++++++++++++++++++ tests/standalone_driver.cxx | 10 ++++----- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/tests/ini_input.cxx b/tests/ini_input.cxx index bee88cb1..58581a66 100644 --- a/tests/ini_input.cxx +++ b/tests/ini_input.cxx @@ -7,6 +7,7 @@ */ #include "ini_input.hpp" +#include // Misc string functions @@ -329,6 +330,25 @@ int INIFile::getData(std::string query) { } // INIFile::getData +/** + * \brief Specialization of getData to return vector of query + * data field + * + * \param [in] query Formatted query string to be parsed + * \return Value of query data field as a vector + */ +template <> +std::vector INIFile::getData(std::string query) { + std::string line = getData(query); + std::istringstream iss( line ); + std::vector res; + int tmp; + while( iss >> tmp ) + res.push_back(tmp); + return res; + +} // INIFile::getData> + /** * \brief Specialization of getData to return bool of query * data field @@ -344,6 +364,28 @@ bool INIFile::getData(std::string query) { } // INIFile::getData +/** + * \brief Specialization of getData to return std::vector of query + * data field + * + * \param [in] query Formatted query string to be parsed + * \return Value of query data field as a std::vector + */ +template <> +std::vector INIFile::getData(std::string query) { + std::string line = getData(query); + std::istringstream iss( line ); + std::vector res; + std::string tmp; + while( iss >> tmp ) + { + bool b = (not tmp.compare("TRUE") or not tmp.compare("ON")); + res.push_back(b); + } + return res; + +} // INIFile::getData> + /** * \brief Specialization of getData to return size_t of query * data field diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 4c27bb7f..536929b9 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -345,12 +345,10 @@ int main(int argc, char** argv) { OPT_KEYWORD("GF.WRITE", gf_settings.writeGF, bool); OPT_KEYWORD("GF.PRINT", gf_settings.print, bool); OPT_KEYWORD("GF.SAVEGFMATS", gf_settings.saveGFmats, bool); - gf_settings.GF_orbs_basis = std::vector(n_active, 0); - for(int i = 0; i < n_active; i++) gf_settings.GF_orbs_basis[i] = i; - gf_settings.GF_orbs_comp = std::vector(n_active, 0); - for(int i = 0; i < n_active; i++) gf_settings.GF_orbs_comp[i] = i; - gf_settings.is_up_basis = std::vector(n_active, true); - gf_settings.is_up_comp = std::vector(n_active, true); + OPT_KEYWORD("GF.ORBS_BASIS", gf_settings.GF_orbs_basis, std::vector); + OPT_KEYWORD("GF.IS_UP_BASIS", gf_settings.is_up_basis, std::vector); + OPT_KEYWORD("GF.ORBS_COMP", gf_settings.GF_orbs_comp, std::vector); + OPT_KEYWORD("GF.IS_UP_COMP", gf_settings.is_up_comp, std::vector); // GF vector std::vector>> GF( From a51b754d4058eea25b6fddc8769fd089e855beda Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Fri, 22 Sep 2023 08:20:42 +0000 Subject: [PATCH 23/35] Committing clang-format changes --- tests/ini_input.cxx | 11 +++++------ tests/standalone_driver.cxx | 12 ++++++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/ini_input.cxx b/tests/ini_input.cxx index 58581a66..2aff6f29 100644 --- a/tests/ini_input.cxx +++ b/tests/ini_input.cxx @@ -7,6 +7,7 @@ */ #include "ini_input.hpp" + #include // Misc string functions @@ -340,11 +341,10 @@ int INIFile::getData(std::string query) { template <> std::vector INIFile::getData(std::string query) { std::string line = getData(query); - std::istringstream iss( line ); + std::istringstream iss(line); std::vector res; int tmp; - while( iss >> tmp ) - res.push_back(tmp); + while(iss >> tmp) res.push_back(tmp); return res; } // INIFile::getData> @@ -374,11 +374,10 @@ bool INIFile::getData(std::string query) { template <> std::vector INIFile::getData(std::string query) { std::string line = getData(query); - std::istringstream iss( line ); + std::istringstream iss(line); std::vector res; std::string tmp; - while( iss >> tmp ) - { + while(iss >> tmp) { bool b = (not tmp.compare("TRUE") or not tmp.compare("ON")); res.push_back(b); } diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 536929b9..e0f32f65 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -345,10 +345,14 @@ int main(int argc, char** argv) { OPT_KEYWORD("GF.WRITE", gf_settings.writeGF, bool); OPT_KEYWORD("GF.PRINT", gf_settings.print, bool); OPT_KEYWORD("GF.SAVEGFMATS", gf_settings.saveGFmats, bool); - OPT_KEYWORD("GF.ORBS_BASIS", gf_settings.GF_orbs_basis, std::vector); - OPT_KEYWORD("GF.IS_UP_BASIS", gf_settings.is_up_basis, std::vector); - OPT_KEYWORD("GF.ORBS_COMP", gf_settings.GF_orbs_comp, std::vector); - OPT_KEYWORD("GF.IS_UP_COMP", gf_settings.is_up_comp, std::vector); + OPT_KEYWORD("GF.ORBS_BASIS", gf_settings.GF_orbs_basis, + std::vector); + OPT_KEYWORD("GF.IS_UP_BASIS", gf_settings.is_up_basis, + std::vector); + OPT_KEYWORD("GF.ORBS_COMP", gf_settings.GF_orbs_comp, + std::vector); + OPT_KEYWORD("GF.IS_UP_COMP", gf_settings.is_up_comp, + std::vector); // GF vector std::vector>> GF( From ff65ee7ed5316da640329a5701025f43cce4c304 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Thu, 5 Oct 2023 08:58:43 +0200 Subject: [PATCH 24/35] Fixed Bug in GF calculation: Call to band diagonalization through Lapackpp was not returning the right eigenvectors, but the eigenvectors to an intermediat tridiagonal matrix. --- src/macis/gf/bandlan.cxx | 3 ++- tests/standalone_driver.cxx | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 411f6363..99bfb658 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -138,7 +138,7 @@ bool GetEigsysBand(std::vector &mat, int nSupDiag, // PREPARE VARIABLES FOR LAPACK lapack::Uplo UPLO = lapack::Uplo::Upper; lapack::Job VECT = lapack::Job::Vec; - lapack::Job COMPZ = lapack::Job::Vec; + lapack::Job COMPZ = lapack::Job::UpdateVec; int N = matsize, LDQ = matsize, LDAB = nSupDiag + 1; std::vector AB((nSupDiag + 1) * N, 0.); std::vector D(N, 0.), E(N - 1, 0.), Q(N * N, 0.); @@ -225,6 +225,7 @@ void BandResolvent( int nbands = nvecs; BandLan(Hop, vecs, bandH, nLanIts, nbands, len_vec, 1.E-6, print); std::cout << "DONE! "; + if(print) { std::ofstream ofile("BLH.dat", std::ios::out); ofile.precision(dbl::max_digits10); diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index e0f32f65..5a3f35c2 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -325,6 +326,7 @@ int main(int argc, char** argv) { double wmin = -8.; double wmax = 8.; size_t nws = 1001; + double beta = 157.; double eta = 0.1; std::complex w0(wmin, eta); std::complex wf(wmax, eta); @@ -332,6 +334,7 @@ int main(int argc, char** argv) { std::complex(0., 0.)); for(int i = 0; i < nws; i++) ws[i] = w0 + (wf - w0) / double(nws - 1) * double(i); + //ws[i] = std::complex(0., 1.) * (2. * i + 1.) * M_PI / beta; // MCSCF Settings macis::GFSettings gf_settings; @@ -361,6 +364,12 @@ int main(int argc, char** argv) { // Occupation numbers std::vector occs(n_active, 1.); + for( int i = 0; i < n_active; i++ ) + occs[i] = active_ordm[i + n_active * i] / 2.; + std::cout << "Occupation Nrs.: "; + for( int i = 0; i < n_active; i++ ) + std::cout << " " << occs[i]; + std::cout << std::endl; // GS vector Eigen::VectorXd psi0 = Eigen::Map( From b797e3095673960dadc0ef22dd528686e7f9869d Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Thu, 5 Oct 2023 06:59:37 +0000 Subject: [PATCH 25/35] Committing clang-format changes --- src/macis/gf/bandlan.cxx | 2 +- tests/standalone_driver.cxx | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 99bfb658..f748f69c 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -225,7 +225,7 @@ void BandResolvent( int nbands = nvecs; BandLan(Hop, vecs, bandH, nLanIts, nbands, len_vec, 1.E-6, print); std::cout << "DONE! "; - + if(print) { std::ofstream ofile("BLH.dat", std::ios::out); ofile.precision(dbl::max_digits10); diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 5a3f35c2..5b64cc21 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -326,7 +326,7 @@ int main(int argc, char** argv) { double wmin = -8.; double wmax = 8.; size_t nws = 1001; - double beta = 157.; + double beta = 157.; double eta = 0.1; std::complex w0(wmin, eta); std::complex wf(wmax, eta); @@ -334,7 +334,7 @@ int main(int argc, char** argv) { std::complex(0., 0.)); for(int i = 0; i < nws; i++) ws[i] = w0 + (wf - w0) / double(nws - 1) * double(i); - //ws[i] = std::complex(0., 1.) * (2. * i + 1.) * M_PI / beta; + // ws[i] = std::complex(0., 1.) * (2. * i + 1.) * M_PI / beta; // MCSCF Settings macis::GFSettings gf_settings; @@ -364,12 +364,11 @@ int main(int argc, char** argv) { // Occupation numbers std::vector occs(n_active, 1.); - for( int i = 0; i < n_active; i++ ) - occs[i] = active_ordm[i + n_active * i] / 2.; - std::cout << "Occupation Nrs.: "; - for( int i = 0; i < n_active; i++ ) - std::cout << " " << occs[i]; - std::cout << std::endl; + for(int i = 0; i < n_active; i++) + occs[i] = active_ordm[i + n_active * i] / 2.; + std::cout << "Occupation Nrs.: "; + for(int i = 0; i < n_active; i++) std::cout << " " << occs[i]; + std::cout << std::endl; // GS vector Eigen::VectorXd psi0 = Eigen::Map( From f838450ad6945fbb40462a4d05827a56cd730ee5 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Mon, 9 Oct 2023 17:10:30 +0200 Subject: [PATCH 26/35] Added functionalities to specify GF frequency grid. --- include/macis/gf/gf.hpp | 24 ++++++++ src/macis/gf/gf.cxx | 123 ++++++++++++++++++++++++++++------------ 2 files changed, 111 insertions(+), 36 deletions(-) diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 6ed73b2c..efdf8b6c 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -52,8 +52,32 @@ struct GFSettings { bool writeGF = false; bool print = false; bool saveGFmats = false; + double wmin = -8.; + double wmax = 8.; + size_t nws = 2001; + double eta = 0.1; + std::string w_scale = "lin"; + bool real_g = true; + bool beta = 1.; }; +/** + * @brief Generates the frequency grid over which to evaluate the GF, + * details of which are specified in the settings instance. We + * have implemented linear, Matsubara and logarithmic frequency + * grids. + * + * @param[in] const GFSettings& settings: Settings defining the frequency + * grid. + * + * @returns std::vector >: Vector of complex frequencies + * building the grid. + * + * @author Carlos Mejuto Zaera + * @date 09/10/2023 + */ +std::vector > GetGFFreqGrid( const GFSettings& settings ); + /** * @brief Gets fermionic sign incurred by inserting an electron of spin * up in a given orbital to a given determinant. diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 8dff6304..61e4c536 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -9,46 +9,97 @@ #include "macis/gf/gf.hpp" namespace macis { -void write_GF(const std::vector > > &GF, - const std::vector > &ws, - const std::vector &GF_orbs, const std::vector &todelete, - const bool is_part) { - using dbl = std::numeric_limits; - size_t nfreqs = ws.size(); - int GFmat_size = GF_orbs.size() - todelete.size(); - - if(GF_orbs.size() > 1) { - std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; - std::ofstream ofile(fname); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++) { - ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; - for(int jjj = 0; jjj < GFmat_size; jjj++) { - for(int lll = 0; lll < GFmat_size; lll++) - ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) - << " " << imag(GF[iii][jjj * GFmat_size + lll]) << " "; + + std::vector > GetGFFreqGrid( const GFSettings& settings) + { + double wmin = settings.wmin; + double wmax = settings.wmax; + double eta = settings.eta; + double beta = settings.beta; + size_t nws = settings.nws; + bool real_g = settings.real_g; + + std::complex fact(0.,0.); + if( real_g ) + fact = std::complex(1., 0.); + else + { + fact = std::complex( 0., 1.); + eta = 0.; + } + + std::vector > ws( nws, std::complex(0.,0.) ); + + std::string scale = settings.w_scale; + if( scale == "lin" ) + { + for( int i = 0; i < nws; i++ ) + ws[i] =fact * ( wmin + (wmax - wmin) / double(nws-1.) * double(i) + + std::complex(0., eta) ); + } + else if( scale == "matsubara" ) + { + if( real_g == true ) + throw(std::runtime_error("Error in GetGFFreqGrid! Asked for 'real' Matsubara frequency grid.")); + for( int i = 0; i < nws; i++ ) + ws[i] = std::complex(0., (2. * double(i) + 1.) * M_PI / beta); + } + else if( scale == "log" ) + { + if( ( wmin < 0. && wmax > 0.) || ( wmin > 0. && wmax < 0. ) ) + throw( std::runtime_error( "Error in GetGFFreqGrid! Requested grid touches or passes by 0." ) ); + for( int i = 0; i < nws; i++ ) + { + double step = std::log(wmin) + ( std::log(wmax) - std::log(wmin) ) / double(nws-1.) * double(i); + ws[i] = fact * std::exp( step ) + std::complex( 0., eta ); } - ofile << std::endl; } + else + throw(std::runtime_error("Error in GetGFFreqGrid! Frequency scale passed is not supported. Options are 'lin', 'log' and 'matsubara'.")); + + return ws; + } - std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" - : "GFMatrix_OrbitalIndices_SUB.dat"; - std::ofstream ofile2(fname2); - for(int iii = 0; iii < GF_orbs.size(); iii++) { - if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) - continue; - ofile2 << GF_orbs[iii] << std::endl; + void write_GF(const std::vector > > &GF, + const std::vector > &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part) { + using dbl = std::numeric_limits; + size_t nfreqs = ws.size(); + int GFmat_size = GF_orbs.size() - todelete.size(); + + if(GF_orbs.size() > 1) { + std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) { + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; + for(int jjj = 0; jjj < GFmat_size; jjj++) { + for(int lll = 0; lll < GFmat_size; lll++) + ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) + << " " << imag(GF[iii][jjj * GFmat_size + lll]) << " "; + } + ofile << std::endl; + } + + std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" + : "GFMatrix_OrbitalIndices_SUB.dat"; + std::ofstream ofile2(fname2); + for(int iii = 0; iii < GF_orbs.size(); iii++) { + if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) + continue; + ofile2 << GF_orbs[iii] << std::endl; + } + } else { + std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; + fname += std::to_string(GF_orbs[0] + 1) + "_" + + std::to_string(GF_orbs[0] + 1) + ".dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " + << real(GF[iii][0]) << " " << imag(GF[iii][0]) << std::endl; } - } else { - std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; - fname += std::to_string(GF_orbs[0] + 1) + "_" + - std::to_string(GF_orbs[0] + 1) + ".dat"; - std::ofstream ofile(fname); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++) - ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " - << real(GF[iii][0]) << " " << imag(GF[iii][0]) << std::endl; } -} } // namespace macis From 65db897035ef8723379de242bd6d193005dde8f2 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Mon, 9 Oct 2023 15:11:16 +0000 Subject: [PATCH 27/35] Committing clang-format changes --- include/macis/gf/gf.hpp | 8 +- src/macis/gf/gf.cxx | 161 ++++++++++++++++++++-------------------- 2 files changed, 83 insertions(+), 86 deletions(-) diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index efdf8b6c..bff444aa 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -53,9 +53,9 @@ struct GFSettings { bool print = false; bool saveGFmats = false; double wmin = -8.; - double wmax = 8.; - size_t nws = 2001; - double eta = 0.1; + double wmax = 8.; + size_t nws = 2001; + double eta = 0.1; std::string w_scale = "lin"; bool real_g = true; bool beta = 1.; @@ -76,7 +76,7 @@ struct GFSettings { * @author Carlos Mejuto Zaera * @date 09/10/2023 */ -std::vector > GetGFFreqGrid( const GFSettings& settings ); +std::vector> GetGFFreqGrid(const GFSettings &settings); /** * @brief Gets fermionic sign incurred by inserting an electron of spin diff --git a/src/macis/gf/gf.cxx b/src/macis/gf/gf.cxx index 61e4c536..fb37bab2 100644 --- a/src/macis/gf/gf.cxx +++ b/src/macis/gf/gf.cxx @@ -10,96 +10,93 @@ namespace macis { - std::vector > GetGFFreqGrid( const GFSettings& settings) - { - double wmin = settings.wmin; - double wmax = settings.wmax; - double eta = settings.eta; - double beta = settings.beta; - size_t nws = settings.nws; - bool real_g = settings.real_g; +std::vector > GetGFFreqGrid(const GFSettings &settings) { + double wmin = settings.wmin; + double wmax = settings.wmax; + double eta = settings.eta; + double beta = settings.beta; + size_t nws = settings.nws; + bool real_g = settings.real_g; - std::complex fact(0.,0.); - if( real_g ) - fact = std::complex(1., 0.); - else - { - fact = std::complex( 0., 1.); - eta = 0.; - } + std::complex fact(0., 0.); + if(real_g) + fact = std::complex(1., 0.); + else { + fact = std::complex(0., 1.); + eta = 0.; + } - std::vector > ws( nws, std::complex(0.,0.) ); + std::vector > ws(nws, std::complex(0., 0.)); - std::string scale = settings.w_scale; - if( scale == "lin" ) - { - for( int i = 0; i < nws; i++ ) - ws[i] =fact * ( wmin + (wmax - wmin) / double(nws-1.) * double(i) - + std::complex(0., eta) ); - } - else if( scale == "matsubara" ) - { - if( real_g == true ) - throw(std::runtime_error("Error in GetGFFreqGrid! Asked for 'real' Matsubara frequency grid.")); - for( int i = 0; i < nws; i++ ) - ws[i] = std::complex(0., (2. * double(i) + 1.) * M_PI / beta); - } - else if( scale == "log" ) - { - if( ( wmin < 0. && wmax > 0.) || ( wmin > 0. && wmax < 0. ) ) - throw( std::runtime_error( "Error in GetGFFreqGrid! Requested grid touches or passes by 0." ) ); - for( int i = 0; i < nws; i++ ) - { - double step = std::log(wmin) + ( std::log(wmax) - std::log(wmin) ) / double(nws-1.) * double(i); - ws[i] = fact * std::exp( step ) + std::complex( 0., eta ); - } + std::string scale = settings.w_scale; + if(scale == "lin") { + for(int i = 0; i < nws; i++) + ws[i] = fact * (wmin + (wmax - wmin) / double(nws - 1.) * double(i) + + std::complex(0., eta)); + } else if(scale == "matsubara") { + if(real_g == true) + throw( + std::runtime_error("Error in GetGFFreqGrid! Asked for 'real' " + "Matsubara frequency grid.")); + for(int i = 0; i < nws; i++) + ws[i] = std::complex(0., (2. * double(i) + 1.) * M_PI / beta); + } else if(scale == "log") { + if((wmin < 0. && wmax > 0.) || (wmin > 0. && wmax < 0.)) + throw(std::runtime_error( + "Error in GetGFFreqGrid! Requested grid touches or passes by 0.")); + for(int i = 0; i < nws; i++) { + double step = std::log(wmin) + (std::log(wmax) - std::log(wmin)) / + double(nws - 1.) * double(i); + ws[i] = fact * std::exp(step) + std::complex(0., eta); } - else - throw(std::runtime_error("Error in GetGFFreqGrid! Frequency scale passed is not supported. Options are 'lin', 'log' and 'matsubara'.")); + } else + throw(std::runtime_error( + "Error in GetGFFreqGrid! Frequency scale passed is not supported. " + "Options are 'lin', 'log' and 'matsubara'.")); - return ws; - } + return ws; +} - void write_GF(const std::vector > > &GF, - const std::vector > &ws, - const std::vector &GF_orbs, const std::vector &todelete, - const bool is_part) { - using dbl = std::numeric_limits; - size_t nfreqs = ws.size(); - int GFmat_size = GF_orbs.size() - todelete.size(); - - if(GF_orbs.size() > 1) { - std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; - std::ofstream ofile(fname); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++) { - ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; - for(int jjj = 0; jjj < GFmat_size; jjj++) { - for(int lll = 0; lll < GFmat_size; lll++) - ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) - << " " << imag(GF[iii][jjj * GFmat_size + lll]) << " "; - } - ofile << std::endl; - } - - std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" - : "GFMatrix_OrbitalIndices_SUB.dat"; - std::ofstream ofile2(fname2); - for(int iii = 0; iii < GF_orbs.size(); iii++) { - if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) - continue; - ofile2 << GF_orbs[iii] << std::endl; +void write_GF(const std::vector > > &GF, + const std::vector > &ws, + const std::vector &GF_orbs, const std::vector &todelete, + const bool is_part) { + using dbl = std::numeric_limits; + size_t nfreqs = ws.size(); + int GFmat_size = GF_orbs.size() - todelete.size(); + + if(GF_orbs.size() > 1) { + std::string fname = is_part ? "LanGFMatrix_ADD.dat" : "LanGFMatrix_SUB.dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) { + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " "; + for(int jjj = 0; jjj < GFmat_size; jjj++) { + for(int lll = 0; lll < GFmat_size; lll++) + ofile << std::scientific << real(GF[iii][jjj * GFmat_size + lll]) + << " " << imag(GF[iii][jjj * GFmat_size + lll]) << " "; } - } else { - std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; - fname += std::to_string(GF_orbs[0] + 1) + "_" + - std::to_string(GF_orbs[0] + 1) + ".dat"; - std::ofstream ofile(fname); - ofile.precision(dbl::max_digits10); - for(int iii = 0; iii < nfreqs; iii++) - ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " - << real(GF[iii][0]) << " " << imag(GF[iii][0]) << std::endl; + ofile << std::endl; + } + + std::string fname2 = is_part ? "GFMatrix_OrbitalIndices_ADD.dat" + : "GFMatrix_OrbitalIndices_SUB.dat"; + std::ofstream ofile2(fname2); + for(int iii = 0; iii < GF_orbs.size(); iii++) { + if(std::find(todelete.begin(), todelete.end(), iii) != todelete.end()) + continue; + ofile2 << GF_orbs[iii] << std::endl; } + } else { + std::string fname = is_part ? "LanGF_ADD_" : "LanGF_SUB_"; + fname += std::to_string(GF_orbs[0] + 1) + "_" + + std::to_string(GF_orbs[0] + 1) + ".dat"; + std::ofstream ofile(fname); + ofile.precision(dbl::max_digits10); + for(int iii = 0; iii < nfreqs; iii++) + ofile << std::scientific << real(ws[iii]) << " " << imag(ws[iii]) << " " + << real(GF[iii][0]) << " " << imag(GF[iii][0]) << std::endl; } +} } // namespace macis From 93e48e82522df6ed29de8ef75711a47f85518e20 Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Mon, 6 Nov 2023 14:29:03 +0100 Subject: [PATCH 28/35] Updating calls to submdspan, since mdspan library changed in which namespace this is. --- src/macis/fcidump.cxx | 4 ++-- tests/fock_matrices.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/macis/fcidump.cxx b/src/macis/fcidump.cxx index 9870077c..8adeabdb 100644 --- a/src/macis/fcidump.cxx +++ b/src/macis/fcidump.cxx @@ -134,7 +134,7 @@ void read_fcidump_1body(std::string fname, col_major_span T) { void read_fcidump_1body(std::string fname, double* T, size_t LDT) { auto norb = read_fcidump_norb(fname); col_major_span T_map(T, LDT, norb); - read_fcidump_1body(fname, KokkosEx::submdspan(T_map, std::pair{0, norb}, + read_fcidump_1body(fname, Kokkos::submdspan(T_map, std::pair{0, norb}, Kokkos::full_extent)); } @@ -178,7 +178,7 @@ void read_fcidump_2body(std::string fname, double* V, size_t LDV) { col_major_span V_map(V, LDV, LDV, LDV, norb); auto sl = std::pair{0, norb}; read_fcidump_2body( - fname, KokkosEx::submdspan(V_map, sl, sl, sl, Kokkos::full_extent)); + fname, Kokkos::submdspan(V_map, sl, sl, sl, Kokkos::full_extent)); } bool is_2body_diagonal(std::string fname) { diff --git a/tests/fock_matrices.cxx b/tests/fock_matrices.cxx index 75a84a05..b587583f 100644 --- a/tests/fock_matrices.cxx +++ b/tests/fock_matrices.cxx @@ -93,14 +93,14 @@ TEST_CASE("Fock Matrices") { macis::matrix_span Fi_span(Fi.data(), norb, norb); auto act_range = std::make_pair(ninact.get(), ninact.get() + nact.get()); - auto Fi_active = macis::KokkosEx::submdspan(Fi_span, act_range, act_range); + auto Fi_active = Kokkos::submdspan(Fi_span, act_range, act_range); for(auto i = 0; i < nact.get(); ++i) for(auto j = 0; j < nact.get(); ++j) { REQUIRE(Ta(i, j) == Fi_active(i, j)); } macis::rank4_span V_span(V.data(), norb, norb, norb, norb); - auto V_act_span = macis::KokkosEx::submdspan(V_span, act_range, act_range, + auto V_act_span = Kokkos::submdspan(V_span, act_range, act_range, act_range, act_range); macis::rank4_span Va(V_active.data(), nact.get(), nact.get(), nact.get(), nact.get()); From 18415d516dbe5c14cac998a6fee6059c8a34c1fb Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Mon, 6 Nov 2023 13:29:50 +0000 Subject: [PATCH 29/35] Committing clang-format changes --- src/macis/fcidump.cxx | 8 ++++---- tests/fock_matrices.cxx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/macis/fcidump.cxx b/src/macis/fcidump.cxx index 8adeabdb..7430a46a 100644 --- a/src/macis/fcidump.cxx +++ b/src/macis/fcidump.cxx @@ -134,8 +134,8 @@ void read_fcidump_1body(std::string fname, col_major_span T) { void read_fcidump_1body(std::string fname, double* T, size_t LDT) { auto norb = read_fcidump_norb(fname); col_major_span T_map(T, LDT, norb); - read_fcidump_1body(fname, Kokkos::submdspan(T_map, std::pair{0, norb}, - Kokkos::full_extent)); + read_fcidump_1body( + fname, Kokkos::submdspan(T_map, std::pair{0, norb}, Kokkos::full_extent)); } void read_fcidump_2body(std::string fname, col_major_span V) { @@ -177,8 +177,8 @@ void read_fcidump_2body(std::string fname, double* V, size_t LDV) { auto norb = read_fcidump_norb(fname); col_major_span V_map(V, LDV, LDV, LDV, norb); auto sl = std::pair{0, norb}; - read_fcidump_2body( - fname, Kokkos::submdspan(V_map, sl, sl, sl, Kokkos::full_extent)); + read_fcidump_2body(fname, + Kokkos::submdspan(V_map, sl, sl, sl, Kokkos::full_extent)); } bool is_2body_diagonal(std::string fname) { diff --git a/tests/fock_matrices.cxx b/tests/fock_matrices.cxx index b587583f..877c4e9b 100644 --- a/tests/fock_matrices.cxx +++ b/tests/fock_matrices.cxx @@ -100,8 +100,8 @@ TEST_CASE("Fock Matrices") { } macis::rank4_span V_span(V.data(), norb, norb, norb, norb); - auto V_act_span = Kokkos::submdspan(V_span, act_range, act_range, - act_range, act_range); + auto V_act_span = + Kokkos::submdspan(V_span, act_range, act_range, act_range, act_range); macis::rank4_span Va(V_active.data(), nact.get(), nact.get(), nact.get(), nact.get()); for(auto i = 0; i < nact.get(); ++i) From e38bdbfac1aa69dafd581b8e2f066d4dc2f6ec2e Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Mon, 28 Oct 2024 09:50:23 +0100 Subject: [PATCH 30/35] Added option to ask for multiple eigenstates in selected_ci_diag. Calls LOBPCG with random guess vectors --- include/macis/asci/grow.hpp | 2 +- include/macis/asci/iteration.hpp | 2 +- include/macis/solvers/lobpcg.hpp | 114 +++++++++++++++++++++ include/macis/solvers/selected_ci_diag.hpp | 64 +++++++++--- include/macis/util/cas.hpp | 2 +- include/macis/util/mcscf.hpp | 2 + tests/sd_build.cxx | 2 +- tests/standalone_driver.cxx | 2 + 8 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 include/macis/solvers/lobpcg.hpp diff --git a/include/macis/asci/grow.hpp b/include/macis/asci/grow.hpp index 5833fb39..a54992af 100644 --- a/include/macis/asci/grow.hpp +++ b/include/macis/asci/grow.hpp @@ -128,7 +128,7 @@ auto asci_grow(ASCISettings asci_settings, MCSCFSettings mcscf_settings, selected_ci_diag( wfn.begin(), wfn.end(), ham_gen, mcscf_settings.ci_matel_tol, mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, - X_local MACIS_MPI_CODE(, comm)); + X_local MACIS_MPI_CODE(, comm), false, mcscf_settings.ci_nstates ); if(world_size > 1) { #ifdef MACIS_ENABLE_MPI diff --git a/include/macis/asci/iteration.hpp b/include/macis/asci/iteration.hpp index 55a86eb2..d6d489e2 100644 --- a/include/macis/asci/iteration.hpp +++ b/include/macis/asci/iteration.hpp @@ -34,7 +34,7 @@ auto asci_iter(ASCISettings asci_settings, MCSCFSettings mcscf_settings, auto E = selected_ci_diag( wfn.begin(), wfn.end(), ham_gen, mcscf_settings.ci_matel_tol, mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, - X_local MACIS_MPI_CODE(, comm)); + X_local MACIS_MPI_CODE(, comm), false, mcscf_settings.ci_nstates); #ifdef MACIS_ENABLE_MPI auto world_size = comm_size(comm); diff --git a/include/macis/solvers/lobpcg.hpp b/include/macis/solvers/lobpcg.hpp new file mode 100644 index 00000000..72029a1b --- /dev/null +++ b/include/macis/solvers/lobpcg.hpp @@ -0,0 +1,114 @@ +/* + * 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 lobpcg.h++ + * + * @brief Implements simple call to LOBPCG to get the lowest few + * eigenstates of a given matrix. + * + * @author Carlos Mejuto Zaera + * @date 25/10/2024 + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace macis { + +/** + * @brief Perform a band Lanczos calculation on the Hamiltonian operator H, starting from vectors qs, for at most nLanIts + * iterations. Returns the first len(qs) eigenvalues, converged to some accuracy. 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] typename Functor &H: Hamiltonian oprator. Just needs to implement a matrix vector product. + * @param[in] std::vector > &qs: Initial set of vetors to perform the band Lanczos on. Deleted on exit. + * @param[out] std::vector &evals: Lowest len(qs) eigenvalues. + * @param[out] std::vector > &evecs: Lowest len(qs) eigenvectors, in the Krylov basis. + * @param[in] int &nLanIts: Number of Lanczos iterations to perform. + * @param[in] double tol: Target tolerance for the eigenvalue convergence. + * @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/10/2024 + */ +template +void LobpcgGS( + size_t dimH, + size_t nstates, + const Functor& H, + std::vector &evals, + std::vector &X, + int maxIts, + double tol = 1.E-8, + bool print = false ) +{ + // Run LOBPCG to get the first few eigenstates of a given + // Hamiltonian + evals.clear(); evals.resize( nstates, 0. ); + X.clear(); X.resize( dimH * nstates, 0. ); + // Hop + lobpcgxx::operator_action_type Hop = + [&]( int64_t n , int64_t k , const double* x , int64_t ldx , + double* y , int64_t ldy ) -> void { + + for( int ik = 0; ik < k; ik++) + H.operator_action(1, 1., x+ik*n, n, 0., y+ik*n, n ); + }; + + // Random vectors + std::default_random_engine gen; + std::normal_distribution<> dist(0., 1.); + auto rand_gen = [&](){ return dist(gen); }; + std::generate( X.begin(), X.end(), rand_gen ); + lobpcgxx::cholqr( dimH, nstates, X.data(), dimH ); // Orthogonalize + + lobpcgxx::lobpcg_settings settings; + settings.conv_tol = tol; + settings.maxiter = maxIts; + lobpcgxx::lobpcg_operator lob_op( Hop ); + + + + std::vector res(nstates); + + try + { + lobpcgxx::lobpcg( settings, dimH , nstates , nstates, + lob_op, evals.data(), X.data(), dimH, + res.data() ); + } + catch( std::runtime_error e ) + { + std::cout << "Runtime error during lobpcg: " << e.what() << std::endl; + } + + if( print ) + { + std::cout << std::scientific << std::setprecision(10) << std::endl ; + for ( int64_t i = 0; i < nstates; ++i ) { + std::cout << " evals[" << i << "] = " << evals[i] + << ", res[" << i << "] = " << res[i] + << std::endl ; + } + } + +} + +}// namespace macis diff --git a/include/macis/solvers/selected_ci_diag.hpp b/include/macis/solvers/selected_ci_diag.hpp index 0a1e293f..41ef723a 100644 --- a/include/macis/solvers/selected_ci_diag.hpp +++ b/include/macis/solvers/selected_ci_diag.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,8 @@ namespace macis { template double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, double davidson_res_tol, - std::vector& C_local, MPI_Comm comm) { + std::vector& C_local, MPI_Comm comm, + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -56,10 +58,28 @@ double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, // Solve EVP MPI_Barrier(comm); auto dav_st = clock_type::now(); - - auto [niter, E] = - p_davidson(H.local_row_extent(), davidson_max_m, op, D_local.data(), - davidson_res_tol, C_local.data() MACIS_MPI_CODE(, H.comm())); + double E = 0.; + size_t niter = 0; + + if( nstates == 1 ) + { + auto [niter0, E0] = + p_davidson(H.local_row_extent(), davidson_max_m, op, D_local.data(), + davidson_res_tol, C_local.data() MACIS_MPI_CODE(, H.comm())); + niter = niter0; E = E0; + } + else + { + std::vector evals; + std::vector evecs; + LobpcgGS( H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol ); + logger->info(" Hamiltonian Eigenvalues:"); + for( int ii = 0; ii < nstates; ii++ ) + logger->info(" --> Eval #{:4}: {:.6e}", ii, evals[ii]); + E = evals[0]; + for( int ii = 0; ii < H.m(); ii++ ) + C_local[ii] = evecs[ii]; + } MPI_Barrier(comm); auto dav_en = clock_type::now(); @@ -75,7 +95,8 @@ double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, template double serial_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, double davidson_res_tol, - std::vector& C) { + std::vector& C, + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -108,9 +129,27 @@ double serial_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, // Solve EVP auto dav_st = clock_type::now(); - - auto [niter, E] = - davidson(H.m(), davidson_max_m, op, D.data(), davidson_res_tol, C.data()); + double E = 0.; + size_t niter = 0; + + if( nstates == 1 ) + { + auto [niter0, E0] = + davidson(H.m(), davidson_max_m, op, D.data(), davidson_res_tol, C.data()); + niter = niter0; E = E0; + } + else + { + std::vector evals; + std::vector evecs; + LobpcgGS( H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol ); + logger->info(" Hamiltonian Eigenvalues:"); + for( int ii = 0; ii < nstates; ii++ ) + logger->info(" --> Eval #{:4}: {:.6e}", ii, evals[ii]); + E = evals[0]; + for( int ii = 0; ii < H.m(); ii++ ) + C[ii] = evecs[ii]; + } auto dav_en = clock_type::now(); @@ -128,7 +167,8 @@ double selected_ci_diag(wavefunction_iterator_t dets_begin, size_t davidson_max_m, double davidson_res_tol, std::vector& C_local, MACIS_MPI_CODE(MPI_Comm comm, ) - const bool quiet = false) { + const bool quiet = false, + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -197,10 +237,10 @@ double selected_ci_diag(wavefunction_iterator_t dets_begin, // Solve EVP #ifdef MACIS_ENABLE_MPI auto E = parallel_selected_ci_diag(H, davidson_max_m, davidson_res_tol, - C_local, comm); + C_local, comm, nstates); #else auto E = - serial_selected_ci_diag(H, davidson_max_m, davidson_res_tol, C_local); + serial_selected_ci_diag(H, davidson_max_m, davidson_res_tol, C_local, nstates); #endif return E; diff --git a/include/macis/util/cas.hpp b/include/macis/util/cas.hpp index 63c8f4a2..304aae1a 100644 --- a/include/macis/util/cas.hpp +++ b/include/macis/util/cas.hpp @@ -53,7 +53,7 @@ double compute_casci_rdms( double E0 = selected_ci_diag(dets.begin(), dets.end(), ham_gen, settings.ci_matel_tol, settings.ci_max_subspace, settings.ci_res_tol, C, - MACIS_MPI_CODE(comm, ) true); + MACIS_MPI_CODE(comm, ) true, settings.ci_nstates); // Compute RDMs ham_gen.form_rdms(dets.begin(), dets.end(), dets.begin(), dets.end(), diff --git a/include/macis/util/mcscf.hpp b/include/macis/util/mcscf.hpp index 9ff31b8f..b49936ef 100644 --- a/include/macis/util/mcscf.hpp +++ b/include/macis/util/mcscf.hpp @@ -27,6 +27,8 @@ struct MCSCFSettings { double ci_res_tol = 1e-8; size_t ci_max_subspace = 20; double ci_matel_tol = std::numeric_limits::epsilon(); + + size_t ci_nstates = 1; }; double casscf_diis(MCSCFSettings settings, NumElectron nalpha, diff --git a/tests/sd_build.cxx b/tests/sd_build.cxx index 9c2a0760..9a779920 100644 --- a/tests/sd_build.cxx +++ b/tests/sd_build.cxx @@ -104,7 +104,7 @@ TEST_CASE("Single Double Build") { double E0 = macis::selected_ci_diag( dets.begin(), dets.end(), ham_gen, mcscf_settings.ci_matel_tol, mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, C_local, - MACIS_MPI_CODE(MPI_COMM_WORLD, ) true); + MACIS_MPI_CODE(MPI_COMM_WORLD, ) true, mcscf_settings.ci_nstates); E0 += E_inactive + E_core; // Compute RDMs ham_gen.form_rdms( diff --git a/tests/standalone_driver.cxx b/tests/standalone_driver.cxx index 5b64cc21..5db07c76 100644 --- a/tests/standalone_driver.cxx +++ b/tests/standalone_driver.cxx @@ -167,6 +167,8 @@ int main(int argc, char** argv) { OPT_KEYWORD("MCSCF.CI_MAX_SUB", mcscf_settings.ci_max_subspace, size_t); OPT_KEYWORD("MCSCF.CI_MATEL_TOL", mcscf_settings.ci_matel_tol, double); + OPT_KEYWORD("MCSCF.CI_NSTATES", mcscf_settings.ci_nstates, size_t); + // ASCI Settings macis::ASCISettings asci_settings; std::string asci_wfn_fname, asci_wfn_out_fname; From fa2442a6b13b21bdc654acde1d555932a04a9650 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Mon, 28 Oct 2024 08:51:12 +0000 Subject: [PATCH 31/35] Committing clang-format changes --- include/macis/asci/grow.hpp | 2 +- include/macis/solvers/lobpcg.hpp | 106 ++++++++++----------- include/macis/solvers/selected_ci_diag.hpp | 51 +++++----- 3 files changed, 72 insertions(+), 87 deletions(-) diff --git a/include/macis/asci/grow.hpp b/include/macis/asci/grow.hpp index a54992af..4ea0c32c 100644 --- a/include/macis/asci/grow.hpp +++ b/include/macis/asci/grow.hpp @@ -128,7 +128,7 @@ auto asci_grow(ASCISettings asci_settings, MCSCFSettings mcscf_settings, selected_ci_diag( wfn.begin(), wfn.end(), ham_gen, mcscf_settings.ci_matel_tol, mcscf_settings.ci_max_subspace, mcscf_settings.ci_res_tol, - X_local MACIS_MPI_CODE(, comm), false, mcscf_settings.ci_nstates ); + X_local MACIS_MPI_CODE(, comm), false, mcscf_settings.ci_nstates); if(world_size > 1) { #ifdef MACIS_ENABLE_MPI diff --git a/include/macis/solvers/lobpcg.hpp b/include/macis/solvers/lobpcg.hpp index 72029a1b..5bb1c785 100644 --- a/include/macis/solvers/lobpcg.hpp +++ b/include/macis/solvers/lobpcg.hpp @@ -17,98 +17,90 @@ */ #pragma once #include -#include +#include + #include +#include #include #include -#include -#include -#include #include +#include #include -#include #include +#include +#include namespace macis { /** - * @brief Perform a band Lanczos calculation on the Hamiltonian operator H, starting from vectors qs, for at most nLanIts - * iterations. Returns the first len(qs) eigenvalues, converged to some accuracy. 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). + * @brief Perform a band Lanczos calculation on the Hamiltonian operator H, + * starting from vectors qs, for at most nLanIts iterations. Returns the first + * len(qs) eigenvalues, converged to some accuracy. 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] typename Functor &H: Hamiltonian oprator. Just needs to implement a matrix vector product. - * @param[in] std::vector > &qs: Initial set of vetors to perform the band Lanczos on. Deleted on exit. + * @param[in] typename Functor &H: Hamiltonian oprator. Just needs to implement + * a matrix vector product. + * @param[in] std::vector > &qs: Initial set of vetors to + * perform the band Lanczos on. Deleted on exit. * @param[out] std::vector &evals: Lowest len(qs) eigenvalues. - * @param[out] std::vector > &evecs: Lowest len(qs) eigenvectors, in the Krylov basis. + * @param[out] std::vector > &evecs: Lowest len(qs) + * eigenvectors, in the Krylov basis. * @param[in] int &nLanIts: Number of Lanczos iterations to perform. * @param[in] double tol: Target tolerance for the eigenvalue convergence. - * @param[in] double thres: Threshold determining when to ignore beta's for being too small. + * @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/10/2024 - */ + */ template -void LobpcgGS( - size_t dimH, - size_t nstates, - const Functor& H, - std::vector &evals, - std::vector &X, - int maxIts, - double tol = 1.E-8, - bool print = false ) -{ +void LobpcgGS(size_t dimH, size_t nstates, const Functor& H, + std::vector& evals, std::vector& X, int maxIts, + double tol = 1.E-8, bool print = false) { // Run LOBPCG to get the first few eigenstates of a given // Hamiltonian - evals.clear(); evals.resize( nstates, 0. ); - X.clear(); X.resize( dimH * nstates, 0. ); + evals.clear(); + evals.resize(nstates, 0.); + X.clear(); + X.resize(dimH * nstates, 0.); // Hop - lobpcgxx::operator_action_type Hop = - [&]( int64_t n , int64_t k , const double* x , int64_t ldx , - double* y , int64_t ldy ) -> void { - - for( int ik = 0; ik < k; ik++) - H.operator_action(1, 1., x+ik*n, n, 0., y+ik*n, n ); - }; + lobpcgxx::operator_action_type Hop = + [&](int64_t n, int64_t k, const double* x, int64_t ldx, double* y, + int64_t ldy) -> void { + for(int ik = 0; ik < k; ik++) + H.operator_action(1, 1., x + ik * n, n, 0., y + ik * n, n); + }; - // Random vectors + // Random vectors std::default_random_engine gen; std::normal_distribution<> dist(0., 1.); - auto rand_gen = [&](){ return dist(gen); }; - std::generate( X.begin(), X.end(), rand_gen ); - lobpcgxx::cholqr( dimH, nstates, X.data(), dimH ); // Orthogonalize + auto rand_gen = [&]() { return dist(gen); }; + std::generate(X.begin(), X.end(), rand_gen); + lobpcgxx::cholqr(dimH, nstates, X.data(), dimH); // Orthogonalize lobpcgxx::lobpcg_settings settings; settings.conv_tol = tol; - settings.maxiter = maxIts; - lobpcgxx::lobpcg_operator lob_op( Hop ); - - + settings.maxiter = maxIts; + lobpcgxx::lobpcg_operator lob_op(Hop); std::vector res(nstates); - try - { - lobpcgxx::lobpcg( settings, dimH , nstates , nstates, - lob_op, evals.data(), X.data(), dimH, - res.data() ); - } - catch( std::runtime_error e ) - { + try { + lobpcgxx::lobpcg(settings, dimH, nstates, nstates, lob_op, evals.data(), + X.data(), dimH, res.data()); + } catch(std::runtime_error e) { std::cout << "Runtime error during lobpcg: " << e.what() << std::endl; } - if( print ) - { - std::cout << std::scientific << std::setprecision(10) << std::endl ; - for ( int64_t i = 0; i < nstates; ++i ) { - std::cout << " evals[" << i << "] = " << evals[i] - << ", res[" << i << "] = " << res[i] - << std::endl ; + if(print) { + std::cout << std::scientific << std::setprecision(10) << std::endl; + for(int64_t i = 0; i < nstates; ++i) { + std::cout << " evals[" << i << "] = " << evals[i] << ", res[" << i + << "] = " << res[i] << std::endl; } } - } -}// namespace macis +} // namespace macis diff --git a/include/macis/solvers/selected_ci_diag.hpp b/include/macis/solvers/selected_ci_diag.hpp index 41ef723a..72316c8b 100644 --- a/include/macis/solvers/selected_ci_diag.hpp +++ b/include/macis/solvers/selected_ci_diag.hpp @@ -24,7 +24,7 @@ template double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, double davidson_res_tol, std::vector& C_local, MPI_Comm comm, - const size_t nstates = 1) { + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -61,24 +61,21 @@ double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, double E = 0.; size_t niter = 0; - if( nstates == 1 ) - { + if(nstates == 1) { auto [niter0, E0] = p_davidson(H.local_row_extent(), davidson_max_m, op, D_local.data(), davidson_res_tol, C_local.data() MACIS_MPI_CODE(, H.comm())); - niter = niter0; E = E0; - } - else - { + niter = niter0; + E = E0; + } else { std::vector evals; std::vector evecs; - LobpcgGS( H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol ); + LobpcgGS(H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol); logger->info(" Hamiltonian Eigenvalues:"); - for( int ii = 0; ii < nstates; ii++ ) + for(int ii = 0; ii < nstates; ii++) logger->info(" --> Eval #{:4}: {:.6e}", ii, evals[ii]); E = evals[0]; - for( int ii = 0; ii < H.m(); ii++ ) - C_local[ii] = evecs[ii]; + for(int ii = 0; ii < H.m(); ii++) C_local[ii] = evecs[ii]; } MPI_Barrier(comm); @@ -94,9 +91,8 @@ double parallel_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, template double serial_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, - double davidson_res_tol, - std::vector& C, - const size_t nstates = 1) { + double davidson_res_tol, std::vector& C, + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -132,23 +128,20 @@ double serial_selected_ci_diag(const SpMatType& H, size_t davidson_max_m, double E = 0.; size_t niter = 0; - if( nstates == 1 ) - { - auto [niter0, E0] = - davidson(H.m(), davidson_max_m, op, D.data(), davidson_res_tol, C.data()); - niter = niter0; E = E0; - } - else - { + if(nstates == 1) { + auto [niter0, E0] = davidson(H.m(), davidson_max_m, op, D.data(), + davidson_res_tol, C.data()); + niter = niter0; + E = E0; + } else { std::vector evals; std::vector evecs; - LobpcgGS( H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol ); + LobpcgGS(H.m(), nstates, op, evals, evecs, 10000, davidson_res_tol); logger->info(" Hamiltonian Eigenvalues:"); - for( int ii = 0; ii < nstates; ii++ ) + for(int ii = 0; ii < nstates; ii++) logger->info(" --> Eval #{:4}: {:.6e}", ii, evals[ii]); E = evals[0]; - for( int ii = 0; ii < H.m(); ii++ ) - C[ii] = evecs[ii]; + for(int ii = 0; ii < H.m(); ii++) C[ii] = evecs[ii]; } auto dav_en = clock_type::now(); @@ -168,7 +161,7 @@ double selected_ci_diag(wavefunction_iterator_t dets_begin, std::vector& C_local, MACIS_MPI_CODE(MPI_Comm comm, ) const bool quiet = false, - const size_t nstates = 1) { + const size_t nstates = 1) { auto logger = spdlog::get("ci_solver"); if(!logger) { logger = spdlog::stdout_color_mt("ci_solver"); @@ -239,8 +232,8 @@ double selected_ci_diag(wavefunction_iterator_t dets_begin, auto E = parallel_selected_ci_diag(H, davidson_max_m, davidson_res_tol, C_local, comm, nstates); #else - auto E = - serial_selected_ci_diag(H, davidson_max_m, davidson_res_tol, C_local, nstates); + auto E = serial_selected_ci_diag(H, davidson_max_m, davidson_res_tol, C_local, + nstates); #endif return E; From b2d334eb5bdec05e3b51539e67dea444c98e845a Mon Sep 17 00:00:00 2001 From: Carlos Mejuto Zaera Date: Tue, 26 Nov 2024 13:26:58 +0100 Subject: [PATCH 32/35] Added minor modification to make Band Lanczos computation of the GF compatible with comlpex wave functions. The normal Lanczos calculation of off-diagonal elements is not appropriate for complex wave functions, though. --- include/macis/gf/gf.hpp | 1 + src/macis/gf/bandlan.cxx | 32 +++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index bff444aa..97b2d99a 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -638,6 +638,7 @@ void RunGFCalc(std::vector>> &GF, for(int iw = 0; iw < ws.size(); iw++) GF[iw][i * nvecs + i] = tGF[iw]; for(int j = i + 1; j < nvecs; j++) { // OFF DIAGONAL ELEMENTS + // NOTE: WORKS ONLY FOR REAL-VALUED WAVE FUNCTIONS. std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; for(size_t iii = 0; iii < nterms; iii++) twfn(iii) = wfns[i * nterms + iii] + wfns[j * nterms + iii]; diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index f748f69c..4e2ffbc8 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -325,14 +325,32 @@ void BandResolvent( ofile.close(); } std::cout << "DONE! COMPUTING RESOLVENT ..."; + if( ispart ) + { #pragma omp parallel for - for(int iw = 0; iw < ws.size(); iw++) { - for(int k = 0; k < nvecs; k++) { - for(int l = 0; l < nvecs; l++) { - for(int i_lan = 0; i_lan < nLanIts; i_lan++) { - res[iw][k * nvecs + l] += S[i_lan * nvecs + k] * 1. / - (ws[iw] + eigvals[i_lan]) * - S[i_lan * nvecs + l]; + for(int iw = 0; iw < ws.size(); iw++) { + for(int k = 0; k < nvecs; k++) { + for(int l = 0; l < nvecs; l++) { + for(int i_lan = 0; i_lan < nLanIts; i_lan++) { + res[iw][k * nvecs + l] += S[i_lan * nvecs + k] * 1. / + (ws[iw] + eigvals[i_lan]) * + S[i_lan * nvecs + l]; + } + } + } + } + } + else + { +#pragma omp parallel for + for(int iw = 0; iw < ws.size(); iw++) { + for(int k = 0; k < nvecs; k++) { + for(int l = 0; l < nvecs; l++) { + for(int i_lan = 0; i_lan < nLanIts; i_lan++) { + res[iw][l * nvecs + k] += S[i_lan * nvecs + k] * 1. / + (ws[iw] + eigvals[i_lan]) * + S[i_lan * nvecs + l]; + } } } } From 365a871684096e3d4b9279990b540c5d26c9ce51 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Tue, 26 Nov 2024 12:27:39 +0000 Subject: [PATCH 33/35] Committing clang-format changes --- include/macis/gf/gf.hpp | 2 +- src/macis/gf/bandlan.cxx | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/macis/gf/gf.hpp b/include/macis/gf/gf.hpp index 97b2d99a..ad2272a7 100644 --- a/include/macis/gf/gf.hpp +++ b/include/macis/gf/gf.hpp @@ -638,7 +638,7 @@ void RunGFCalc(std::vector>> &GF, for(int iw = 0; iw < ws.size(); iw++) GF[iw][i * nvecs + i] = tGF[iw]; for(int j = i + 1; j < nvecs; j++) { // OFF DIAGONAL ELEMENTS - // NOTE: WORKS ONLY FOR REAL-VALUED WAVE FUNCTIONS. + // NOTE: WORKS ONLY FOR REAL-VALUED WAVE FUNCTIONS. std::cout << "DOING ELEMENT (" << i << ", " << j << ")" << std::endl; for(size_t iii = 0; iii < nterms; iii++) twfn(iii) = wfns[i * nterms + iii] + wfns[j * nterms + iii]; diff --git a/src/macis/gf/bandlan.cxx b/src/macis/gf/bandlan.cxx index 4e2ffbc8..2662ce72 100644 --- a/src/macis/gf/bandlan.cxx +++ b/src/macis/gf/bandlan.cxx @@ -325,8 +325,7 @@ void BandResolvent( ofile.close(); } std::cout << "DONE! COMPUTING RESOLVENT ..."; - if( ispart ) - { + if(ispart) { #pragma omp parallel for for(int iw = 0; iw < ws.size(); iw++) { for(int k = 0; k < nvecs; k++) { @@ -339,9 +338,7 @@ void BandResolvent( } } } - } - else - { + } else { #pragma omp parallel for for(int iw = 0; iw < ws.size(); iw++) { for(int k = 0; k < nvecs; k++) { From 7e6eb0257d00591e30e1c59b30f55efe62b753f3 Mon Sep 17 00:00:00 2001 From: carlos mejuto zaera Date: Fri, 7 Mar 2025 14:11:49 +0100 Subject: [PATCH 34/35] Changed Fetch command for blaspp, to refer to most recent commit. Was needed to resolve some compilation issues. --- include/macis/gf/lanczos.hpp | 9 ++++++--- include/macis/sd_operations.hpp | 1 + include/macis/util/orbital_rotation_utilities.hpp | 1 + src/lobpcgxx/CMakeLists.txt | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index 97677769..0a1779b2 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -603,9 +603,12 @@ void GetGS(const MatOp &H, double &E0, Eigen::VectorXd &psi0, int64_t n = H.rows(); // Initial vector. We choose (1,0,0,0,...)t // for HF, Otherwhise (1,1,1,1,...)t - Eigen::VectorXd start_psi = - isHF ? Eigen::VectorXd::Zero(n) : Eigen::VectorXd::Ones(n); - start_psi(0) = 1.; + Eigen::VectorXd start_psi = Eigen::VectorXd::Ones(n); + if( isHF ) + { + start_psi= Eigen::VectorXd::Zero(n); + start_psi(0) = 1.; + } // Determine lowest eigenvalue for the given // tolerance. Eigen::VectorXd psi0_Lan; diff --git a/include/macis/sd_operations.hpp b/include/macis/sd_operations.hpp index 7c889134..0ce4e56b 100644 --- a/include/macis/sd_operations.hpp +++ b/include/macis/sd_operations.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace macis { diff --git a/include/macis/util/orbital_rotation_utilities.hpp b/include/macis/util/orbital_rotation_utilities.hpp index fee7bb1a..749e212f 100644 --- a/include/macis/util/orbital_rotation_utilities.hpp +++ b/include/macis/util/orbital_rotation_utilities.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include namespace macis { diff --git a/src/lobpcgxx/CMakeLists.txt b/src/lobpcgxx/CMakeLists.txt index 6b77a88d..1feef8ea 100644 --- a/src/lobpcgxx/CMakeLists.txt +++ b/src/lobpcgxx/CMakeLists.txt @@ -21,7 +21,7 @@ if(NOT lapackpp_FOUND ) include( FetchContent ) FetchContent_Declare( blaspp GIT_REPOSITORY https://github.com/icl-utk-edu/blaspp.git - GIT_TAG 01b5678bb764755254e907e6c56d4054b0ebabc1 + #GIT_TAG 01b5678bb764755254e907e6c56d4054b0ebabc1 ) FetchContent_Declare( lapackpp GIT_REPOSITORY https://github.com/icl-utk-edu/lapackpp.git From 8930b91bbe10e3ad85d286a12b432fdb1f48ba63 Mon Sep 17 00:00:00 2001 From: Clang Robot Date: Fri, 7 Mar 2025 13:12:35 +0000 Subject: [PATCH 35/35] Committing clang-format changes --- include/macis/gf/lanczos.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/macis/gf/lanczos.hpp b/include/macis/gf/lanczos.hpp index 0a1779b2..97b893c7 100644 --- a/include/macis/gf/lanczos.hpp +++ b/include/macis/gf/lanczos.hpp @@ -604,10 +604,9 @@ void GetGS(const MatOp &H, double &E0, Eigen::VectorXd &psi0, // Initial vector. We choose (1,0,0,0,...)t // for HF, Otherwhise (1,1,1,1,...)t Eigen::VectorXd start_psi = Eigen::VectorXd::Ones(n); - if( isHF ) - { - start_psi= Eigen::VectorXd::Zero(n); - start_psi(0) = 1.; + if(isHF) { + start_psi = Eigen::VectorXd::Zero(n); + start_psi(0) = 1.; } // Determine lowest eigenvalue for the given // tolerance.