HelloSodiumChlorideInFortran.f90 5.93 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
! OpenMM HelloSodiumChloride example in Fortran 95
program HelloSodiumChloride
use OpenMM
implicit none

!-------------------------------------------------------------------------------
!                   MODELING AND SIMULATION PARAMETERS
!-------------------------------------------------------------------------------
real*8 StepSizeInFs, ReportIntervalInFs, SimulationTimeInPs
parameter(StepSizeInFs = 2)
parameter(ReportIntervalInFs = 10)
parameter(SimulationTimeInPs = 100)
integer NumSilentSteps
parameter(NumSilentSteps = (ReportIntervalInFs / StepSizeInFs + 0.5))

type Atom
    character*4       pdb
    real*8            mass
    real*8            charge
    real*8            vdwRadiusInAng
    real*8            vdwEnergyInKcal
    real*8            initPosInAng(3)
end type

integer NAtom
parameter(NAtom=6)
type(Atom) atoms(NAtom)
character*50 name
type(OpenMM_String) dir

atoms(1) = Atom(' NA ', 22.99,  1, 1.8680, 0.00277, (/  8, 0, 0  /))
atoms(2) = Atom(' CL ', 35.45, -1, 2.4700, 0.1000,  (/ -8, 0, 0  /))
atoms(3) = Atom(' NA ', 22.99,  1, 1.8680, 0.00277, (/  0, 9, 0  /))
atoms(4) = Atom(' CL ', 35.45, -1, 2.4700, 0.1000,  (/  0,-9, 0  /))
atoms(5) = Atom(' NA ', 22.99,  1, 1.8680, 0.00277, (/  0, 0,-10 /))
atoms(6) = Atom(' CL ', 35.45, -1, 2.4700, 0.1000,  (/  0, 0, 10 /))

call OpenMM_String_create(dir, '')
call OpenMM_Platform_getDefaultPluginsDirectory(dir)
call OpenMM_String_get(dir, name)
print *,'dir="',name,'"'
call OpenMM_Platform_loadPluginsFromDirectory(dir)

call simulateNaCl(atoms)

! Allow subroutines to inherit type definitions from program level
CONTAINS

!-------------------------------------------------------------------------------
!                               NaCl SIMULATION
!-------------------------------------------------------------------------------
subroutine simulateNaCl(atoms)
implicit none
type(Atom)                      atoms(NAtom)
type(OpenMM_System)             system
type(OpenMM_NonbondedForce)     nonbond
type(OpenMM_Force)              nonbondAsForce
type(OpenMM_Context)            context
type(OpenMM_VerletIntegrator)   verlet
type(OpenMM_Integrator)         integrator
type(OpenMM_Vec3Array)          initialPositionsInNm
character*10 platformName
real*8 posInNm(3),a(3),b(3),c(3), cutoff
! Periodic box size and cutoff in nm
parameter(a=(/5,0,0/), b=(/0,5,0/), c=(/0,0,5/), cutoff=2)
integer i

call OpenMM_System_create(system)
call OpenMM_NonbondedForce_create(nonbond)
call OpenMM_NonbondedForce_asForce(nonbond, nonbondAsForce)
call OpenMM_System_addForce(system, nonbondAsForce)

call OpenMM_NonbondedForce_setNonbondedMethod(nonbond, &
        OpenMM_NonbondedForce_CutoffPeriodic)
! cutoff distance here is 
call OpenMM_NonbondedForce_setCutoffDistance(nonbond, cutoff)
call OpenMM_NonbondedForce_setPeriodicBoxVectors(nonbond, a, b, c)

call OpenMM_Vec3Array_create(initialPositionsInNm, 0)
do i=1,NAtom
    call OpenMM_System_addParticle(system, atoms(i)%mass)
    call OpenMM_NonbondedForce_addParticle(nonbond,                 &
            atoms(i)%charge,                                        &
            atoms(i)%vdwRadiusInAng  * OpenMM_NmPerAngstrom         &
                                     * OpenMM_SigmaPerVdwRadius,    &
            atoms(i)%vdwEnergyInKcal * OpenMM_KJPerKcal)
    ! Convert this atom's initial position from Angstroms to nm
    call OpenMM_Vec3_scale(atoms(i)%initPosInAng, OpenMM_NmPerAngstrom, posInNm)
    call OpenMM_Vec3Array_append(initialPositionsInNm, posInNm)
end do

call OpenMM_VerletIntegrator_create(verlet, StepSizeInFs * OpenMM_PsPerFs)
call OpenMM_VerletIntegrator_asIntegrator(verlet, integrator)
call OpenMM_Context_create(context, system, integrator)
call OpenMM_Context_setPositions(context, initialPositionsInNm)

call OpenMM_Context_getPlatformName(context, platformName)

print "('REMARK  Using OpenMM platform ', A)", platformName
call writePDB(atoms, context)

do
    call OpenMM_Integrator_step(integrator, NumSilentSteps)
    call writePDB(atoms, context)
    if (OpenMM_Context_getTime(context) >= SimulationTimeInPs) exit
end do

! Clean up top-level heap allocated objects that we're done with now.

call OpenMM_Vec3Array_destroy(initialPositionsInNm)
call OpenMM_Context_destroy(context)
call OpenMM_Integrator_destroy(integrator)

end subroutine

!-------------------------------------------------------------------------------
!                                PDB FILE WRITER
!-------------------------------------------------------------------------------
subroutine writePDB(atoms, context)
implicit none
type(Atom) atoms(NAtom)
type(OpenMM_Context) context
integer, save :: modelFrameNumber = 0

type (OpenMM_State) state
type (OpenMM_Vec3Array) posArray
integer npos, i, j
real*8 energy
real*8 posInAng(3), posInNm(3)

! Caution: at the moment asking for energy requires use of slow Reference 
! platform calculation.

! Don't forget to destroy this State when you're done with it.
call OpenMM_Context_createState(context,                                           &
        OpenMM_State_Positions + OpenMM_State_Velocities + OpenMM_State_Energy,    &
        state)

energy = OpenMM_State_getPotentialEnergy(state)        &
         + OpenMM_State_getKineticEnergy(state)

! Positions are maintained as a Vec3Array inside the State. This will give
! us access, but don't destroy it yourself -- it will go away with the State.
call OpenMM_State_getPositions(state, posArray)
npos = OpenMM_Vec3Array_size(posArray)
modelFrameNumber = modelFrameNumber + 1
print "('MODEL',5X,I0)", modelFrameNumber
print "('REMARK 250 time=', F0.3, ' picoseconds; Energy=', F0.3, ' kilojoules/mole')", &
    OpenMM_State_getTime(state), energy
do i = 1,npos
    call OpenMM_Vec3Array_get(posArray, i, posInNm)
    call OpenMM_Vec3_scale(posInNm, OpenMM_AngstromsPerNm, posInAng)
    print "('ATOM  ', I5, ' ', A4, ' SLT     1    ', 3F8.3, '  1.00  0.00            ')", &
        i, atoms(i)%pdb, posInAng
end do

print "('ENDMDL')"

! Clean up the State memory
call OpenMM_State_destroy(state)
end subroutine

END PROGRAM