PROGRAM md ! !Purpose: !The main program to calculate the thermal conductivity of solid argon in a NVT ensemble. ! !Record of revisions: ! Date Programmer Description of change ! ==== ========== ====================== ! 11/24/2004 Xuan Zheng Force calculation. ! 11/27/2004 Xuan Zheng Modify the initialization subroutine to calculate the ! old position using the randomly generated velocity. ! Add the integrate subroutine. ! 12/04/2004 Xuan Zheng Add common blocks. ! 12/07/2004 Xuan Zheng Fix the error caused by the drift of the mass center ! z direction. IMPLICIT none ! !Declare variables. !qid: id of the run. !fpar: file name of the paprameter file. !finitial: file name of the initial conditin output. !lpx: length of the qid. !natoms: number of atoms in the box. !rho: density (in reduced units). !box: size of the box. !hbox: half of the box. !temp: inintial temperature. !nstep: total number of steps. !vx(natoms): velocity of atom i in the x direction. !vy(natoms): velocity of atom i in the y direction. !vz(natoms): velocity of atom i in the z direction. !fx(natoms), fy(natoms), fz(natoms): force on every atom along x, y, z directions. !rcut: curoff radius. !upot: potential energy. !press: pressure of the system. !x(natoms), y(natoms), z(natoms): positions of the atoms. !xo(natoms), yo(natoms), zo(natoms): old positons of the atoms. !xn(natoms), yn(natoms), zn(natoms): new positions of the atoms. !step: the number of the current step. !nwarm: number of warm up steps. !ukin: kinetic energy of the system. !kin(10000): output kinetic energy. !write_scaler: intervals between write out scalers. COMMON /block1/ x, y, z COMMON /block2/ xo, yo, zo COMMON /block3/ vx, vy, vz, ukin COMMON /block4/ fx, fy, fz, upot COMMON /block5/ box, tstep COMMON /block6/ rcut, point, list COMMON /block7/ pot, j2x, j2y, j2z COMMON /block8/ qstep, nquench, quench_times, quench_interval COMMON /block9/ temp CHARACTER qid*8, fpar*14, finitial*14, flambda*14, fkin*14, & fpos*14, fcur*14 INTEGER natoms, lpx, i, j, nstep, step, write_scaler, nscaler, & quench_interval, quench_times, nquench, qstep, maxnab PARAMETER (natoms=108) PARAMETER (maxnab=natoms*150) INTEGER point(natoms), list(maxnab), mavg, nequ PARAMETER (mavg=10000, nequ=100000) DOUBLE PRECISION tstep, rho, box, hbox, temp, & x(natoms), y(natoms), z(natoms), & vx(natoms), vy(natoms), vz(natoms), & fx(natoms), fy(natoms), fz(natoms), & xo(natoms), yo(natoms), zo(natoms), & xn(natoms), yn(natoms), zn(natoms), & rcut, upot, press, ukin, & kin(100000), pot(natoms), j2x, j2y, j2z, jx, jy, jz, & jxi(5000000), jyi(5000000), jzi(5000000), & sigma, eps, kb, mass, realt, & jijj, volume, temp2, lambda, & heatcorr(mavg), lambdacoeff, unitconv, potential(100000) PARAMETER (sigma=3.405D-10) PARAMETER (eps=1.65398276D-21) PARAMETER (kb=1.38062D-23, mass=6.67545D-26) !Read parameters from qid.par. ! ! Format of the qid.par file: ! rcut ! rho ! temp ! nstep ! tstep ! quench_interval ! quench_times ! write_scaler WRITE (*,*) 'Input the run id:' READ (*,'(a)') qid lpx=index(qid,' ')-1 fpar=qid(1:lpx)//'.par' finitial=qid(1:lpx)//'.ini' flambda=qid(1:lpx)//'.lbd' fkin=qid(1:lpx)//'.erg' fpos=qid(1:lpx)//'.pos' fcur=qid(1:lpx)//'.cur' OPEN (UNIT=9,FILE=fpar,STATUS='OLD') READ (9,*) rcut WRITE (*,*) rcut READ (9,*) rho WRITE (*,*) rho READ (9,*) temp WRITE (*,*) temp READ (9,*) nstep WRITE (*,*) nstep READ (9,*) tstep WRITE (*,*) tstep READ (9,*) quench_interval WRITE (*,*) quench_interval READ (9,*) quench_times WRITE(*,*) quench_times READ(9,*) write_scaler WRITE(*,*) write_scaler ! Calculate the box size and half of the box. box=(DBLE(natoms)/rho)**(1.D00/3.D00) realt=DSQRT(mass*sigma*sigma/eps) ! write(*,*) 'realt=', realt ! write(*,*) 'box', box hbox=0.5D00*box nquench=0 step=0 qstep=0 CALL initial WRITE (*,*) 'Initialization done.' ! write (*,*) 'temp after initial',temp CALL neighborlist WRITE (*,*) 'Neighbor list generated.' ! write (*,*) 'temp after neighbor',temp ! call force ! write(*,*) temp ! call integrate ! write(*,*) temp WRITE(*,*) 'MD loop.....' !MD loop. DO i=1, nstep step=step+1 qstep=qstep+1 ! write(*,*) pot(1) CALL force CALL heatcurrent(jx, jy, jz) ! write(*,*) pot(1) jxi(i)=jx jyi(i)=jy jzi(i)=jz ! write(*,*) temp CALL integrate ! write(*,*) temp nscaler=(step/write_scaler)+1 kin(nscaler)=ukin ! write(*,*) upot potential(nscaler)=upot ENDDO !calculate the thermal conductivity. ! DO i=1, natoms ! write(*,*) pot(i) ! ENDDO jijj=0.0D0 WRITE(*,*) 'MD loop done.' DO i=1, mavg heatcorr(i)=0.0D00 DO j=nequ, nstep-i heatcorr(i)=heatcorr(i)+jxi(i+j)*jxi(j) & +jyi(i+j)*jyi(j)+jzi(i+j)*jzi(j) ENDDO heatcorr(i)=heatcorr(i)/(nstep-i-nequ) jijj=jijj+heatcorr(i) ENDDO WRITE (*,*) 'Heat correlation function generated.' ! write(*,*) jijj unitconv=eps*eps*sigma*sigma/realt/realt jijj=jijj*unitconv volume=box*box*box*sigma*sigma*sigma temp2=temp*temp*eps*eps/kb/kb ! write(*,*) 'temp2', temp2 lambdacoeff=tstep*realt/volume/temp2/kb/3 lambda=lambdacoeff*jijj write(*,*) 'thermal conductivity', lambda DO i=1, mavg heatcorr(i)=unitconv*lambdacoeff*heatcorr(i) ENDDO OPEN (UNIT=11,FILE=flambda,STATUS='unknown') WRITE(11,*) 'temperature=', temp, temp*119.8, 'K' WRITE(11,*) 'thermal conductivity=', lambda, 'W m-1 K-1' DO i=1, mavg WRITE (11, *) i, heatcorr(i) ENDDO ! potential=0.0D0 OPEN (UNIT=10,FILE=fkin,STATUS='unknown') DO i=1, nscaler ! DO j=1, natoms ! potential=pot(j)+potential ! ENDDO ! potential=0.5D0*potential WRITE (10,*) i, kin(i), potential(i) ! potential=0.0D0 ENDDO OPEN (UNIT=12,FILE=fpos,STATUS='unknown') WRITE(12,*) natoms WRITE(12,*) box DO i=1, natoms WRITE (12, *) x(i), y(i), z(i) ENDDO OPEN (UNIT=13,FILE=fcur,STATUS='unknown') DO i=nequ, nequ+1000 WRITE (13, *) i, jxi(i) ENDDO END ! End of the main program. ! Begin of the subroutine to initialize the system. SUBROUTINE initial ! !Purpose: !To distribute the atoms in a cubic lattice, and assign every atom a velocity. !The velocity is normalized to the desired temperature. !Calculate the previous position using the generated velocity. ! IMPLICIT none COMMON /block1/ x, y, z COMMON /block2/ xo, yo, zo COMMON /block3/ vx, vy, vz, ukin COMMON /block5/ box, tstep COMMON /block9/ temp INTEGER natoms PARAMETER (natoms=108) DOUBLE PRECISION box, tstep DOUBLE PRECISION x(natoms), y(natoms), z(natoms), & vx(natoms), vy(natoms), vz(natoms), ukin, & xo(natoms), yo(natoms), zo(natoms) INTEGER n, iref, ix, iy, iz, m, i DOUBLE PRECISION del, v2, vx0, vy0, vz0, vx0t, vy0t, vz0t, & temp, rangauss, f del=(box**3)**(1.D00/3.D00) ! write (*,*) box, del ! WRITE(*,*) natoms n=DNINT((DBLE(natoms)*0.25D00)**(1.D00/3.D00)) ! write (*,*) n del=0.5D00*del/DBLE(n) ! write(*,*) 'del=', del !sublattice 1. x(1)=0.0D00 y(1)=0.0D00 z(1)=0.0D00 !sublattice 2. x(2)=del y(2)=del z(2)=0.0D0 !sublattice 3. x(3)=0.0D00 y(3)=del z(3)=del !sublattice 4. x(4)=del y(4)=0.0D00 z(4)=del m=0 ! Put the atoms into a cubic lattice. DO iz=1, n DO iy=1, n DO ix=1, n DO iref=1,4 x(iref+m)=x(iref)+2.0D00*del*DBLE(ix-1) y(iref+m)=y(iref)+2.0D00*del*DBLE(iy-1) z(iref+m)=z(iref)+2.0D00*del*DBLE(iz-1) ENDDO m=m+4 END DO END DO END DO ! Set up initial velocities of the atoms. vx0=0.D0 vy0=0.D0 vz0=0.D0 v2=0.0D00 DO i=1, natoms vx(i)=rangauss() vy(i)=rangauss() vz(i)=rangauss() vx0=vx0+vx(i) vy0=vy0+vy(i) vz0=vz0+vz(i) v2=v2+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) ENDDO ! Set center of mass movement to zero. And scale to the desired temperature. vx0=vx0/DBLE(natoms) vy0=vy0/DBLE(natoms) vz0=vz0/DBLE(natoms) vx0t=0.D0 vy0t=0.D0 vz0t=0.D0 f = DSQRT(3.0D0*DBLE(natoms)*temp/v2) ! write(*,*) 'temp=', temp v2=0.D0 DO i=1, natoms vx(i)=(vx(i)-vx0)*f vy(i)=(vy(i)-vy0)*f vz(i)=(vz(i)-vz0)*f vx0t=vx0t+vx(i) vy0t=vy0t+vy(i) vz0t=vz0t+vz(i) v2=v2+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) ENDDO v2=v2/3.0D0/DBLE(natoms) vx0t=vx0t/natoms vy0t=vy0t/natoms vz0t=vz0t/natoms ! write(*,*) 'inittemp', v2 ! write(*,*) 'velocity of center', vx0t, vy0t, vz0t !Calcuate the previous position using the generated velocity. DO i=1, natoms xo(i)=x(i)-tstep*vx(i) yo(i)=y(i)-tstep*vy(i) zo(i)=z(i)-tstep*vz(i) ! write(*,*) xo(i), yo(i), zo(i) ! write(*,*) x(i), y(i), z(i) ENDDO END !End of initialization. ! SUBROUTINE neighborlist !purpose: !subroutine to calculate the verlet neighbor list. Because it is solid, !the neighbor list do not need update. ! IMPLiCIT none COMMON /block1/ x, y, z COMMON /block5/ box, tstep COMMON /block6/ rcut, point, list INTEGER natoms, maxnab PARAMETER (natoms=108, maxnab=natoms*150) INTEGER point(natoms), list(maxnab) DOUBLE PRECISION x(natoms), y(natoms), z(natoms), box, tstep, rcut DOUBLE PRECISION xi, yi, zi, dx, dy, dz, d2, boxi, rlist2 INTEGER i, nlist,j boxi=1/box rlist2=(rcut+0.1D0)*(rcut+0.1D0) nlist=0 WRITE(*,*) 'Generating neighbor list.......' DO i=1, natoms-1 point(i)=nlist+1 xi=x(i) yi=y(i) zi=z(i) ! WRITE(*,*) 'neighbor list' DO j=i+1, natoms dx=xi-x(j) dy=yi-y(j) dz=zi-z(j) ! write (*,*) dx dx=dx-DNINT(dx*boxi)*box dy=dy-DNINT(dy*boxi)*box dz=dz-DNINT(dz*boxi)*box d2=dx*dx+dy*dy+dz*dz ! write(*,*) d2 IF (d2 .LT. rlist2) THEN nlist=nlist+1 ! write(*,*) nlist list(nlist)=j ENDIF ENDDO ENDDO ! WRITE (*,*) 'Neighbor list done' point(natoms)=nlist+1 END ! ! SUBROUTINE force ! !Purpose: !To calculate the force, the potential energy, and the heat current. ! ! IMPLICIT none COMMON /block1/ x, y, z COMMON /block3/ vx, vy, vz, ukin COMMON /block4/ fx, fy, fz, upot COMMON /block5/ box, tstep COMMON /block6/ rcut, point, list COMMON /block7/ pot, j2x, j2y, j2z !Declare variables: !fx(i) !fy(i) !fz(i) !upot: potential energy of the system. !press: pressure of the system. !dx, dy, dz: distance of two atoms in the x, y, z direction, respectively. !d2: dx^2+dy^2+dz^2. !d2i: inverse of d2. !d6i=d2i^3 !rcutoff: cutoff radius !rcutoff2: square of the cutoff radius. !ecut: potential energy at the cutoff radius. ! INTEGER natoms, i, j, jbeg, jend, jnab, maxnab PARAMETER (natoms=108, maxnab=natoms*150) INTEGER point(natoms), list(maxnab) DOUBLE PRECISION x(natoms), y(natoms), z(natoms), xi, yi, zi DOUBLE PRECISION fx(natoms), fy(natoms), fz(natoms) DOUBLE PRECISION vx(natoms), vy(natoms), vz(natoms) DOUBLE PRECISION upot, virial, press, rcut, rcut2, rcut2i, rcut6i DOUBLE PRECISION dx, dy, dz, d2, d2i, d6i, d12i, ff, ecut, tstep DOUBLE PRECISION box, hbox, boxi, uij, vij, ukin DOUBLE PRECISION pot(natoms), j2x, j2y, j2z, fvx, fvy, fvz rcut2=rcut*rcut rcut2i=1.0D0/rcut2 rcut6i=rcut2i*rcut2i*rcut2i ecut=4.0D00*rcut6i*(rcut6i-1.0D00) boxi=1/box !Set forces, potential energy and pressure to zero. DO i=1, natoms fx(i)=0.0D0 fy(i)=0.0D0 fz(i)=0.0D0 pot(i)=0.0D00 END DO upot=0.0D00 virial=0.0D00 press=0.0D0 j2x=0.0D0 j2y=0.0D0 j2z=0.0D0 DO i=1, natoms-1 jbeg=point(i) jend=point(i+1)-1 IF (jbeg .LE. jend) THEN xi=x(i) yi=y(i) zi=z(i) DO jnab=jbeg, jend j=list(jnab) ! write(*,*) j dx=xi-x(j) dy=yi-y(j) dz=zi-z(j) dx=dx-DNINT(dx*boxi)*box dy=dy-DNINT(dy*boxi)*box dz=dz-DNINT(dz*boxi)*box d2=dx*dx+dy*dy+dz*dz IF (d2 .LT. rcut2) THEN d2i=1.0D0/d2 d6i=d2i*d2i*d2i d12i=d6i*d6i uij=4.0D00*(d12i-d6i) upot=upot+uij-ecut vij=uij+4.0D0*d12i virial=virial+vij ff=6.0D00*vij*d2i pot(i)=pot(i)+uij-ecut pot(j)=pot(j)+uij-ecut fx(i)=fx(i)+ff*dx fy(i)=fy(i)+ff*dy fz(i)=fz(i)+ff*dz fx(j)=fx(j)-ff*dx fy(j)=fy(j)-ff*dy fz(j)=fz(j)-ff*dz !second term of j(t). fvx=dx*ff*(vx(i)+vx(j)) fvy=dy*ff*(vy(i)+vy(j)) fvz=dz*ff*(vz(i)+vz(j)) j2x=j2x+dx*(fvx+fvy+fvz) j2y=j2y+dy*(fvx+fvy+fvz) j2z=j2z+dz*(fvx+fvy+fvz) ENDIF ENDDO ENDIF ENDDO END SUBROUTINE heatcurrent(jx, jy, jz) ! !purpose: !to calculate the heat current. ! IMPLICIT none COMMON /block3/ vx, vy, vz, ukin COMMON /block4/ fx, fy, fz, upot COMMON /block5/ box, tstep COMMON /block7/ pot, j2x, j2y, j2z INTEGER natoms, i PARAMETER (natoms=108) DOUBLE PRECISION vx(natoms), vy(natoms), vz(natoms), ukin, & fx(natoms), fy(natoms), fz(natoms), tstep, pot(natoms), & j2x, j2y, j2z, jx, jy, jz, e(natoms), box, upot jx=0.0D0 jy=0.0D0 jz=0.0D0 DO i=1, natoms e(i)=0.0D0 ENDDO DO i=1, natoms e(i)=vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) e(i)=e(i)+pot(i) e(i)=0.5D0*e(i) ! write(*,*) pot(i) jx=jx+vx(i)*e(i) jy=jy+vy(i)*e(i) jz=jz+vz(i)*e(i) ENDDO jx=jx+0.5D0*j2x jy=jy+0.5D0*j2y jz=jz+0.5D0*j2z END ! SUBROUTINE integrate ! !Purpose: !To integrate the equation of motion using Verlet algorithm. ! IMPLICIT none COMMON /block1/ x, y, z COMMON /block2/ xo, yo, zo COMMON /block3/ vx, vy, vz, ukin COMMON /block4/ fx, fy, fz, upot COMMON /block5/ box, tstep COMMON /block8/ qstep, nquench, quench_times, quench_interval COMMON /block9/ temp INTEGER i, step, natoms, nwarm, nquench, qstep, quench_times PARAMETER (natoms=108) INTEGER quench_interval DOUBLE PRECISION x(natoms), y(natoms), z(natoms) DOUBLE PRECISION xo(natoms), yo(natoms), zo(natoms) DOUBLE PRECISION fx(natoms), fy(natoms), fz(natoms) DOUBLE PRECISION xn(natoms), yn(natoms), zn(natoms) DOUBLE PRECISION vx(natoms), vy(natoms), vz(natoms), upot DOUBLE PRECISION ukin, tstep, tstep2, i2tstep, scale, box, temp ukin=0.0D0 tstep2=tstep*tstep i2tstep=0.5D0/tstep !Integrate the equation of motion using Verlet algorithm. DO i=1, natoms xn(i)=2.0D0*x(i)-xo(i)+fx(i)*tstep2 yn(i)=2.0D0*y(i)-yo(i)+fy(i)*tstep2 zn(i)=2.0D0*z(i)-zo(i)+fz(i)*tstep2 vx(i)=(xn(i)-xo(i))*i2tstep vy(i)=(yn(i)-yo(i))*i2tstep vz(i)=(zn(i)-zo(i))*i2tstep !write(*,*) vx(i), vy(i), vz(i) ukin=ukin+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) ! write (*,*) 'ukin=', ukin ENDDO ! write(*,*) zn(5), zo(5), i2tstep !For the warm up steps, use the velocity scaling to get the exact temperature. IF(qstep.EQ. quench_interval .AND. nquench .LE. quench_times) THEN ! write(*,*) ukin scale=DSQRT(temp*3.0D0*DBLE(natoms)/ukin) qstep=0 nquench=nquench+1 ELSE scale=1.0D0 ENDIF ! write (*,*) temp, scale ukin=0.0D0 DO i=1, natoms !Scale the velocity of the atoms to the initial temperature. vx(i)=scale*vx(i) vy(i)=scale*vy(i) vz(i)=scale*vz(i) xn(i)=xo(i)+2.0D0*vx(i)*tstep yn(i)=yo(i)+2.0D0*vy(i)*tstep zn(i)=zo(i)+2.0D0*vz(i)*tstep ukin=ukin+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) xo(i)=x(i) yo(i)=y(i) zo(i)=z(i) x(i)=xn(i) y(i)=yn(i) z(i)=zn(i) !Put the atoms back into the box. If the new positons are moved, the old positions must be moved !too. IF (x(i) .GT. box) THEN x(i)=x(i)-box xo(i)=xo(i)-box ELSEIF (x(i) .LT. 0.0D0) THEN x(i)=x(i)+box xo(i)=xo(i)+box ENDIF IF (y(i) .GT. box) THEN y(i)=y(i)-box yo(i)=yo(i)-box ELSEIF (y(i) .LT. 0.0D0) THEN y(i)=y(i)+box yo(i)=yo(i)+box ENDIF IF (z(i) .GT. box) THEN z(i)=z(i)-box zo(i)=zo(i)-box ELSEIF (z(i) .LT. 0.0D0) THEN z(i)=z(i)+box zo(i)=zo(i)+box ENDIF ENDDO END FUNCTION ran_uniform() ! !Purpose: !To generate a serial of uniformly distributed random numbers with the seed idum. ! IMPLICIT none INTEGER idum DOUBLE PRECISION ran_uniform,ran2 SAVE idum DATA idum/-10/ ran_uniform = ran2(idum) RETURN END FUNCTION ran2(idum) IMPLICIT none INTEGER idum,im1,im2,imm1,ia1,ia2, & iq1,iq2,ir1,ir2,ntab,ndiv DOUBLE PRECISION ran2,am,eps,rnmx PARAMETER (im1=2147483563,im2=2147483399, & am=1.0d0/im1,imm1=im1-1,ia1=40014, & ia2=40692,iq1=53668,iq2=52774,ir1=12211, & ir2=3791,ntab=32,ndiv=1+imm1/ntab, & eps=1.2d-7,rnmx=1.0d0-eps) INTEGER idum2,j,k,iv(Ntab),iy SAVE iv,iy,idum2 DATA idum2/123456789/, iv/ntab*0/, iy/0/ IF (idum.LE.0) THEN idum=MAX(-idum,1) idum2=idum DO j=ntab+8,1,-1 k=idum/iq1 idum=ia1*(idum-k*iq1)-k*ir1 IF (idum.LT.0) idum=idum+im1 IF (j.LE.ntab) iv(j)=idum ENDDO iy=iv(1) ENDIF k=idum/iq1 idum=ia1*(idum-k*iq1)-k*ir1 IF (idum.LT.0) idum=idum+im1 k=idum2/iq2 idum2=ia2*(idum2-k*iq2)-k*ir2 IF (idum2.LT.0) idum2=idum2+im2 j=1+iy/ndiv iy=iv(j)-idum2 iv(j)=idum IF(iy.LT.1)iy=iy+imm1 ran2=Min(am*iy,rnmx) RETURN END FUNCTION rangauss() ! !Purpose: !To generate random numbers from a gaussian distribution. ! DOUBLE PRECISION ran_uniform, rangauss, v1, v2, rsq 100 v1=2.0D0*ran_uniform()-1.0D0 v2=2.0D0*ran_uniform()-1.0D0 rsq=v1*v1+v2*v2 IF (rsq .GE. 1.0D0 .OR. rsq .LE. 0.0D0) GOTO 100 rangauss=v1*DSQRT(-2.0D0*DLOG(rsq)/rsq) RETURN END