# 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 && j0) 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;i0){ // 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) ;c20){ // 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;ifixw){ 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 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;k1e-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& Norms = Norm[s]; chmatrix& Ys = Y[s]; smatrix& 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 -mu, v -> -v !!! for(l=0;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) * for(qj=0; qj * IDYs_(k,q_j) cdouble sum = 0.; for(k=0;k::iterator mi=Norms.fix_first(8*i+k,0); for(j=i ;j(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::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::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::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& Norms = Norm[s]; for(int i=0; i& Norms = Norm[s]; for(int i=0; i1) 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