Top Banner
2.370 Project Report Molecular Dynamics Simulation of a Lennard-Jones Fluid Bolin Liao In this project, a molecular dynamics study is carried out on a Lennard-Jones fluid. Main algorithms implemented and their basic features include: 1) Cell list based force calculation is used to speed up the simulation and save computation resource; 2) Nose-Hoover thermostat is added to maintain the system temperature within a reasonable fluctuation range (the impace of different “thermostat mass” is also studied), with Beeman predictor-corrector integration algorithm to shorten the time needed for reaching equilibrium; 3) Long range corrections are added when calculating total potential energy and pressure, and good agreements are achieved between MD and Monte Carlo simulation results; 3) Brownian dynamics simulation is carried out to measure the diffusion coefficient, and good agreement is achieved when compared to experiment data. In the following parts of this report, details of the algorithms and data structures that are used in each stage of this simulation will be presented, while the complete codes attached as an appendix. The codes are written in Fortran. 1. Initialization Two purposes are to be achieved in the initialization stage (SUBROUTINE init). The first is to arrange the atoms in a simple cubic structure, as their initial positions, and the second is to assign velocities from a Maxwell distribution to each atom, and rescale them in order to obtain desired temperature and guarantee a rest center of mass. The arrangement of atoms is straightforward. For generating velocities from a Maxwell distribution, a polar form Box-Muller algorithm is used to generate a Gaussian distribution from 2-dimensional uniform distribution, and then all velocities are rescaled to achieve zero average velocity and correct temperature. Codes: FUNCTION rangauss() !Polar form Box-Muller Gaussian random number generator REAL*8 ran_uniform, rangauss, v1, v2, rsq 100 CALL RANDOM_NUMBER(v1) v1=2.0*v1-1.0 CALL RANDOM_NUMBER(v2) v2=2.0*v2-1.0 rsq=v1*v1+v2*v2 IF (rsq .GE. 1.0 .OR. rsq .LE. 0.0) GOTO 100
28

MD-LJasdf

Nov 07, 2014

Download

Documents

asdafsdfj kja;sdkfja;skdfja;kdjf;akdj;fakdjf;akdj;falfaskdjad;aldfj;afjaskdfj;askfj;askdjf;adjkfdkjf;askdjf;askdfja;skdfasdfasdf asdfdfjdkjfkdjfkdjfkdkfjkadjldfj
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: MD-LJasdf

2.370 Project Report

Molecular Dynamics Simulation of a Lennard-Jones Fluid

Bolin Liao

In this project, a molecular dynamics study is carried out on a Lennard-Jones fluid. Main

algorithms implemented and their basic features include: 1) Cell list based force calculation is

used to speed up the simulation and save computation resource; 2) Nose-Hoover thermostat is

added to maintain the system temperature within a reasonable fluctuation range (the impace

of different “thermostat mass” is also studied), with Beeman predictor-corrector integration

algorithm to shorten the time needed for reaching equilibrium; 3) Long range corrections are

added when calculating total potential energy and pressure, and good agreements are achieved

between MD and Monte Carlo simulation results; 3) Brownian dynamics simulation is carried

out to measure the diffusion coefficient, and good agreement is achieved when compared to

experiment data. In the following parts of this report, details of the algorithms and data

structures that are used in each stage of this simulation will be presented, while the complete

codes attached as an appendix. The codes are written in Fortran.

1. Initialization Two purposes are to be achieved in the initialization stage (SUBROUTINE init). The first is to

arrange the atoms in a simple cubic structure, as their initial positions, and the second is to

assign velocities from a Maxwell distribution to each atom, and rescale them in order to obtain

desired temperature and guarantee a rest center of mass. The arrangement of atoms is

straightforward. For generating velocities from a Maxwell distribution, a polar form Box-Muller

algorithm is used to generate a Gaussian distribution from 2-dimensional uniform distribution,

and then all velocities are rescaled to achieve zero average velocity and correct temperature.

Codes:

FUNCTION rangauss()

!Polar form Box-Muller Gaussian random number generator

REAL*8 ran_uniform, rangauss, v1, v2, rsq

100 CALL RANDOM_NUMBER(v1)

v1=2.0*v1-1.0

CALL RANDOM_NUMBER(v2)

v2=2.0*v2-1.0

rsq=v1*v1+v2*v2

IF (rsq .GE. 1.0 .OR. rsq .LE. 0.0) GOTO 100

Page 2: MD-LJasdf

rangauss=v1*SQRT(-2.0*LOG(rsq)/rsq)

RETURN

END

!----------------------------------------------------------------------------

!----------------------------------------------------------------------

SUBROUTINE init (temp,rho,pos,vel,len)

USE constants

IMPLICIT NONE

!assign initial positions and velocities to the atoms

REAL*8 temp !temp: Temperature of the simulation

REAL*8 rho !rho: Number density of the simulation

REAL*8 pos(dim,num) !Position record matrix

REAL*8 vel(dim,num) !Velocity record matrix

REAL*8 rangauss !Gaussian random number generator

REAL*8 vol !volume of the system

REAL*8 len !length of the box

REAL*8 gsize !grid size of a unit cell

INTEGER num_pd !number of particles per dimension

INTEGER i,j,k !control variable for the loops

INTEGER n !label of particles

REAL*8 v_sum(dim) !average velocity

REAL*8 v2_sum !mean-square velocity

REAL*8 sf !temperature scaling factor

vol = num/rho

len = vol ** (1.0/3.0)

num_pd = INT(num ** (1.0/3.0))

gsize = len/num_pd

!position initialization: arrange atoms in a single cubic structure

n = 1

outer: DO i = 1,num_pd

DO j = 1,num_pd

DO k = 1,num_pd

if (n .GT. num) EXIT outer

pos(1,n) = (i-1)*gsize

pos(2,n) = (j-1)*gsize

pos(3,n) = (k-1)*gsize

n = n + 1

END DO

END DO

END DO outer

!velocity initialization: Maxwell distribution with rescaling

v_sum(1:dim)=0;

v2_sum = 0;

DO i = 1,num

vel(1,i) = rangauss()

