Martin Lísal prosinec 2003 APLIKACE (pokračování) 1 Paralelní molekulární dynamika 1.1 Úvod Molekulární dynamika (MD) slouží k řešení pohybu N molekul, jejichž interakce je popsána potenciálem u. Uvažujme pro jednoduchost systém částic reagujích Lennardovým-Jonesovým (LJ) potenciálem ( ) 12 ( ) 6 u LJ (r ij ) = 4ε σ σ (1) r ij kde r ij je vzálenost mezi molekulami i a j, ε a σ jsou resp. energetický a délkový LJ parametr. V MD programech se více než 90% výpočtového času spotřebuje na výpočet celkové energie systému U, viriálu W a sil f ij. Ty se spočtou pro LJ tekutinu následujícím způsobem: r ij U = U c + U LRC N 1 N = u LJ (r ij ) + 8 [ ( )9 ( ) ] 1 σ σ 3 i=1 j=i+1 3 πnερσ3 3 r c r c kde r c je poloměr ořezání a ρ je hustota. W = W c + W LRC = 1 N 1 N 3 i=1 j=i+1 w LJ (r ij ) + 16 [ ( )9 ( ) ] 2 σ σ 3 3 πnερσ3 3 r c r c (2) (3) kde w LJ = r ( du LJ /dr ). f ij = 1 [ du LJ ] (r ij ) r ij (4) r ij dr ij = f ji (5) 1
1.2 Paralelizace dvojnásobného cyklu v MD programu Paralelizací dvojnásobného cyklu do i=1,n-1 Vnejsi cyklus do j=i+1,n Vnitrni cyklus... ve výpočtu U c, W c a f ij lze docílit značného urychlení běhu MD programů. Paralelizaci dvojnásobného cyklu lze provést následujícím způsobem: 1. Každý proces spočte jen část vnějšího cyklu t.j. spočte jen část z U c, W c a f ij. To lze provést následujícím způsobem: do i=1+myrank,n-1,nprocs Vnejsi cyklus do j=i+1,n Vnitrni cyklus... 2. Použitím MPI příkazu MPI ALLREDUCE sečteme části U c, W c a f ij z jednotlivých procesů a výsledné U c, W c a f ij se uloží na všechny procesy. 2
Program pro paralelní MD Lennardovy-Jonesovy tekutiny může vypadat následovně: Parallel NVT MD of Lennard-Jones Fluids ulj=4*eps*[(sig/r)^12-(sig/r)^6] program ParNVTmdLJ include mpif.h preprocessor directive System Data integer,parameter :: nmax=5000 Max # of Molecules real(8),parameter :: dt=0.005d0 Time Step real(8) :: rcut=1.0d0 Cut-Off Radius integer,parameter :: nom=500 # of Molecules real(8),parameter :: temp=2.0d0 Reduced Temperature real(8),parameter :: dens=0.4d0 Reduced Number Density Declaration of Variables integer :: nrun,nprint,nstep real(8) :: vol,box,boxinv,rcutsq,time, U,W,U_LRC,W_LRC,u_ac,P_ac, sum_u,sum_p,ssq_u,ssq_p real(8),dimension(nmax) :: x,y,z, vx,vy,vz, fx,fy,fz character(len=3) :: yesno character(len=30) :: cnfile integer :: nprocs, # of processes myrank, my process rank ierr,ip start up MPI 3
call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) Input if(myrank == 0) then print*,"# of Time Steps:" read*,nrun print*,"# of Time Steps for Printing:" read*,nprint print*,"read Configurational File (yes/no):" read*,yesno print*,"name of Configurational File:" read*,cnfile broadcast input call MPI_BCAST(nrun,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) call MPI_BCAST(nprint,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr) call MPI_BCAST(yesno,3,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr) call MPI_BCAST(cnfile,30,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr) Simulation Set-Up Values call values(nom,rcut,dens,vol,box,boxinv,rcutsq,u_lrc,w_lrc) Initial Output if(myrank == 0) then call output(1,nstep,nrun,nom,rcut,temp,dens,vol,box, 4
time,u_ac,p_ac,sum_u,sum_p,ssq_u,ssq_p) Initialization if((yesno == yes ).or.(yesno == YES )) then Read from File; One Processor at a Time do ip=0,nprocs-1 if(myrank == ip) then call readcn(nmax,x,y,z,vx,vy,vz,cnfile) call MPI_BARRIER(MPI_COMM_WORLD,ierr) else Positions from fcc Lattice and Velocity from Maxwell-Boltzmann s Distribution call init_conf(nom,temp,box,x,y,z,vx,vy,vz) Zeroth Thermo Accumulators call zero(sum_u,sum_p,ssq_u,ssq_p) MD cyclus time=0.0d0 do nstep=1,nrun Energy, Virial and Forces call force(nom,box,boxinv,rcutsq,u,w, x,y,z,fx,fy,fz, myrank,nprocs) 5
Leap-Frog Algorithm call Leap_Frog(nom,dt,temp,box,boxinv, x,y,z,vx,vy,vz,fx,fy,fz) Termodynamic Quantities call thermo(nom,temp,dens,vol,u,u_lrc,w,w_lrc,u_ac,p_ac, sum_u,sum_p,ssq_u,ssq_p) Periodic Output time=time+dt if(myrank == 0) then if(mod(nstep,nprint) == 0) then call output(2,nstep,nrun,nom,rcut,temp,dens,vol,box, time,u_ac,p_ac,sum_u,sum_p,ssq_u,ssq_p) Final Write to File if(myrank == 0) then call writcn(nmax,x,y,z,vx,vy,vz,cnfile) Final Output call output(3,nstep,nrun,nom,rcut,temp,dens,vol,box, time,u_ac,p_ac,sum_u,sum_p,ssq_u,ssq_p) shut down MPI call MPI_FINALIZE(ierr) stop "ParNVTmdLJ: End of Calcs" end program ParNVTmdLJ 6
Simulation Set-Up Values subroutine values(nom,rcut,dens,vol,box,boxinv,rcutsq,u_lrc,w_lrc) Declaration of Variables integer :: nom real(8) :: rcut,rcutsq,dens,vol,box,boxinv, pi,ircut3,ircut9,u_lrc,w_lrc Volume, Length of Box and Cut-Off Radius vol=dble(nom)/dens box=vol**(1.0/3.0) boxinv=1.0d0/box if(rcut > 1.0d0) rcut=1.0d0 rcut=rcut*(box/2.0d0) rcutsq=rcut**2 LJ LRC pi=dacos(-1.0d0) ircut3=1.0d0/(rcutsq*rcut) ircut9=ircut3*ircut3*ircut3 U_LRC=(8.0d0/3.0d0)*pi*dble(nom)*dens*((1.0d0/3.0d0)*ircut9-ircut3) W_LRC=(16.0d0/3.0d0)*pi*dble(nom)*dens*((2.0d0/3.0d0)*ircut9-ircut3) end subroutine values Positions from fcc Lattice and Velocity from Maxwell-Boltzmann s Distribution subroutine init_conf(nom,temp,box,x,y,z,vx,vy,vz) Declaration of Variables 7
integer :: nom,ncc,m,ix,iy,iz,iref,i,iseed real(8) :: gauss real(8) :: temp,box, x(*),y(*),z(*), vx(*),vy(*),vz(*), cell,cell2,rtemp, sumvx,sumvy,sumvz,sumv2, temp_conf,fs Check # of Molecules ncc=(nom/4)**(1.0/3.0)+0.1d0 if(4*ncc**3 /= nom) stop "init_conf: Wrong # of Molecules" Positions of Molecules, fcc Lattice cell=1.0d0/dble(ncc) cell2=0.5d0*cell x(1)=0.0d0 y(1)=0.0d0 z(1)=0.0d0 x(2)=cell2 y(2)=cell2 z(2)=0.0d0 x(3)=0.0d0 y(3)=cell2 z(3)=cell2 x(4)=cell2 y(4)=0.0d0 z(4)=cell2 Construct Lattice from Unit Cell 8
m=0 do iz=1,ncc do iy=1,ncc do ix=1,ncc do iref=1,4 x(iref+m)=x(iref)+cell*dble(ix-1) y(iref+m)=y(iref)+cell*dble(iy-1) z(iref+m)=z(iref)+cell*dble(iz-1) m=m+4 Shift Positions do i=1,nom x(i)=(x(i)-0.5d0)*box y(i)=(y(i)-0.5d0)*box z(i)=(z(i)-0.5d0)*box Velocity from Maxwell-Boltzmann s Distribution, Total Momentum and Kinetic Energy iseed=425001 rtemp=dsqrt(temp) sumvx=0.0d0 sumvy=0.0d0 sumvz=0.0d0 sumv2=0.0d0 do i=1,nom vx(i)=rtemp*gauss(iseed) vy(i)=rtemp*gauss(iseed) vz(i)=rtemp*gauss(iseed) sumvx=sumvx+vx(i) sumvy=sumvy+vy(i) sumvz=sumvz+vz(i) 9
sumv2=sumv2+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) sumvx=sumvx/dble(nom) sumvy=sumvy/dble(nom) sumvz=sumvz/dble(nom) Actual Temperature temp_conf=sumv2/dble(3*nom-4) Scaling Factor fs=dsqrt(temp/temp_conf) Remove Total Momentum and Scale Velocities do i=1,nom vx(i)=fs*(vx(i)-sumvx) vy(i)=fs*(vy(i)-sumvy) vz(i)=fs*(vz(i)-sumvz) end subroutine init_conf Calculate Energy, Virial and Forces subroutine force(nom,box,boxinv,rcutsq,u,w, x,y,z,fx,fy,fz, myrank,nprocs) include mpif.h preprocessor directive Declaration of Variables integer :: nom,i,j real(8) :: box,boxinv,rcutsq,u,w, xij,yij,zij,fxij,fyij,fzij, rijsq,sr2,sr6,uij,wij,fij real(8) :: x(*),y(*),z(*), 10
fx(*),fy(*),fz(*) integer :: nprocs, # of processes myrank, my process rank ierr,ip real(8) :: qu,qw real(8) :: qfx(nom),qfy(nom),qfz(nom) Zeroth Energy, Virial and Forces qu=0.0d0 qw=0.0d0 qfx=0.0d0 qfy=0.0d0 qfz=0.0d0 Outer Cycle do i=1+myrank,nom-1,nprocs Inner Cycle do j=i+1,nom Distance Between Molecules xij=x(i)-x(j) yij=y(i)-y(j) zij=z(i)-z(j) Periodic Boundary Conditions xij=xij-dnint(xij*boxinv)*box yij=yij-dnint(yij*boxinv)*box zij=zij-dnint(zij*boxinv)*box Cut-Off rijsq=xij*xij+yij*yij+zij*zij 11
if(rijsq < rcutsq) then Auxiliary Variables sr2=1.0d0/rijsq sr6=sr2*sr2*sr2 Potential Energy uij=4.0d0*sr6*(sr6-1.0d0) qu=qu+uij Virial wij=(-1.0d0)*24.0d0*sr6*(2.0d0*sr6-1.0d0) qw=qw-(wij/3.0d0) Forces fij=(-1.0d0)*(wij/rijsq) - w(r_ij)/r_ij^2 fxij=fij*xij fyij=fij*yij fzij=fij*zij qfx(i)=qfx(i)+fxij qfy(i)=qfy(i)+fyij qfz(i)=qfz(i)+fzij qfx(j)=qfx(j)-fxij qfy(j)=qfy(j)-fyij qfz(j)=qfz(j)-fzij Add Results Together call MPI_ALLREDUCE(qfx,fx,nom,MPI_REAL8,MPI_SUM, MPI_COMM_WORLD,ierr) call MPI_ALLREDUCE(qfy,fy,nom,MPI_REAL8,MPI_SUM, 12
MPI_COMM_WORLD,ierr) call MPI_ALLREDUCE(qfz,fz,nom,MPI_REAL8,MPI_SUM, MPI_COMM_WORLD,ierr) call MPI_ALLREDUCE(qU,U,1,MPI_REAL8,MPI_SUM, MPI_COMM_WORLD,ierr) call MPI_ALLREDUCE(qW,W,1,MPI_REAL8,MPI_SUM, MPI_COMM_WORLD,ierr) end subroutine force Leap-Frog Algorithm subroutine Leap_Frog(nom,dt,temp,box,boxinv, x,y,z,vx,vy,vz,fx,fy,fz) Declaration of Variables integer :: nom,i real(8) :: dt,temp,box,boxinv,sum_vx,sum_vy,sum_vz, K,temp_ac,beta real(8) :: x(*),y(*),z(*), vx(*),vy(*),vz(*), fx(*),fy(*),fz(*) Zeroth Accumulators K=0.0d0 sum_vx=0.0d0 sum_vy=0.0d0 sum_vz=0.0d0 do i=1,nom v_u(t)=v(t-dt/2)+(dt/2)*[f(t)/m] vx(i)=vx(i)+(dt/2.0d0)*fx(i) vy(i)=vy(i)+(dt/2.0d0)*fy(i) vz(i)=vz(i)+(dt/2.0d0)*fz(i) 13
Kinetic Energy K=K+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) Total Momentum sum_vx=sum_vx+vx(i) sum_vy=sum_vy+vy(i) sum_vz=sum_vz+vz(i) sum_vx=sum_vx/dble(nom) sum_vy=sum_vy/dble(nom) sum_vz=sum_vz/dble(nom) Actual Temperature temp_ac=k/dble(3*nom-4) Scaling Factor beta=dsqrt(temp/temp_ac) v(t)=beta*v_u(t) v(t+dt/2)=(2-1/beta)*v(t)+(dt/2)*[f(t)/m] r(t+dt)=r(t)+dt*v(t+dt/2) K=0.0d0 do i=1,nom v(t)=beta*v_u(t) vx(i)=beta*(vx(i)-sum_vx) vy(i)=beta*(vy(i)-sum_vy) vz(i)=beta*(vz(i)-sum_vz) Kinetic Energy K=K+vx(i)*vx(i)+vy(i)*vy(i)+vz(i)*vz(i) 14
v(t+dt/2)=(2-1/beta)*v(t)+(dt/2)*[f(t)/m] vx(i)=(2.0d0-(1.0d0/beta))*vx(i)+(dt/2.0d0)*fx(i) vy(i)=(2.0d0-(1.0d0/beta))*vy(i)+(dt/2.0d0)*fy(i) vz(i)=(2.0d0-(1.0d0/beta))*vz(i)+(dt/2.0d0)*fz(i) r(t+dt)=r(t)+dt*v(t+dt/2) x(i)=x(i)+vx(i)*dt y(i)=y(i)+vy(i)*dt z(i)=z(i)+vz(i)*dt Periodic Boundary Conditions x(i)=x(i)-dnint(x(i)*boxinv)*box y(i)=y(i)-dnint(y(i)*boxinv)*box z(i)=z(i)-dnint(z(i)*boxinv)*box end subroutine Leap_Frog Zeroth Thermo Accumulators subroutine zero(sum_u,sum_p,ssq_u,ssq_p) Declaration of Variables real(8) :: sum_u,sum_p,ssq_u,ssq_p Zeroth sum Accumulators sum_u=0.0d0 sum_p=0.0d0 Zeroth ssq Accumulators ssq_u=0.0d0 15
ssq_p=0.0d0 end subroutine zero Termodynamic Quantities subroutine thermo(nom,temp,dens,vol,u,u_lrc,w,w_lrc,u_ac,p_ac, sum_u,sum_p,ssq_u,ssq_p) Declaration of Variables integer :: nom real(8) :: temp,dens,vol,u,u_lrc,w,w_lrc,u_ac,p_ac, sum_u,sum_p,ssq_u,ssq_p Instantaneous Thermodynamic Quantities u_ac=(u+u_lrc)/dble(nom) energy per particle P_ac=dens*temp+(W+W_LRC)/vol pressure sum Accumulators sum_u=sum_u+u_ac sum_p=sum_p+p_ac ssq Accumulators ssq_u=ssq_u+u_ac**2 ssq_p=ssq_p+p_ac**2 end subroutine thermo Output subroutine output(kk,nstep,nrun,nom,rcut,temp,dens,vol,box, Declaration of Variables time,u_ac,p_ac,sum_u,sum_p,ssq_u,ssq_p) 16
integer :: kk,nstep,nrun,nom real(8) :: rcut,temp,dens,vol,box,time,u_ac,p_ac, sum_u,sum_p,ssq_u,ssq_p, avr_u,avr_p,flc_u,flc_p if(kk == 1) then Initial Output write(*,*) " *** Initial Output ***" write(*,fmt="(a,e13.5)") "Temperature: ",temp write(*,fmt="(a,e13.5)") "Density: ",dens write(*,*) write(*,fmt="(a,i4)") "# of Molecules: ",nom write(*,fmt="(a,e13.5)") "Cut-Off Distance: ",rcut write(*,fmt="(a,e13.5)") "Volume of Box: ",vol write(*,fmt="(a,e13.5)") "Length of Box: ",box return if(kk == 2) then Periodic Output write(*,*) write(*,fmt="(a,i8,a,e13.5)") " # of time steps:",nstep, " time:",time write(*,fmt="(5(a))") " u* "," P*" write(*,fmt="(8(e13.5))") u_ac,p_ac write(*,fmt="(8(e13.5))") sum_u/dble(nstep),sum_p/dble(nstep) return if(kk == 3) then Final Output Ensemble Averages avr_u=sum_u/dble(nrun) 17
avr_p=sum_p/dble(nrun) Ensemble Fluctuations flc_u=dsqrt(dabs((ssq_u/dble(nrun))-avr_u**2)) flc_p=dsqrt(dabs((ssq_p/dble(nrun))-avr_p**2)) write(*,*) write(*,*) " *** Final Output ***" write(*,*) " Ensemble Averages" write(*,fmt="(5(a))") " u* "," P*" write(*,fmt="(8(e13.5))") avr_u,avr_p write(*,*) " Ensemble Fluctuations" write(*,fmt="(5(a))") " u* "," P*" write(*,fmt="(8(e13.5))") flc_u,flc_p return end subroutine output Read from File subroutine readcn(nmax,x,y,z,vx,vy,vz,cnfile) Declaration of Variables integer :: nmax real(8) :: x(nmax),y(nmax),z(nmax), vx(nmax),vy(nmax),vz(nmax) integer,parameter :: cnunit=10 character(len=*) :: cnfile Unformatted File open(unit=cnunit,file=cnfile,status="old",form="unformatted") read(cnunit) x,y,z read(cnunit) vx,vy,vz close(unit=cnunit) end subroutine readcn 18
Write to File subroutine writcn(nmax,x,y,z,vx,vy,vz,cnfile) Declaration of Variables integer :: nom,nmax real(8) :: x(nmax),y(nmax),z(nmax), vx(nmax),vy(nmax),vz(nmax) integer,parameter :: cnunit=10 character(len=*) :: cnfile Unformatted File open(unit=cnunit,file=cnfile,status="unknown",form="unformatted") write(cnunit) x,y,z write(cnunit) vx,vy,vz close(unit=cnunit) end subroutine writcn RANDOM VARIATE FROM THE STANDARD NORMAL DISTRIBUTION. THE DISTRIBUTION IS GAUSSIAN WITH ZERO MEAN AND UNIT VARIANCE. KNUTH D, THE ART OF COMPUTER PROGRAMMING, ADDISON-WESLEY, 1978 function gauss(iseed) Declaration of Variables integer :: iseed,i real(8) :: gauss real(8),parameter :: A1=3.949846138d0,A3=0.252408784d0, A5=0.076542912d0,A7=0.008355968d0, A9=0.029899776d0 real(8) :: SUM,R,R2 19
SUM=0.0d0 do I=1,12 SUM=SUM+dble(ran(iseed)) R=(SUM-6.0d0)/4.0d0 R2=R*R gauss=((((a9*r2+a7)*r2+a5)*r2+a3)*r2+a1)*r end function gauss 20