"vscode:/vscode.git/clone" did not exist on "8eedf2be0d34aed35adccdb481b750ebbba41c42"
HelloSodiumChlorideInFortran.f90 10.6 KB
Newer Older
Michael Sherman's avatar
Michael Sherman committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
! -----------------------------------------------------------------------------
!     OpenMM(tm) HelloSodiumChloride example in Fortran 95 (June 2009)
! ------------------------------------------------------------------------------
! This is a complete, self-contained "hello world" example demonstrating 
! GPU-accelerated constant temperature simulation of a very simple system with
! just nonbonded forces, consisting of several sodium (Na+) and chloride (Cl-) 
! ions in implicit solvent. A multi-frame PDB file is written to stdout which 
! can be read by VMD or other visualization tool to produce an animation of the 
! resulting trajectory.
!
! Pay particular attention to the handling of units in this example. Incorrect
! handling of units is a very common error; this example shows how you can
! continue to work with Amber-style units like Angstroms, kCals, and van der
! Waals radii while correctly communicating with OpenMM in nm, kJ, and sigma.
!
! This example is written entirely in Fortran 95, using a Fortran interface 
! module which is NOT official parts of the OpenMM distribution.
! ------------------------------------------------------------------------------
19
20

!-------------------------------------------------------------------------------
Michael Sherman's avatar
Michael Sherman committed
21
!                ATOM, FORCE FIELD, AND SIMULATION PARAMETERS
22
!-------------------------------------------------------------------------------
Michael Sherman's avatar
Michael Sherman committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
! We'll define this module as a simplified example of the kinds of data
! structures that may already be in an MD program that is to be converted
! to use OpenMM.
MODULE MyAtomInfo
    ! Simulation parameters:
    real*8 Temperature, FrictionInPerPs, SolventDielectric, SoluteDielectric
    parameter(Temperature        = 300) !Kelvins
    parameter(FrictionInPerPs    = 91)  !collisions per picosecond
    parameter(SolventDielectric  = 80)  !typical for water
    parameter(SoluteDielectric   = 2)   !typical for protein
    
    real*8 StepSizeInFs, ReportIntervalInFs, SimulationTimeInPs
    parameter(StepSizeInFs       = 2)   !integration step size (fs)
    parameter(ReportIntervalInFs = 50)  !how often for PDB frame (fs)
    parameter(SimulationTimeInPs = 100) !total simulation time (ps)
    
    ! Currently energy calculation is not available in the GPU kernels so
    ! asking for it requires slow Reference Platform computation at 
    ! reporting intervals.
    logical, parameter :: WantEnergy = .true.
43

Michael Sherman's avatar
Michael Sherman committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    ! Atom and force field information:
    type Atom
        character*4       pdb
        real*8            mass, charge, vdwRadiusInAng, vdwEnergyInKcal
        real*8            gbsaRadiusInAng, gbsaScaleFactor
        real*8            initPosInAng(3)
        real*8            posInAng(3) ! leave room for runtime state info
    end type
    integer, parameter :: NumAtoms = 6
    type (Atom) :: atoms(NumAtoms) = (/ &
    ! pdb   mass charge vdwRad vdwEnergy  gbRad gbScale   initPos      pos
Atom(' NA ',22.99,  1,  1.8680, 0.00277,  1.992,  0.8, (/ 8, 0,  0/), (/0,0,0/)),&
Atom(' CL ',35.45, -1,  2.4700, 0.1000,   1.735,  0.8, (/-8, 0,  0/), (/0,0,0/)),&
Atom(' NA ',22.99,  1,  1.8680, 0.00277,  1.992,  0.8, (/ 0, 9,  0/), (/0,0,0/)),&
Atom(' CL ',35.45, -1,  2.4700, 0.1000,   1.735,  0.8, (/ 0,-9,  0/), (/0,0,0/)),&
Atom(' NA ',22.99,  1,  1.8680, 0.00277,  1.992,  0.8, (/ 0, 0,-10/), (/0,0,0/)),&
Atom(' CL ',35.45, -1,  2.4700, 0.1000,   1.735,  0.8, (/ 0, 0, 10/), (/0,0,0/)) &
    /)
END MODULE
63
64

!-------------------------------------------------------------------------------
Michael Sherman's avatar
Michael Sherman committed
65
!                                MAIN PROGRAM
66
!-------------------------------------------------------------------------------
Michael Sherman's avatar
Michael Sherman committed
67
68
69
PROGRAM HelloSodiumChloride
use OpenMM
use MyAtomInfo
70
71
implicit none

