Skip to content

Commit ece1510

Browse files
committed
Added Version 1 MD code
1 parent a1fe004 commit ece1510

File tree

1 file changed

+319
-0
lines changed

1 file changed

+319
-0
lines changed

md-v1.f90

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
module precision
2+
implicit none
3+
save
4+
integer, parameter :: ip = selected_int_kind(15)
5+
integer, parameter :: dp = selected_real_kind(15)
6+
end module precision
7+
8+
program md
9+
10+
! Molecular Dynamics code for equilibration of Liquid Argon
11+
! Author: Alex Pacheco
12+
! Date : Jan 30, 2014
13+
14+
! This program simulates the equilibration of Liquid Argon
15+
! starting from a FCC crystal structure using Lennard-Jones
16+
! potential and velocity verlet algorithm
17+
! See md-orig.f90 for more details about this program
18+
19+
! Disclaimer:
20+
! This is code can be used as an introduction to molecular dynamics. There are lot more
21+
! concepts in MD that are not covered here.
22+
23+
! Parameters:
24+
! npartdim : number of unit cells, uniform in all directions. change to nonuniform if you desire
25+
! natom : number of atoms
26+
! nstep : nummber of simulation time steps
27+
! tempK : equilibration temperature
28+
! dt : simulation time steps
29+
! boxl : length of simulation box in all directions
30+
! alat : lattice constant for fcc crystal
31+
! kb : boltzmann constant, set to 1 for simplicity
32+
! mass : mass of Ar atom, set to 1 for simplicity
33+
! epsilon, sigma : LJ parameters, set to 1 for simplicity
34+
! rcell : FCC unit cell
35+
! coord, coord_t0 : nuclear positions for each step, current and initial
36+
! vel, vel_t0 : nuclear velocities for each step
37+
! acc, acc_t0 : nuclear acceleration for each step
38+
! force, pener : force and potential energy at current step
39+
! avtemp : average temperature at current time step
40+
! scale : scaling factor to set current temperature to desired temperature
41+
! gasdev : Returns a normally distributed deviate with zero mean and unit variance from Numerical recipes
42+
43+
use precision
44+
implicit none
45+
integer(ip), parameter :: npartdim = 10
46+
integer(ip), parameter :: natom = 4.d0 * npartdim ** 3
47+
integer(ip), parameter :: nstep = 1000
48+
real(dp), parameter :: tempK = 10, dt = 1d-3
49+
integer(ip) :: istep
50+
real(dp) :: boxl(3), alat
51+
integer(ip) :: n, i, j, k, l
52+
53+
real(dp) :: coord_t0(natom,3), coord(natom,3)
54+
real(dp) :: vel_t0(natom,3), vel(natom,3)
55+
real(dp) :: acc_t0(natom,3), acc(natom,3)
56+
real(dp) :: force(natom,3), pener, mass
57+
58+
real(dp) :: vcm(3), r(3), rr, r2, r6, f(3)
59+
real(dp) :: avtemp, ke, kb, epsilon, sigma, scale
60+
real(dp) :: gasdev
61+
! For timing analysis
62+
real(dp) :: init_time, start_time, end_time
63+
integer, dimension(8) :: value
64+
65+
! Format statements
66+
1000 format(i8)
67+
1100 format(a,2x,3f12.6)
68+
1200 format(a,2x,e15.8)
69+
1300 format(a,2x,i8,2x,e15.8,1x,e15.8)
70+
71+
alat = 2d0 ** (2d0/3d0)
72+
boxl = npartdim * alat
73+
kb = 1.d0
74+
mass = 1.d0
75+
epsilon = 1.d0
76+
sigma = 1.d0
77+
78+
!=================================================
79+
! Initialize coordinates and random velocities
80+
!=================================================
81+
82+
call date_and_time(VALUES=value)
83+
init_time = real(value(5)*3600,dp) + real(value(6)*60,dp) + real(value(7),dp) + real(value(8),dp)/1000d0
84+
! Set initial coordinates, velocity and acceleration to zero
85+
coord_t0 = 0d0 ; vel_t0 = 0d0 ; acc_t0 = 0d0
86+
call initialize(natom, npartdim, alat, coord_t0, vel_t0)
87+
88+
open(unit=1,file='atom.xyz',status='unknown')
89+
write(1,1000) natom
90+
write(1,*)
91+
do i = 1, natom
92+
write(1,1100) 'Ar', coord_t0(i,1), coord_t0(i,2), coord_t0(i,3)
93+
end do
94+
95+
! Set Linear Momentum to zero
96+
call linearmom(natom, vel_t0)
97+
98+
! get current temperature
99+
call get_temp(natom, vel_t0, avtemp, mass, kb)
100+
print 1200, 'Initial Average Temperature: ', avtemp
101+
102+
! scale initial velocity to desired temperature
103+
scale = sqrt( tempK / avtemp )
104+
vel_t0 = vel_t0 * scale
105+
call get_temp(natom, vel_t0, avtemp, mass, kb)
106+
print 1200, 'Initial Scaled Average Temperature: ', avtemp
107+
108+
call date_and_time(VALUES=value)
109+
start_time = real(value(5)*3600,dp) + real(value(6)*60,dp) + real(value(7),dp) + real(value(8),dp)/1000d0
110+
111+
!=================================================
112+
! MD Simulation
113+
!=================================================
114+
115+
do istep = 1, nstep
116+
117+
! Get new atom positions from Velocity Verlet Algorithm
118+
call verlet(coord, coord_t0, vel, vel_t0, acc, acc_t0, force, pener, natom, mass, dt, boxl)
119+
120+
! Set Linear Momentum to zero
121+
call linearmom(natom, vel)
122+
123+
! compute average temperature
124+
call get_temp(natom, vel, avtemp, mass, kb)
125+
print 1300, 'Average Temperature: ' , istep, avtemp, pener
126+
127+
scale = sqrt ( tempk / avtemp )
128+
! Reset for next time step
129+
coord_t0 = coord
130+
acc_t0 = acc
131+
! scale velocity to desired temperature
132+
vel_t0 = vel * scale
133+
134+
! Write current coordinates to xyz file for visualization
135+
write(1,1000) natom
136+
write(1,*)
137+
do i = 1, natom
138+
write(1,1100) 'Ar', coord_t0(i,1), coord_t0(i,2), coord_t0(i,3)
139+
end do
140+
end do
141+
close(1)
142+
143+
call date_and_time(VALUES=value)
144+
end_time = real(value(5)*3600,dp) + real(value(6)*60,dp) + real(value(7),dp) + real(value(8),dp)/1000d0
145+
write(6,'(a,f12.3,/,a,f12.3)') 'Init Time: ', start_time - init_time, &
146+
'Sim Time: ', end_time - start_time
147+
148+
end program md
149+
150+
subroutine initialize(natom, npartdim, alat, coord_t0, vel_t0)
151+
use precision
152+
implicit none
153+
integer(ip) :: natom, npartdim
154+
real(dp), dimension(natom,3) :: coord_t0, vel_t0
155+
integer(ip) :: n, i, j, k, l
156+
real(dp) :: alat, rcell(3,4)
157+
158+
! Create FCC unit cell
159+
rcell = 0d0
160+
rcell(1,2) = 0.5d0 * alat
161+
rcell(2,2) = 0.5d0 * alat
162+
rcell(2,3) = 0.5d0 * alat
163+
rcell(3,3) = 0.5d0 * alat
164+
rcell(1,4) = 0.5d0 * alat
165+
rcell(3,4) = 0.5d0 * alat
166+
167+
! Create a FCC crystal structure
168+
n = 1
169+
do i = 1, npartdim
170+
do j = 1, npartdim
171+
do k = 1, npartdim
172+
do l = 1, 4
173+
coord_t0(n,1) = alat * real(i - 1, dp) + rcell(1,l)
174+
coord_t0(n,2) = alat * real(j - 1, dp) + rcell(2,l)
175+
coord_t0(n,3) = alat * real(k - 1, dp) + rcell(3,l)
176+
n = n + 1
177+
end do
178+
end do
179+
end do
180+
end do
181+
182+
! Assign initial random velocities
183+
do i = 1, natom
184+
do j = 1, 3
185+
vel_t0(i,j) = gasdev()
186+
end do
187+
end do
188+
189+
contains
190+
function gasdev()
191+
use precision
192+
implicit none
193+
real(dp) :: gasdev
194+
real(dp) :: v1, v2, fac, rsq
195+
real(dp), save :: gset
196+
logical, save :: available = .false.
197+
198+
if (available) then
199+
gasdev = gset
200+
available = .false.
201+
else
202+
do
203+
call random_number(v1)
204+
call random_number(v2)
205+
v1 = 2.d0 * v1 - 1.d0
206+
v2 = 2.d0 * v2 - 1.d0
207+
rsq = v1**2 + v2**2
208+
if ( rsq > 0.d0 .and. rsq < 1.d0 ) exit
209+
end do
210+
fac = sqrt(-2.d0 * log(rsq) / rsq)
211+
gasdev = v1 * fac
212+
gset = v2 * fac
213+
available = .true.
214+
end if
215+
end function gasdev
216+
217+
end subroutine initialize
218+
219+
subroutine verlet(coord, coord_t0, vel, vel_t0, acc, acc_t0, force, pener, natom, mass, dt, boxl)
220+
use precision
221+
implicit none
222+
real(dp), dimension(natom,3) :: coord, vel, acc, force
223+
real(dp), dimension(natom,3) :: coord_t0, vel_t0, acc_t0
224+
real(dp) :: pener
225+
integer(ip) :: natom, i, j, k
226+
real(dp) :: mass, dt, boxl(3)
227+
real(dp) :: r(3), f(3)
228+
real(dp) :: rr, r2, r6
229+
230+
! Set coordinates, velocity, acceleration and force at next time step to zero
231+
coord = 0d0 ; vel = 0d0 ; acc = 0d0 ; force = 0d0
232+
pener = 0d0
233+
234+
! Get new atom positions from Velocity Verlet Algorithm
235+
do i = 1, natom
236+
coord(i,:) = coord_t0(i,:) + vel_t0(i,:) * dt + 0.5d0 * acc_t0(i,:) * dt ** 2
237+
! Apply PBC to coordinates
238+
do j = 1, 3
239+
if ( coord(i,j) > boxl(j) ) then
240+
coord(i,j) = coord(i,j) - boxl(j)
241+
else if ( coord(i,j) < 0d0 ) then
242+
coord(i,j) = coord(i,j) + boxl(j)
243+
endif
244+
end do
245+
end do
246+
247+
! Get force at new atom positions
248+
! Using Lennard Jones Potential
249+
! Hint: you might want to also seperate the potential and force calculation into a separate subroutine
250+
! this will be useful if you want to use other potentials
251+
252+
do i = 1, natom - 1
253+
do j = i + 1, natom
254+
r(:) = coord(i,:) - coord(j,:)
255+
! minimum image criterion
256+
r = r - nint( r / boxl ) * boxl
257+
! Hint: Use dot_product
258+
rr = r(1) ** 2 + r(2) ** 2 + r(3) ** 2
259+
r2 = 1.d0 / rr
260+
r6 = r2 ** 3
261+
! Lennard Jones Potential
262+
! V = 4 * epsilon * [ (sigma/r)**12 - (sigma/r)**6 ]
263+
! = 4 * epsilon * (sigma/r)**6 * [ (sigma/r)**2 - 1 ]
264+
! = 4 * r**(-6) * [ r**(-2) - 1 ] for epsilon=sigma=1
265+
! F_i = 48 * epsilon * (sigma/r)**6 * (1/r**2) * [ ( sigma/r)** 6 - 0.5 ] * i where i = x,y,z
266+
! = 48 * r**(-8) * [ r**(-6) - 0.5 ] * i for epsilon=sigma=1
267+
pener = pener + 4d0 * r6 * ( r6 - 1.d0 )
268+
f = 48d0 * r2 * r6 * ( r6 - 0.5d0 ) * r
269+
force(i,:) = force(i,:) + f(:)
270+
force(j,:) = force(j,:) - f(:)
271+
end do
272+
end do
273+
274+
! Calculate Acceleration and Velocity at current time step
275+
acc = force / mass
276+
vel = vel_t0 + 0.5d0 * ( acc + acc_t0 ) * dt
277+
278+
end subroutine verlet
279+
280+
subroutine linearmom(natom, vel)
281+
use precision
282+
implicit none
283+
integer(ip) :: natom
284+
real(dp) :: vel(natom,3)
285+
integer(ip) :: i
286+
real(dp) :: vcm(3)
287+
288+
! First get center of mass velocity
289+
vcm = 0d0
290+
do i = 1, 3
291+
vcm(i) = sum(vel(:,i))
292+
end do
293+
vcm = vcm / real(natom,dp)
294+
295+
! Now remove center of mass velocity from all atoms
296+
do i = 1, natom
297+
vel(i,:) = vel(i,:) - vcm(:)
298+
end do
299+
300+
end subroutine linearmom
301+
302+
subroutine get_temp(natom, vel, avtemp, mass, kb)
303+
use precision
304+
implicit none
305+
integer(ip) :: natom
306+
real(dp) :: vel(natom,3)
307+
real(dp) :: avtemp
308+
real(dp) :: mass, kb
309+
integer(ip) :: i, j
310+
real(dp) :: ke
311+
312+
ke = 0d0
313+
do i = 1, natom
314+
ke = ke + dot_product(vel(i,:),vel(i,:))
315+
end do
316+
avtemp = mass * ke / ( 3d0 * kb * real( natom - 1, dp))
317+
318+
end subroutine get_temp
319+

0 commit comments

Comments
 (0)