1 /* 2 * This source code is part of 3 * 4 * HelFEM 5 * - 6 * Finite element methods for electronic structure calculations on small systems 7 * 8 * Written by Susi Lehtola, 2018- 9 * Copyright (c) 2018- Susi Lehtola 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 2 14 * of the License, or (at your option) any later version. 15 */ 16 17 #ifndef SADATOM_DFTGRID_H 18 #define SADATOM_DFTGRID_H 19 20 #include "basis.h" 21 22 namespace helfem { 23 namespace sadatom { 24 namespace dftgrid { 25 26 /// Worker class 27 class DFTGridWorker { 28 protected: 29 /// Basis set 30 const helfem::sadatom::basis::TwoDBasis *basp; 31 32 /// Total quadrature weight 33 arma::rowvec wtot; 34 35 /// List of basis functions in element 36 arma::uvec bf_ind; 37 /// Values of important functions in grid points, Nbf * Ngrid 38 arma::mat bf; 39 /// Radial gradient 40 arma::mat bf_rho; 41 42 /// Density helper matrices: P_{uv} chi_v, and P_{uv} nabla(chi_v) 43 arma::mat Pv, Pv_rho; 44 /// Same for spin-polarized 45 arma::mat Pav, Pav_rho; 46 arma::mat Pbv, Pbv_rho; 47 48 /// Is gradient needed? 49 bool do_grad; 50 /// Is kinetic energy density needed? 51 bool do_tau; 52 /// Is laplacian needed? 53 bool do_lapl; 54 55 /// Spin-polarized calculation? 56 bool polarized; 57 58 /// GGA functional used? (Set in compute_xc, only affects eval_Fxc) 59 bool do_gga; 60 /// Meta-GGA tau used? (Set in compute_xc, only affects eval_Fxc) 61 bool do_mgga_t; 62 /// Meta-GGA lapl used? (Set in compute_xc, only affects eval_Fxc) 63 bool do_mgga_l; 64 65 // LDA stuff: 66 67 /// Density, Nrho x Npts 68 arma::mat rho; 69 /// Energy density, Npts 70 arma::rowvec exc; 71 /// Functional derivative of energy wrt electron density, Nrho x Npts 72 arma::mat vxc; 73 74 // GGA stuff 75 76 /// Gradient of electron density, (3 x Nrho) x Npts 77 arma::mat grho; 78 /// Dot products of gradient of electron density, N x Npts; N=1 for closed-shell and 3 for open-shell 79 arma::mat sigma; 80 /// Functional derivative of energy wrt gradient of electron density 81 arma::mat vsigma; 82 83 // Meta-GGA stuff 84 85 /// Laplacian of electron density 86 arma::mat lapl; 87 /// Kinetic energy density 88 arma::mat tau; 89 90 /// Functional derivative of energy wrt laplacian of electron density 91 arma::mat vlapl; 92 /// Functional derivative of energy wrt kinetic energy density 93 arma::mat vtau; 94 95 public: 96 /// Dummy constructor 97 DFTGridWorker(); 98 /// Constructor 99 DFTGridWorker(const helfem::sadatom::basis::TwoDBasis * basp); 100 /// Destructor 101 ~DFTGridWorker(); 102 103 /// Check necessity of computing gradient and laplacians, necessary for compute_bf! 104 void check_grad_tau_lapl(int x_func, int c_func); 105 /// Get necessity of computing gradient and laplacians 106 void get_grad_tau_lapl(bool & grad, bool & tau, bool & lapl) const; 107 /// Set necessity of computing gradient and laplacians, necessary for compute_bf! 108 void set_grad_tau_lapl(bool grad, bool tau, bool lapl); 109 110 /// Compute basis functions on grid points 111 void compute_bf(size_t iel); 112 /// Free memory 113 void free(); 114 115 /// Update values of density, restricted calculation 116 void update_density(const arma::mat & P); 117 /// Update values of density, unrestricted calculation 118 void update_density(const arma::mat & Pa, const arma::mat & Pb); 119 /// Screen out small densities 120 void screen_density(double thr); 121 122 /// Compute number of electrons 123 double compute_Nel() const; 124 125 /// Initialize XC arrays 126 void init_xc(); 127 /// Compute XC functional from density and add to total XC 128 /// array. Pot toggles evaluation of potential 129 void compute_xc(int func_id, const arma::vec & params, bool pot=true); 130 /// Evaluate exchange/correlation energy 131 double eval_Exc() const; 132 /// Zero out energy 133 void zero_Exc(); 134 135 /// Evaluate overlap matrix 136 void eval_overlap(arma::mat & S) const; 137 138 /// Evaluate Fock matrix, restricted calculation 139 void eval_Fxc(arma::mat & H) const; 140 /// Evaluate Fock matrix, unrestricted calculation 141 void eval_Fxc(arma::mat & Ha, arma::mat & Hb, bool beta=true) const; 142 }; 143 144 /// Wrapper routine 145 class DFTGrid { 146 private: 147 /// Pointer to basis set 148 const helfem::sadatom::basis::TwoDBasis * basp; 149 150 public: 151 /// Dummy constructor 152 DFTGrid(); 153 /// Constructor 154 DFTGrid(const helfem::sadatom::basis::TwoDBasis * basp); 155 /// Destructor 156 ~DFTGrid(); 157 158 /// Compute Fock matrix, exchange-correlation energy and integrated electron density, restricted case 159 void eval_Fxc(int x_func, const arma::vec & x_pars, int c_func, const arma::vec & c_pars, const arma::mat & P, arma::mat & H, double & Exc, double & Nel, double thr); 160 /// Compute Fock matrix, exchange-correlation energy and integrated electron density, unrestricted case 161 void eval_Fxc(int x_func, const arma::vec & x_pars, int c_func, const arma::vec & c_pars, const arma::mat & Pa, const arma::mat & Pb, arma::mat & Ha, arma::mat & Hb, double & Exc, double & Nel, bool beta, double thr); 162 163 /// Evaluate overlap 164 arma::mat eval_overlap(); 165 }; 166 167 /// BLAS routine for LDA-type quadrature increment_lda(arma::mat & H,const arma::rowvec & vxc,const arma::Mat<T> & f)168 template<typename T> void increment_lda(arma::mat & H, const arma::rowvec & vxc, const arma::Mat<T> & f) { 169 if(f.n_cols != vxc.n_elem) { 170 std::ostringstream oss; 171 oss << "Number of functions " << f.n_cols << " and potential values " << vxc.n_elem << " do not match!\n"; 172 throw std::runtime_error(oss.str()); 173 } 174 if(H.n_rows != f.n_rows || H.n_cols != f.n_rows) { 175 std::ostringstream oss; 176 oss << "Size of basis function (" << f.n_rows << "," << f.n_cols << ") and Fock matrix (" << H.n_rows << "," << H.n_cols << ") doesn't match!\n"; 177 throw std::runtime_error(oss.str()); 178 } 179 180 // Form helper matrix 181 arma::Mat<T> fhlp(f); 182 for(size_t i=0;i<fhlp.n_rows;i++) 183 for(size_t j=0;j<fhlp.n_cols;j++) 184 fhlp(i,j)*=vxc(j); 185 H+=arma::real(fhlp*arma::trans(f)); 186 } 187 188 /// BLAS routine for GGA-type quadrature increment_gga(arma::mat & H,const arma::mat & gn,const arma::Mat<T> & f,arma::Mat<T> f_x)189 template<typename T> void increment_gga(arma::mat & H, const arma::mat & gn, const arma::Mat<T> & f, arma::Mat<T> f_x) { 190 if(gn.n_cols!=3) { 191 throw std::runtime_error("Grad rho must have three columns!\n"); 192 } 193 if(f.n_rows != f_x.n_rows || f.n_cols != f_x.n_cols) { 194 throw std::runtime_error("Sizes of basis function and derivative matrices doesn't match!\n"); 195 } 196 if(H.n_rows != f.n_rows || H.n_cols != f.n_rows) { 197 throw std::runtime_error("Sizes of basis function and Fock matrices doesn't match!\n"); 198 } 199 200 // Compute helper: gamma_{ip} = \sum_c \chi_{ip;c} gr_{p;c} 201 // (N, Np) = (N Np; c) (Np, 3) 202 arma::Mat<T> gamma(f.n_rows,f.n_cols); 203 gamma.zeros(); 204 { 205 // Helper 206 arma::rowvec gc; 207 208 // x gradient 209 gc=arma::strans(gn.col(0)); 210 for(size_t j=0;j<f_x.n_cols;j++) 211 for(size_t i=0;i<f_x.n_rows;i++) 212 f_x(i,j)*=gc(j); 213 gamma+=f_x; 214 } 215 216 // Form Fock matrix 217 H+=arma::real(gamma*arma::trans(f) + f*arma::trans(gamma)); 218 } 219 } 220 } 221 } 222 223 #endif 224