git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@6378 f3b2605a-c512-4ea7-a41b-209d697bcdaa
This commit is contained in:
17
lib/awpmd/systems/interact/TCP/tcpdefs.h
Normal file
17
lib/awpmd/systems/interact/TCP/tcpdefs.h
Normal file
@ -0,0 +1,17 @@
|
||||
# ifndef _TCPDEFS_H
|
||||
# define _TCPDEFS_H
|
||||
|
||||
//Constants
|
||||
const double sqr_2_over_3 = 0.816496580927726;
|
||||
const double two_over_sqr_pi = 1.12837916709551;
|
||||
|
||||
# ifndef PLASMA_UNITS // using GridMD units: A, eV, m_proton=1
|
||||
const double h_plank=0.06442021524615668;
|
||||
const double h_sq=h_plank*h_plank;
|
||||
const double m_electron=1./1836.1527556560675;
|
||||
const double m_proton=1.;
|
||||
const double coul_pref=14.39965172693122; // e^2/(4*pi*eps0), eV*A
|
||||
const double eV_to_K=11604.447517053462; // Temperature in K correspondent to 1eV
|
||||
# endif
|
||||
|
||||
# endif
|
||||
890
lib/awpmd/systems/interact/TCP/wpmd.cpp
Normal file
890
lib/awpmd/systems/interact/TCP/wpmd.cpp
Normal file
@ -0,0 +1,890 @@
|
||||
# include "wpmd.h"
|
||||
|
||||
|
||||
|
||||
// Calculates derivative overlap matrix IDD
|
||||
void OverlapDeriv::calc_der_overlap(bool self, cdouble cc1, cdouble c2){
|
||||
cVector_3 I3 = I1 * ((bb_4a + 2.5) / w12.a);
|
||||
cdouble I4 = I0 * ( bb_4a *(bb_4a + 5.) + 3.75 ) / w12.a / w12.a;
|
||||
|
||||
// calculate derivatives <(phi_k)'_q_k | (phi_l)'_q_l>:
|
||||
IDD.set(0, 0, I4 - (d1.l + d2.l)*I2 + d1.l*d2.l*I0 ); // over a_k_re and a_l_re
|
||||
IDD.set(0, 1, i_unit*( I4 - (d1.l + d2.m)*I2 + d1.l*d2.m*I0 ) ); // over a_k_re and a_l_im
|
||||
if(!self)
|
||||
IDD.set(1, 0, i_unit1*( I4 + (d1.m - d2.l)*I2 - d1.m*d2.l*I0 ) ); // over a_k_im and a_l_re
|
||||
else
|
||||
IDD.set(1,0, conj(IDD(0,1)));
|
||||
IDD.set(1, 1, I4 + (d1.m - d2.m)*I2 - d1.m*d2.m*I0 ); // over a_k_im and a_l_im
|
||||
|
||||
for(int i=0;i<3;i++){
|
||||
IDD.set(0, (i+1)*2, -I3[i] + d1.l*I1[i] + d2.u[i]*(d1.l*I0 - I2) ); // over a_k_re and b_l_re
|
||||
IDD.set(0, (i+1)*2+1, i_unit1*( I3[i] - d1.l*I1[i] + d2.v[i]*(I2 - d1.l*I0) ) ); // over a_k_re and b_l_im
|
||||
IDD.set(1, (i+1)*2, i_unit *( I3[i] + d1.m*I1[i] + d2.u[i]*(I2 + d1.m*I0) ) ); // over a_k_im and b_l_re
|
||||
IDD.set(1, (i+1)*2+1, -I3[i] - d1.m*I1[i] - d2.v[i]*(d1.m*I0 + I2) ); // over a_k_im and b_l_im
|
||||
if(!self) {
|
||||
IDD.set((i+1)*2, 0, -I3[i] + d2.l*I1[i] + d1.u[i]*(d2.l*I0 - I2) ); // over b_k_re and a_l_re
|
||||
IDD.set((i+1)*2+1, 0, i_unit *( I3[i] - d2.l*I1[i] - d1.v[i]*(I2 - d2.l*I0) ) ); // over b_k_im and a_l_re
|
||||
IDD.set((i+1)*2, 1, i_unit1*( I3[i] - d2.m*I1[i] + d1.u[i]*(I2 - d2.m*I0) ) ); // over b_k_re and a_l_im
|
||||
IDD.set((i+1)*2+1, 1, -I3[i] + d2.m*I1[i] - d1.v[i]*(d2.m*I0 - I2) ); // over b_k_im and a_l_im
|
||||
}
|
||||
else{
|
||||
IDD.set((i+1)*2, 0, conj(IDD(0,(i+1)*2)) ); // over b_k_re and a_l_re
|
||||
IDD.set((i+1)*2+1, 0, conj(IDD(0,(i+1)*2+1)) ); // over b_k_im and a_l_re
|
||||
IDD.set((i+1)*2, 1, conj(IDD(1,(i+1)*2)) ); // over b_k_re and a_l_im
|
||||
IDD.set((i+1)*2+1, 1, conj(IDD(1,(i+1)*2+1)) ); // over b_k_im and a_l_im
|
||||
}
|
||||
|
||||
for(int j=0;j<3;j++){
|
||||
if(!self || j>=i){
|
||||
cdouble I2ij = I0 / w12.a *
|
||||
(i==j ? w12.b[i]*w12.b[i] / w12.a / 4 + 0.5
|
||||
: w12.b[i]*w12.b[j] / w12.a / 4);
|
||||
// over b_k_re and b_l_re
|
||||
IDD.set((j+1)*2, (i+1)*2, I2ij + d1.u[i]*I1[j] + d2.u[j]*(I1[i] + d1.u[i]*I0) );
|
||||
// over b_k_re and b_l_im
|
||||
IDD.set((j+1)*2, (i+1)*2+1, i_unit *( I2ij + d1.u[i]*I1[j] + d2.v[j]*(I1[i] + d1.u[i]*I0) ) );
|
||||
// over b_k_im and b_l_re
|
||||
if(!self || i!=j)
|
||||
IDD.set((j+1)*2+1, (i+1)*2, i_unit1*( I2ij - d1.v[i]*I1[j] + d2.u[j]*(I1[i] - d1.v[i]*I0) ) );
|
||||
else
|
||||
IDD.set((j+1)*2+1, (i+1)*2, conj(IDD((i+1)*2,(j+1)*2+1)));
|
||||
// over b_k_im and b_l_im
|
||||
IDD.set((j+1)*2+1,(i+1)*2+1, I2ij - d1.v[i]*I1[j] + d2.v[j]*(I1[i] - d1.v[i]*I0) );
|
||||
}
|
||||
else{ // self && j<i
|
||||
// over b_k_re and b_l_re
|
||||
IDD.set((j+1)*2, (i+1)*2, conj(IDD((i+1)*2, (j+1)*2)) );
|
||||
// over b_k_re and b_l_im
|
||||
IDD.set((j+1)*2, (i+1)*2+1, conj(IDD((i+1)*2+1,(j+1)*2)) );
|
||||
// over b_k_im and b_l_re
|
||||
IDD.set((j+1)*2+1, (i+1)*2, conj(IDD((i+1)*2,(j+1)*2+1)) );
|
||||
// over b_k_im and b_l_im
|
||||
IDD.set((j+1)*2+1,(i+1)*2+1, conj(IDD((i+1)*2+1,(j+1)*2+1 )) );
|
||||
}
|
||||
} // j
|
||||
} // i
|
||||
|
||||
if(real(cc1)){ // adding terms for split-packet
|
||||
|
||||
IDD.set(8, 0, c2*da2_re() ); // over c_1_re and a_2_re
|
||||
IDD.set(8, 1, c2*da2_im() ); // over c_1_re and a_2_im
|
||||
IDD.set(9, 0, -i_unit*c2*da2_re() ); // over c_1_im and a_2_re
|
||||
IDD.set(9, 1, -i_unit*c2*da2_im() ); // over c_1_im and a_2_im
|
||||
|
||||
IDD.set(0, 8, cc1*da1_re() ); // over c_2_re and a_1_re
|
||||
IDD.set(1, 8, cc1*da1_im() ); // over c_2_re and a_1_im
|
||||
IDD.set(0, 9, i_unit*cc1*da1_re() ); // over c_2_im and a_1_re
|
||||
IDD.set(1, 9, i_unit*cc1*da1_im() ); // over c_2_im and a_1_im
|
||||
|
||||
for(int i=0;i<3;i++){
|
||||
IDD.set(8, 2+2*i, c2*db2_re(i) ); // over c_1_re and b_2_re
|
||||
IDD.set(8, 2+2*i+1, c2*db2_im(i) ); // over c_1_re and b_2_im
|
||||
IDD.set(9, 2+2*i, -i_unit*c2*db2_re(i) ); // over c_1_im and b_2_re
|
||||
IDD.set(9, 2+2*i+1, -i_unit*c2*db2_im(i) ); // over c_1_im and b_2_im
|
||||
|
||||
IDD.set(2+2*i, 8, cc1*db1_re(i) ); // over c_2_re and b_1_re
|
||||
IDD.set(2+2*i+1, 8, cc1*db1_im(i) ); // over c_2_re and b_1_im
|
||||
IDD.set(2+2*i, 9, i_unit*cc1*db1_re(i) ); // over c_2_im and i_1_re
|
||||
IDD.set(2+2*i+1, 9, i_unit*cc1*db1_im(i) ); // over c_2_im and a_1_im
|
||||
}
|
||||
|
||||
IDD.set(8, 8, I0 ); // over c_1_re and c_2_re
|
||||
IDD.set(8, 9, i_unit*I0 ); // over c_1_re and c_2_im
|
||||
IDD.set(9, 8, -i_unit*I0 ); // over c_1_im and c_2_re
|
||||
IDD.set(9, 9, I0 ); // over c_1_im and c_2_im
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
WavePacket AWPMD::create_wp(Vector_3 &x, Vector_3 &v, double &w, double &pw, double mass){
|
||||
if(mass<0)
|
||||
mass=me;
|
||||
if(constraint==FIX){
|
||||
if(w0>0)
|
||||
w=w0;
|
||||
pw=0.;
|
||||
}
|
||||
|
||||
double rw;
|
||||
if(Lextra>0){ // width PBC, keeping the width are within [0,Lextra]
|
||||
w=fmod(w,Lextra);
|
||||
if(w<0) w+=Lextra;
|
||||
rw=w; // WP width for energy evaluation is within [0, L/2]
|
||||
if(rw > Lextra/2) rw = Lextra - rw;
|
||||
}
|
||||
else
|
||||
rw=w;
|
||||
|
||||
WavePacket wp;
|
||||
wp.init(rw,x,v*mass*one_h,pw*one_h);
|
||||
return wp;
|
||||
}
|
||||
|
||||
|
||||
void AWPMD::resize(int flag){
|
||||
for(int s=0;s<2;s++){
|
||||
//0. resizing matrices
|
||||
Y[s].init(ne[s],1);
|
||||
O[s].init(ne[s],1);
|
||||
Oflg[s].init(ne[s],1);
|
||||
//Te[s].init(nel,1);
|
||||
//Tei[s].init(nel,1);
|
||||
Eep[s].assign((size_t)nwp[s],0);
|
||||
Eeip[s].assign((size_t)nwp[s],0);
|
||||
Eeep[s].assign((size_t)nwp[s],0);
|
||||
Ewp[s].assign((size_t)nwp[s],0);
|
||||
|
||||
if(flag&(0x8|0x4) && approx!=HARTREE){ //electron forces, L and M are needed
|
||||
M[s].init(ne[s],nvar[s]);
|
||||
L[s].init(ne[s],nvar[s]);
|
||||
}
|
||||
}
|
||||
Eiep.assign((size_t)ni,0);
|
||||
Eiip.assign((size_t)ni,0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//e sets Periodic Boundary Conditions
|
||||
//e using bit flags: 0x1 -- PBC along X
|
||||
//e 0x2 -- PBC along Y
|
||||
//e 0x4 -- PBC along Z
|
||||
//e cell specifies the lengths of the simulation box in all directions
|
||||
//e if PBCs are used, the corresponding coordinates of electrons and ions
|
||||
//e in periodic directions must be within a range [0, cell[per_dir])
|
||||
//e @returns 1 if OK
|
||||
int AWPMD::set_pbc(const Vector_3P pcell, int pbc_){
|
||||
if(!pcell)
|
||||
pbc=0;
|
||||
else{
|
||||
pbc=pbc_;
|
||||
cell=*pcell;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//e setup elctrons: forms internal wave packet representations
|
||||
//e if PBCs are used the coords must be within a range [0, cell)
|
||||
int AWPMD::set_electrons(int s, int n, Vector_3P x, Vector_3P v, double* w, double* pw, double mass, double *q)
|
||||
{
|
||||
if(s < 0 || s > 1)
|
||||
return LOGERR(-1,fmt("AWPMD.set_electrons: invaid s setting (%d)!",s),LINFO);
|
||||
|
||||
norm_matrix_state[s] = NORM_UNDEFINED;
|
||||
nwp[s]=ne[s]=n;
|
||||
nvar[s]=8*n;
|
||||
wp[s].resize(n);
|
||||
|
||||
partition1[s].clear();
|
||||
for(int i=0;i<n;i++){
|
||||
wp[s][i]=create_wp(x[i],v[i],w[i],pw[i], mass);
|
||||
// assign default partition
|
||||
partition1[s].push_back(i+1);
|
||||
}
|
||||
|
||||
// assign electronic charge
|
||||
if(q)
|
||||
qe[s].assign(q,q+nwp[s]);
|
||||
else
|
||||
qe[s].assign(nwp[s],-1);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//e setup ion charges and coordinates
|
||||
//e if PBCs are used the coords must be within a range [0, cell)
|
||||
int AWPMD::set_ions(int n, double* q, Vector_3P x)
|
||||
{
|
||||
ni = n;
|
||||
qi.resize(n);
|
||||
xi.resize(n);
|
||||
partition1[2].clear();
|
||||
for(int i=0;i<n;i++){
|
||||
qi[i] = q[i], xi[i] = x[i];
|
||||
// assign default partition for ions
|
||||
partition1[2].push_back(i+1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//e same as interaction, but using Hartee factorization (no antisymmetrization)
|
||||
int AWPMD::interaction_hartree(int flag, Vector_3P fi, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c){
|
||||
|
||||
// 0. resizing the arrays if needed
|
||||
enum APPROX tmp=HARTREE;
|
||||
swap(tmp,approx); // do not neeed large matrices
|
||||
resize(flag);
|
||||
swap(tmp,approx);
|
||||
//1. clearing forces
|
||||
clear_forces(flag,fi,fe_x,fe_p,fe_w,fe_pw,fe_c);
|
||||
|
||||
Eee = Ew = 0.;
|
||||
for(int s1=0;s1<2;s1++){
|
||||
Ee[s1]=0.;
|
||||
Eei[s1]=0.;
|
||||
for(int c1=0;c1<ne[s1];c1++){
|
||||
// width part
|
||||
double w1=wp[s1][c1].get_width();
|
||||
/*double sgn1=1;
|
||||
if(Lextra>0){ // width PBC
|
||||
if(w1>Lextra-w1){
|
||||
w1=-(Lextra-w1); // '-' is to change derivative sign
|
||||
sgn1=-1;
|
||||
}
|
||||
}*/
|
||||
Vector_3 r1=wp[s1][c1].get_r();
|
||||
Vector_3 p=wp[s1][c1].get_p()*h_plank;
|
||||
Vector_3 pw=wp[s1][c1].get_pwidth()*h_plank;
|
||||
// energy contribution
|
||||
Ee[s1] += (p.norm2()+pw.norm2())/(2*me);
|
||||
Ew += h2_me*9./(8.*w1*w1);
|
||||
if(constraint == HARM) Ew += harm_w0_4 * w1*w1;
|
||||
// width force contribution
|
||||
//double dE=2*Epot/w;
|
||||
//if(d->fw1)d->fw1[c1]+=dE;
|
||||
//if(fw2 && fw2!=fw1)fw2[c1]+=dE;
|
||||
|
||||
// e-e interaction
|
||||
for(int s2=s1;s2<2;s2++){
|
||||
for(int c2=(s1==s2 ? c1+1 : 0) ;c2<ne[s2];c2++){
|
||||
double w2=wp[s2][c2].get_width();
|
||||
Vector_3 v12=wp[s2][c2].get_r()-r1;
|
||||
// position PBC
|
||||
v12=v12.rcell1(cell,pbc);
|
||||
double r12=v12.normalize();
|
||||
/*double sgn2=1; // signs
|
||||
if(Lextra>0){ // width PBC
|
||||
if(w2>Lextra-w2){
|
||||
w2=-(Lextra-w2); // '-' is to change derivative sign
|
||||
sgn2=-1;
|
||||
}
|
||||
}*/
|
||||
double wsq=w1*w1+w2*w2;
|
||||
double argw=sqrt((2./3.)*wsq);
|
||||
|
||||
//double arg=r12/argw;
|
||||
//double erfa=erf(arg);
|
||||
double Epot=coul_pref*erf_div(r12,1./argw); //erfa/r12;
|
||||
Eee+=Epot;
|
||||
|
||||
// force contribution
|
||||
/*double dEw=coul_pref*two_over_sqr_pi*exp(-arg*arg)/argw;
|
||||
double dEpot=(Epot-dEw)/r12;
|
||||
if(!d->fixw){
|
||||
dEw/=wsq;
|
||||
if(d->fw1 && c1>=0){
|
||||
d->fw1[c1]+=sgn1*dEw*w1;
|
||||
}
|
||||
if(d->fw2){
|
||||
d->fw2[c2]+=sgn2*dEw*w2;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
// e-i interaction
|
||||
double wsq1=w1*w1;
|
||||
double argw=sqr_2_over_3*w1;
|
||||
for(int i=0;i<ni;i++){
|
||||
Vector_3 v12=xi[i]-r1;
|
||||
// position PBC
|
||||
v12=v12.rcell1(cell,pbc);
|
||||
double r12=v12.normalize();
|
||||
|
||||
//double arg=r12/argw;
|
||||
//double erfa=erf(arg);
|
||||
double cel=-coul_pref*qi[i]; // electron charge is always -1
|
||||
double Epot=cel*erf_div(r12,1./argw); //erfa/r12;
|
||||
Eei[s1]+=Epot;
|
||||
//printf("(%g %g %g)- (%g %g %g)\n",r1[0],r1[1],r1[2],xi[i][0],xi[i][1],xi[i][2]);
|
||||
//printf("awp(%d,%d:%d)[%g]: %g\n",i,s1,c1,r12,Epot);
|
||||
// force contribution
|
||||
if(flag&0x3){
|
||||
double arg=r12/argw;
|
||||
double dEw=cel*two_over_sqr_pi*exp(-arg*arg)/argw;
|
||||
double dEpot=(Epot-dEw)/r12;
|
||||
fi[i]+=v12*dEpot; // ionic force
|
||||
}
|
||||
// electron force
|
||||
/*if(!d->fixw){
|
||||
dEw/=wsq;
|
||||
if(d->fw1 && c1>=0){
|
||||
d->fw1[c1]+=sgn1*dEw*w1;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if(calc_ii)
|
||||
interaction_ii(flag,fi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//e initializes internal buffers for calculations (set_electrons must be called first)
|
||||
//int init(){}
|
||||
|
||||
//e calculates interaction in the system of ni ions + electrons
|
||||
//e the electonic subsystem must be previously setup by set_electrons, ionic by set_ions
|
||||
//e the iterators are describing ionic system only
|
||||
// 0x1 -- give back ion forces
|
||||
// 0x2 -- add ion forces to the existing set
|
||||
// 0x4 -- calculate derivatives for electronic time step (NOT IMPLEMENTED)
|
||||
//e if PBCs are used the coords must be within a range [0, cell)
|
||||
int AWPMD::interaction(int flag, Vector_3P fi, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c){
|
||||
if(approx==HARTREE)
|
||||
return interaction_hartree(flag,fi,fe_x,fe_p,fe_w,fe_pw,fe_c);
|
||||
// 0. resizing the arrays if needed
|
||||
resize(flag);
|
||||
// 1. clearing forces
|
||||
clear_forces(flag,fi,fe_x,fe_p,fe_w,fe_pw,fe_c);
|
||||
|
||||
//2. calculating overlap matrix
|
||||
for(int s=0;s<2;s++){
|
||||
int nes = ne[s];
|
||||
if(nes == 0) continue;
|
||||
|
||||
for(int k=0;k<nes;k++){
|
||||
Y[s].set(k,k,1.); // Diagonal elements (=1)
|
||||
Oflg[s](k,k) = 1;
|
||||
for(int l=k+1;l<nes;l++){
|
||||
cdouble I0kl = pbc_mul(wp[s][l],wp[s][k]).integral(); // Non-diagonal elements
|
||||
Y[s].set(k,l,I0kl);
|
||||
Oflg[s](k,l) = (norm(I0kl) > ovl_tolerance);
|
||||
}
|
||||
}
|
||||
O[s] = Y[s]; // save overlap matrix
|
||||
|
||||
//3. inverting the overlap matrix
|
||||
int info=0;
|
||||
if(nes){
|
||||
/*FILE *f1=fopen(fmt("matrO_%d.d",s),"wt");
|
||||
fileout(f1,Y[s],"%15g");
|
||||
fclose(f1);8*/
|
||||
|
||||
ZPPTRF("L",&nes,Y[s].arr,&info);
|
||||
// analyze return code here
|
||||
if(info<0)
|
||||
return LOGERR(info,fmt("AWPMD.interacton: call to ZPTRF failed (exitcode %d)!",info),LINFO);
|
||||
ZPPTRI("L",&nes,Y[s].arr,&info);
|
||||
if(info<0)
|
||||
return LOGERR(info,fmt("AWPMD.interacton: call to ZPTRI failed (exitcode %d)!",info),LINFO);
|
||||
|
||||
|
||||
/*f1=fopen(fmt("matrY_%d.d",s),"wt");
|
||||
fileout(f1,Y[s],"%15g");
|
||||
fclose(f1);*/
|
||||
}
|
||||
|
||||
// Clearing matrices for electronic forces
|
||||
if(flag&0x4){
|
||||
Te[s].Set(0.);
|
||||
Tei[s].Set(0.);
|
||||
}
|
||||
}
|
||||
|
||||
Vector_3 ndr;
|
||||
// calculating single particle contribution
|
||||
for(int s=0;s<2;s++){
|
||||
Ee[s]=Eei[s]=0.;
|
||||
for(int k=0;k<ne[s];k++){
|
||||
for(int l=k;l<ne[s];l++){
|
||||
|
||||
if( !Oflg[s](k,l) ) continue; // non-overlapping WPs
|
||||
|
||||
// electrons kinetic energy
|
||||
WavePacket wk=wp[s][k];
|
||||
WavePacket& wl=wp[s][l];
|
||||
if(pbc)
|
||||
ndr=move_to_image(wl,wk);
|
||||
|
||||
WavePacket wkl=wl*conj(wk);
|
||||
//Vector_3 rrkl=wkl.get_r();
|
||||
cVector_3 v1=wl.b*conj(wk.a)-conj(wk.b)*wl.a;
|
||||
cdouble v=(v1*v1)/wkl.a;
|
||||
v-=6.*conj(wk.a)*wl.a;
|
||||
v/=wkl.a;
|
||||
cdouble I0kl = O[s](k,l);
|
||||
cdouble dE=-h2_me*I0kl*v/2;
|
||||
if(flag&0x4) // matrix needed only for electronic forces
|
||||
Te[s].set(k,l,dE);
|
||||
// energy component (trace)
|
||||
dE*=Y[s](l,k);
|
||||
Ee[s]+=(l==k ? 1. : 2.)*real(dE);
|
||||
|
||||
cVector_3 dkl=wkl.b/(2.*wkl.a);
|
||||
|
||||
// e-i energy
|
||||
cdouble sum(0.,0.);
|
||||
for(int i=0;i<ni;i++){ // ions loop
|
||||
cVector_3 gkli=dkl - cVector_3(xi[i]);
|
||||
|
||||
if(pbc) // correcting the real part (distance) according to PBC
|
||||
gkli=rcell1(gkli,cell,pbc);
|
||||
//-Igor- gkli=cVector_3(real(gkli).rcell1(cell,pbc),imag(gkli));
|
||||
|
||||
cdouble ngkli=gkli.norm();
|
||||
cdouble c=sqrt(wkl.a);
|
||||
//cdouble ttt = cerf_div(ngkli,c);
|
||||
dE=-coul_pref*(qi[i])*I0kl*cerf_div(ngkli,c);
|
||||
|
||||
sum+=dE;
|
||||
if(flag&0x3){// calculate forces on ions
|
||||
if(fabs(real(ngkli))+fabs(imag(ngkli))>1e-10){
|
||||
cdouble arg=ngkli*c;
|
||||
cdouble dEw=-coul_pref*qi[i]*I0kl*two_over_sqr_pi*exp(-arg*arg)*c;
|
||||
dE=(dE-dEw)/ngkli;
|
||||
dE*=Y[s](l,k);
|
||||
Vector_3 dir=-real(gkli);
|
||||
dir.normalize();
|
||||
fi[i]+=(l==k ? 1. : 2.)*real(dE)*dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
dE=sum;
|
||||
if(flag&0x4) // matrix needed only for electronic forces
|
||||
Tei[s].set(k,l,dE);
|
||||
// energy component (trace)
|
||||
dE*=Y[s](l,k);
|
||||
Eei[s]+=(l==k ? 1. : 2.)*real(dE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculating e-e interaction
|
||||
Eee = Ew = 0.;
|
||||
// same spin
|
||||
for(int s=0;s<2;s++){ // spin
|
||||
for(int k=0;k<ne[s];k++){ //c1
|
||||
for(int l=k+1;l<ne[s];l++){ //c3
|
||||
for(int m=k;m<ne[s];m++){ //c2
|
||||
|
||||
if( Oflg[s](k,m) ) {
|
||||
WavePacket wkm=pbc_mul(wp[s][m],wp[s][k]);
|
||||
cVector_3 dkm=wkm.b/(2*wkm.a);
|
||||
cdouble I0km=O[s](k,m);
|
||||
|
||||
// kl-mn
|
||||
for(int n=l;n<ne[s];n++){ //c4
|
||||
if(n<=m || !Oflg[s](l,n)) continue;
|
||||
|
||||
WavePacket wln=pbc_mul(wp[s][n],wp[s][l]);
|
||||
if(pbc) // reducing the pair to elementary cell
|
||||
ndr=move_to_image(wkm,wln); // mind the derivative: wln.b+=wln.a*ndr, wln.lz+=-wln.a*ndr^2-i*wln.old_p*ndr;
|
||||
//Vector_3 rln=wln.get_r();
|
||||
|
||||
cVector_3 dln=wln.b/(2*wln.a);
|
||||
cdouble dd=(dkm-dln).norm();
|
||||
cdouble c=1./sqrt(1./wln.a+1./wkm.a);
|
||||
cdouble Vklmn=coul_pref*I0km*O[s](l,n)*cerf_div(dd,c);
|
||||
|
||||
//cdouble arge=dkm*dkm*wkm.a+dln*dln*wln.a+wkm.lz+wln.lz;
|
||||
//cdouble Vklmn=0.5*coul_pref*M_PI*M_PI*M_PI*exp(arge)*cerf_div(dd,c)/pow(wln.a*wkm.a,3./2.);
|
||||
cdouble dE=Vklmn*(Y[s](m,k)*Y[s](n,l)-Y[s](m,l)*Y[s](n,k));
|
||||
double rdE=real(dE);
|
||||
if(m!=k || n!=l) // not the same pair
|
||||
rdE*=2;
|
||||
Eee+=rdE;
|
||||
}//n
|
||||
}
|
||||
|
||||
if( Oflg[s](l,m) ) {
|
||||
WavePacket wlm=pbc_mul(wp[s][m],wp[s][l]);
|
||||
cVector_3 dlm=wlm.b/(2*wlm.a);
|
||||
cdouble I0lm=O[s](l,m);
|
||||
|
||||
// kl-nm
|
||||
for(int n=l;n<ne[s];n++){
|
||||
if(n<=m || !Oflg[s](k,n)) continue;
|
||||
|
||||
WavePacket wkn=pbc_mul(wp[s][n],wp[s][k]);
|
||||
if(pbc) // reducing the pair to elementary cell
|
||||
ndr=move_to_image(wlm,wkn); // mind the derivative: wln.b+=wln.a*ndr, wln.lz+=-wln.a*ndr^2-i*wln.old_p*ndr;
|
||||
|
||||
cVector_3 dkn=wkn.b/(2*wkn.a);
|
||||
cdouble dd=(dkn-dlm).norm();
|
||||
cdouble c=1./sqrt(1./wkn.a+1./wlm.a);
|
||||
cdouble Vklnm=coul_pref*I0lm*O[s](k,n)*cerf_div(dd,c);
|
||||
|
||||
cdouble dE=Vklnm*(Y[s](n,k)*Y[s](m,l)-Y[s](n,l)*Y[s](m,k));
|
||||
double rdE=real(dE);
|
||||
if(m!=k || n!=l) // not the same pair
|
||||
rdE*=2;
|
||||
Eee+=rdE;
|
||||
}//n
|
||||
}
|
||||
}// m
|
||||
}// l
|
||||
}// k
|
||||
}// s
|
||||
|
||||
// different spin
|
||||
for(int k=0;k<ne[0];k++){ // skm=0 //c1
|
||||
for(int l=0;l<ne[1];l++){ // sln=1 //c3
|
||||
for(int m=k;m<ne[0];m++){ //c2
|
||||
if( Oflg[0](k,m) ) {
|
||||
WavePacket wkm=pbc_mul(wp[0][m],wp[0][k]);
|
||||
cVector_3 dkm=wkm.b/(2*wkm.a);
|
||||
cdouble I0km=O[0](k,m);
|
||||
|
||||
for(int n=l;n<ne[1];n++){ // km-ln //c4
|
||||
if( Oflg[1](n,l) ) {
|
||||
WavePacket wln=pbc_mul(wp[1][l],wp[1][n]);
|
||||
if(pbc) // reducing the pair to elementary cell
|
||||
ndr=move_to_image(wkm,wln); // mind the derivative: wln.b+=wln.a*ndr, wln.lz+=-wln.a*ndr^2-i*wln.old_p*ndr;
|
||||
//Vector_3 rln=wln.get_r();
|
||||
|
||||
cVector_3 dln=wln.b/(2*wln.a);
|
||||
cdouble dd=(dkm-dln).norm();
|
||||
cdouble c=1./sqrt(1./wln.a+1./wkm.a);
|
||||
cdouble Vklmn=coul_pref*I0km*wln.integral()*cerf_div(dd,c);
|
||||
|
||||
cdouble dE=Vklmn*Y[0](m,k)*Y[1](n,l);
|
||||
int Mkm=(m==k ? 1: 2);
|
||||
int Mln=(n==l ? 1: 2);
|
||||
double rdE=Mkm*Mln*real(dE); //!!!
|
||||
Eee+=rdE;
|
||||
} //if
|
||||
} // n
|
||||
} //if
|
||||
} // m
|
||||
}// l
|
||||
}// k
|
||||
if(calc_ii)
|
||||
interaction_ii(flag,fi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//e Calculates Norm matrix and performs LU-factorization
|
||||
//e The result is saved in AWPMD::Norm[s]
|
||||
void AWPMD::norm_matrix(int s){
|
||||
// Internal variables
|
||||
int k, l, i, j, qi, qj;
|
||||
int nes = ne[s], nes8 = nes*8, nnes8 = nes*nes8;
|
||||
|
||||
if(!nes) return;
|
||||
|
||||
// References for frequently used arrays
|
||||
sqmatrix<double>& Norms = Norm[s];
|
||||
chmatrix& Ys = Y[s];
|
||||
smatrix<unsigned char>& Oflgs = Oflg[s];
|
||||
|
||||
// Allocate of vectors and matrices
|
||||
Norms.init(nes8,1);
|
||||
IDD.init(nes8,1);
|
||||
if(ID.size() != nnes8)
|
||||
ID.resize(nnes8), IDYs.resize(nnes8), ipiv.resize(nes8);
|
||||
|
||||
// Calculate first and second derivatives
|
||||
for(k=0;k<nes;k++){
|
||||
int k8 = k*8;
|
||||
WavePacket& wk = wp[s][k];
|
||||
NormDeriv dk(wk);
|
||||
dk = conj(dk); // conjugate: mu -> -mu, v -> -v !!!
|
||||
|
||||
for(l=0;l<nes;l++){
|
||||
if( !Oflgs(k,l) ) continue; // non-overlapping WPs
|
||||
|
||||
int l8 = l*8;
|
||||
WavePacket wl = wp[s][l];
|
||||
if(pbc) move_to_image(wk,wl);
|
||||
WavePacket wkl=conj(wk)*wl;
|
||||
NormDeriv dl(wl);
|
||||
|
||||
cdouble I0 = O[s](k,l);
|
||||
cVector_3 I1 = wkl.b * (I0 / wkl.a / 2);
|
||||
cdouble bb_4a = wkl.b.norm2() / wkl.a / 4;
|
||||
cdouble I2 = I0 * (bb_4a + 1.5) / wkl.a;
|
||||
|
||||
// calculate derivatives <phi_k | (phi_l)'_q_l>:
|
||||
int idx = k + l*nes8;
|
||||
if(k != l) {
|
||||
ID[idx] = dl.l*I0 - I2; // over a_l_re
|
||||
ID[idx+nes] = i_unit*(dl.m*I0 - I2); // over a_l_im
|
||||
for(i=0;i<3;i++){
|
||||
ID[idx+((i+1)*2)*nes] = dl.u[i]*I0 + I1[i]; // over b_l_re
|
||||
ID[idx+((i+1)*2+1)*nes] = i_unit*(dl.v[i]*I0 + I1[i]); // over b_l_im
|
||||
}
|
||||
} else { // k == l
|
||||
ID[idx] = i_unit*imag(dl.l); // over a_l_re
|
||||
ID[idx+nes] = i_unit*(dl.m - I2); // over a_l_im
|
||||
for(i=0;i<3;i++){
|
||||
ID[idx+((i+1)*2)*nes] = dl.u[i] + I1[i]; // over b_l_re
|
||||
ID[idx+((i+1)*2+1)*nes] = 0.; // over b_l_im
|
||||
}
|
||||
}
|
||||
|
||||
if(k <= l) {
|
||||
cVector_3 I3 = I1 * ((bb_4a + 2.5) / wkl.a);
|
||||
cdouble I4 = I0 * ( bb_4a *(bb_4a + 5.) + 3.75 ) / wkl.a / wkl.a;
|
||||
|
||||
// calculate derivatives <(phi_k)'_q_k | (phi_l)'_q_l>:
|
||||
IDD.set(k8, l8, I4 - (dk.l + dl.l)*I2 + dk.l*dl.l*I0 ); // over a_k_re and a_l_re
|
||||
IDD.set(k8, l8+1, i_unit*( I4 - (dk.l + dl.m)*I2 + dk.l*dl.m*I0 ) ); // over a_k_re and a_l_im
|
||||
if(k != l) IDD.set(k8+1, l8, i_unit1*( I4 + (dk.m - dl.l)*I2 - dk.m*dl.l*I0 ) ); // over a_k_im and a_l_re
|
||||
IDD.set(k8+1, l8+1, I4 + (dk.m - dl.m)*I2 - dk.m*dl.m*I0 ); // over a_k_im and a_l_im
|
||||
|
||||
for(i=0;i<3;i++){
|
||||
IDD.set(k8, l8+(i+1)*2, -I3[i] + dk.l*I1[i] + dl.u[i]*(dk.l*I0 - I2) ); // over a_k_re and b_l_re
|
||||
IDD.set(k8, l8+(i+1)*2+1, i_unit1*( I3[i] - dk.l*I1[i] + dl.v[i]*(I2 - dk.l*I0) ) ); // over a_k_re and b_l_im
|
||||
IDD.set(k8+1, l8+(i+1)*2, i_unit *( I3[i] + dk.m*I1[i] + dl.u[i]*(I2 + dk.m*I0) ) ); // over a_k_im and b_l_re
|
||||
IDD.set(k8+1, l8+(i+1)*2+1, -I3[i] - dk.m*I1[i] - dl.v[i]*(dk.m*I0 + I2) ); // over a_k_im and b_l_im
|
||||
if(k != l) {
|
||||
IDD.set(k8+(i+1)*2, l8, -I3[i] + dl.l*I1[i] + dk.u[i]*(dl.l*I0 - I2) ); // over b_k_re and a_l_re
|
||||
IDD.set(k8+(i+1)*2+1, l8, i_unit *( I3[i] - dl.l*I1[i] - dk.v[i]*(I2 - dl.l*I0) ) ); // over b_k_im and a_l_re
|
||||
IDD.set(k8+(i+1)*2, l8+1, i_unit1*( I3[i] - dl.m*I1[i] + dk.u[i]*(I2 - dl.m*I0) ) ); // over b_k_re and a_l_im
|
||||
IDD.set(k8+(i+1)*2+1, l8+1, -I3[i] + dl.m*I1[i] - dk.v[i]*(dl.m*I0 - I2) ); // over b_k_im and a_l_im
|
||||
}
|
||||
|
||||
for(j=0;j<3;j++){
|
||||
cdouble I2ij = I0 / wkl.a *
|
||||
(i==j ? wkl.b[i]*wkl.b[i] / wkl.a / 4 + 0.5
|
||||
: wkl.b[i]*wkl.b[j] / wkl.a / 4);
|
||||
// over b_k_re and b_l_re
|
||||
IDD.set(k8+(j+1)*2, l8+(i+1)*2, I2ij + dk.u[i]*I1[j] + dl.u[j]*(I1[i] + dk.u[i]*I0) );
|
||||
// over b_k_re and b_l_im
|
||||
IDD.set(k8+(j+1)*2, l8+(i+1)*2+1, i_unit *( I2ij + dk.u[i]*I1[j] + dl.v[j]*(I1[i] + dk.u[i]*I0) ) );
|
||||
// over b_k_im and b_l_re
|
||||
if(k != l) IDD.set(k8+(j+1)*2+1, l8+(i+1)*2, i_unit1*( I2ij - dk.v[i]*I1[j] + dl.u[j]*(I1[i] - dk.v[i]*I0) ) );
|
||||
// over b_k_im and b_l_im
|
||||
IDD.set(k8+(j+1)*2+1, l8+(i+1)*2+1, I2ij - dk.v[i]*I1[j] + dl.v[j]*(I1[i] - dk.v[i]*I0) );
|
||||
} // j
|
||||
} // i
|
||||
} // if(k <= l)
|
||||
} // k
|
||||
} // l
|
||||
|
||||
// Calculate matrix product IDYs_(k,q_j) = Ys_(k,l) * <phi_l | (phi_j)'_q_j>
|
||||
for(qj=0; qj<nes8; qj++){
|
||||
j = qj / 8;
|
||||
int idx = qj*nes;
|
||||
for(k=0;k<nes;k++) {
|
||||
cdouble sum = 0.;
|
||||
for(l=0;l<nes;l++)
|
||||
if( Oflgs(l,j) ) sum += ID[idx+l] * Ys(k,l);
|
||||
IDYs[idx+k] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Norm-matrix
|
||||
for(qi=0; qi<nes8; qi++){
|
||||
i = qi / 8;
|
||||
int idxqi = qi*nes;
|
||||
|
||||
Norms(qi,qi) = 0.; // zero diagonal elements
|
||||
|
||||
for(qj=qi+1; qj<nes8; qj++){
|
||||
j = qj / 8;
|
||||
int idxqj = qj*nes;
|
||||
|
||||
// Calculate matrix product sum = <(phi_i)'_q_i | phi_k> * IDYs_(k,q_j)
|
||||
cdouble sum = 0.;
|
||||
for(k=0;k<nes;k++)
|
||||
if( Oflgs(i,k) )
|
||||
sum += IDYs[idxqj+k] * conj(ID[idxqi+k]);
|
||||
|
||||
// Update norm-matrix taking into account its anti-symmetry
|
||||
double a = Oflgs(i,j) ? // IDD = 0 for non-overlapping WPs
|
||||
h_plank2 * imag( (sum - IDD(qi,qj))*Ys(j,i) ) :
|
||||
h_plank2 * imag( sum*Ys(j,i) );
|
||||
Norms(qi,qj) = a;
|
||||
Norms(qj,qi) = -a;
|
||||
} // qj
|
||||
} // qi
|
||||
|
||||
# if 1
|
||||
// transform norm matrix to the physical variables
|
||||
for(i=0;i<nes;i++){
|
||||
WavePacket wi=wp[s][i];
|
||||
for(k=0;k<8;k++){
|
||||
// iterator to list all N(8*i+k,*) with fixed 8*i+k
|
||||
sqmatrix<double>::iterator mi=Norms.fix_first(8*i+k,0);
|
||||
for(j=i ;j<nes;j++){ // TO DO: run this loop from i+1 and take simplectic form for (i,i) block
|
||||
WavePacket wj=wp[s][j];
|
||||
wj.int2phys_der< eq_second >(mi+8*j,mi+8*j,mi+8*j+3,mi+8*j+6,mi+8*j+7);
|
||||
}
|
||||
}// finished line of blocks from right
|
||||
for(k= 8*i;k<nes8;k++){ // TO DO: run this loop from 8*i+8 and take simplectic form for (i,i) block
|
||||
// iterator to list all N(8i+*,k) by fixed k
|
||||
sqmatrix<double>::iterator mi=Norms.fix_second(8*i,k);
|
||||
wi.int2phys_der< eq_second >(mi,mi,mi+3,mi+6,mi+7);
|
||||
}// finished line of blocks from left
|
||||
|
||||
for(k=0;k<8;k++){ // filling the lower triangle according to antisymmetry
|
||||
for(j=8*i+8;j<nes8;j++)
|
||||
Norms(j,8*i+k)=-Norms(8*i+k,j);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
# if 0
|
||||
|
||||
// transform norm matrix to the physical variables
|
||||
for(i=0;i<nes;i++){
|
||||
WavePacket wi=wp[s][i];
|
||||
for(j=i;j<nes;j++){
|
||||
WavePacket wj=wp[s][j];
|
||||
for(k=0;k<8;k++){
|
||||
// iterator to list all N(8*i+k,*) with fixed 8*i+k
|
||||
sqmatrix<double>::iterator mi=Norms.fix_first(8*i+k,8*j);
|
||||
wj.int2phys_der< eq_second >(mi,mi,mi+3,mi+6,mi+7);
|
||||
}
|
||||
for(k=0;k<8;k++){
|
||||
// iterator to list all N(8*i+k,*) with fixed 8*i+k
|
||||
sqmatrix<double>::iterator mi=Norms.fix_second(8*i,8*j+k);
|
||||
wi.int2phys_der< eq_second >(mi,mi,mi+3,mi+6,mi+7);
|
||||
}
|
||||
if(i!=j){
|
||||
for(int k1=0;k1<8;k1++){
|
||||
for(int k2=0;k2<8;k2++)
|
||||
Norms(8*j+k1,8*i+k2)=-Norms(8*i+k2,8*j+k1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
norm_matrix_state[s] = NORM_CALCULATED;
|
||||
}
|
||||
|
||||
//e Norm matrix LU-factorization
|
||||
void AWPMD::norm_factorize(int s) {
|
||||
if( norm_matrix_state[s] != NORM_CALCULATED) norm_matrix(s);
|
||||
|
||||
int nes8 = ne[s]*8, info;
|
||||
DGETRF(&nes8, &nes8, Norm[s].arr, &nes8, &ipiv[0], &info);
|
||||
if(info < 0)
|
||||
LOGERR(info,fmt("AWPMD.norm_factorize: call to DGETRF failed (exitcode %d)!",info),LINFO);
|
||||
|
||||
norm_matrix_state[s] = NORM_FACTORIZED;
|
||||
}
|
||||
|
||||
|
||||
//e Norm matrix inversion
|
||||
void AWPMD::norm_invert(int s) {
|
||||
if( norm_matrix_state[s] != NORM_FACTORIZED) norm_factorize(s);
|
||||
|
||||
int nes8 = ne[s]*8, info;
|
||||
int IDD_size = (int)IDD.get_datasize(nes8);
|
||||
|
||||
DGETRI(&nes8, Norm[s].arr, &nes8, &ipiv[0], (double*)IDD.arr, &IDD_size, &info); // use IDD for work storage
|
||||
if(info < 0)
|
||||
LOGERR(info,fmt("AWPMD.norm_invert: call to DGETRI failed (exitcode %d)!",info),LINFO);
|
||||
|
||||
norm_matrix_state[s] = NORM_INVERTED;
|
||||
}
|
||||
|
||||
|
||||
//e Get the determinant of the norm-matrix for the particles with spin s
|
||||
double AWPMD::norm_matrix_det(int s) {
|
||||
double det = 1.;
|
||||
int nes8 = ne[s]*8;
|
||||
|
||||
if(!nes8) return det;
|
||||
if(norm_matrix_state[s] != NORM_FACTORIZED) norm_factorize(s);
|
||||
|
||||
sqmatrix<double>& Norms = Norm[s];
|
||||
for(int i=0; i<nes8; i++)
|
||||
det *= Norms(i, i); // product of the diagonal elements
|
||||
|
||||
return det;
|
||||
}
|
||||
|
||||
|
||||
//e Get the determinant logarithm of the norm-matrix for the particles with spin s
|
||||
double AWPMD::norm_matrix_detl(int s) {
|
||||
double detl = 0.;
|
||||
int nes8 = ne[s]*8;
|
||||
|
||||
if(!nes8) return detl;
|
||||
if(norm_matrix_state[s] != NORM_FACTORIZED) norm_factorize(s);
|
||||
|
||||
sqmatrix<double>& Norms = Norm[s];
|
||||
for(int i=0; i<nes8; i++)
|
||||
detl += log(fabs( Norms(i, i) )); // product of the diagonal elements
|
||||
|
||||
return detl;
|
||||
}
|
||||
|
||||
|
||||
double AWPMD::get_energy(){
|
||||
double res=Eee + Ew;
|
||||
for(int s=0;s<2;s++)
|
||||
res+=Eei[s]+Ee[s];
|
||||
if(calc_ii)
|
||||
res+=Eii;
|
||||
return res;
|
||||
}
|
||||
|
||||
//e makes timestep of electronic component (NOT IMPLEMENTED)
|
||||
int AWPMD::step(double dt){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//e gets current electronic coordinates
|
||||
int AWPMD::get_electrons(int spin, Vector_3P x, Vector_3P v, double* w, double* pw, double mass){
|
||||
if(spin<0 || spin >1)
|
||||
return -1; // invalid spin: return LOGERR(-1,fmt("AWPMD.get_electrons: invaid spin setting (%d)!",spin),LINFO);
|
||||
if(mass<0)
|
||||
mass=me;
|
||||
for(int i=0;i<ni;i++){
|
||||
w[i]=sqrt(3./(4*real(wp[spin][i].a)));
|
||||
pw[i]=-2*w[i]*imag(wp[spin][i].a)/one_h; //pw[i]=-h_plank2*w[i]*imag(wp[spin][i].a);
|
||||
x[i]=real(wp[spin][i].b)/(2*real(wp[spin][i].a));
|
||||
v[i]=(pw[i]*x[i]/w[i] + imag(wp[spin][i].b)/one_h)/mass; //v[i]=(pw[i]*x[i]/w[i] + h_plank*imag(wp[spin][i].b))/m_electron;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AWPMD::clear_forces(int flag,Vector_3P fi, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c){
|
||||
if(flag&0x1){
|
||||
for(int i=0;i<ni;i++)
|
||||
fi[i]=Vector_3(0.);
|
||||
}
|
||||
if(flag&0x4 && !(flag&0x10)){ // electron forces requested in physical representation
|
||||
for(int s1=0;s1<2;s1++){ // clearing forces
|
||||
for(int c1=0;c1<ne[s1];c1++){
|
||||
fe_x[c1]=Vector_3(0,0,0);
|
||||
fe_p[c1]=Vector_3(0,0,0);
|
||||
fe_w[c1]=0;
|
||||
fe_pw[c1]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AWPMD::interaction_ii(int flag,Vector_3P fi){
|
||||
Eii=0.;
|
||||
for(int i=0;i<ni;i++){
|
||||
for(int j=i+1;j<ni;j++){
|
||||
double M12e, M12f;
|
||||
_mytie(M12e,M12f)=check_part1ii(i,j);
|
||||
if(M12f){
|
||||
Vector_3 rij=xi[i]-xi[j];
|
||||
double r=rij.norm();
|
||||
double dE=coul_pref*qi[i]*qi[j]/r;
|
||||
Eii+=M12e*dE;
|
||||
|
||||
Eiip[i]+=0.5*M12e*dE;
|
||||
Eiip[j]+=0.5*M12e*dE;
|
||||
|
||||
if(flag&0x3){ // ion forces needed
|
||||
Vector_3 df=-M12f*dE*rij/(r*r);
|
||||
fi[i]+=df;
|
||||
fi[j]-=df;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
658
lib/awpmd/systems/interact/TCP/wpmd.h
Normal file
658
lib/awpmd/systems/interact/TCP/wpmd.h
Normal file
@ -0,0 +1,658 @@
|
||||
/*s***************************************************************************
|
||||
*
|
||||
* Copyright (c), Ilya Valuev 2005 All Rights Reserved.
|
||||
*
|
||||
* Author : Ilya Valuev, MIPT, Moscow, Russia
|
||||
*
|
||||
* Project : GridMD, ivutils
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*s****************************************************************************
|
||||
* $Log: wpmd.h,v $
|
||||
* Revision 1.4 2011/06/11 16:53:55 valuev
|
||||
* sync with LAMMPS
|
||||
*
|
||||
* Revision 1.3 2011/06/11 16:45:23 morozov
|
||||
* Fixed erf.c for Windows and Unix
|
||||
*
|
||||
* Revision 1.2 2011/06/10 19:25:17 morozov
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.43 2011/06/10 19:20:53 valuev
|
||||
* fixes
|
||||
*
|
||||
* Revision 1.42 2011/06/09 22:55:08 valuev
|
||||
* norm matrices
|
||||
*
|
||||
* Revision 1.41 2011/06/07 19:58:42 valuev
|
||||
* corrected partitions
|
||||
*
|
||||
* Revision 1.40 2011/06/07 17:43:00 valuev
|
||||
* added Y derivatives
|
||||
*
|
||||
* Revision 1.39 2011/06/03 08:13:33 valuev
|
||||
* added partitions to account for ghost atoms
|
||||
*
|
||||
* Revision 1.38 2011/06/02 22:11:17 morozov
|
||||
* Compatibility with LAPACK library
|
||||
*
|
||||
* Revision 1.37 2011/06/01 23:45:35 valuev
|
||||
* modified for LAMMPS compatibility
|
||||
*
|
||||
* Revision 1.36 2011/05/28 17:16:22 valuev
|
||||
* fixed template<>, some fixes to UHF
|
||||
*
|
||||
* Revision 1.35 2011/05/25 21:30:48 morozov
|
||||
* Compatibility with ICC 11.1
|
||||
*
|
||||
* Revision 1.34 2011/05/25 05:23:43 valuev
|
||||
* fixed variable transformation for norm matrix
|
||||
*
|
||||
* Revision 1.33 2011/05/24 19:54:32 valuev
|
||||
* fixed sqmatrix::iterator
|
||||
*
|
||||
* Revision 1.32 2011/05/21 23:06:49 valuev
|
||||
* Norm matrix transform to pysical variables
|
||||
*
|
||||
* Revision 1.31 2011/05/20 21:39:49 valuev
|
||||
* separated norm calculation
|
||||
*
|
||||
* Revision 1.30 2011/05/14 18:56:19 valuev
|
||||
* derivative for ee split interactions
|
||||
*
|
||||
* Revision 1.29 2011/05/05 08:56:02 valuev
|
||||
* working split wp version
|
||||
*
|
||||
* Revision 1.28 2011/05/04 16:48:52 valuev
|
||||
* fixed syntax
|
||||
*
|
||||
* Revision 1.27 2011/05/04 09:04:48 valuev
|
||||
* completed wp_split (except for ee forces)
|
||||
*
|
||||
* Revision 1.26 2011/04/29 03:07:20 valuev
|
||||
* new split wp features
|
||||
*
|
||||
* Revision 1.25 2011/04/22 09:52:49 valuev
|
||||
* working on split WP
|
||||
*
|
||||
* Revision 1.24 2011/04/20 08:43:09 valuev
|
||||
* started adding split packet WPMD
|
||||
*
|
||||
* Revision 1.23 2010/09/03 12:17:48 morozov
|
||||
* The order of parameters in Norm matrix is changed to mimic the order of the single WP parameter storage
|
||||
*
|
||||
* Revision 1.22 2009/08/27 00:01:36 morozov
|
||||
* First working MPI equilibration
|
||||
*
|
||||
* Revision 1.21 2009/04/14 14:44:10 valuev
|
||||
* fixed momentum calculation in hartree model, added "fix" constraint and model="hartree"
|
||||
* to parameters
|
||||
*
|
||||
* Revision 1.20 2009/04/13 17:00:45 morozov
|
||||
* Fixed norm-matrix ratio in AWPMC algorithm
|
||||
*
|
||||
* Revision 1.19 2009/04/06 17:00:28 morozov
|
||||
* Fixed Hartree version of WPMC
|
||||
*
|
||||
* Revision 1.18 2009/04/01 10:06:37 valuev
|
||||
* added Hartee factorization to AWPMD
|
||||
*
|
||||
* Revision 1.17 2009/03/24 16:10:05 morozov
|
||||
* Fixed errors in Norm-matrix calculation related to PBC
|
||||
*
|
||||
* Revision 1.16 2009/03/17 11:40:04 morozov
|
||||
* The prefactor of NormMatrix is corrected
|
||||
*
|
||||
* Revision 1.15 2008/07/23 16:42:12 valuev
|
||||
* Added AWPMD Monte-Carlo
|
||||
*
|
||||
* Revision 1.14 2008/07/23 15:58:32 valuev
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.13 2008/07/21 02:23:22 morozov
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.12 2008/07/18 18:15:31 morozov
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.11 2008/05/29 13:33:05 valuev
|
||||
* VASP band structure
|
||||
*
|
||||
* Revision 1.10 2008/05/14 17:17:26 morozov
|
||||
* Passed 2- and 3-electron test. Added Norm matrix.
|
||||
*
|
||||
* Revision 1.9 2008/05/05 17:29:32 morozov
|
||||
* Fixed errors with Hermitian matrix indeces. Redesigned cVector_3 operations.
|
||||
*
|
||||
* Revision 1.8 2008/04/28 22:16:45 valuev
|
||||
* restructured coulomb term
|
||||
*
|
||||
* Revision 1.7 2008/04/28 09:54:13 valuev
|
||||
* corrected summation for Eee part
|
||||
*
|
||||
*******************************************************************************/
|
||||
# ifndef WPMD_H
|
||||
# define WPMD_H
|
||||
|
||||
/** @file wpmd.h
|
||||
@brief Classes for Wave Packet Molecular Dynamics of two component plasma. */
|
||||
|
||||
# ifndef _USE_MATH_DEFINES
|
||||
# define _USE_MATH_DEFINES
|
||||
# endif
|
||||
# include <complex>
|
||||
# include <vector>
|
||||
# include <cmath>
|
||||
# include "logexc.h"
|
||||
# include "cvector_3.h"
|
||||
# include "pairhash.h"
|
||||
# include "TCP/tcpdefs.h"
|
||||
# include "wavepacket.h"
|
||||
# include "erf.h"
|
||||
# include "cerf.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
# include "lapack_inter.h"
|
||||
|
||||
typedef hmatrix<cdouble> chmatrix;
|
||||
|
||||
const cdouble i_unit = cdouble(0.,1.), i_unit1 = -i_unit;
|
||||
const double h_plank2 = h_plank * 2.;
|
||||
|
||||
//cdouble ccerf(const cdouble &a);
|
||||
|
||||
//e calculates cerf(c*z)/z
|
||||
inline cdouble cerf_div(const cdouble &z, const cdouble &c=i_unit){
|
||||
if((fabs(real(z))+fabs(imag(z)))<1e-8)
|
||||
return c*two_over_sqr_pi;
|
||||
else
|
||||
return cerf(z*c)/z;
|
||||
}
|
||||
|
||||
//e calculates erf(c*z)/z
|
||||
inline double erf_div(const double &z, double c=1){
|
||||
if(fabs(z)<1e-8)
|
||||
return c*two_over_sqr_pi;
|
||||
else
|
||||
return erf(z*c)/z;
|
||||
}
|
||||
|
||||
template<class T1, class T2>
|
||||
struct _myrefpair{
|
||||
T1& first;
|
||||
T2& second;
|
||||
_myrefpair(T1& a, T2 &b):first(a),second(b){}
|
||||
_myrefpair operator=(const pair<T1,T2> &other){
|
||||
first=other.first;
|
||||
second=other.second;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template< class T1, class T2>
|
||||
_myrefpair<T1,T2> _mytie(T1& var1, T2 &var2){
|
||||
return _myrefpair<T1,T2>(var1, var2);
|
||||
}
|
||||
|
||||
inline pair<double,double> operator*(const pair<double,double> &right, double left){
|
||||
return make_pair(right.first*left,right.second*left);
|
||||
}
|
||||
|
||||
// Auxilary class to handle the normalizing term derivatives
|
||||
class NormDeriv
|
||||
{
|
||||
public:
|
||||
cdouble l; // lambda = (f over a_re)
|
||||
double m; // mu = (f over a_im) / i
|
||||
cVector_3 u; // u = (f over b_re)
|
||||
Vector_3 v; // v = (f over b_im) / i
|
||||
|
||||
NormDeriv() {}
|
||||
NormDeriv(const WavePacket& wp) { set(wp); }
|
||||
|
||||
//e Create NormDeriv object and calculate the derivatived for the given WP
|
||||
void set(const WavePacket& wp){
|
||||
Vector_3 br = real(wp.b), bi = imag(wp.b);
|
||||
double ar = real(wp.a), ai = imag(wp.a);
|
||||
double i_2ar = 0.5 / ar, ai_ar = ai / ar;
|
||||
|
||||
v = (-i_2ar) * br;
|
||||
m = v.norm2();
|
||||
u = v * (i_unit1 * ai_ar) - wp.b * i_2ar;
|
||||
l = (1.5*i_2ar + m) + cdouble(0.,2.) * ( (br*bi)*i_2ar*i_2ar - m*ai_ar );
|
||||
}
|
||||
};
|
||||
|
||||
inline NormDeriv conj(const NormDeriv& src){
|
||||
NormDeriv dst;
|
||||
dst.l = conj(src.l);
|
||||
dst.m = -src.m;
|
||||
dst.u = conj(src.u);
|
||||
dst.v = - src.v;
|
||||
return dst;
|
||||
}
|
||||
|
||||
///\en Auxilary class to handle derivatives of overlaps
|
||||
class OverlapDeriv{
|
||||
public:
|
||||
WavePacket w1, w2, w12;
|
||||
NormDeriv d1, d2;
|
||||
cdouble I0, I2;
|
||||
cVector_3 I1;
|
||||
cdouble bb_4a;
|
||||
sqmatrix<cdouble> IDD;
|
||||
|
||||
|
||||
OverlapDeriv():I0(0),I1(0),IDD(10){}
|
||||
|
||||
void set1(const WavePacket& w1_) {
|
||||
w1=w1_;
|
||||
d1.set(w1);
|
||||
d1=conj(d1);
|
||||
}
|
||||
|
||||
//e Create NormDeriv object and calculate the derivatived for the given WP
|
||||
void set2(const WavePacket& w2_, const cdouble *I0_=NULL){
|
||||
w2=w2_;
|
||||
d2.set(w2);
|
||||
w12=conj(w1)*w2;
|
||||
if(!I0_)
|
||||
I0 = w12.integral();
|
||||
else
|
||||
I0=*I0_;
|
||||
I1 = w12.b * (I0 / w12.a / 2);
|
||||
bb_4a = w12.b.norm2() / w12.a / 4;
|
||||
I2 = I0 * (bb_4a + 1.5) / w12.a;
|
||||
}
|
||||
|
||||
cdouble da2_re() const {
|
||||
return (d2.l*I0 - I2);
|
||||
}
|
||||
|
||||
cdouble da2_im() const {
|
||||
return i_unit*(d2.m*I0 - I2);
|
||||
}
|
||||
|
||||
cdouble da1_re() const {
|
||||
return (d1.l*I0 - I2);
|
||||
}
|
||||
|
||||
cdouble da1_im() const {
|
||||
return -i_unit*(d1.m*I0 - I2);
|
||||
}
|
||||
|
||||
cdouble db2_re(int i) const {
|
||||
return d2.u[i]*I0 + I1[i];
|
||||
}
|
||||
|
||||
cdouble db2_im(int i) const {
|
||||
return i_unit*(d2.v[i]*I0 + I1[i]);
|
||||
}
|
||||
|
||||
cdouble db1_re(int i) const {
|
||||
return d1.u[i]*I0 + I1[i];
|
||||
}
|
||||
|
||||
cdouble db1_im(int i) const {
|
||||
return -i_unit*(d1.v[i]*I0 + I1[i]);
|
||||
}
|
||||
|
||||
///\en Calculates derivative overlap matrix IDD
|
||||
void calc_der_overlap(bool self=false, cdouble cc1=0., cdouble c2=0.);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class AWPMD {
|
||||
//protected:
|
||||
public:
|
||||
int ne[2], ni;
|
||||
int nwp[2]; ///<\en number of wavepackets (same as ne for unsplit version)
|
||||
int nvar[2]; ///<\en full number of dynamic variables for each spin
|
||||
chmatrix O[2], Y[2], Te[2], Tei[2];
|
||||
smatrix<unsigned char> Oflg[2]; ///<\en equals 0 for non-overlaping packets
|
||||
sqmatrix<double> Norm[2]; ///<\en Norm matrix
|
||||
vector<WavePacket> wp[2]; ///<\en wave packets for electrons (spin up =0 and down =1)
|
||||
vector<double> qe[2]; ///<\en electron charges
|
||||
vector<double> qi; ///<\en ion charges
|
||||
vector<Vector_3> xi; ///<\en ion coordinates
|
||||
int pbc; ///<\en pbc flag
|
||||
Vector_3 cell; ///<\en cell coordinates (L1,L2,L3)
|
||||
double Lextra; ///<\en width PBC, unset if negative
|
||||
double harm_w0_4;
|
||||
double w0;
|
||||
int calc_ii; ///<\en flag indicating whether to calculate ion-ion interaction
|
||||
int norm_needed; ///<\en flag indicating whether to prepare norm matrix data in interaction function
|
||||
|
||||
enum {NORM_UNDEFINED, NORM_CALCULATED, NORM_FACTORIZED, NORM_INVERTED};
|
||||
int norm_matrix_state[2];
|
||||
|
||||
// Arrays for temporal data
|
||||
chmatrix IDD; // Second derivatives of the overlap integral (used in Norm matrix)
|
||||
vector<cdouble> ID, IDYs; // First derivatives of the overlap integral (used in Norm matrix)
|
||||
vector<int> ipiv; // The pivot indices array
|
||||
|
||||
recmatrix<cdouble> L[2]; ///<\en overlap derivative matrix for each spin
|
||||
recmatrix<cdouble> M[2]; ///<\en 'normalized' overlap derivative matrix for each spin: M=YL
|
||||
|
||||
public:
|
||||
enum {NONE=0, HARM, FIX, RELAX} constraint;
|
||||
|
||||
///\em Sets approximation level for quantum problem: \n
|
||||
/// HARTREE Hartree product (no antisymmetrization) \n
|
||||
/// DPRODUCT product of det0*det1 of antisymmetrized functions for spins 0, 1 \n
|
||||
/// UHF unrestricted Hartree-Fock
|
||||
enum APPROX {HARTREE, DPRODUCT, UHF } approx;
|
||||
///\em Sets overlap matrix element to zero if the overlap norm is less than this value
|
||||
double ovl_tolerance;
|
||||
|
||||
double Ee[2]; ///<\en electron kinetic energy for each spin
|
||||
double Eei[2]; ///<\en electron-ion energy for each spin
|
||||
double Eee, Ew; ///<\en electron-electron energy
|
||||
double Eii; ///<\en ion-ion energy
|
||||
double Edk; ///<\en sum of diagonal kinetic energy terms
|
||||
double Edc; ///<\en sum of diagonal Coulomb energy terms
|
||||
|
||||
vector<double> Eep[2]; ///<\en per particle electron kinetic energy for each spin
|
||||
vector<double> Eeip[2]; ///<\en per particle electron-ion energy for each spin
|
||||
vector<double> Eeep[2]; ///<\en per particle electron-electron energy for each spin
|
||||
vector<double> Ewp[2]; ///<\en per particle restrain energy for each spin
|
||||
vector<double> Eiep; ///<\en per particle ion-electron energy
|
||||
vector<double> Eiip; ///<\en per particle ion-ion energy
|
||||
|
||||
|
||||
///\en \{ Conversion constants that depend on the unit system used (for LAMMPS compatibility).
|
||||
/// Default is GRIDMD units. Change them according to your unit system.
|
||||
double me; ///<\en electron mass (LAMMPS: me in the appropriate unit system)
|
||||
double one_h; ///<\en inverse of Plancks constant (LAMMPS: conversion [(m*v)/h] to [distance] )
|
||||
double h2_me; ///<\en Plancks constant squared divided by electron mass (LAMMPS: conversion [h^2/(m*r^2)] to [Energy] )
|
||||
double coul_pref; ///<\en Coulomb prefactor (e2 for GRIDMD) (LAMMPS: conversion [q^2/r] to [Energy] )
|
||||
/// \}
|
||||
|
||||
///\en 0 -- indicates that the inter-partition force should be full, and energy half,\n
|
||||
/// 1 -- inter-partition force and energy counts one half (LAMMPS compatibility)
|
||||
int newton_pair;
|
||||
|
||||
//int myid; ///<\en id for partitions
|
||||
|
||||
///\en Partition arrays storing the tags of particles. The initial tags should be >0.
|
||||
/// If the tag stored is <0, then the particle is ghost with -tag.
|
||||
/// partition1[2] is for ions, 0, 1 for each electron spin
|
||||
vector<int> partition1[3];
|
||||
//vector<int> partition2[3]; ///<\en 2 for ions
|
||||
|
||||
|
||||
int tag_index(int i, int j){
|
||||
return i==j ? -1 : (i>j ? (i-2)*(i-1)/2+j : (j-2)*(j-1)/2+i );
|
||||
}
|
||||
|
||||
|
||||
///\en 1 -- all my, -1 all other, 2 -- my mixed term, -2 -- other mixed term
|
||||
int check_ee(int s1,int icj1,int ick2){
|
||||
//printf(" (%d %d) ",partition1[s1][icj1],partition1[s1][ick2]);
|
||||
int c1=(int)(partition1[s1][icj1]>0);
|
||||
int c2=(int)(partition1[s1][ick2]>0);
|
||||
int res;
|
||||
if(c1!=c2){ // mixed
|
||||
int tag1=abs(partition1[s1][icj1]);
|
||||
int tag2=abs(partition1[s1][ick2]);
|
||||
int num=tag_index(tag1-1,tag2-1);
|
||||
if(num<0){ // compare wave packets
|
||||
int cmp= s1<2 ?
|
||||
wp[s1][icj1].compare(wp[s1][ick2],1e-15) :
|
||||
compare_vec(xi[icj1],xi[ick2],1e-15);
|
||||
if((cmp>0 && c1) || (cmp<0 && c2))
|
||||
res= 2; // my mixed term
|
||||
else
|
||||
res= -2; // not my term
|
||||
}
|
||||
else // parity check
|
||||
res=num%2 ? 2 : -2;
|
||||
}
|
||||
else if(c1)
|
||||
res=1; // all my
|
||||
else
|
||||
res=-1; // all other
|
||||
return res;
|
||||
}
|
||||
|
||||
///\en Returns electron-electron inter-partition multipliers for energy (first) and force (second)
|
||||
/// for a 4- and 2- electron additive terms (all inter-partition interactions are
|
||||
/// calculated only once based on particle tags)
|
||||
/// If force multiplier is zero, then the term may be omitted (energy will also be zero).
|
||||
/// NOW ASSIGNS BASED ON THE FIRST PAIR ONLY
|
||||
pair<double, double> check_part1(int s1,int icj1,int ick2, int s2=-1,int icj3=-1,int ick4=-1){
|
||||
int res=check_ee(s1,icj1,ick2);
|
||||
if(res==1){ // my term
|
||||
//printf(" *\n");
|
||||
return make_pair(1.,1.); // all at my partition
|
||||
}
|
||||
else if(res==-1){
|
||||
//printf(" \n");
|
||||
return make_pair(0.,0.); // all at other partition
|
||||
}
|
||||
else if(res==2){
|
||||
//printf(" *\n");
|
||||
return make_pair(1.,1.); // my inter-partition
|
||||
}
|
||||
else if(res==-2){
|
||||
//printf(" \n");
|
||||
return make_pair(0., newton_pair ? 0.0 : 1. ); // other inter-partition: must add force if newton comm is off
|
||||
}
|
||||
return make_pair(0.,0.); // nonsense
|
||||
}
|
||||
|
||||
///\en Returns elctron-ion inter-partition multipliers for energy (first) and force (second)
|
||||
/// for ion-electron additive terms (all inter-partition interactions are
|
||||
/// calculated only once based on particle tags)
|
||||
/// If force multiplier is zero, then the term may be omitted (energy will also be zero).
|
||||
/// BASED ON ION ATTACHMENT
|
||||
pair<double,double> check_part1ei(int s1,int icj1,int ick2, int ion){
|
||||
//printf("%d ",partition1[2][ion]);
|
||||
int ci=(int)(partition1[2][ion]>0);
|
||||
|
||||
if(!newton_pair){ // care about mixed terms
|
||||
int cee=check_ee(s1,icj1,ick2);
|
||||
if((cee==2 || cee==-2) || (ci && cee==-1) || (!ci && cee==1)) // all mixed variants
|
||||
make_pair(0., 1. ); // other inter-partition: must add force if newton comm is off
|
||||
}
|
||||
if(ci){
|
||||
//printf(" *\n");
|
||||
return make_pair(1.,1.); // my term
|
||||
}
|
||||
else{
|
||||
//printf(" \n");
|
||||
return make_pair(0.,0.); // all at other partition
|
||||
}
|
||||
}
|
||||
|
||||
///\en Returns ion-ion inter-partition multipliers for energy (first) and force (second)
|
||||
/// for ion-electron additive terms (all inter-partition interactions are
|
||||
/// calculated only once based on particle tags)
|
||||
/// If force multiplier is zero, then the term may be omitted (energy will also be zero).
|
||||
pair<double,double> check_part1ii(int ion1, int ion2){
|
||||
return check_part1(2,ion1,ion2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AWPMD():pbc(0),Lextra(-1),constraint(NONE),newton_pair(1) {
|
||||
nvar[0]=nvar[1]=ne[0]=ne[1]=ni=0;
|
||||
norm_matrix_state[0] = norm_matrix_state[1] = NORM_UNDEFINED;
|
||||
ovl_tolerance=0.;
|
||||
approx = DPRODUCT;
|
||||
|
||||
me=m_electron;
|
||||
one_h=1./h_plank;
|
||||
h2_me=h_sq/me;
|
||||
coul_pref=::coul_pref;
|
||||
|
||||
calc_ii=0;
|
||||
norm_needed=0;
|
||||
}
|
||||
|
||||
protected:
|
||||
//e translates wp2 to the nearest image postion relative to wp1
|
||||
//e gets the translation vector
|
||||
Vector_3 move_to_image(const WavePacket &wp1, WavePacket &wp2) const {
|
||||
Vector_3 r1=wp1.get_r();
|
||||
Vector_3 r2=wp2.get_r();
|
||||
Vector_3 dr=r2-r1;
|
||||
Vector_3 ndr=dr.rcell(cell,pbc); // [0,L)
|
||||
ndr=ndr.rcell1(cell,pbc); // [-L/2,L/2)
|
||||
ndr-=dr;
|
||||
wp2=wp2.translate(ndr); // wln.b=wln.b+ndr.a
|
||||
return ndr;
|
||||
}
|
||||
|
||||
//e gets the overlap packet taking PBC into account
|
||||
WavePacket pbc_mul(const WavePacket &wp1, const WavePacket &wp2) const {
|
||||
if(!pbc)
|
||||
return wp1*conj(wp2);
|
||||
Vector_3 r1=wp1.get_r();
|
||||
Vector_3 r2=wp2.get_r();
|
||||
Vector_3 dr=r2-r1; // distance
|
||||
Vector_3 drn=dr.rcell1(cell,pbc); // distance within PBC
|
||||
Vector_3 rtrans=drn-dr; // new location of wp2 according to PBC (nearest image)
|
||||
WavePacket wpn=wp2.translate(rtrans);
|
||||
wpn=wp1*(conj(wpn));
|
||||
// reducing the result to elementary cell
|
||||
//r1=wpn.get_r();
|
||||
//r2=r1.rcell(cell,pbc);
|
||||
//dr=r2-r1;
|
||||
//wpn=wpn.translate(dr);
|
||||
return wpn;
|
||||
}
|
||||
///\en resizes all internal arrays according to new electrons added
|
||||
virtual void resize(int flag);
|
||||
public:
|
||||
|
||||
|
||||
|
||||
///\en Prepares to setup a new system of particles using \ref add_ion() and add_electron().
|
||||
/// There is no need to call this function when using
|
||||
/// \ref set_electrons() and \ref set_ions() to setup particles.
|
||||
virtual void reset(){
|
||||
for(int s=0;s<2;s++){
|
||||
nwp[s]=ne[s]=nvar[s]=0;
|
||||
wp[s].clear();
|
||||
qe[s].clear();
|
||||
partition1[s].clear();
|
||||
//partition2[s].clear();
|
||||
}
|
||||
partition1[2].clear();
|
||||
ni=0;
|
||||
xi.clear();
|
||||
qi.clear();
|
||||
}
|
||||
|
||||
//e sets Periodic Boundary Conditions
|
||||
//e using bit flags: 0x1 -- PBC along X
|
||||
//e 0x2 -- PBC along Y
|
||||
//e 0x4 -- PBC along Z
|
||||
//e cell specifies the lengths of the simulation box in all directions
|
||||
//e if PBCs are used, the corresponding coordinates of electrons and ions
|
||||
//e in periodic directions must be within the range [0, cell[per_dir])
|
||||
//e @returns 1 if OK
|
||||
int set_pbc(const Vector_3P pcell=NULL, int pbc_=0x7);
|
||||
|
||||
///\en Setup electrons: forms internal wave packet representations.
|
||||
/// If PBCs are used the coords must be within a range [0, cell).
|
||||
/// Default electron mass is AWPMD::me.
|
||||
/// Default (q=NULL )electron charges are -1.
|
||||
int set_electrons(int spin, int n, Vector_3P x, Vector_3P v, double* w, double* pw, double mass=-1, double *q=NULL);
|
||||
|
||||
//e setup ion charges and coordinates
|
||||
//e if PBCs are used the coords must be within a range [0, cell)
|
||||
int set_ions(int n, double* q, Vector_3P x);
|
||||
|
||||
///\en Adds an ion with charge q and position x,
|
||||
/// \return id of the ion starting from 0
|
||||
/// The tags must be nonzero, >0 for the local particle, <0 for ghost particle.
|
||||
/// Unique particle id is abs(tag).
|
||||
/// Default tag (0) means inserting the current particle id as local particle.
|
||||
int add_ion(double q, const Vector_3 &x, int tag=0){
|
||||
qi.push_back(q);
|
||||
xi.push_back(x);
|
||||
ni=(int)xi.size();
|
||||
if(tag==0)
|
||||
tag=ni;
|
||||
partition1[2].push_back(tag);
|
||||
return ni-1;
|
||||
}
|
||||
|
||||
|
||||
//e calculates interaction in the system of ni ions + electrons
|
||||
//e the electonic subsystem must be previously setup by set_electrons, ionic by set_ions
|
||||
//e the iterators are describing ionic system only
|
||||
// 0x1 -- give back ion forces
|
||||
// 0x2 -- add ion forces to the existing set
|
||||
// 0x4 -- calculate derivatives for electronic time step (NOT IMPLEMENTED)
|
||||
//e if PBCs are used the coords must be within a range [0, cell)
|
||||
virtual int interaction(int flag=0, Vector_3P fi=NULL, Vector_3P fe_x=NULL,
|
||||
Vector_3P fe_p=NULL, double *fe_w=NULL, double *fe_pw=NULL, Vector_2P fe_c=NULL);
|
||||
|
||||
//e same as interaction, but using Hartee factorization (no antisymmetrization)
|
||||
virtual int interaction_hartree(int flag=0, Vector_3P fi=NULL, Vector_3P fe_x=NULL,
|
||||
Vector_3P fe_p=NULL, double *fe_w=NULL, double *fe_pw=NULL, Vector_2P fe_c=NULL);
|
||||
|
||||
///\en Calculates ion-ion interactions and updates Eii and ion forces if requested. This function
|
||||
/// is called form intaraction() and interaction_hartree if calc_ii is set.
|
||||
virtual int interaction_ii(int flag,Vector_3P fi=NULL);
|
||||
|
||||
//e Calculates Norm matrix
|
||||
//e The result is saved in AWPMD::Norm[s]
|
||||
void norm_matrix(int s);
|
||||
|
||||
//e Performs LU-factorization of the Norm matrix
|
||||
//e AWPMD::Norm[s] is replaced by the LU matrix
|
||||
void norm_factorize(int s);
|
||||
|
||||
//e Invert Norm matrix
|
||||
//e AWPMD::Norm[s] is replaced by the inverted matrix
|
||||
void norm_invert(int s);
|
||||
|
||||
//e Get the determinant of the norm-matrix for the particles with spin s
|
||||
double norm_matrix_det(int s);
|
||||
|
||||
//e Get the determinant logarithm of the norm-matrix for the particles with spin s
|
||||
double norm_matrix_detl(int s);
|
||||
|
||||
double get_energy();
|
||||
|
||||
//e makes timestep of electronic component (NOT IMPLEMENTED)
|
||||
int step(double dt);
|
||||
|
||||
///\en Gets current electronic coordinates.
|
||||
/// Transforms the momenta to velocity v according to mass setting (-1 means me)
|
||||
int get_electrons(int spin, Vector_3P x, Vector_3P v, double* w, double* pw, double mass=-1);
|
||||
|
||||
void set_harm_constr(double w0) {
|
||||
constraint = HARM;
|
||||
harm_w0_4 = h_sq*9./(8.*m_electron)/(w0*w0*w0*w0);
|
||||
}
|
||||
|
||||
void set_fix_constr(double w0_) {
|
||||
constraint = FIX;
|
||||
w0 = w0_;
|
||||
}
|
||||
|
||||
///\en Prepares force arrays according to \a flag setting for interaction()
|
||||
virtual void clear_forces(int flagi,Vector_3P fi, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c=NULL);
|
||||
|
||||
|
||||
///\en Creates wave packet acording to the given physical parameters.
|
||||
/// The function may change its arguments by applying existing constraints!
|
||||
/// Default mass (-1) is the electron mass AWPMD::me.
|
||||
WavePacket create_wp(Vector_3 &x, Vector_3 &v, double &w, double &pw, double mass=-1);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
# endif
|
||||
1325
lib/awpmd/systems/interact/TCP/wpmd_split.cpp
Normal file
1325
lib/awpmd/systems/interact/TCP/wpmd_split.cpp
Normal file
File diff suppressed because it is too large
Load Diff
204
lib/awpmd/systems/interact/TCP/wpmd_split.h
Normal file
204
lib/awpmd/systems/interact/TCP/wpmd_split.h
Normal file
@ -0,0 +1,204 @@
|
||||
# ifndef WPMD_SPLIT_H
|
||||
# define WPMD_SPLIT_H
|
||||
|
||||
/** @file wpmd.h
|
||||
@brief Representation of electrons by multiple wave packets within WPMD */
|
||||
|
||||
/*s****************************************************************************
|
||||
* $Log: wpmd_split.h,v $
|
||||
* Revision 1.2 2011/06/11 16:53:55 valuev
|
||||
* sync with LAMMPS
|
||||
*
|
||||
* Revision 1.1 2011/06/10 17:15:07 morozov
|
||||
* First Windows project with the correct directory structure
|
||||
*
|
||||
* Revision 1.17 2011/06/09 22:55:08 valuev
|
||||
* norm matrices
|
||||
*
|
||||
* Revision 1.16 2011/06/07 19:58:42 valuev
|
||||
* corrected partitions
|
||||
*
|
||||
* Revision 1.15 2011/06/07 17:43:00 valuev
|
||||
* added Y derivatives
|
||||
*
|
||||
* Revision 1.14 2011/06/03 08:13:33 valuev
|
||||
* added partitions to account for ghost atoms
|
||||
*
|
||||
* Revision 1.13 2011/06/01 23:45:35 valuev
|
||||
* modified for LAMMPS compatibility
|
||||
*
|
||||
* Revision 1.12 2011/05/28 17:16:22 valuev
|
||||
* fixed template<>, some fixes to UHF
|
||||
*
|
||||
* Revision 1.11 2011/05/27 08:43:52 valuev
|
||||
* fixed split packet antisymmetrized version
|
||||
*
|
||||
* Revision 1.10 2011/05/25 05:23:43 valuev
|
||||
* fixed variable transformation for norm matrix
|
||||
*
|
||||
* Revision 1.9 2011/05/24 19:54:32 valuev
|
||||
* fixed sqmatrix::iterator
|
||||
*
|
||||
* Revision 1.8 2011/05/20 21:39:49 valuev
|
||||
* separated norm calculation
|
||||
*
|
||||
* Revision 1.7 2011/05/14 18:56:19 valuev
|
||||
* derivative for ee split interactions
|
||||
*
|
||||
* Revision 1.6 2011/05/05 08:56:02 valuev
|
||||
* working split wp version
|
||||
*
|
||||
* Revision 1.5 2011/05/04 16:48:52 valuev
|
||||
* fixed syntax
|
||||
*
|
||||
* Revision 1.4 2011/05/04 09:04:48 valuev
|
||||
* completed wp_split (except for ee forces)
|
||||
*
|
||||
* Revision 1.3 2011/04/22 09:54:24 valuev
|
||||
* working on split WP
|
||||
*
|
||||
* Revision 1.1 2011/04/20 08:43:09 valuev
|
||||
* started adding split packet WPMD
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "wpmd.h"
|
||||
|
||||
|
||||
class AWPMD_split: public AWPMD {
|
||||
protected:
|
||||
int s_add, spl_add;
|
||||
public:
|
||||
vector<Vector_2> split_c[2]; ///<\en split coefficients for electrons (c_re, c_im) or (psi,phi) depending on the norm mode
|
||||
vector<int> nspl[2]; ///<\en number of wave packets for each electron (size is ne[i])
|
||||
|
||||
vector<double> wf_norm[2]; ///<\en norms for each electron
|
||||
vector<double> wf_norm_der[2]; ///<\en norm derivative
|
||||
vector<cdouble> ovl_der[2]; ///<\en overlap derivative: \<psi|psi'\>
|
||||
vector<double> E_der[2]; ///<\en energy derivative with respect to {a,b} coordinates
|
||||
|
||||
|
||||
vector< cdouble > Lh[2]; ///<\en Substitute for L in Hartree case: block matrices 1x(10*nspl[i])
|
||||
vector< sqmatrix<double> > Normh[2]; ///<\en Substitute for Norm in Hartree case: block matrices
|
||||
|
||||
///\en resizes all internal arrays according to new electrons (wavepackets) added
|
||||
virtual void resize(int flag);
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
AWPMD_split():s_add(0),spl_add(0){}
|
||||
|
||||
|
||||
///\en Prepares to setup a new system of particles using \ref add_ion(),
|
||||
/// \ref add_electron() and \ref add_split().
|
||||
/// There is no need to call this function when using
|
||||
/// \ref set_electrons() and \ref set_ions() to setup particles.
|
||||
virtual void reset(){
|
||||
for(int s=0;s<2;s++){
|
||||
split_c[s].clear();
|
||||
nspl[s].clear();
|
||||
}
|
||||
s_add=0;
|
||||
spl_add=0;
|
||||
AWPMD::reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///\en Setup electrons: forms internal wave packet representations.
|
||||
/// If PBCs are used the coords must be within the range [0, cell)
|
||||
/// the \a splits array defines the number of wavepackets required for each electron
|
||||
/// the data for splits should be placed in the corresponding data arrays
|
||||
/// \a c array contains the splits mixing coefficints
|
||||
/// \a n is the number of electrons of a given spin component
|
||||
/// Electron velocity v is multiplied by mass to obtain momentum.
|
||||
/// Default mass (-1) means me.
|
||||
/// Electronic charges q are -1 by default (when q=NULL), otherwise the charges are assigned for each split
|
||||
int set_electrons(int s, int nel, Vector_3P x, Vector_3P v, double* w, double* pw, Vector_2 *c, int *splits, double mass=-1, double *q=NULL);
|
||||
|
||||
|
||||
///\en Starts adding new electron: continue with \ref add_split functions.
|
||||
int add_electron(int s){
|
||||
if(s < 0 || s > 1)
|
||||
return LOGERR(-1,fmt("AWPMD_split.add_electron: invaid spin setting (%d)!",s),LINFO);
|
||||
s_add=s;
|
||||
spl_add=0;
|
||||
return ne[s_add];
|
||||
}
|
||||
|
||||
///\en Adds a new split to current electron.
|
||||
/// May change the arguments according to the constraints set.
|
||||
/// \return global id of the wavepacket (starting from 0 for each spin s)
|
||||
/// Electron velocity v is multiplied by mass to obtain momentum.
|
||||
/// Default mass (-1) means me.
|
||||
/// The tags must be nonzero, >0 for the local particle, <0 for ghost particle.
|
||||
/// Unique particle id is abs(tag).
|
||||
/// Default tag (0) means inserting the current particle id as local particle.
|
||||
int add_split(Vector_3 &x, Vector_3 &v, double &w, double &pw, Vector_2 &c, double mass=-1, double q=-1., int tag=0);
|
||||
|
||||
|
||||
///\en gets current electronic coordinates, and (optionally) number of wave packets for each electron
|
||||
int get_electrons(int spin, Vector_3P x, Vector_3P v, double* w, double* pw, cdouble *c, int *splits=NULL, double mass=-1);
|
||||
|
||||
|
||||
void eterm_deriv(int ic1,int s1, int c1,int k1,int ic2,int s2, int c2,int j2,cdouble pref,
|
||||
const OverlapDeriv &o,cdouble v,cdouble dv_aj_conj,
|
||||
cdouble dv_ak,cVector_3 dv_bj_conj, cVector_3 dv_bk);
|
||||
|
||||
///\en adds the derivatives of Y for the term v*Y[s](c2,c1)
|
||||
void y_deriv(cdouble v,int s, int c2, int c1);
|
||||
|
||||
|
||||
///\en Calculates block norms an derivatives
|
||||
void calc_norms(int flag);
|
||||
|
||||
///\en Prepares force arrays according to \a flag setting for interaction()
|
||||
virtual void clear_forces(int flagi,Vector_3P fi, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c);
|
||||
|
||||
///\en Calcualtes the overlap between two electrons taking all split WPs into account.
|
||||
/// Norms must be pre-calculated.
|
||||
cdouble overlap(int ic1, int s1, int c1,int ic2, int s2, int c2);
|
||||
|
||||
//e same as interaction, but using Hartee factorization (no antisymmetrization)
|
||||
int interaction_hartree(int flag=0, Vector_3P fi=NULL, Vector_3P fe_x=NULL,
|
||||
Vector_3P fe_p=NULL, double *fe_w=NULL, double *fe_pw=NULL, Vector_2P fe_c=NULL);
|
||||
|
||||
///\en Calculates interaction in the system of ni ions + electrons
|
||||
/// the electonic subsystem must be previously setup by set_electrons, ionic by set_ions
|
||||
/// 0x1 -- give back ion forces \n
|
||||
/// 0x2 -- add ion forces to the existing set \n
|
||||
/// 0x4 -- calculate electronic forces \n
|
||||
/// 0x8 -- add electronic forces to the existing arrays \n
|
||||
/// 0x10 -- calculate internal electronic derivatives only: \n
|
||||
/// will not update electronic force arrays, which may be NULL, \n
|
||||
/// the forces may be obtained then using \ref get_el_forces() for all WPs \n
|
||||
/// or separately for each WP using \ref get_wp_force()
|
||||
/// if PBCs are used the coords must be within a range [0, cell)
|
||||
int interaction(int flag=0, Vector_3P fi=NULL, Vector_3P fe_x=NULL,
|
||||
Vector_3P fe_p=NULL, double *fe_w=NULL, double *fe_pw=NULL, Vector_2P fe_c=NULL);
|
||||
|
||||
///\en Get electronic forcess in the arrays provided, using calculated internal representation
|
||||
/// Valid flag settings are:\n
|
||||
/// 0x4 -- overwrite existing forces \n
|
||||
/// 0x8 -- add electronic forces to the existing arrays \n
|
||||
void get_el_forces(int flag, Vector_3P fe_x,
|
||||
Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c);
|
||||
|
||||
|
||||
void get_wp_force(int s, int ispl, Vector_3P fe_x, Vector_3P fe_p, double *fe_w, double *fe_pw, Vector_2P fe_c){
|
||||
WavePacket wk=wp[s][ispl];
|
||||
int indw1=8*ispl;
|
||||
int indn1=(nvar[s]/10)*8+2*ispl;
|
||||
wk.int2phys_der< eq_minus_second >(E_der[s].begin()+indw1,(double *)fe_x,(double *)fe_p,fe_w,fe_pw,1./one_h);
|
||||
*fe_c=-Vector_2(E_der[s][indn1],E_der[s][indn1+1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# endif
|
||||
Reference in New Issue
Block a user