vel(2,i) = rangauss()

vel(3,i) = rangauss()

v_sum(1) = v_sum(1) + vel(1,i)

v_sum(2) = v_sum(2) + vel(2,i)

v_sum(3) = v_sum(3) + vel(3,i)

v2_sum = v2_sum + vel(1,i)*vel(1,i)+vel(2,i)*vel(2,i)+vel(3,i)*vel(3,i)

END DO

v_sum(1) = v_sum(1)/REAL(num) !average velocity

Page 3: MD-LJasdf

v_sum(2) = v_sum(2)/REAL(num)

v_sum(3) = v_sum(3)/REAL(num)

v2_sum = v2_sum/REAL(num) !average velocity square

sf = SQRT(3.0*temp/v2_sum) !scaling factor to desired temperature

!Rescale the velocity to set the initial temperature

v2_sum = 0

DO i = 1,num

vel(1,i) = (vel(1,i)-v_sum(1))*sf

vel(2,i) = (vel(2,i)-v_sum(2))*sf

vel(3,i) = (vel(3,i)-v_sum(3))*sf

v2_sum = v2_sum + vel(1,i)*vel(1,i)+vel(2,i)*vel(2,i)+vel(3,i)*vel(3,i)

END DO

RETURN

END SUBROUTINE init

After initialization, the atom positions are as shown below:

0 2 4 6 8 10 12

0

5

10

0

2

4

6

8

10

12

x

Initialized Position

y

z

Page 4: MD-LJasdf

The velocity distribution is shown below:

We can tell from this distribution fitting plot that the average value of velocities is zero and the

variance of the distribution is 4.996 (the given temperature is 5), which matches the given

conditions very well.

2. Cell list and force calculation To speed up force calculation, a cell list is implemented. First the simulation volume is divided

to smaller cells with size equal to or slightly larger than the cut-off radius. Then a cell list is built

up that contains the labels of the atoms that are in certain cell. The basic data structure used in

my program is a link list1. The link list consists of two matrices: cell and link. Each cell has a

corresponding link list that stores the information of what atoms are located in this cell, the

head of which is stored in the matrix cell, while the label of the next atom in the link list is

stored in the matrix link. All elements of the cell matrix are initialized to zero. Then scan all the

atoms, locate them to certain cell, and insert the atom into the link list of the corresponding cell

that it belongs to, which follows the standard routine of operations on a link list.

1 D. Frankel, B. Smit, “Understanding Molecular Simulation”, 2

nd edition, pp550-552, 2002

-6 -4 -2 0 2 4 60

0.02

0.04

0.06

0.08

0.1

0.12

0.14

0.16

0.18

Data

Den

sity

Initial Distribution

Gaussian

mean: -6e-17, variance 4.996

Page 5: MD-LJasdf

Codes: (set up cell list)

SUBROUTINE cell_list (pos,cell,ncel,rcel,link)

!generating cell_list

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

INTEGER ncel !number of cells per dimension

REAL*8 rcel !size of a cell

INTEGER n !label of particles

INTEGER i,j,k !loop control

INTEGER cellx,celly,cellz !id of the cell for certain atom

INTEGER link(num)

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1)

!initialize the cell list

cell(0:ncel-1,0:ncel-1,0:ncel-1) = 0

!set up the cell list

DO n = 1,num !scan all atoms

!locate the atom to certain cell

cellx = INT(pos(1,n)/rcel)

celly = INT(pos(2,n)/rcel)

cellz = INT(pos(3,n)/rcel)

!insert the atom into the link list of the corresponding cell

link(n) = cell(cellx,celly,cellz)

cell(cellx,celly,cellz)=n;

END DO

RETURN

END SUBROUTINE cell_list

After setting up the cell list, force calculation is straight forward. First scan all the atoms, and

locate it to certain cell, then find the head of the link list of the cell by referring to matrix cell,

which is the first atom in the cell, then calculate the potential energy and forces between the

two atoms, and finally move on to the next atom in the link list by referring to matrix link, until

reaching the tail of the link list, which is marked by 0, indicating the search of this cell is finished.

The nearest 26 cells of the cell also need to be scanned to calculate forces on a certain atom. By

this means, it is not necessary to scan all other atoms to calculate the force on a certain atom,

instead only 27 cells need to be scanned, which speeds up the force calculation a lot. Another

complication of force calculation has to do with the periodic boundary condition. I set up a

signal matrix called period to mark whether a periodic boundary condition is encountered and

adjust the position of the corresponding atoms accordingly.

Page 6: MD-LJasdf

Codes: (force calculation)

SUBROUTINE force_calculation (pos,cell,link,ncel,rcel,force,len,potential)

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num) !position matrix

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1) !cell list

INTEGER link(num) !link list

INTEGER ncel !number of cells per dimension

REAL*8 rcel !size of cells

REAL*8 force(dim,num) !force matrix

REAL*8 len !size of the box

INTEGER n !labels for atoms

INTEGER cellx,celly,cellz !id of the cell for certain atom

REAL*8 pos1(dim) !the positon of the other atom that interacts with the

current atom

INTEGER id !the label of the other atom

INTEGER i,j,k,m,ii,jj,kk !loop control

INTEGER period(dim)

!flag for periodic b.c. 0:no periodic,1:lower bound,2:upper bound

REAL*8 distance(dim) !distance in each dimensions

REAL*8 radius2,radius6,radius6i !square of the distance

REAL*8 potential(num),uij !potential energy for each atom

DO n = 1,num !consider the atom labeled n

cellx = INT(pos(1,n)/rcel) !find which cell this atom sits in

celly = INT(pos(2,n)/rcel)

cellz = INT(pos(3,n)/rcel)

force(1,n)=0 !initialize forces

force(2,n)=0

force(3,n)=0

potential(n)=0 !initalize the internal energy

DO i = cellx-1,cellx+1 !scan the nearest 27 cells

DO j = celly-1,celly+1

DO k = cellz-1,cellz+1

ii=i; !keep track of the control variable for recovery

jj=j;

kk=k;

!implementing periodic boundary condition

period(1:dim)=0 !intialize the flag