Michael Sherman's avatar
Michael Sherman committed
72
73
74
!-------------------------------------------------------------------------------
!                   MODELING AND SIMULATION PARAMETERS
!-------------------------------------------------------------------------------
75

Michael Sherman's avatar
Michael Sherman committed
76
77
78
79
80
81
82
83
84
85
integer NumReports, NumSilentSteps
parameter(NumReports = (SimulationTimeInPs*1000 / ReportIntervalInFs + 0.5))
parameter(NumSilentSteps = (ReportIntervalInFs / StepSizeInFs + 0.5))

type (OpenMM_Objects) omm
character*10 platformName
real*8 timeInPs, energyInKcal
integer frame

call myInitializeOpenMM(omm, platformName)
86
87

print "('REMARK  Using OpenMM platform ', A)", platformName
Michael Sherman's avatar
Michael Sherman committed
88
89
call myGetOpenMMState(omm, timeInPs, energyInKcal)
call myWritePDBFrame(0, timeInPs, energyInKcal)
90

Michael Sherman's avatar
Michael Sherman committed
91
92
93
94
do frame = 1, NumReports
    call myStepWithOpenMM(omm, NumSilentSteps)
    call myGetOpenMMState(omm, timeInPs, energyInKcal)
    call myWritePDBFrame(frame, timeInPs, energyInKcal)
95
96
97
end do

! Clean up top-level heap allocated objects that we're done with now.
Michael Sherman's avatar
Michael Sherman committed
98
call myTerminateOpenMM(omm)
99

Michael Sherman's avatar
Michael Sherman committed
100
END PROGRAM
101
102
103
104

!-------------------------------------------------------------------------------
!                                PDB FILE WRITER
!-------------------------------------------------------------------------------
Michael Sherman's avatar
Michael Sherman committed
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
! Given state data, output a single frame (pdb "model") of the trajectory
SUBROUTINE myWritePDBFrame(frameNum, timeInPs, energyInKcal)
    use MyAtomInfo
    implicit none
    integer frameNum
    real*8  timeInPs, energyInKcal
    integer n
    
    print "('MODEL',5X,I0)", frameNum
    print "('REMARK 250 time=', F0.3, ' picoseconds; Energy=', F0.3, ' kcal/mole')", &
        timeInPs, energyInKcal
    do n = 1,NumAtoms
        print "('ATOM  ', I5, ' ', A4, ' SLT     1    ', 3F8.3, '  1.00  0.00')",    &
            n, atoms(n)%pdb, atoms(n)%posInAng
    end do
    
    print "('ENDMDL')"
END SUBROUTINE 

!-------------------------------------------------------------------------------
!                            OpenMM-USING CODE
!-------------------------------------------------------------------------------

SUBROUTINE myInitializeOpenMM(omm, platformName)
    use OpenMM; use MyAtomInfo
    implicit none
    type (OpenMM_Objects) omm
    character*10 platformName

    ! These are temporary OpenMM objects used and discarded here.
    type(OpenMM_Vec3Array)          initialPosInNm
    type(OpenMM_NonbondedForce)     nonbond
    type(OpenMM_Force)              nonbondAsForce
    type(OpenMM_GBSAOBCForce)       gbsa
    type(OpenMM_Force)              gbsaAsForce
    type(OpenMM_LangevinIntegrator) langevin
    real*8 posInNm(3)
    integer n

    character*50 name
    type(OpenMM_String) dir
    
    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 OpenMM_System_create(omm%system)
    call OpenMM_NonbondedForce_create(nonbond)
    call OpenMM_GBSAOBCForce_create(gbsa)
    
    ! Convert specific force types to generic OpenMM_Force so that we can
    ! add them to the OpenMM_System.
    call OpenMM_NonbondedForce_asForce(nonbond, nonbondAsForce)
    call OpenMM_GBSAOBCForce_asForce(gbsa, gbsaAsForce)
    call OpenMM_System_addForce(omm%system, nonbondAsForce)
    call OpenMM_System_addForce(omm%system, gbsaAsForce)

    ! Specify dielectrics for GBSA implicit solvation.
    call OpenMM_GBSAOBCForce_setSolventDielectric(gbsa, SolventDielectric)
    call OpenMM_GBSAOBCForce_setSoluteDielectric(gbsa, SoluteDielectric)
    
    call OpenMM_Vec3Array_create(initialPosInNm, 0)
    do n=1,NumAtoms
        print *,'atom ',n,atoms(n)
        call OpenMM_System_addParticle(omm%system, atoms(n)%mass)
    
        call OpenMM_NonbondedForce_addParticle(nonbond,                 &
                atoms(n)%charge,                                        &
                atoms(n)%vdwRadiusInAng  * OpenMM_NmPerAngstrom         &
                                         * OpenMM_SigmaPerVdwRadius,    &
                atoms(n)%vdwEnergyInKcal * OpenMM_KJPerKcal)
    
        call OpenMM_GBSAOBCForce_addParticle(gbsa,                      &
                atoms(n)%charge,                                        &
                atoms(n)%gbsaRadiusInAng * OpenMM_NmPerAngstrom,        &
                atoms(n)%gbsaScaleFactor)
    
        ! Convert this atom's initial position from Angstroms to nm
        call OpenMM_Vec3_scale(atoms(n)%initPosInAng, OpenMM_NmPerAngstrom, posInNm)
        call OpenMM_Vec3Array_append(initialPosInNm, posInNm)
    end do
    
    call OpenMM_LangevinIntegrator_create(langevin,                     &
                                          Temperature, FrictionInPerPs, &
                                          StepSizeInFs * OpenMM_PsPerFs)
    call OpenMM_LangevinIntegrator_asIntegrator(langevin, omm%integrator)
    call OpenMM_Context_create(omm%context, omm%system, omm%integrator)
    call OpenMM_Context_setPositions(omm%context, initialPosInNm)
    
    call OpenMM_Context_getPlatformName(omm%context, platformName)
