//////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008 The Regents of the University of California // // This file is part of Qbox // // Qbox is distributed 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. // See the file COPYING in the root directory of this distribution // or . // //////////////////////////////////////////////////////////////////////////////// // // PartialChargeCmd.cpp // //////////////////////////////////////////////////////////////////////////////// #include "PartialChargeCmd.h" #include #include #include "Context.h" #include "Sample.h" #include "Basis.h" #include "Atom.h" #include "ChargeDensity.h" using namespace std; //////////////////////////////////////////////////////////////////////////////// int PartialChargeCmd::action(int argc, char **argv) { string usage(" Use: partial_charge [-spin {1|2}] name radius"); // parse arguments // plot [-spin {1|2}] name radius // ispin = 0: include both spins // ispin = 1: include first spin // ispin = 2: include second spin int ispin = 0; double radius = 0.0; string atom_name; if ( !(argc==3 || argc==5) ) { if ( ui->onpe0() ) cout << usage << endl; return 1; } const int nspin = s->wf.nspin(); // process arguments int iarg = 1; if ( !strcmp(argv[iarg],"-spin") ) { if ( nspin != 2 ) { if ( ui->onpe0() ) cout << "nspin = 1, cannot select spin" << endl; return 1; } iarg++; // process argument: ispin if ( iarg==argc ) { if ( ui->onpe0() ) cout << usage << endl; return 1; } ispin = atoi(argv[iarg]); if ( ispin < 1 || ispin > 2 ) { if ( ui->onpe0() ) cout << " spin must be 1 or 2" << endl; return 1; } iarg++; } // argument must be the atom name followed by the radius if ( iarg==argc ) { if ( ui->onpe0() ) cout << usage << endl; return 1; } atom_name = argv[iarg]; iarg++; if ( iarg==argc ) { if ( ui->onpe0() ) cout << usage << endl; return 1; } radius = atof(argv[iarg]); // find atom and check validity of radius argument Atom* a = s->atoms.findAtom(atom_name); if ( a == 0 ) { if ( ui->onpe0() ) cout << " PartialChargeCmd: atom " << atom_name << " not defined" << endl; return 1; } if ( radius <= 0.0 ) { if ( ui->onpe0() ) cout << " PartialChargeCmd: radius must be positive" << endl; return 1; } D3vector pos = a->position(); if ( ui->onpe0() ) { cout << setprecision(5) << " Atom " << atom_name << " at " << pos << endl; cout << " radius = " << radius << endl; } const Context& ctxt = s->wf.sd_context(); ChargeDensity cd(s->wf); Basis *vbasis = cd.vbasis(); cd.update_density(); const double omega = vbasis->cell().volume(); double sum = 0.0; const double fac = 4.0 * M_PI * radius * radius * radius / omega; // G=0 term if ( nspin == 1 ) { sum = fac * cd.rhog[0][0].real() / 3.0; } else { // nspin == 2 if ( ispin == 0 ) sum = fac * ( cd.rhog[0][0].real() + cd.rhog[1][0].real() ) / 3.0; else if ( ispin == 1 ) sum = fac * cd.rhog[0][0].real() / 3.0; else sum = fac * cd.rhog[1][0].real() / 3.0; } // Start sum after G=0 coeff if in first process row int igstart = 0; if ( ctxt.myrow() == 0 ) { // skip G=0 coefficient igstart = 1; } const int ngloc = cd.rhog[0].size(); const double *gx = vbasis->gx_ptr(0); const double *gy = vbasis->gx_ptr(1); const double *gz = vbasis->gx_ptr(2); const double *g = vbasis->g_ptr(); for ( int ig = igstart; ig < ngloc; ig++ ) { // translate origin: compute exp(i G*pos ) double arg = pos.x*gx[ig] + pos.y*gy[ig] + pos.z*gz[ig]; double c = cos(arg); double s = sin(arg); // Re ( c(G) * (c + i*s )) = Re(c(G))*c - Im(c(G)*s complex cg; if ( nspin == 1 ) { cg = cd.rhog[0][ig]; } else { // nspin == 2 if ( ispin == 0 ) cg = cd.rhog[0][ig] + cd.rhog[1][ig]; else if ( ispin == 1 ) cg = cd.rhog[0][ig]; else cg = cd.rhog[1][ig]; } // real part of coefficient of translated function double ctrans_re = cg.real() * c - cg.imag() * s; // product of norms: g * radius double gr = g[ig]*radius; // Bessel function j1(z) = sin(z)/z^2 - cos(z)/z double j1gr = sin(gr)/(gr*gr) - cos(gr)/gr; // factor 2 in next line: G and -G sum += 2.0 * fac * ctrans_re * j1gr / gr; } // accumulate sum across tasks ctxt.dsum('c',1,1,&sum,1); if ( ui->onpe0() ) { cout << " 0 ) cout << "\" spin=\"" << ispin; cout << "\"> " << setprecision(6) << sum << " " << endl; } return 0; }