!adjust the cell id and set up the flags

IF(ii .LT. 0) THEN

ii = ii + ncel

period(1) = 1

END IF

IF(ii .GT. ncel-1) THEN

ii = ii - ncel

period(1) = 2

END IF

IF(jj .LT. 0) THEN

jj = jj + ncel

period(2) = 1

END IF

IF(jj .GT. ncel-1) THEN

jj = jj - ncel

period(2) = 2

Page 7: MD-LJasdf

END IF

IF(kk .LT. 0) THEN

kk = kk + ncel

period(3) = 1

END IF

IF(kk .GT. ncel-1) THEN

kk = kk - ncel

period(3) = 2

END IF

!start from the head of the chain

id=cell(ii,jj,kk)

DO WHILE (id .NE. 0) !if not reached the tail of the chain

IF (id .EQ. n) THEN !if find the atom itself, skip

id = link(id)

CYCLE

END IF

!find the position of the interacting atom

DO m=1,dim

IF (period(m) .EQ. 0) THEN

pos1(m)=pos(m,id)

ELSE IF (period(m) .EQ. 1) THEN

pos1(m)=pos(m,id)-len

ELSE IF (period(m) .EQ. 2) THEN

pos1(m)=pos(m,id)+len

END IF

!distance between the two atoms in each dimension

distance(m)=pos(m,n)-pos1(m)

END DO

!if the atom is outside the cut-off radius, continue to the next atom

radius2 =

distance(1)*distance(1)+distance(2)*distance(2)+distance(3)*distance(3)

IF (radius2 .GT. rcut*rcut) THEN

id = link(id)

CYCLE

END IF

radius6 = radius2**3

radius6i = 1.0/radius6

!calculate potential energy

uij = 4*radius6i*(radius6i-1)

potential(n) = potential(n) + uij - ucut

!caululate forces

DO m = 1,dim

force(m,n) = force(m,n) +

distance(m)*6*(uij+4*(radius6i**2))/radius2

END DO

!move on to the next atom in the chain

id = link(id)

END DO

END DO

END DO

END DO

END DO

END SUBROUTINE force_calculation

Page 8: MD-LJasdf

3. Integration of EOM Knowing the forces on each atom, the next step is to integrate the equations of motion to make

the system start evolving with time. To keep a stable temperature along the simulation, a Nose-

Hoover thermostat is added to the system. Since the Nose-Hoover thermostat is generally not

compatible with velocity Verlet algorithm2, the Beeman predictor-corrector algorithm is chosen

as the integration scheme. Since in Beeman algorithm the forces in the previous time point are

needed to launch the iteration, a bootstrap subroutine using velocity Verlet algorithm is

designed to launch the system at the first step.

Codes: (launch the system at the first step)

SUBROUTINE bootstrap(pos,vel,force,len,temp,trace)

!bootstrap the system using velocity Verlet algorithm

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

REAL*8 vel(dim,num)

REAL*8 force(dim,num)

INTEGER i,j !loop control

REAL*8 sumv(dim) !summation of velocity

REAL*8 sumv2 !summation of velocity square

REAL*8 sf !temperature scaling factor

REAL*8 len !box size

REAL*8 temp !temperature

REAL*8 trace(dim,num) !trace matrix

REAL*8 delta_pos !the relative translation of position, adding up to trace

sumv(1:dim)=0 !initialize the average velocity

sumv2=0 !initialize the average squared velocity

DO i = 1,num

DO j = 1,dim

!calculate the relative motion

delta_pos = vel(j,i)*time_step + force(j,i)/(2.0*mass)*time_step*time_step

!update the position, and keep track of the trace(for diffusion experiment)

pos(j,i) = pos(j,i) + delta_pos

trace(j,i) = trace(j,i) + delta_pos

!update the velocity

vel(j,i) = vel(j,i) + force(j,i)/mass*time_step

sumv(j) = sumv(j) + vel(j,i)

sumv2 = sumv2 + vel(j,i)*vel(j,i)

!adjust position according to periodic boundary conditions

IF (pos(j,i) .LT. 0) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len + len

IF (pos(j,i) .GT. len) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len

END DO

END DO

!rescaling the velocity again

sumv(1)=sumv(1)/REAL(num)

sumv(2)=sumv(2)/REAL(num)

sumv(3)=sumv(3)/REAL(num)

sumv2=sumv2/REAL(num)

2 D. Frankel, B. Smit, “Understanding Molecular Simulation”, 2

nd edition, pp535, 2002

Page 9: MD-LJasdf

sf = SQRT(3.0*temp/sumv2)

sumv2=0

DO i = 1,num

DO j = 1,dim

vel(j,i) = (vel(j,i)-sumv(j))*sf

sumv2 = sumv2 + vel(j,i)*vel(j,i)

END DO

END DO

WRITE (*,*) 'Bootstrap Temperature: ' , sumv2/REAL(num)/3.0

END SUBROUTINE bootstrap

For subsequent time steps, the Beeman algorithm is used to integrate the equations of motion.

The Nose-Hoover thermostat is added in the force calculation process in a Beeman iteration.

The thermostat feedback variable ksi evolves with time, while the time derivative of ksi

depends on the difference between the actual temperature and the given temperature. The

“mass” of the thermostat determines the feedback sensitivity and thus the temperature

fluctuation. The impacts of different thermostat mass are evaluated in this project.

02

46

810

12

0

5

10

0

2

4

6

8

10

12

x

After Boostrap

y

z

Page 10: MD-LJasdf

Codes (Beeman integration algorithm)

SUBROUTINE

beeman(pos,vel,force,force1,cell,link,ncel,rcel,len,potential,ksi,trace)

!integrate the EOM using Beeman's predictor-corrector algorithm with Nose-

Hoover thermostat

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

REAL*8 vel(dim,num),velp(dim,num) !velp:the predicted velocity

!forces at the previous, current and the next time point

REAL*8 force(dim,num),force1(dim,num),force2(dim,num)

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1) !cell list

INTEGER link(num)!link list

INTEGER ncel !number of cells per dimension

REAL*8 rcel,len,potential(num)