END SUBROUTINE


!-------------------------------------------------------------------------------
!                     COPY STATE BACK TO CPU FROM OpenMM
!-------------------------------------------------------------------------------
SUBROUTINE myGetOpenMMState(omm, timeInPs, energyInKcal)
use OpenMM; use MyAtomInfo
205
implicit none
Michael Sherman's avatar
Michael Sherman committed
206
207
type (OpenMM_Objects) omm
real*8  timeInPs, energyInKcal
208

Michael Sherman's avatar
Michael Sherman committed
209
type (OpenMM_State)     state
210
type (OpenMM_Vec3Array) posArray
Michael Sherman's avatar
Michael Sherman committed
211
212
integer                 infoMask
integer                 n
213
214
215
216
integer npos, i, j
real*8 energy
real*8 posInAng(3), posInNm(3)

Michael Sherman's avatar
Michael Sherman committed
217
218
219
220
221
222
infoMask = OpenMM_State_Positions
if (WantEnergy) then
    infoMask = infoMask + OpenMM_State_Velocities ! for KE (cheap)
    infoMask = infoMask + OpenMM_State_Energy     ! for PE (very expensive)
end if
! Forces are also available (and cheap).
223
224

! Don't forget to destroy this State when you're done with it.
Michael Sherman's avatar
Michael Sherman committed
225
226
call OpenMM_Context_createState(omm%context, infoMask, state) 
timeInPs = OpenMM_State_getTime(state) ! OpenMM time is in ps already.
227
228
229
230
231


! 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)
Michael Sherman's avatar
Michael Sherman committed
232
233
234
do n = 1, NumAtoms
    call OpenMM_Vec3Array_get(posArray, n, posInNm)
    call OpenMM_Vec3_scale(posInNm, OpenMM_AngstromsPerNm, atoms(n)%posInAng)
235
236
end do

Michael Sherman's avatar
Michael Sherman committed
237
238
239
240
241
242
energyInKcal = 0
if (WantEnergy) then
    energyInKcal = (  OpenMM_State_getPotentialEnergy(state)   &
                    + OpenMM_State_getKineticEnergy(state))    &
                   * OpenMM_KcalPerKJ
end if
243
244
245

! Clean up the State memory
call OpenMM_State_destroy(state)
Michael Sherman's avatar
Michael Sherman committed
246
247
248
249
250
251
252
253
254
255
256
END SUBROUTINE

SUBROUTINE myStepWithOpenMM(omm, numSteps)
    use OpenMM
    implicit none
    type (OpenMM_Objects) omm
    integer numSteps
    
    call OpenMM_Integrator_step(omm%integrator, numSteps)
END SUBROUTINE

257
258


Michael Sherman's avatar
Michael Sherman committed
259
260
261
262
263
264
SUBROUTINE myTerminateOpenMM(omm)
    use OpenMM
    implicit none
    type (OpenMM_Objects) omm
    call OpenMM_Objects_destroy(omm)
END SUBROUTINE