/* 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. 29, 1997 * * Calculate the U matrices, the C column_bundles, and charge density n. * */ /* $Id: calcUVCn.cpp,v 1.13.2.12 2003/05/29 18:54:13 ivan Exp $ */ #include "header.h" /* * Calculate the U matrices and their various powers: * * U[k] = Y[k]^O(Y[k]) */ void calc_U(Elecinfo &einfo,Elecvars &evars) { #ifdef DFT_PROFILING timerOn(14); // Turn on calc_U timer #endif // DFT_PROFILING int q; for (q=0; q < einfo.nstates; q++) { BlochState &s=evars.states[q]; ColumnBundle OY(s.Y); /* does: U[k] = Y[k]^(O(Y[k])); */ O(s.Y,OY); s.U = s.Y^OY; s.U.hermetian = 1; // U is hermetian, so set the flag s.Umhalf = Uminusonehalf(s.U,s.W,s.mu); } #ifdef DFT_PROFILING timerOff(14); // Turn off calc_U timer #endif // DFT_PROFILING } /* * Calculate the subspace rotation matrix : V[q] = exp(iB[q]) */ void calc_V(Elecinfo &einfo, Elecvars &evars) { int q,i; /* If we aren't doing subspace rotations, then we should do nothing! */ if (!einfo.subspace_rotation) return; #ifdef DFT_PROFILING timerOn(41); // Calc V timer #endif diag_matrix expibeta(evars.states[0].B.nr);//assuming everybody is the same // consider moving it inside the loop for (q=0; q < einfo.nstates; q++) { BlochState &s=evars.states[q]; /* B[k] = Z[k]*beta[k]*Zdag[k] */ diagonalize_herm(s.beta,s.Z,s.B,s.B.nr); /* V[k] = Z[k]*exp(i*beta[k])*Zdag[k] */ for (i=0; i < s.B.nr; i++) { #ifdef SCALAR_IS_COMPLEX complex ibeta; ibeta.x = 0.0; ibeta.y = s.beta[i]; expibeta.c[i] = exp(ibeta); #elif defined SCALAR_IS_REAL #error "Don't know how to do subspace rotations for real" #else #error scalar is neither complex nor real #endif } s.V = s.Z*(expibeta*herm_adjoint(s.Z)); } #ifdef DFT_PROFILING timerOff(41); // Calc V timer #endif } /* * Calculate the orthonormal wavefunctions: * * state[q]: C = Y*Umhalf*Vdag */ void calc_C(Elecinfo &einfo,Elecvars &evars) { #ifdef DFT_PROFILING timerOn(15); // Turn on calc_C timer #endif // DFT_PROFILING int q; //just loop over the bloch states and transform Y to C for (q=0; q < einfo.nstates; q++) { BlochState &s = evars.states[q]; if (einfo.subspace_rotation) /* C = Y*Umhalf; */ do_ColumnBundle_matrix_mult(s.Y, s.Umhalf*herm_adjoint(s.V), s.C, 0); else do_ColumnBundle_matrix_mult(s.Y, s.Umhalf,s.C, 0); } #ifdef DFT_PROFILING timerOff(15); // Turn off calc_C timer #endif // DFT_PROFILING } /* Combines U, V, and C */ void calc_UVC(Elecinfo &einfo,Elecvars &evars) { calc_U(einfo,evars); calc_V(einfo,evars); calc_C(einfo,evars); } /* Calculate electron density: n = sum_k { w[q]*diagouter(F[q],I*C[q]) } */ void calc_n(Elecinfo &einfo, Elecvars &evars, Lattice &lattice, Symmetries &symm) { #ifdef DFT_PROFILING timerOn(16); // Turn on calc_n timer #endif // DFT_PROFILING /* Get local pointer to the relevant variables to make the formulae * legible */ RealSpaceScalarFieldColumn &n = evars.n; /* reference */ RealSpaceScalarFieldColumn &n_up = evars.n_up; /* reference */ RealSpaceScalarFieldColumn &n_dn = evars.n_dn; /* reference */ // RealSpaceScalarFieldColumn &n_ud = evars.n_ud; /* reference */ // RealSpaceScalarFieldColumn &n_du = evars.n_du; /* reference */ //ipd: these guys are always present, no need of if sttatement n.zero_out(); n_up.zero_out(); n_dn.zero_out(); //ipd: change the += below w/ multadds to save space for (int q=0; q < einfo.nstates; q++){ BlochState &s = evars.states[q]; switch(einfo.spintype){ case NOSPIN: // NOSPIN MODE n += ((scalar)s.w)*diagouterI(s.F,s.C); break; case ZSPIN: // ZSPIN MODE switch (s.qnum.spin){ case 1 : n_up += ((scalar)s.w)*diagouterI(s.F,s.C); break; case -1 : n_dn += ((scalar)s.w)*diagouterI(s.F,s.C); break; default : die("Bad spin designation in ZSPIN mode: %d", s.qnum.spin); } break; default: die("Invalid spintype: %d", einfo.spintype); } } switch(einfo.spintype){ case NOSPIN: // symmetrize the total charge density. symmetrize_n(n, &symm); break; case ZSPIN: // symmetrize symmetrize_n(n_up, &symm); symmetrize_n(n_dn, &symm); n = n_up; n+= n_dn; break; default: die("Invalid spintype: %d", einfo.spintype); } // integral of n should be number of electrons per unit cell. /*ipd: it's more complicated for wavelets -- several choices: * do s^(JN) - may be expensive * add just the top level grids - terrible * make a basis dependent function still have to deal w/ it's cost real sum = REAL(sum_vector(n)); sum *= lattice.unit_cell_volume / n.n; if ( fabs(sum/einfo.nelectrons-1) > 1e-4 ) { dft_log(DFT_ANAL_LOG, ">>>>Real space charge integrates to %g != %g (nelectrons)\n", sum, einfo.nelectrons); die("Quiting due to violation of charge conservation."); } */ #ifdef DFT_PROFILING timerOff(16); // Turn off calc_n timer #endif // DFT_PROFILING } // Combines U, V, C and n void calc_UVCn(Elecinfo &einfo,Elecvars &evars, Lattice &lattice,Symmetries &symm) { calc_U(einfo,evars); calc_V(einfo,evars); calc_C(einfo,evars); calc_n(einfo,evars,lattice,symm); }