REAL*8 ksi !friction factor

INTEGER i,j !loop control

REAL*8 trace(dim,num) !trace of the atoms

REAL*8 delta_pos !relative motion

DO i = 1,num

DO j = 1,dim

!calculate relative motion

delta_pos = vel(j,i)*time_step +

time_step*time_step/6*(4*force1(j,i)-force(j,i))/mass

pos(j,i) = pos(j,i) + delta_pos

trace(j,i) = trace(j,i) + delta_pos

!periodic boundary conditions

IF (pos(j,i) .LT. 0) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len + len

IF (pos(j,i) .GT. len) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len

!predicted velocities

velp(j,i) = vel(j,i) + time_step/2*(3*force1(j,i)-force(j,i))/mass

END DO

END DO

!update cell list and calculate forces

CALL cell_list(pos,cell,ncel,rcel,link)

CALL force_calculation (pos,cell,link,ncel,rcel,force2,len,potential)

DO i = 1,num

DO j = 1,dim

!calculate forces incorporating thermostat

force2(j,i)=force2(j,i)-ksi*mass*velp(j,i)

!corrected velocity

vel(j,i) = vel(j,i) + time_step/6*(2*force2(j,i)+5*force1(j,i)-

force(j,i))/mass

END DO

END DO

RETURN

END SUBROUTINE beeman

Page 11: MD-LJasdf

To maintain a stable temperature, generally two methods could be used, velocity-rescaling and

adding a thermostat. I first tried adding Nose-Hoover thermostat at the beginning, without

temperature rescaling, and played with the thermostat mass, and I got the following results:

From this plot we could see relatively large fluctuations of temperature and very slow

convergence. To get a more stable temperature and faster convergence, I tried first rescaling

the system for 100 time steps, then turning on the thermostat and stopping the rescaling, and I

got the following result, which indicates a much more stable temperature.

0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5

x 104

4

4.2

4.4

4.6

4.8

5

5.2

5.4

5.6

5.8

6

t

tem

pera

ture

Thermostat test (w/o rescaling, T=5)

Q=100

Q=10

Q=1

Q=0.1

0 1000 2000 3000 4000 5000 6000 7000 8000 9000 100004

4.2

4.4

4.6

4.8

5

5.2

5.4

5.6

5.8

6

t

tem

pera

ture

Thermostat test (with rescaling)

Page 12: MD-LJasdf

4. Measurement After the system reaches equilibrium, measurements of the system properties could be carried

out. In this project, temperature, pressure, total potential energy and diffusion coefficient are

measured. Temperature and pressure are measured as described in the project assignment.

The diffusion coefficient is measured using the random-walk model, where the traces of each

atom are recorded in a matrix called trace. The summation of the squares of the relative

displacements of all the atoms is supposed to increase linearly with time, mimicking a diffusion

process, the slope of which gives the diffusion coefficient.

Codes: (measurement of the system)

SUBROUTINE measure(pos,vel,temp1,pressure,etot,v_ave,potential,rho)

!measure system properties

USE constants

IMPLICIT NONE

REAL*8 rho,vol !number density and volume

REAL*8 pos(dim,num)

REAL*8 vel(dim,num)

REAL*8 temp1 !current temperature

REAL*8 pressure, pxx, pyy, pzz !current pressure

REAL*8 etot !total energy of the system

REAL*8 potential(num), psum !potential energy

REAL*8 v_ave(dim) !average velocity of each dimension

REAL*8 sumv2 !summation of velocity square

REAL*8 radius !distance between two atoms

REAL*8 force !force between two atoms

INTEGER i,j

!calculate average velocities

v_ave(1:dim)=0

DO i = 1,num

DO j = 1,dim

v_ave(j) = v_ave(j) + vel(j,i)

END DO

END DO

v_ave(1) = v_ave(1)/REAL(num)

v_ave(2) = v_ave(2)/REAL(num)

v_ave(3) = v_ave(3)/REAL(num)

!calculate temperature

sumv2 = 0

DO i = 1,num

DO j = 1,dim

sumv2 = sumv2 + (vel(j,i)-v_ave(j))*(vel(j,i)-v_ave(j))

END DO

END DO

temp1 = sumv2/REAL(num)/3.0

!calculate total potential energy

psum = 0

DO i = 1,num

psum = psum + potential(i)

END DO

etot = psum/2.0/REAL(num)

Page 13: MD-LJasdf

!measure the pressure

vol = REAL(num)/rho

pxx = 0 !configurational pressure

pyy = 0

pzz = 0

DO i = 1,num

DO j = i+1,num

radius = (pos(1,i)-pos(1,j))*(pos(1,i)-pos(1,j)) + (pos(2,i)-

pos(2,j))*(pos(2,i)-pos(2,j)) +(pos(3,i)-pos(3,j))*(pos(3,i)-pos(3,j))

force = 4.0/(radius**4)*(12/(radius**3)-6)

pxx = pxx + (pos(1,i)-pos(1,j))*(pos(1,i)-pos(1,j))*force

pyy = pyy + (pos(2,i)-pos(2,j))*(pos(2,i)-pos(2,j))*force

pzz = pzz + (pos(3,i)-pos(3,j))*(pos(3,i)-pos(3,j))*force

END DO

END DO

pressure = rho*temp1+(pxx+pyy+pzz)/3.0/vol

RETURN

END SUBROUTINE measure

The codes for diffusion experiment are scattered in different parts of whole program, which

could be found in the appendix.

5. Long Range Corrections Long range corrections for total potential energy and pressure are incorporated in this project.

The long-range corrections are provided in the following two equations:

∫ ( )

(

)

(

)

Codes: (long-range corrections)

!-----------------------------------------------------------------

SUBROUTINE long_range_correction(rho,ucor,pcor)

USE constants

IMPLICIT NONE

!calculate the long range corrections for potential energy and pressure

REAL*8 rho !numdensity of the simulation

REAL*8 ucor !long range correction for potential energy

REAL*8 pcor !long range correction for pressure

ucor = 8.0*3.1415926*rho*(1.0/(9.0*rcut**9)-1.0/(3.0*rcut**3))

