/* DFT++ is a density functional package developed by the research group of Professor Tomas Arias Copyright 1996-2003 Sohrab Ismail-Beigi This file is part of DFT++. DFT++ is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. DFT++ is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with DFT++; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Please see the file CREDITS for a list of authors. For academic users, we request that publications using results obtained with this software reference "New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000). and, if using the wavelet basis, further reference "Multiresolution analysis of electronic structure: semicardinal and wavelet bases," T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999). and "Robust ab initio calculation of condensed matter: transparent convergence through semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003). For your convenience, preprints of the above articles may be obtained from http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively. */ /* * Sohrab Ismail-Beigi Mar. 30, 1997 * * Calculates the gradient of the energy versus the electronic variables * Y (and also all the various routines needed to do this). * */ /* $Id: calcelecgrad.cpp,v 1.15.2.25 2003/05/29 18:54:14 ivan Exp $ */ #include "header.h" #include "parallel.h" /* * Calculates the local part of the self-consistent potential. */ void calc_Vscloc(Elecvars &evars, Elecinfo &einfo, Symmetries &symm) { #ifdef DFT_PROFILING timerOn(25); // Turn on calc_Vscloc timer #endif // DFT_PROFILING int dir,dag; RealSpaceScalarFieldColumn &Vscloc = evars.Vscloc; CoeffSpaceScalarFieldColumn &Vlocpot = evars.Vlocpot; CoeffSpaceScalarFieldColumn &d = evars.d; RealSpaceScalarFieldColumn &n = evars.n; switch (einfo.exc_opt) { case DFT_EXCORR_GGA_PBE: { RealSpaceScalarFieldColumn rtemp(n); CoeffSpaceScalarFieldColumn ctemp(d); // TAA: Test of gradient "D" functions (remove at cleanup) // { // Basis *basis = n.basis; // Lattice *lattice = basis->basis_spec->lattice; // int Nx,Ny,Nz,Nx2,Ny2,Nz2,NyNz,NxNyNz; // Nx = basis->basis_spec->Nx; Nx2 = Nx/2; // Ny = basis->basis_spec->Ny; Ny2 = Ny/2; // Nz = basis->basis_spec->Nz; Nz2 = Nz/2; // NyNz = Ny*Nz; // NxNyNz=basis->basis_spec->NxNyNz; // RealSpaceScalarFieldColumn Dx(n); // for (int i=-Nx2; i < Nx2; i++) // for (int j=-Ny2; j < Ny2; j++) // for (int k=-Nz2; k < Nz2; k++) // { // int index = 0; // if (k < 0) index += k+Nz; else index += k; // if (j < 0) index += Nz*(j+Ny); else index += Nz*j; // if (i < 0) index += NyNz*(i+Nx); else index += NyNz*i; // n.data.d[index] = cos(11*2*M_PI*j/((double) Nx))*lattice->R.m[0][0]/(2*M_PI); // } // int dir,dag; // apply_D(dir=1,dag=0,n,Dx); // double tmp=0.; // FILE *fid=fopen("out","w"); // for (int i=0; iKE/einfo.nelectrons) and this (times 2.0) is used * as the roll-over value of the kinetic energy for the preconditioning. */ void calc_elecgrad_pgrad_and_Hsub(ColumnBundle **Ygrad, ColumnBundle **pYgrad, ComplexMatrix **Bgrad, ComplexMatrix **pBgrad, Everything &everything) { #ifdef DFT_PROFILING timerOn(10); // Turn on calc_elecgrad_... timer #endif // DFT_PROFILING Elecinfo &einfo = everything.elecinfo; Elecvars &evars = everything.elecvars; Symmetries &symm = everything.symm; int q; /* Local workspaces */ /* * to avoid allocate/deallocate many times, create for largest * col_length. */ // can't do this anymore: problem? --csg // // int max_col_length = 0; //for (q=0; q < einfo.nstates; q++) // if (max_col_length < s.C.col_length) // max_col_length = s.C.col_length; // // ColumnBundle tmp(bs[0].C.tot_ncols,max_col_length); /* Roll-over value for kinetic preconditioning: 2.0*average kinetic * energy per band. */ // This is now computed inside K. //real KErollover; //KErollover = 2.0*ener.KE/einfo.nelectrons; calc_Vscloc(evars,einfo,symm); for (q=0; q < einfo.nstates; q++) { BlochState &s = evars.states[q]; ColumnBundle tmp(s.C); /* * In this wonderful mess below, we calculate the subspace Hamiltonian, * the gradient, and the preconditioned gradient! The formulae: * C[q] = Y[q]*Umhalf[q]*Vdag[q] * Hsub[q] = C[q]*Hsp(C[q]) * Ygrad[q] = w[q]*(g1 + g2) * g1 = Pbar(Hsp(C[q]*F[q]*V[q]*Umhalf[q])) * = Pbar(Hsp(Y[q]*Umhalf[q]*Vdag[q]*F[q]*V[q]*Umhalf[q])) * g2 = O(C[q]*V[q]*Q(Vdag[q]*[Hsub[q],F[q]]*V[q])) * pYgrad[q] = w[q]*(Pbar(precond(Pbar(Hsp(Y[q])))) + g2) */ /* First we calculate Hsp(Y[q]), Hsp(Y[q])*Umhalf[q]*Vdag[q]=Hsp(C[q]), and Hsub[q] */ // here pYgrad is the OUTPUT apply_Hsp(s.Y,*pYgrad[q],*s.Vscloc, everything); if (einfo.subspace_rotation) do_ColumnBundle_matrix_mult(*pYgrad[q], (s.Umhalf)*herm_adjoint(s.V), tmp,0); else do_ColumnBundle_matrix_mult(*pYgrad[q],(s.Umhalf),tmp,0); s.Hsub = (s.C)^tmp; /* Digonalize Hsub[q] */ s.Hsub.hermetian = 1; diagonalize_herm(s.Hsub_eigs,s.Hsub_evecs,s.Hsub, s.Hsub.nr); /* Now calculate g1 and the first term of pYgrad[q] */ apply_Pbar(s.C,*pYgrad[q],tmp); if (einfo.subspace_rotation) do_ColumnBundle_matrix_mult( tmp, (s.Umhalf)*herm_adjoint(s.V)*(s.F)*(s.V) *(s.Umhalf), *Ygrad[q],0); else do_ColumnBundle_matrix_mult(tmp,(s.Umhalf)*(s.F)* (s.Umhalf),*Ygrad[q],0); //precond_inv_kinetic(tmp,KErollover); // ipd 09/14/02: Uncommenting the next 2 lines to the original state // looks like matt forgot about them :( K(tmp,everything); apply_Pbar(s.C,tmp,*pYgrad[q]); // Ygrad contains Pbar*Hsp*Y*Umhalf*F*Umhalf // tmp contains Pbar*Hsp*Y // Precondition only the first term in the gradient. // ipd 09/14/02: Commenting out the next 2 lines to the original state //*pYgrad[q] = *Ygrad[q]; //K(*pYgrad[q],everything); /* Add in g2 = O*C*Q() term to Ygrad[q] and pYgrad[q] */ if (einfo.subspace_rotation) do_ColumnBundle_matrix_mult( s.C, (s.V)*Q(herm_adjoint(s.V)* ((s.Hsub)*(s.F)-(s.F)*(s.Hsub))* (s.V),s.W,s.mu), tmp,0); else do_ColumnBundle_matrix_mult(s.C, Q((s.Hsub)*(s.F)-(s.F)* (s.Hsub),s.W,s.mu), tmp,0); //apply_O_inplace(tmp); O(tmp,tmp); *Ygrad[q] += tmp; // Use if we're only preconditioning the first term. *pYgrad[q] += tmp; // Precondition here. //*pYgrad[q] = *Ygrad[q]; //K(*pYgrad[q],everything); /* scale by weights */ *Ygrad[q] *= s.w; *pYgrad[q] *= s.w; /* Calc B gradient and symmetrize it */ /* Bgrad[q] = R([Hsub[q],F[q]]) */ if (einfo.subspace_rotation) { *Bgrad[q] = R(((s.Hsub)*(s.F)-(s.F)*(s.Hsub)),s.Z, s.beta); *Bgrad[q] += herm_adjoint(*Bgrad[q]); *Bgrad[q] *= (0.5 * (s.w)); *pBgrad[q] = ((scalar) einfo.pcond_for_Bgrad) * (*Bgrad[q]); } } #ifdef DFT_PROFILING timerOff(10); // Turn off calc_elecgrad_... timer #endif // DFT_PROFILING } /* * Calculates the energy gradient versus Y of the "energy" (objective) * function used in band structure calculations: * * E_band = sum_q tr( C[q]^H*C[q] ) */ void calc_elecgrad_band_struct(ColumnBundle **Ygrad, Everything &everything) { #ifdef DFT_PROFILING timerOn(10); // Turn on calc_elecgrad_... timer #endif // DFT_PROFILING Elecinfo &einfo = everything.elecinfo; Elecvars &evars = everything.elecvars; int q; /* Local copies to make the formulae easier to read */ //column_bundle *C = evars.C; //matrix *Umhalf = evars.Umhalf; /* * Local workspace: * to avoid allocate/deallocate many times, create for largest col_length. */ //int max_col_length = 0; //for (q=0; q < einfo.nstates; q++) // if (max_col_length < s.C.col_length) // max_col_length = s.C.col_length; //ColumnBundle tmp(bs[0].C.tot_ncols,max_col_length); for (q=0; q < einfo.nstates; q++){ BlochState &s = evars.states[q]; // manually adjust ColumnBundle length; //tmp.col_length = s.C.col_length; //copy_innards_ColumnBundle(&(s.C),&tmp); ColumnBundle tmp(s.C); /* * Calc Y gradient, with formula give by: * Ygrad[q] = Pbar(H(C[q]))*U[q]^{-1/2} */ apply_Hsp(s.C,*Ygrad[q],*s.Vscloc, everything); do_ColumnBundle_matrix_mult(*Ygrad[q],s.Umhalf,tmp,0); apply_Pbar(s.C,tmp,*Ygrad[q]); } #ifdef DFT_PROFILING timerOff(10); // Turn off calc_elecgrad_... timer #endif // DFT_PROFILING } /* * This routine calculates the gradient and preconditioned gradient * for band structure minimizations. Preconditioning is done just * like above, except that since we don't have the kinetic energy * of the electrons explicitely, we *GUESS*: the average kinetic * energy per electron for choosing the preconditioner roll-over point * is chosen to be 1 Hartree for now. */ void calc_elecgrad_pgrad_band_struct(ColumnBundle **Ygrad, ColumnBundle **pYgrad, Everything &everything) { #ifdef DFT_PROFILING timerOn(10); // Turn on calc_elecgrad_... timer #endif // DFT_PROFILING Elecinfo &einfo = everything.elecinfo; Elecvars &evars = everything.elecvars; int q; /* Local copies to make the formulae easier to read */ // column_bundle *C = evars.C; // column_bundle *Y = evars.Y; // matrix *Umhalf = evars.Umhalf; /* Local workspaces: * to avoid allocate/deallocate many times create for largest col_length. */ //int max_col_length = 0; //for (q=0; q < einfo.nstates; q++) // if (max_col_length < bs[q].C.col_length) // max_col_length = bs[q].C.col_length; //ColumnBundle tmp(bs[0].C.tot_ncols,max_col_length); /* Roll-over value for kinetic preconditioning: 2.0*average kinetic * energy per band. */ // This is now done in K. //real kinetic_energy_per_electron = 1.0; // ener.KE/einfo.nelectrons //real KErollover; //KErollover = 2.0 * kinetic_energy_per_electron; for (q=0; q < einfo.nstates; q++) { BlochState &s = evars.states[q]; // manually adjust ColumnBundle length; //tmp.col_length = bs[q].C.col_length; //copy_innards_ColumnBundle(&(bs[q].C),&tmp); ColumnBundle tmp(s.C); /* * Compute gradient and preconditioned gradient. Formulae: * Ygrad[q] = Pbar(H(Y[q]))*U^-1 * pYgrad[q] = Pbar(precondition(Pbar(H(Y[q])))) */ apply_Hsp(s.Y,*pYgrad[q],*s.Vscloc, everything); apply_Pbar(s.C,*pYgrad[q],tmp); do_ColumnBundle_matrix_mult(tmp,(s.Umhalf)*(s.Umhalf), *Ygrad[q],0); //precond_inv_kinetic(tmp,KErollover); K(tmp,everything); apply_Pbar(s.C,tmp,*pYgrad[q]); } #ifdef DFT_PROFILING timerOff(10); // Turn off calc_elecgrad_... timer #endif // DFT_PROFILING } /* * Prints the eigenenergies of the subspace Hamiltonian for each * state. */ void print_Hsub_eigs(Everything &everything,Output *out) { Elecinfo &einfo = everything.elecinfo; Elecvars &evars = everything.elecvars; int q,i; out->printf("Band energies:\n"); for (q=0; q < einfo.nstates; q++){ out->printf("\nstate = %d q_k = [ %lg %lg %lg ] w = %lg", q,evars.states[q].qnum.kvec.v[0], evars.states[q].qnum.kvec.v[1], evars.states[q].qnum.kvec.v[2], evars.states[q].w); if (einfo.spintype == FREESPIN) out->printf(" spin = free\n"); else out->printf(" spin = %d\n",evars.states[q].qnum.spin); out->printf("%4s %13s %13s %13s\n", "band","filling ","diag(Hsub) ","epsilon "); out->printf("-------------------------------------------------\n"); for (i=0; i < evars.states[q].Hsub.nr; i++) out->printf("%4d %13.6le %13.6le %13.6le\n", i,REAL(evars.states[q].F.c[i]), REAL(evars.states[q].Hsub(i,i)), evars.states[q].Hsub_eigs[i]); } out->flush(); }