////////////////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////////////////
//
// PlotCmd.C:
//
////////////////////////////////////////////////////////////////////////////////
#include "PlotCmd.h"
#include "isodate.h"
#include "release.h"
#include
#include
#include
#include
#include "Context.h"
#include "Sample.h"
#include "SampleReader.h"
#include "Basis.h"
#include "EnergyFunctional.h"
#include "FourierTransform.h"
#include "SlaterDet.h"
#include "Matrix.h"
#include "Species.h"
#include "Atom.h"
#include "ChargeDensity.h"
using namespace std;
////////////////////////////////////////////////////////////////////////////////
int PlotCmd::action(int argc, char **argv)
{
string usage(" Use: plot filename\n"
" plot -density [-spin {1|2}] filename\n"
" plot -vlocal [-spin {1|2}] filename\n"
" plot -wf n [-spin {1|2}] filename\n"
" plot -wfs nmin nmax [-spin {1|2}] filename");
// parse arguments
// plot filename : plot atoms in xyz format
// plot -density filename : plot atoms and density in cube format
// plot -vlocal filename : plot atoms and vlocal in cube format
// plot -wf filename : plot atoms and wf in cube format
// plot -wf filename : plot atoms and wfs to in cube fmt
// spin: 1 = first spin (up), 2 = second spin (down)
if ( (argc < 2) || (argc > 7) )
{
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
bool plot_atoms = true;
bool xyz = true;
bool plot_density = false;
bool plot_vlocal = false;
bool plot_wf = false;
bool plot_wfs = false;
int nmin,nmax,nwf;
// ispin = 0: plot both spins
// ispin = 1: plot first spin
// ispin = 2: plot second spin
int ispin = 0;
string filename;
// process arguments
int iarg = 1;
while ( iarg < argc )
{
if ( !strcmp(argv[iarg],"-density") )
{
plot_density = true;
xyz = false;
}
else if ( !strcmp(argv[iarg],"-vlocal") )
{
plot_vlocal = true;
xyz = false;
}
else if ( !strcmp(argv[iarg],"-wf") )
{
plot_wf = true;
xyz = false;
// process argument: n
iarg++;
if ( iarg == argc )
{
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
nmin = atoi(argv[iarg]) - 1;
nmax = nmin;
nwf = 1;
if ( nmin < 0 || nmax >= s->wf.nst() || nmin > nmax )
{
if ( ui->onpe0() )
cout << " nmin or nmax incompatible with nst="
<< s->wf.nst() << endl;
return 1;
}
}
else if ( !strcmp(argv[iarg],"-wfs") )
{
plot_wfs = true;
xyz = false;
// process argument: nmin
iarg++;
if ( iarg==argc )
{
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
nmin = atoi(argv[iarg]) - 1;
// process argument: nmax
iarg++;
if ( iarg==argc )
{
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
nmax = atoi(argv[iarg]) - 1;
nwf = nmax-nmin+1;
if ( nmin < 0 || nmax >= s->wf.nst() || nmin > nmax )
{
if ( ui->onpe0() )
cout << " nmin or nmax incompatible with nst="
<< s->wf.nst() << endl;
return 1;
}
}
else if ( !strcmp(argv[iarg],"-spin") )
{
if ( !(plot_density || plot_wf || plot_wfs) )
{
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
if ( s->wf.nspin() != 2 )
{
if ( ui->onpe0() )
cout << "nspin = 1, cannot select spin" << endl;
return 1;
}
// process argument: ispin
iarg++;
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;
}
}
else
{
// argument must be the file name
filename = argv[iarg];
}
iarg++;
} // while iarg
// Must specify spin if plotting wave functions when nspin==2
if ( s->wf.nspin()==2 && (plot_vlocal||plot_wf||plot_wfs) && ispin==0 )
{
if ( ui->onpe0() )
cout << " must use -spin if nspin==2" << endl;
return 1;
}
ofstream os;
vector tmpr;
int np0 = 0;
int np1 = 0;
int np2 = 0;
const Context& ctxt = *s->wf.spincontext();
if ( plot_density )
{
ChargeDensity cd(s->wf);
cd.update_density();
tmpr.resize(cd.vft()->np012());
np0 = cd.vft()->np0();
np1 = cd.vft()->np1();
np2 = cd.vft()->np2();
if ( s->wf.nspin() == 1 )
{
for ( int i = 0; i < cd.vft()->np012loc(); i++ )
tmpr[i] = cd.rhor[0][i];
}
else
{
if ( ispin == 0 )
{
// plot both spins
for ( int i = 0; i < cd.vft()->np012loc(); i++ )
tmpr[i] = cd.rhor[0][i] + cd.rhor[1][i];
}
else
{
// plot one spin only
// ispin==1 or ispin==2
for ( int i = 0; i < cd.vft()->np012loc(); i++ )
tmpr[i] = cd.rhor[ispin-1][i];
}
}
// send blocks of tmpr to pe0
// send from first context column only
for ( int i = 0; i < ctxt.nprow(); i++ )
{
bool iamsending = ctxt.mycol() == 0 && i == ctxt.myrow();
// send size of tmpr block
int size=-1;
if ( ctxt.onpe0() )
{
if ( iamsending )
{
// sending to self, size not needed
}
else
ctxt.irecv(1,1,&size,1,i,0);
}
else
{
if ( iamsending )
{
size = cd.vft()->np012loc();
ctxt.isend(1,1,&size,1,0,0);
}
}
// send tmpr block
if ( ctxt.onpe0() )
{
if ( iamsending )
{
// do nothing, data is already in place
}
else
{
int istart = cd.vft()->np0() * cd.vft()->np1() *
cd.vft()->np2_first(i);
ctxt.drecv(size,1,&tmpr[istart],1,i,0);
}
}
else
{
if ( iamsending )
{
ctxt.dsend(size,1,&tmpr[0],1,0,0);
}
}
}
} // plot_density
else if ( plot_vlocal )
{
ChargeDensity cd(s->wf);
EnergyFunctional ef(*s,cd);
cd.update_density();
cd.update_rhor();
bool compute_stress = false;
ef.update_vhxc(compute_stress);
FourierTransform *vft = cd.vft();
Basis *vbasis = cd.vbasis();
tmpr.resize(cd.vft()->np012());
np0 = cd.vft()->np0();
np1 = cd.vft()->np1();
np2 = cd.vft()->np2();
if ( s->wf.nspin() == 1 )
{
for ( int i = 0; i < cd.vft()->np012loc(); i++ )
tmpr[i] = ef.v_r[0][i];
}
else
{
if ( ispin == 0 )
{
// should not get here
// ispin must be set if nspin==2
if ( ui->onpe0() )
cout << usage << endl;
return 1;
}
else
{
// plot one spin only
// ispin==1 or ispin==2
for ( int i = 0; i < cd.vft()->np012loc(); i++ )
tmpr[i] = ef.v_r[ispin-1][i];
}
}
// send blocks of tmpr to pe0
// send from first context column only
for ( int i = 0; i < ctxt.nprow(); i++ )
{
bool iamsending = ctxt.mycol() == 0 && i == ctxt.myrow();
// send size of tmpr block
int size=-1;
if ( ctxt.onpe0() )
{
if ( iamsending )
{
// sending to self, size not needed
}
else
ctxt.irecv(1,1,&size,1,i,0);
}
else
{
if ( iamsending )
{
size = cd.vft()->np012loc();
ctxt.isend(1,1,&size,1,0,0);
}
}
// send tmpr block
if ( ctxt.onpe0() )
{
if ( iamsending )
{
// do nothing, data is already in place
}
else
{
int istart = cd.vft()->np0() * cd.vft()->np1() *
cd.vft()->np2_first(i);
ctxt.drecv(size,1,&tmpr[istart],1,i,0);
}
}
else
{
if ( iamsending )
{
ctxt.dsend(size,1,&tmpr[0],1,0,0);
}
}
}
} // plot_vlocal
else if ( plot_wf || plot_wfs )
{
// compute wf or wf squared and store in tmpr
if ( ctxt.onpe0() )
{
ctxt.ibcast_send(1,1,&nwf,1);
ctxt.ibcast_send(1,1,&nmin,1);
ctxt.ibcast_send(1,1,&nmax,1);
}
else
{
ctxt.ibcast_recv(1,1,&nwf,1,0,0);
ctxt.ibcast_recv(1,1,&nmin,1,0,0);
ctxt.ibcast_recv(1,1,&nmax,1,0,0);
}
if ( nwf > 0 && s->wf.nst() == 0 )
{
cout << " no states in sample" << endl;
return 1;
}
int isp_min, isp_max;
SlaterDet *sdp;
if ( ispin == 0 )
{
// -spin was not specified:
if ( s->wf.nspin() == 1 )
{
isp_min = 0; isp_max = 0;
}
else
{
isp_min = 0; isp_max = 1;
}
}
else
{
isp_min = ispin-1; isp_max = ispin-1;
}
const Basis& basis = s->wf.sd(0,0)->basis();
np0 = basis.np(0);
np1 = basis.np(1);
np2 = basis.np(2);
FourierTransform ft(basis,np0,np1,np2);
vector > wftmp(ft.np012loc());
vector wftmpr(ft.np012());
tmpr.resize(ft.np012());
tmpr.assign(ft.np012(),0.0);
for ( int isp = isp_min; isp <= isp_max; isp++ )
{
sdp = s->wf.sd(isp,0);
const ComplexMatrix& c = sdp->c();
for ( int n = nmin; n <= nmax; n++ )
{
if ( n >= s->wf.nst(isp) )
{
if ( ui->onpe0() )
cout << "invalid wave function index: " << n+1
<< " > nst(ispin)" << endl;
return 1;
}
// compute real-space wavefunction
// transform wf on ctxt.mycol() hosting state n
if ( c.pc(n) == c.context().mycol() )
{
//os << " state " << n << " is stored on column "
// << ctxt_.mycol() << " local index: " << c_.y(n) << endl;
int nloc = c.y(n); // local index
ft.backward(c.cvalptr(c.mloc()*nloc),&wftmp[0]);
double *a = (double*) &wftmp[0];
if ( basis.real() )
{
// real function: plot wf
for ( int i = 0; i < ft.np012loc(); i++ )
wftmpr[i] = a[2*i];
}
else
{
// complex function: plot modulus
for ( int i = 0; i < ft.np012loc(); i++ )
wftmpr[i] = sqrt(a[2*i]*a[2*i] + a[2*i+1]*a[2*i+1]);
}
}
// send blocks of wftmpr to pe0
for ( int i = 0; i < c.context().nprow(); i++ )
{
bool iamsending = c.pc(n) == c.context().mycol() &&
i == c.context().myrow();
// send size of wftmpr block
int size=-1;
if ( c.context().onpe0() )
{
if ( iamsending )
{
// sending to self, size not needed
}
else
c.context().irecv(1,1,&size,1,i,c.pc(n));
}
else
{
if ( iamsending )
{
size = ft.np012loc();
c.context().isend(1,1,&size,1,0,0);
}
}
// send wftmpr block
if ( c.context().onpe0() )
{
if ( iamsending )
{
// do nothing, data is already in place
}
else
{
int istart = ft.np0() * ft.np1() * ft.np2_first(i);
c.context().drecv(size,1,&wftmpr[istart],1,i,c.pc(n));
}
}
else
{
if ( iamsending )
{
c.context().dsend(size,1,&wftmpr[0],1,0,0);
}
}
}
// process the data on task 0
if ( c.context().onpe0() )
{
// wftmpr is now complete on task 0
if ( plot_wfs )
{
// multiple wfs, accumulate square
for ( int i = 0; i < ft.np012(); i++ )
{
tmpr[i] += wftmpr[i]*wftmpr[i];
}
}
else
{
// plot individual wf
for ( int i = 0; i < ft.np012(); i++ )
{
tmpr[i] = wftmpr[i];
}
}
}
} // for n
} // for isp
} // if plot_wf || plot_wfs
// tmpr now contains the function to plot on task 0
if ( ctxt.onpe0() )
os.open(filename.c_str());
if ( plot_atoms )
{
if ( ctxt.onpe0() )
{
if ( xyz )
{
const double a0 = 0.529177;
int natoms = s->atoms.size();
os << natoms << endl;
os << "Created " << isodate() << " by qbox-" << release() << endl;
const int nsp = s->atoms.nsp();
for ( int is = 0; is < nsp; is++ )
{
Species* sp = s->atoms.species_list[is];
string symbol = sp->symbol();
const int na = s->atoms.na(is);
for ( int ia = 0; ia < na; ia++ )
{
Atom *ap = s->atoms.atom_list[is][ia];
os << setprecision(5);
os << symbol << " " << a0*ap->position() << endl;
}
}
}
else
{
// write header and atoms
os << "Created " << isodate() << " by qbox-" << release() << endl;
os << endl;
int natoms = s->atoms.size();
D3vector a0 = s->atoms.cell().a(0);
D3vector a1 = s->atoms.cell().a(1);
D3vector a2 = s->atoms.cell().a(2);
os << natoms << " " << -0.5*(a0+a1+a2) << endl;
// write unit cell
os << np0 << " " << a0/np0 << endl;
os << np1 << " " << a1/np1 << endl;
os << np2 << " " << a2/np2 << endl;
const int nsp = s->atoms.nsp();
for ( int is = 0; is < nsp; is++ )
{
Species* sp = s->atoms.species_list[is];
const int z = sp->atomic_number();
const int na = s->atoms.na(is);
for ( int ia = 0; ia < na; ia++ )
{
Atom *ap = s->atoms.atom_list[is][ia];
os << setprecision(5);
os << z << " " << ((double) z) << " " << ap->position() << endl;
}
}
}
}
} // if plot_atoms
if ( plot_density || plot_vlocal || plot_wf || plot_wfs )
{
// process the function in tmpr
if ( ctxt.onpe0() )
{
os.setf(ios::scientific,ios::floatfield);
os << setprecision(5);
for ( int i = 0; i < np0; i++ )
{
const int ip = (i + np0/2 ) % np0;
for ( int j = 0; j < np1; j++ )
{
const int jp = (j + np1/2 ) % np1;
for ( int k = 0; k < np2; k++ )
{
const int kp = (k + np2/2 ) % np2;
os << setw(13) << tmpr[ip+np0*(jp+np1*kp)];
if ( ( k % 6 ) == 5 )
os << endl;
}
if ( ( np2 % 6 ) != 0 )
os << endl;
}
}
}
} // if plot_density || ...
os.close();
return 0;
}