pcor = 16.0*3.1415926*rho*(2.0/(9.0*rcut**9)-1.0/(3.0*rcut**3))

RETURN

END SUBROUTINE long_range_correction

!-----------------------------------------------------------------

Page 14: MD-LJasdf

6. Test of Performance Test Conditions 1: temperature = 5, number density = 0.5

Here I show the time evolution of pressure for systems consist of 1000 and 8000 atoms

respectively. And we can see apparently less fluctuations in a larger system. The convergence is

fast, generally after 100 time steps (~2 ps), the system will be in equilibrium. The averaged

pressure is around 4.3, which is comparable with the Monte Carlo result (=4.65).

0 100 200 300 400 500 600 700 800 900 1000-1

0

1

2

3

4

5

time

pre

ssure

Pressure Vs. Time (T=5, n=0.5)

n=1000

n=8000

Page 15: MD-LJasdf

Potential energy measured: -2.1, comparable with the Monte Carlo result (= -2.37)

Test Condition 2: temperature = 2, number density = 0.9

The measured pressure is around 9, while the Monte Carlo gives 9.1.

0 100 200 300 400 500 600 700 800 900 1000

-3

-2.5

-2

-1.5

-1

time

pote

ntia

l en

erg

y

Potential Energy vs. Time (T=5, n=0.5)

n=1000

n=8000

0 100 200 300 400 500 600 700 800 900 10006

7

8

9

10

11

12

13

14

15

16

time

pre

ssure

Pressure (T=2, rho=0.9)

n=1000

n=8000

Page 16: MD-LJasdf

Measured potential energy is -4.5, while the Monte Carlo gives -5.

Test Condition 3 : temperature = 1, number density = 0.05

0 100 200 300 400 500 600 700 800 900 1000-5

-4.5

-4

-3.5

-3

-2.5

time

Pote

ntia

l en

erg

y

Potential energy (T=2, rho=0.9)

n= 8000

n= 1000

0 500 1000 1500 2000 2500 3000 3500 4000 4500 50000

0.01

0.02

0.03

0.04

0.05

0.06

0.07

0.08

0.09

0.1

time

pre

ssure

Pressure (T=1, rho=0.05)

n=1000

n=8000

Page 17: MD-LJasdf

Measured pressure: 0.043, while the Monte Carlo gives 0.037

Measured potential energy: -0.34, while Monte Carlo gives -0.478

Test Condition 4 : temperature = 1.1709 (140K), number density = 0.904 ( m-3)

0 500 1000 1500 2000 2500 3000 3500 4000 4500 5000-0.35

-0.3

-0.25

-0.2

-0.15

-0.1

-0.05

0

time

Pote

ntia

l en

erg

y

Potential Energy (T=1, rho=0.05)

n=1000

n=8000

0 100 200 300 400 500 600 700 800 900 10004

5

6

7

8

9

10

11

12

time

pote

ntia

l

Pressure ( T=1.1709, rho=0.904)

1000

8000

Page 18: MD-LJasdf

Measured pressure: 4.7 (197.3 MPa)

The slope of the linear fitting is 0.431. Since the slope equals 6D in 3-dimension case, so the

diffusion coefficient is D=0.431/6=0.0718, which is equivalent to

⁄ .

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

0

0.05

0.1

0.15

0.2

0.25

0.3

0.35

0.4

time

R2

Random Walk

R^2

Linear Fit

Page 19: MD-LJasdf

Appendix: The complete codes:

!Molecular Dynamics Simulation of Lennard-Jones liquid

!Author: Bolin Liao Date: 05/09/2011

!All Rights Reserved

!Nose-Hoover Thermostat with Beeman predictor-corrector algorithm

!

!---------------------------------------------------------------

!define constants

MODULE constants

IMPLICIT NONE

INTEGER num

PARAMETER (num = 8000)

INTEGER dim !dimension of the simulation

PARAMETER (dim = 3)

REAL*8 time_step !time step

PARAMETER (time_step = 1.e-3)

REAL*8 rcut !cut-off radius

PARAMETER (rcut = 2.4)

REAL*8 ucut !cut-off energy

PARAMETER (ucut=4.0/(rcut**6)*(1/(rcut**6)-1))

REAL*8 mass !mass of the particle

PARAMETER (mass=1.0)

REAL*8 qmass !Nose-Hoover thermostat mass

PARAMETER (qmass=10)

END MODULE constants

!----------------------------------------------------------------------

PROGRAM md

USE constants

IMPLICIT NONE

REAL*8 temp !assigned temperature

REAL*8 temp1 !current temperature

REAL*8 pressure !measured pressure

REAL*8 rho !assigned number density

REAL*8 pos(dim,num) !position matrix

REAL*8 vel(dim,num) !velocity matrix

REAL*8 v_ave(dim) !average velocity

REAL*8 len !length of the box

INTEGER ncel !number of cells

REAL*8 rcel !size of a cell

INTEGER, ALLOCATABLE, DIMENSION(:,:,:) :: cell !cell list

INTEGER link(num) !link list for cells

REAL*8 force(dim,num),force1(dim,num) !force matrix

REAL*8 potential(num) !potential energy

REAL*8 ucor !long range correction for potential energy

REAL*8 pcor !long range correction for pressure

REAL*8 etot !total energy

REAL*8 ksi !friction factor for Nose-Hoover thermostat

REAL*8 trace(dim,num),trace2 !trace of all atoms - for calculating Diffusion

Coefficient

REAL*8 sf !temperature scaling factor

INTEGER cyc !cycle of simulation

Page 20: MD-LJasdf

INTEGER i,j,k !loop control

WRITE (*,*) 'Input Simulation Temperature'

READ (*,*) temp

WRITE(*,*) 'Input Simulation Density'

READ (*,*) rho

WRITE(*,*) 'Input Simulation Cycle'

READ (*,*) cyc

OPEN (UNIT=21, FILE='test.dat', STATUS='REPLACE')

!initialization

CALL init (temp,rho,pos,vel,len)

WRITE (*,*) 'Initialization Done!'

