ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/mdtools/md_code/f_longRange_module.F90
Revision: 167
Committed: Fri Nov 8 14:21:52 2002 UTC (21 years, 8 months ago) by chuckv
File size: 13984 byte(s)
Log Message:
First commit of mpi force code.

File Contents

# Content
1 module long_range_forces
2 use definitions, ONLY : dp, ndim
3 use simulation
4 implicit none
5
6
7
8
9 real(kind = dp ) :: rlistsq
10 real(kind = dp ) :: rcutsq
11
12
13
14
15
16
17
18 subroutine long_range_force ( check_exclude, &
19 pair_i, pair_j, n_pairs, natoms, sigma, epslon, &
20 box, &
21 rx, ry, rz, fx, fy, fz, &
22 v, &
23 update, point, list, maxnab, &
24 rx0, ry0, rz0, &
25 ux, uy, uz, &
26 tx, ty, tz, &
27 ex, ey, ez, &
28 mu, rrf, rtaper, &
29 dielectric, &
30 is_dipole, is_vdw, is_lj, is_ssd, &
31 Axx, Axy, Axz, &
32 Ayx, Ayy, Ayz, &
33 Azx, Azy, Azz )
34
35 implicit none
36
37 ! This routine implements the Verlet neighbor list for all of
38 ! the long range force calculations. After a pair has been
39 ! determined to lie within the neighbor list, the pair is passed
40 ! to the appropriate force functions.
41
42
43
44 ! Passed Arguments
45
46 integer :: n_pairs ! the number of excluded pairs
47 integer :: natoms ! the number of atoms in the system
48 integer :: maxnab ! the max number of neighbors for the verlet list
49
50 logical(kind=2) :: check_exclude ! boolean to check for exclusion pairs
51 logical(kind=2) :: update ! boolean to update the neighbor list
52
53 double precision rcut ! the VDW/LJ cutoff radius
54 double precision rlist ! Verlet list cutoff
55 double precision box_x, box_y, box_z ! periodic boundry conditions
56 double precision rrf ! dipole reaction field cutoff
57 double precision rtaper ! the taper radius of the rxn field
58 double precision dielectric ! the dielectric cnst. of the rxn field
59 double precision v ! the potential energy
60
61
62
63 ! Passed Arrays
64
65 integer, dimension(n_pairs):: pair_i, pair_j ! the excluded pairs i and j
66 integer, dimension(natoms) :: point ! the Verlet list ptr array
67 integer, dimension(maxnab) :: list ! the verlet list
68
69 logical(kind=2), dimension(natoms) :: is_dipole ! dipole boolean array
70 logical(kind=2), dimension(natoms) :: is_vdw ! VDW boolean array
71 logical(kind=2), dimension(natoms) :: is_lj ! LJ boolean array
72 logical(kind=2), dimension(natoms) :: is_ssd ! ssd boolean array
73
74 double precision, dimension(natoms) :: sigma ! VDW/LJ distance prmtr.
75 double precision, dimension(natoms) :: epslon ! VDW/LJ well depth prmtr.
76 double precision, dimension(natoms) :: rx, ry, rz ! positions
77 double precision, dimension(natoms) :: fx, fy, fz ! forces
78 double precision, dimension(natoms) :: rx0, ry0, rz0 ! intial verlet positions
79 double precision, dimension(natoms) :: ux, uy, uz ! dipole unit vectors
80 double precision, dimension(natoms) :: tx, ty, tz ! torsions
81 double precision, dimension(natoms) :: ex, ey, ez ! reacion field
82 double precision, dimension(natoms) :: mu ! dipole moments
83 double precision, dimension(natoms) :: Axx, Axy, Axz ! rotational array
84 double precision, dimension(natoms) :: Ayx, Ayy, Ayz !
85 double precision, dimension(natoms) :: Azx, Azy, Azz !
86
87 ! local variables
88
89 double precision rxi, ryi, rzi
90 double precision rcutsq, rlstsq, rrfsq, rijsq, rij
91 double precision rxij, ryij, rzij
92 double precision prerf ! a reaction field preterm
93
94 double precision, dimension(9,natoms) :: A
95
96 integer :: i, j, k, ix, jx, nlist
97 integer :: jbeg, jend, jnab
98
99 logical :: exclude_temp1, exclude_temp2, exclude
100
101
102 !*******************************************************************
103
104 do i=1, natoms
105 A(1,i) = Axx(i)
106 A(2,i) = Axy(i)
107 A(3,i) = Axz(i)
108
109 A(4,i) = Ayx(i)
110 A(5,i) = Ayy(i)
111 A(6,i) = Ayz(i)
112
113 A(7,i) = Azx(i)
114 A(8,i) = Azy(i)
115 A(9,i) = Azz(i)
116 end do
117
118
119 rlstsq = rlist * rlist
120 rcutsq = rcut * rcut
121 rrfsq = rrf * rrf
122
123 prerf = 14.39257d0 * 2.0d0 * ( dielectric - 1.0d0 ) / &
124 ( ( 2.0d0 * dielectric + 1.0d0 ) * rrfsq * rrf )
125
126 ! ** zero forces **
127
128 do I = 1, natoms
129
130 fx(i) = 0.0d0
131 fy(i) = 0.0d0
132 fz(i) = 0.0d0
133
134 tx(i) = 0.0d0
135 ty(i) = 0.0d0
136 tz(i) = 0.0d0
137
138 ex(i) = 0.0d0
139 ey(i) = 0.0d0
140 ez(i) = 0.0d0
141
142 end do
143
144 V = 0.0d0
145
146 if ( update ) then
147
148
149 ! ** save current configuration, construct **
150 ! ** neighbour list and calculate forces **
151
152 call long_range_save(natoms,rx,ry,rz,rx0,ry0,rz0)
153
154 nlist = 0
155
156 do i = 1, natoms - 1
157
158 point(i) = nlist + 1
159
160 rxi = rx(i)
161 ryi = ry(i)
162 rzi = rz(i)
163
164 do j = i + 1, natoms
165
166 rxij = rx(j) - rxi
167 ryij = ry(j) - ryi
168 rzij = rz(j) - rzi
169
170 exclude = .false.
171
172 if( check_exclude ) then
173
174 do k = 1, n_pairs
175
176 ! add 1 for c -> fortran indexing
177 ix = pair_i(k) + 1
178 jx = pair_j(k) + 1
179 exclude_temp1 = (i.eq.ix).and.(j.eq.jx)
180 exclude_temp2 = (i.eq.jx).and.(j.eq.ix)
181
182 if(exclude_temp1.or.exclude_temp2) then
183
184 exclude = .true.
185 endif
186 enddo
187 endif
188
189 if(.not.exclude) then
190
191 rxij = rxij - box_x * dsign( 1.0d0, rxij ) &
192 * int( (dabs( rxij / box_x ) + 0.5d0) )
193 ryij = ryij - box_y * dsign( 1.0d0, ryij ) &
194 * int( (dabs( ryij / box_y ) + 0.5d0) )
195 rzij = rzij - box_z * dsign( 1.0d0, rzij ) &
196 * int( (dabs( rzij / box_z ) + 0.5d0) )
197
198 rijsq = rxij * rxij + ryij * ryij + rzij * rzij
199
200 if ( rijsq .lt. rlstsq ) then
201
202 nlist = nlist + 1
203 list(nlist) = j
204
205 ! ** remove this check if maxnab is appropriate **
206
207 if ( nlist .eq. maxnab ) then
208 write(*,*) i, j, nlist, maxnab, rijsq, rlstsq
209 stop 'list too small'
210 endif
211
212 if ( rijsq .lt. rcutsq ) then
213
214 if ( is_vdw(i) .and. is_vdw(j) ) then
215 call force_VDW( i, j, rcutsq, rijsq, sigma, epslon, &
216 v, fx, fy, fz, rxij, ryij, rzij, natoms )
217 endif
218
219 if ( is_lj(i) .and. is_lj(j) ) then
220 call force_lj( i, j, rcutsq, rijsq, sigma, epslon, v, &
221 fx, fy, fz, rxij, ryij, rzij, natoms )
222 endif
223
224 if( is_ssd(i) .and. is_ssd(j) ) then
225
226 rij = dsqrt(rijsq);
227
228 call ssd_forces( natoms, i, j, i, j, rxij, ryij, rzij, &
229 rij, v, rijsq, fx, fy, fz, tx, ty, tz, A )
230 end if
231
232 endif
233
234 if( is_dipole(i) .and. is_dipole(j) ) then
235 if( rijsq .lt. rrfsq ) then
236
237 call dipole_rf( i, j, rrfsq, rijsq, v, rxij, ryij, &
238 rzij, rrf, dielectric, rtaper, natoms, &
239 ux, uy, uz, mu, fx, fy, fz, tx, ty, tz, &
240 ex, ey, ez, prerf )
241 endif
242 end if
243 endif
244 endif
245
246 enddo
247
248 end do
249
250 point(natoms) = nlist + 1
251
252 else
253
254
255 !** use the list to find the neighbours **
256
257 do i = 1, natoms - 1
258
259 jbeg = point(i)
260 jend = point(i+1) - 1
261
262 !** check that atom i has neighbours **
263
264 if( jbeg .le. jend ) then
265
266 rxi = rx(i)
267 ryi = ry(i)
268 rzi = rz(i)
269
270 do jnab = jbeg, jend
271
272 j = list(jnab)
273
274 rxij = rx(j) - rxi
275 ryij = ry(j) - ryi
276 rzij = rz(j) - rzi
277
278 rxij = rxij - box_x * dsign( 1.0d0, rxij ) &
279 * int( dabs( rxij / box_x ) + 0.5d0 )
280 ryij = ryij - box_y * dsign( 1.0d0, ryij ) &
281 * int( dabs( ryij / box_y ) + 0.5d0 )
282 rzij = rzij - box_z * dsign( 1.0d0, rzij ) &
283 * int( dabs( rzij / box_z ) + 0.5d0 )
284
285 rijsq = rxij * rxij + ryij * ryij + rzij * rzij
286
287 if ( rijsq .lt. rcutsq ) then
288
289 if ( is_vdw(i) .and. is_vdw(j) ) then
290 call force_VDW( i, j, rcutsq, rijsq, sigma, epslon, &
291 v, fx, fy, fz, rxij, ryij, rzij, natoms )
292 endif
293
294 if ( is_lj(i) .and. is_lj(j) ) then
295 call force_lj( i, j, rcutsq, rijsq, sigma, epslon, v, &
296 fx, fy, fz, rxij, ryij, rzij, natoms )
297 endif
298
299 if( is_ssd(i) .and. is_ssd(j) ) then
300
301 rij = dsqrt(rijsq);
302
303 call ssd_forces( natoms, i, j, i, j, rxij, ryij, rzij, &
304 rij, v, rijsq, fx, fy, fz, tx, ty, tz, A )
305 end if
306
307 endif
308
309
310 if( is_dipole(i) .and. is_dipole(j) ) then
311 if( rijsq .lt. rrfsq ) then
312
313 call dipole_rf( i, j, rrfsq, rijsq, v, rxij, ryij, &
314 rzij, rrf, dielectric, rtaper, natoms, &
315 ux, uy, uz, mu, fx, fy, fz, tx, ty, tz, &
316 ex, ey, ez, prerf )
317 endif
318 endif
319
320 end do
321 endif
322 end do
323 endif
324
325 ! calculate the reaction field effect
326
327 !!$ call reaction_field( v, prerf, natoms, mu, ux, uy, uz, tx, ty, tz, &
328 !!$ ex, ey, ez, is_dipole )
329
330
331 end subroutine long_range_force
332
333
334
335 subroutine long_range_check ( rcut, rlist, update, natoms, &
336 rx,ry,rz,rx0,ry0,rz0)
337
338
339 !*******************************************************************
340 !** decides whether the list needs to be reconstructed. **
341 !** **
342 !** principal variables: **
343 !** **
344 !** real rx(n),ry(n),rz(n) atom positions **
345 !** real rx0(n),ry0(n),rz0(n) coordinates at last update **
346 !** real rlist radius of verlet list **
347 !** real rcut cutoff distance for forces **
348 !** real dispmx largest displacement **
349 !** integer n number of atoms **
350 !** logical update if true the list is updated **
351 !** **
352 !** usage: **
353 !** **
354 !** check is called to set update before every call to force. **
355 !*******************************************************************
356
357
358 ! Passed variables
359
360 integer :: natoms
361
362 logical(kind=2) :: update
363
364 double precision rcut, rlist
365
366 ! Passed arrays
367 double precision, dimension(natoms) :: rx, ry, rz
368 double precision, dimension(natoms) :: rx0, ry0, rz0
369
370 ! local variables
371
372 double precision dispmx
373
374 integer :: i
375
376 !*******************************************************************
377
378 !** calculate maximum displacement since last update **
379
380 dispmx = 0.0d0
381
382 do i = 1, natoms
383
384 !write(*,*) 'calling displacement', i
385
386 dispmx = max ( dabs ( rx(i) - rx0(i) ), dispmx )
387 dispmx = max ( dabs ( ry(i) - ry0(i) ), dispmx )
388 dispmx = max ( dabs ( rz(i) - rz0(i) ), dispmx )
389
390 !write(*,*) 'called displacement', i
391
392 end do
393
394 !** a conservative test of the list skin crossing **
395
396 dispmx = 2.0d0 * dsqrt ( 3.0d0 * dispmx ** 2 )
397
398 update = ( dispmx .gt. ( rlist - rcut ) )
399
400
401 return
402 end subroutine long_range_check
403
404
405
406 subroutine long_range_save(natoms,rx,ry,rz,rx0,ry0,rz0)
407
408
409 !*******************************************************************
410 !** saves current configuration for future checking. **
411 !** **
412 !** principal variables: **
413 !** **
414 !** real rx(n),ry(n),rz(n) atom positions **
415 !** real rx0(n),ry0(n),rz0(n) storage locations for save **
416 !** integer n number of atoms **
417 !** **
418 !** usage: **
419 !** **
420 !** save is called whenever the new verlet list is constructed. **
421 !*******************************************************************
422
423 integer :: i
424
425 integer :: natoms
426
427 double precision, dimension(natoms) :: rx, ry, rz
428 double precision, dimension(natoms) :: rx0, ry0, rz0
429
430 !*******************************************************************
431
432 do i = 1, natoms
433
434 rx0(i) = rx(i)
435 ry0(i) = ry(i)
436 rz0(i) = rz(i)
437
438 end do
439
440 return
441 end subroutine long_range_save
442
443 end module long_range_forces