!calculate long range correction factors

CALL long_range_correction(rho,ucor,pcor)

WRITE (21,*) 'long range correction for potential:', ucor

WRITE (21,*) 'long range correction for pressure:', pcor

!initialize the cell list parameters

ncel=INT(len/rcut)

rcel=len/REAL(ncel)

WRITE (*,*) 'len: ', len,'ncel: ',ncel,'rcel: ',rcel

ALLOCATE (cell(0:ncel-1,0:ncel-1,0:ncel-1))

!set up cell list and calculate forces

CALL cell_list(pos,cell,ncel,rcel,link)

CALL force_calculation (pos,cell,link,ncel,rcel,force,len,potential)

!bootstrap the system

trace(1:dim,1:num) = 0 !initialize the trace matrix

CALL bootstrap(pos,vel,force,len,temp,trace)

CALL cell_list(pos,cell,ncel,rcel,link)

CALL force_calculation (pos,cell,link,ncel,rcel,force1,len,potential)

ksi = 0 !initialize the friction factor

DO i = 1,cyc

CALL

beeman(pos,vel,force,force1,cell,link,ncel,rcel,len,potential,ksi,trace)

force = force1

CALL cell_list(pos,cell,ncel,rcel,link)

CALL force_calculation (pos,cell,link,ncel,rcel,force1,len,potential)

CALL measure(pos,vel,temp1,pressure,etot,v_ave,potential,rho)

pressure = pressure + pcor

etot = etot + ucor

!calculate the collective displacement to obtain diffusion coefficient

trace2 = 0

DO j = 1,num

trace2 = trace2 + trace(1,j)*trace(1,j) + trace(2,j)*trace(2,j) +

trace(3,j)*trace(3,j)

END DO

trace2 = trace2/REAL(num)

200 FORMAT (F12.7,F12.7,F12.7,F12.7)

WRITE (21,200) temp1, pressure, etot,trace2

WRITE (*,200) temp1, pressure, etot,trace2

!Rescaling till 200 time steps to turn on thermostat

IF (i .LT. 200) THEN

sf = SQRT(temp/temp1)

vel = vel * sf

Page 21: MD-LJasdf

ELSE

ksi = ksi + (3*num+1)/qmass*(temp1-temp)*time_step

END IF

END DO

CLOSE (UNIT=21)

END PROGRAM md

!----------------------------------------------------------------------

!----------------------------------------------------------------------

SUBROUTINE init (temp,rho,pos,vel,len)

USE constants

IMPLICIT NONE

REAL*8 temp !temp: Temperature of the simulation

REAL*8 rho !rho: Number density of the simulation

REAL*8 pos(dim,num) !Position record matrix

REAL*8 vel(dim,num) !Velocity record matrix

REAL*8 rangauss !Gaussian random number generator

REAL*8 vol !volume of the system

REAL*8 len !length of the box

REAL*8 gsize !grid size of a unit cell

INTEGER num_pd !number of particles per dimension

INTEGER i,j,k !control variable for the loops

INTEGER n !label of particles

REAL*8 v_sum(dim) !average velocity

REAL*8 v2_sum !mean-square velocity

REAL*8 sf !temperature scaling factor

vol = num/rho

len = vol ** (1.0/3.0)

num_pd = INT(num ** (1.0/3.0))

!WRITE (*,*) 'number of particles per side' , num_pd

gsize = len/num_pd

!position initialization

n = 1

outer: DO i = 1,num_pd

DO j = 1,num_pd

DO k = 1,num_pd

if (n .GT. num) EXIT outer

pos(1,n) = (i-1)*gsize

pos(2,n) = (j-1)*gsize

pos(3,n) = (k-1)*gsize

n = n + 1

END DO

END DO

END DO outer

!velocity initialization

v_sum(1:dim)=0;

v2_sum = 0;

DO i = 1,num

vel(1,i) = rangauss()

vel(2,i) = rangauss()

vel(3,i) = rangauss()

Page 22: MD-LJasdf

v_sum(1) = v_sum(1) + vel(1,i)

v_sum(2) = v_sum(2) + vel(2,i)

v_sum(3) = v_sum(3) + vel(3,i)

v2_sum = v2_sum + vel(1,i)*vel(1,i)+vel(2,i)*vel(2,i)+vel(3,i)*vel(3,i)

END DO

v_sum(1) = v_sum(1)/REAL(num) !average velocity

v_sum(2) = v_sum(2)/REAL(num)

v_sum(3) = v_sum(3)/REAL(num)

v2_sum = v2_sum/REAL(num) !average velocity square

sf = SQRT(3.0*temp/v2_sum) !scaling factor to desired temperature

!Rescale the velocity to set the initial temperature

v2_sum = 0

DO i = 1,num

vel(1,i) = (vel(1,i)-v_sum(1))*sf

vel(2,i) = (vel(2,i)-v_sum(2))*sf

vel(3,i) = (vel(3,i)-v_sum(3))*sf

v2_sum = v2_sum + vel(1,i)*vel(1,i)+vel(2,i)*vel(2,i)+vel(3,i)*vel(3,i)

END DO

!WRITE (21,*) v2_sum/REAL(num)/3.0

RETURN

END SUBROUTINE init

!----------------------------------------------------------------------------

-

!----------------------------------------------------------------------------

-

SUBROUTINE cell_list (pos,cell,ncel,rcel,link)

!generating cell_list

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

INTEGER ncel !number of cells per dimension

REAL*8 rcel !size of a cell

INTEGER n !label of particles

INTEGER i,j,k !loop control

INTEGER cellx,celly,cellz !id of the cell for certain atom

INTEGER link(num)

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1)

!initialize the cell list

cell(0:ncel-1,0:ncel-1,0:ncel-1) = 0

!set up the cell list

DO n = 1,num !scan all atoms

!locate the atom

cellx = INT(pos(1,n)/rcel)

celly = INT(pos(2,n)/rcel)

cellz = INT(pos(3,n)/rcel)

!insert the atom into the link list

link(n) = cell(cellx,celly,cellz)

cell(cellx,celly,cellz)=n;

END DO

RETURN

END SUBROUTINE cell_list

Page 23: MD-LJasdf

!----------------------------------------------------------------------------

-

!----------------------------------------------------------------------------

-

SUBROUTINE force_calculation (pos,cell,link,ncel,rcel,force,len,potential)

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num) !position matrix

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1) !cell list

INTEGER link(num) !link list

INTEGER ncel !number of cells per dimension

REAL*8 rcel !size of cells

REAL*8 force(dim,num) !force matrix

REAL*8 len !size of the box

INTEGER n !labels for atoms

INTEGER cellx,celly,cellz !id of the cell for certain atom

REAL*8 pos1(dim) !the positon of the other atom that interacts with the

current atom

INTEGER id !the label of the other atom

INTEGER i,j,k,m,ii,jj,kk !loop control

INTEGER period(dim)

!flag for periodic boundary condition 0:no periodic, 1: lower bound, 2: upper

bound

REAL*8 distance(dim) !distance in each dimensions

REAL*8 radius2,radius6,radius6i !square of the distance

REAL*8 potential(num),uij !potential energy for each atom

DO n = 1,num !consider the atom labeled n

cellx = INT(pos(1,n)/rcel) !find which cell this atom sits in

celly = INT(pos(2,n)/rcel)

cellz = INT(pos(3,n)/rcel)

force(1,n)=0 !initialize forces

force(2,n)=0

force(3,n)=0

potential(n)=0 !initalize the internal energy

DO i = cellx-1,cellx+1 !scan the nearest 27 cells

DO j = celly-1,celly+1

DO k = cellz-1,cellz+1

ii=i; !keep track of the control variable for recovery

jj=j;

kk=k;

!implementing periodic boundary condition

period(1:dim)=0 !intialize the flag

!adjust the cell id and set up the flags

IF(ii .LT. 0) THEN

ii = ii + ncel

period(1) = 1

END IF

IF(ii .GT. ncel-1) THEN

ii = ii - ncel

period(1) = 2

END IF

IF(jj .LT. 0) THEN

jj = jj + ncel

period(2) = 1

END IF

Page 24: MD-LJasdf

IF(jj .GT. ncel-1) THEN

jj = jj - ncel

period(2) = 2

END IF

IF(kk .LT. 0) THEN

kk = kk + ncel

period(3) = 1

END IF

IF(kk .GT. ncel-1) THEN

kk = kk - ncel

period(3) = 2

END IF

!start from the head of the chain

id=cell(ii,jj,kk)

DO WHILE (id .NE. 0) !if not reached the tail of the chain

IF (id .EQ. n) THEN !if find the atom itself, skip

id = link(id)

CYCLE

END IF

!find the position of the interacting atom

DO m=1,dim

IF (period(m) .EQ. 0) THEN

pos1(m)=pos(m,id)

ELSE IF (period(m) .EQ. 1) THEN

pos1(m)=pos(m,id)-len

ELSE IF (period(m) .EQ. 2) THEN

pos1(m)=pos(m,id)+len

END IF

distance(m)=pos(m,n)-pos1(m) !distance between the

two atoms in each dimension

END DO

!if the atom is outside the cut-off radius, continue to

the next atom

radius2 =

distance(1)*distance(1)+distance(2)*distance(2)+distance(3)*distance(3)

IF (radius2 .GT. rcut*rcut) THEN

id = link(id)

CYCLE

END IF

radius6 = radius2**3

radius6i = 1.0/radius6

!calculate potential energy

uij = 4*radius6i*(radius6i-1)

potential(n) = potential(n) + uij - ucut

!caululate forces

DO m = 1,dim

force(m,n) = force(m,n) +

distance(m)*6*(uij+4*(radius6i**2))/radius2

END DO

!move on to the next atom in the chain

id = link(id)

END DO

END DO

END DO

END DO

END DO

END SUBROUTINE force_calculation

Page 25: MD-LJasdf

!----------------------------------------------------------------------------

-

!----------------------------------------------------------------------------

-

SUBROUTINE bootstrap(pos,vel,force,len,temp,trace)

!bootstrap the system using velocity Verlet algorithm

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

REAL*8 vel(dim,num)

REAL*8 force(dim,num)

INTEGER i,j !loop control

REAL*8 sumv(dim) !summation of velocity

REAL*8 sumv2 !summation of velocity square

REAL*8 sf !temperature scaling factor

REAL*8 len !box size

REAL*8 temp !temperature

REAL*8 trace(dim,num) !trace matrix

REAL*8 delta_pos !the relative translation of position, adding up to trace

sumv(1:dim)=0 !initialize the average velocity

sumv2=0 !initialize the average squared velocity

DO i = 1,num

DO j = 1,dim

!calculate the relative move

delta_pos = vel(j,i)*time_step +

force(j,i)/(2.0*mass)*time_step*time_step

!update the position, and keep track of the trace(for diffusion

experiment)

pos(j,i) = pos(j,i) + delta_pos

trace(j,i) = trace(j,i) + delta_pos

!update the velocity

vel(j,i) = vel(j,i) + force(j,i)/mass*time_step

sumv(j) = sumv(j) + vel(j,i)

sumv2 = sumv2 + vel(j,i)*vel(j,i)

!adjust position according to periodic boundary conditions

IF (pos(j,i) .LT. 0) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len +

len

IF (pos(j,i) .GT. len) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len

END DO

END DO

!rescaling the velocity again

sumv(1)=sumv(1)/REAL(num)

sumv(2)=sumv(2)/REAL(num)

sumv(3)=sumv(3)/REAL(num)

sumv2=sumv2/REAL(num)

sf = SQRT(3.0*temp/sumv2)

sumv2=0

DO i = 1,num

DO j = 1,dim

vel(j,i) = (vel(j,i)-sumv(j))*sf

sumv2 = sumv2 + vel(j,i)*vel(j,i)

END DO

END DO

WRITE (*,*) 'Bootstrap Temperature: ' , sumv2/REAL(num)/3.0

END SUBROUTINE bootstrap

Page 26: MD-LJasdf

!----------------------------------------------------------------------------

-

!----------------------------------------------------------------------------

-

SUBROUTINE

beeman(pos,vel,force,force1,cell,link,ncel,rcel,len,potential,ksi,trace)

!integrate the EOM using Beeman's predictor-corrector algorithm with Nose-

Hoover thermostat

USE constants

IMPLICIT NONE

REAL*8 pos(dim,num)

REAL*8 vel(dim,num),velp(dim,num) !velp:the predicted velocity

!forces at the previous, current and the next time point

REAL*8 force(dim,num),force1(dim,num),force2(dim,num)

INTEGER cell(0:ncel-1,0:ncel-1,0:ncel-1) !cell list

INTEGER link(num)!link list

INTEGER ncel !number of cells per dimension

REAL*8 rcel,len,potential(num)

REAL*8 ksi !friction factor

INTEGER i,j !loop control

REAL*8 trace(dim,num) !trace of the atoms

REAL*8 delta_pos !relative motion

DO i = 1,num

DO j = 1,dim

!calculate relative motion

delta_pos = vel(j,i)*time_step +

time_step*time_step/6*(4*force1(j,i)-force(j,i))/mass

pos(j,i) = pos(j,i) + delta_pos

trace(j,i) = trace(j,i) + delta_pos

!periodic boundary conditions

IF (pos(j,i) .LT. 0) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len +

len

IF (pos(j,i) .GT. len) pos(j,i) = pos(j,i) - INT(pos(j,i)/len)*len

!predicted velocities

velp(j,i) = vel(j,i) + time_step/2*(3*force1(j,i)-force(j,i))/mass

END DO

END DO

!update cell list and calculate forces

CALL cell_list(pos,cell,ncel,rcel,link)

CALL force_calculation (pos,cell,link,ncel,rcel,force2,len,potential)

DO i = 1,num

DO j = 1,dim

!calculate forces incorporating thermostat

force2(j,i)=force2(j,i)-ksi*mass*velp(j,i)

!corrected velocity

vel(j,i) = vel(j,i) + time_step/6*(2*force2(j,i)+5*force1(j,i)-

force(j,i))/mass

END DO

END DO

RETURN

END SUBROUTINE beeman

Page 27: MD-LJasdf

!----------------------------------------------------------------------------

-

!----------------------------------------------------------------------------

-

SUBROUTINE measure(pos,vel,temp1,pressure,etot,v_ave,potential,rho)

!measure system properties

USE constants

IMPLICIT NONE

REAL*8 rho,vol !number density and volume

REAL*8 pos(dim,num)

REAL*8 vel(dim,num)

REAL*8 temp1 !current temperature

REAL*8 pressure, pxx, pyy, pzz !current pressure

REAL*8 etot !total energy of the system

REAL*8 potential(num), psum !potential energy

REAL*8 v_ave(dim) !average velocity of each dimension

REAL*8 sumv2 !summation of velocity square

REAL*8 radius !distance between two atoms

REAL*8 force !force between two atoms

INTEGER i,j

!calculate average velocities

v_ave(1:dim)=0

DO i = 1,num

DO j = 1,dim

v_ave(j) = v_ave(j) + vel(j,i)

END DO

END DO

v_ave(1) = v_ave(1)/REAL(num)

v_ave(2) = v_ave(2)/REAL(num)

v_ave(3) = v_ave(3)/REAL(num)

!calculate temperature

sumv2 = 0

DO i = 1,num

DO j = 1,dim

sumv2 = sumv2 + (vel(j,i)-v_ave(j))*(vel(j,i)-v_ave(j))

END DO

END DO

temp1 = sumv2/REAL(num)/3.0

!calculate total potential energy

psum = 0

DO i = 1,num

psum = psum + potential(i)

END DO

etot = psum/2.0/REAL(num)

!measure the pressure

vol = REAL(num)/rho

pxx = 0 !configurational pressure

pyy = 0

pzz = 0

DO i = 1,num

DO j = i+1,num

radius = (pos(1,i)-pos(1,j))*(pos(1,i)-pos(1,j)) + (pos(2,i)-

pos(2,j))*(pos(2,i)-pos(2,j)) +(pos(3,i)-pos(3,j))*(pos(3,i)-pos(3,j))

Page 28: MD-LJasdf

force = 4.0/(radius**4)*(12/(radius**3)-6)

pxx = pxx + (pos(1,i)-pos(1,j))*(pos(1,i)-pos(1,j))*force

pyy = pyy + (pos(2,i)-pos(2,j))*(pos(2,i)-pos(2,j))*force

pzz = pzz + (pos(3,i)-pos(3,j))*(pos(3,i)-pos(3,j))*force

END DO

END DO

pressure = rho*temp1+(pxx+pyy+pzz)/3.0/vol

RETURN

END SUBROUTINE measure

!-----------------------------------------------------------------

!-----------------------------------------------------------------

SUBROUTINE long_range_correction(rho,ucor,pcor)

USE constants

IMPLICIT NONE

!calculate the long range corrections for potential energy and pressure

REAL*8 rho !numdensity of the simulation

REAL*8 ucor !long range correction for potential energy

REAL*8 pcor !long range correction for pressure

ucor = 8.0*3.1415926*rho*(1.0/(9.0*rcut**9)-1.0/(3.0*rcut**3))

pcor = 16.0*3.1415926*rho*(2.0/(9.0*rcut**9)-1.0/(3.0*rcut**3))

RETURN

END SUBROUTINE long_range_correction

!-----------------------------------------------------------------

!-----------------------------------------------------------------

FUNCTION rangauss()

!

!To generate random numbers from a gaussian distribution.

!

REAL*8 ran_uniform, rangauss, v1, v2, rsq

100 CALL RANDOM_NUMBER(v1)

v1=2.0*v1-1.0

CALL RANDOM_NUMBER(v2)

v2=2.0*v2-1.0

rsq=v1*v1+v2*v2

IF (rsq .GE. 1.0 .OR. rsq .LE. 0.0) GOTO 100

rangauss=v1*SQRT(-2.0*LOG(rsq)/rsq)

RETURN

END

!----------------------------------------------------------------------------

---