ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE_old/src/mdtools/libmdCode/do_Forces.F90
Revision: 367
Committed: Wed Mar 19 17:29:49 2003 UTC (21 years, 5 months ago) by mmeineke
File size: 20613 byte(s)
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 chuckv 306 !! do_Forces.F90
2     !! module do_Forces
3 chuckv 292 !! Calculates Long Range forces.
4 chuckv 306
5 chuckv 292 !! @author Charles F. Vardeman II
6     !! @author Matthew Meineke
7 mmeineke 367 !! @version $Id: do_Forces.F90,v 1.26 2003-03-19 17:29:49 mmeineke Exp $, $Date: 2003-03-19 17:29:49 $, $Name: not supported by cvs2svn $, $Revision: 1.26 $
8 chuckv 292
9     module do_Forces
10 gezelter 360 use force_globals
11 chuckv 292 use simulation
12     use definitions
13 gezelter 328 use atype_module
14 gezelter 325 use neighborLists
15 gezelter 330 use lj
16     use sticky_pair
17 gezelter 309 use dipole_dipole
18 gezelter 332 use reaction_field
19 gezelter 364 use gb_pair
20 chuckv 292 #ifdef IS_MPI
21     use mpiSimulation
22     #endif
23 gezelter 356
24 chuckv 292 implicit none
25     PRIVATE
26    
27 gezelter 356 #define __FORTRAN90
28     #include "fForceField.h"
29    
30 gezelter 329 logical, save :: do_forces_initialized = .false.
31     logical, save :: FF_uses_LJ
32     logical, save :: FF_uses_sticky
33     logical, save :: FF_uses_dipoles
34     logical, save :: FF_uses_RF
35     logical, save :: FF_uses_GB
36     logical, save :: FF_uses_EAM
37 chuckv 292
38 gezelter 329 public :: init_FF
39 gezelter 330 public :: do_force_loop
40 gezelter 329
41 chuckv 292 contains
42    
43 gezelter 358 subroutine init_FF(LJMIXPOLICY, use_RF_c, thisStat)
44 gezelter 356
45 gezelter 358 integer, intent(in) :: LJMIXPOLICY
46 mmeineke 359 logical, intent(in) :: use_RF_c
47 gezelter 356
48 chuckv 331 integer, intent(out) :: thisStat
49 gezelter 332 integer :: my_status, nMatches
50     integer, pointer :: MatchList(:)
51 gezelter 360 real(kind=dp) :: rcut, rrf, rt, dielect
52 gezelter 329
53 gezelter 332 !! assume things are copacetic, unless they aren't
54 chuckv 331 thisStat = 0
55 gezelter 356
56     !! Fortran's version of a cast:
57 gezelter 358 FF_uses_RF = use_RF_c
58 gezelter 332
59     !! init_FF is called *after* all of the atom types have been
60     !! defined in atype_module using the new_atype subroutine.
61     !!
62     !! this will scan through the known atypes and figure out what
63     !! interactions are used by the force field.
64 gezelter 358
65 gezelter 332 FF_uses_LJ = .false.
66     FF_uses_sticky = .false.
67     FF_uses_dipoles = .false.
68     FF_uses_GB = .false.
69     FF_uses_EAM = .false.
70    
71     call getMatchingElementList(atypes, "is_LJ", .true., nMatches, MatchList)
72     deallocate(MatchList)
73     if (nMatches .gt. 0) FF_uses_LJ = .true.
74 gezelter 358
75 gezelter 332 call getMatchingElementList(atypes, "is_DP", .true., nMatches, MatchList)
76     deallocate(MatchList)
77     if (nMatches .gt. 0) FF_uses_dipoles = .true.
78 gezelter 358
79 gezelter 332 call getMatchingElementList(atypes, "is_Sticky", .true., nMatches, &
80     MatchList)
81     deallocate(MatchList)
82     if (nMatches .gt. 0) FF_uses_Sticky = .true.
83    
84     call getMatchingElementList(atypes, "is_GB", .true., nMatches, MatchList)
85     deallocate(MatchList)
86     if (nMatches .gt. 0) FF_uses_GB = .true.
87 gezelter 358
88 gezelter 332 call getMatchingElementList(atypes, "is_EAM", .true., nMatches, MatchList)
89     deallocate(MatchList)
90     if (nMatches .gt. 0) FF_uses_EAM = .true.
91 gezelter 358
92 gezelter 356 !! check to make sure the FF_uses_RF setting makes sense
93 gezelter 358
94 gezelter 360 if (FF_uses_dipoles) then
95     rrf = getRrf()
96     rt = getRt()
97     call initialize_dipole(rrf, rt)
98     if (FF_uses_RF) then
99     dielect = getDielect()
100     call initialize_rf(rrf, rt, dielect)
101     endif
102     else
103     if (FF_uses_RF) then
104 gezelter 332 write(default_error,*) 'Using Reaction Field with no dipoles? Huh?'
105     thisStat = -1
106     return
107     endif
108     endif
109 gezelter 356
110     if (FF_uses_LJ) then
111 gezelter 358
112 gezelter 360 call getRcut(rcut)
113    
114 gezelter 358 select case (LJMIXPOLICY)
115     case (LB_MIXING_RULE)
116 gezelter 360 call init_lj_FF(LB_MIXING_RULE, rcut, my_status)
117 gezelter 358 case (EXPLICIT_MIXING_RULE)
118 gezelter 360 call init_lj_FF(EXPLICIT_MIXING_RULE, rcut, my_status)
119 gezelter 356 case default
120     write(default_error,*) 'unknown LJ Mixing Policy!'
121     thisStat = -1
122     return
123 gezelter 358 end select
124 gezelter 356 if (my_status /= 0) then
125     thisStat = -1
126     return
127     end if
128     endif
129    
130     if (FF_uses_sticky) then
131     call check_sticky_FF(my_status)
132     if (my_status /= 0) then
133     thisStat = -1
134     return
135     end if
136     endif
137 gezelter 332
138 gezelter 364 if (FF_uses_GB) then
139     call check_gb_pair_FF(my_status)
140     if (my_status .ne. 0) then
141     thisStat = -1
142     return
143     endif
144     endif
145    
146     if (FF_uses_GB .and. FF_uses_LJ) then
147     endif
148    
149    
150 gezelter 329 do_forces_initialized = .true.
151    
152     end subroutine init_FF
153 gezelter 358
154 gezelter 329
155 gezelter 317 !! Does force loop over i,j pairs. Calls do_pair to calculates forces.
156 gezelter 358 !------------------------------------------------------------->
157 gezelter 325 subroutine do_force_loop(q, A, u_l, f, t, tau, pot, do_pot_c, do_stress_c, &
158 gezelter 329 error)
159 gezelter 317 !! Position array provided by C, dimensioned by getNlocal
160 chuckv 292 real ( kind = dp ), dimension(3,getNlocal()) :: q
161 gezelter 317 !! Rotation Matrix for each long range particle in simulation.
162 gezelter 325 real( kind = dp), dimension(9,getNlocal()) :: A
163 gezelter 317 !! Unit vectors for dipoles (lab frame)
164 chuckv 292 real( kind = dp ), dimension(3,getNlocal()) :: u_l
165 gezelter 317 !! Force array provided by C, dimensioned by getNlocal
166 chuckv 292 real ( kind = dp ), dimension(3,getNlocal()) :: f
167 gezelter 317 !! Torsion array provided by C, dimensioned by getNlocal
168 gezelter 325 real( kind = dp ), dimension(3,getNlocal()) :: t
169 gezelter 317 !! Stress Tensor
170 gezelter 325 real( kind = dp), dimension(9) :: tau
171     real ( kind = dp ) :: pot
172     logical ( kind = 2) :: do_pot_c, do_stress_c
173 gezelter 329 logical :: do_pot
174     logical :: do_stress
175 gezelter 317 #ifdef IS_MPI
176     real( kind = DP ) :: pot_local
177 gezelter 329 integer :: nrow
178     integer :: ncol
179 gezelter 317 #endif
180 gezelter 330 integer :: nlocal
181 gezelter 329 integer :: natoms
182 gezelter 325 logical :: update_nlist
183     integer :: i, j, jbeg, jend, jnab
184 gezelter 317 integer :: nlist
185 gezelter 325 real( kind = DP ) :: rijsq, rlistsq, rcutsq, rlist, rcut
186 gezelter 330 real(kind=dp),dimension(3) :: d
187     real(kind=dp) :: rfpot, mu_i, virial
188     integer :: me_i
189     logical :: is_dp_i
190 gezelter 317 integer :: neighborListSize
191 gezelter 330 integer :: listerror, error
192 chuckv 331 integer :: localError
193 chuckv 292
194 gezelter 329 !! initialize local variables
195 gezelter 325
196 chuckv 292 #ifdef IS_MPI
197 gezelter 329 nlocal = getNlocal()
198     nrow = getNrow(plan_row)
199     ncol = getNcol(plan_col)
200     #else
201     nlocal = getNlocal()
202     natoms = nlocal
203 chuckv 292 #endif
204 gezelter 329
205 chuckv 331 call getRcut(rcut,rc2=rcutsq)
206 gezelter 317 call getRlist(rlist,rlistsq)
207    
208 chuckv 331 call check_initialization(localError)
209     if ( localError .ne. 0 ) then
210     error = -1
211     return
212     end if
213 gezelter 329 call zero_work_arrays()
214    
215     do_pot = do_pot_c
216     do_stress = do_stress_c
217    
218     ! Gather all information needed by all force loops:
219 gezelter 317
220 gezelter 329 #ifdef IS_MPI
221 chuckv 292
222 gezelter 309 call gather(q,q_Row,plan_row3d)
223     call gather(q,q_Col,plan_col3d)
224 gezelter 329
225     if (FF_UsesDirectionalAtoms() .and. SimUsesDirectionalAtoms()) then
226     call gather(u_l,u_l_Row,plan_row3d)
227     call gather(u_l,u_l_Col,plan_col3d)
228    
229     call gather(A,A_Row,plan_row_rotation)
230     call gather(A,A_Col,plan_col_rotation)
231     endif
232 gezelter 317
233 gezelter 329 #endif
234 gezelter 317
235 gezelter 329 if (FF_RequiresPrepairCalc() .and. SimRequiresPrepairCalc()) then
236     !! See if we need to update neighbor lists
237     call checkNeighborList(nlocal, q, rcut, rlist, update_nlist)
238     !! if_mpi_gather_stuff_for_prepair
239     !! do_prepair_loop_if_needed
240     !! if_mpi_scatter_stuff_from_prepair
241     !! if_mpi_gather_stuff_from_prepair_to_main_loop
242     else
243     !! See if we need to update neighbor lists
244     call checkNeighborList(nlocal, q, rcut, rlist, update_nlist)
245     endif
246    
247 gezelter 297 #ifdef IS_MPI
248 chuckv 292
249 gezelter 297 if (update_nlist) then
250    
251 gezelter 329 !! save current configuration, construct neighbor list,
252     !! and calculate forces
253 gezelter 334 call saveNeighborList(q)
254 gezelter 297
255     neighborListSize = getNeighborListSize()
256 gezelter 329 nlist = 0
257 gezelter 297
258     do i = 1, nrow
259     point(i) = nlist + 1
260    
261     inner: do j = 1, ncol
262    
263 gezelter 334 if (skipThisPair(i,j)) cycle inner
264 gezelter 329
265 gezelter 317 call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
266 gezelter 330
267 gezelter 297 if (rijsq < rlistsq) then
268    
269     nlist = nlist + 1
270    
271     if (nlist > neighborListSize) then
272 gezelter 325 call expandNeighborList(nlocal, listerror)
273 gezelter 297 if (listerror /= 0) then
274 gezelter 329 error = -1
275 gezelter 297 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
276     return
277     end if
278     endif
279    
280     list(nlist) = j
281 gezelter 317
282 gezelter 297 if (rijsq < rcutsq) then
283 gezelter 356 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
284     u_l, A, f, t)
285 gezelter 297 endif
286     endif
287     enddo inner
288     enddo
289 chuckv 292
290 gezelter 297 point(nrow + 1) = nlist + 1
291    
292 gezelter 329 else !! (of update_check)
293 chuckv 292
294 gezelter 297 ! use the list to find the neighbors
295     do i = 1, nrow
296     JBEG = POINT(i)
297     JEND = POINT(i+1) - 1
298     ! check thiat molecule i has neighbors
299     if (jbeg .le. jend) then
300 gezelter 317
301 gezelter 297 do jnab = jbeg, jend
302     j = list(jnab)
303 gezelter 317
304     call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
305 gezelter 356 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
306     u_l, A, f, t)
307 gezelter 317
308 gezelter 297 enddo
309     endif
310     enddo
311     endif
312 gezelter 329
313 gezelter 297 #else
314    
315     if (update_nlist) then
316 chuckv 292
317 gezelter 297 ! save current configuration, contruct neighbor list,
318     ! and calculate forces
319 gezelter 334 call saveNeighborList(q)
320 gezelter 297
321     neighborListSize = getNeighborListSize()
322     nlist = 0
323 gezelter 329
324 gezelter 297 do i = 1, natoms-1
325     point(i) = nlist + 1
326 gezelter 329
327 gezelter 297 inner: do j = i+1, natoms
328 gezelter 329
329 gezelter 334 if (skipThisPair(i,j)) cycle inner
330 gezelter 329
331 gezelter 317 call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
332 chuckv 295
333 gezelter 297 if (rijsq < rlistsq) then
334 gezelter 317
335 gezelter 297 nlist = nlist + 1
336    
337     if (nlist > neighborListSize) then
338 mmeineke 367 call expandNeighborList(natoms, listerror)
339 gezelter 297 if (listerror /= 0) then
340 gezelter 329 error = -1
341 gezelter 297 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
342     return
343     end if
344     endif
345    
346     list(nlist) = j
347 gezelter 329
348 gezelter 297 if (rijsq < rcutsq) then
349 gezelter 356 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
350     u_l, A, f, t)
351 gezelter 297 endif
352     endif
353 chuckv 292 enddo inner
354 gezelter 297 enddo
355    
356     point(natoms) = nlist + 1
357    
358     else !! (update)
359    
360     ! use the list to find the neighbors
361 gezelter 330 do i = 1, natoms-1
362 gezelter 297 JBEG = POINT(i)
363     JEND = POINT(i+1) - 1
364     ! check thiat molecule i has neighbors
365     if (jbeg .le. jend) then
366    
367     do jnab = jbeg, jend
368     j = list(jnab)
369 gezelter 317
370     call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
371 gezelter 356 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
372     u_l, A, f, t)
373 gezelter 317
374 gezelter 297 enddo
375     endif
376     enddo
377     endif
378 gezelter 317
379 gezelter 297 #endif
380 gezelter 317
381 gezelter 329 ! phew, done with main loop.
382 gezelter 317
383 chuckv 292 #ifdef IS_MPI
384 gezelter 329 !!distribute forces
385 gezelter 317
386 gezelter 309 call scatter(f_Row,f,plan_row3d)
387     call scatter(f_Col,f_temp,plan_col3d)
388 chuckv 295 do i = 1,nlocal
389 gezelter 309 f(1:3,i) = f(1:3,i) + f_temp(1:3,i)
390 chuckv 295 end do
391 gezelter 329
392     if (FF_UsesDirectionalAtoms() .and. SimUsesDirectionalAtoms()) then
393 gezelter 309 call scatter(t_Row,t,plan_row3d)
394     call scatter(t_Col,t_temp,plan_col3d)
395 gezelter 329
396 chuckv 295 do i = 1,nlocal
397 gezelter 309 t(1:3,i) = t(1:3,i) + t_temp(1:3,i)
398 chuckv 295 end do
399     endif
400 gezelter 309
401 chuckv 295 if (do_pot) then
402     ! scatter/gather pot_row into the members of my column
403 gezelter 309 call scatter(pot_Row, pot_Temp, plan_row)
404 chuckv 295
405     ! scatter/gather pot_local into all other procs
406     ! add resultant to get total pot
407     do i = 1, nlocal
408 gezelter 309 pot_local = pot_local + pot_Temp(i)
409 chuckv 295 enddo
410    
411 gezelter 309 pot_Temp = 0.0_DP
412    
413     call scatter(pot_Col, pot_Temp, plan_col)
414 chuckv 295 do i = 1, nlocal
415 gezelter 309 pot_local = pot_local + pot_Temp(i)
416 chuckv 295 enddo
417    
418 gezelter 330 endif
419     #endif
420    
421 gezelter 329 if (FF_RequiresPostpairCalc() .and. SimRequiresPostpairCalc()) then
422    
423     if (FF_uses_RF .and. SimUsesRF()) then
424    
425     #ifdef IS_MPI
426     call scatter(rf_Row,rf,plan_row3d)
427     call scatter(rf_Col,rf_Temp,plan_col3d)
428     do i = 1,nlocal
429     rf(1:3,i) = rf(1:3,i) + rf_Temp(1:3,i)
430     end do
431     #endif
432    
433     do i = 1, getNlocal()
434    
435 gezelter 330 rfpot = 0.0_DP
436 gezelter 329 #ifdef IS_MPI
437     me_i = atid_row(i)
438     #else
439     me_i = atid(i)
440     #endif
441     call getElementProperty(atypes, me_i, "is_DP", is_DP_i)
442     if ( is_DP_i ) then
443     call getElementProperty(atypes, me_i, "dipole_moment", mu_i)
444     !! The reaction field needs to include a self contribution
445     !! to the field:
446     call accumulate_self_rf(i, mu_i, u_l)
447     !! Get the reaction field contribution to the
448     !! potential and torques:
449 gezelter 330 call reaction_field_final(i, mu_i, u_l, rfpot, t, do_pot)
450 gezelter 329 #ifdef IS_MPI
451     pot_local = pot_local + rfpot
452     #else
453     pot = pot + rfpot
454     #endif
455     endif
456     enddo
457     endif
458     endif
459    
460    
461     #ifdef IS_MPI
462    
463     if (do_pot) then
464 gezelter 309 pot = pot_local
465 gezelter 329 !! we assume the c code will do the allreduce to get the total potential
466     !! we could do it right here if we needed to...
467 chuckv 295 endif
468    
469 gezelter 329 if (do_stress) then
470 gezelter 330 call mpi_allreduce(tau, tau_Temp,9,mpi_double_precision,mpi_sum, &
471 gezelter 309 mpi_comm_world,mpi_err)
472 gezelter 330 call mpi_allreduce(virial, virial_Temp,1,mpi_double_precision,mpi_sum, &
473 gezelter 309 mpi_comm_world,mpi_err)
474     endif
475 chuckv 295
476 gezelter 329 #else
477 chuckv 295
478 gezelter 329 if (do_stress) then
479 gezelter 309 tau = tau_Temp
480     virial = virial_Temp
481 chuckv 295 endif
482    
483 gezelter 329 #endif
484    
485 chuckv 295 end subroutine do_force_loop
486    
487 gezelter 356 subroutine do_pair(i, j, rijsq, d, do_pot, do_stress, u_l, A, f, t)
488 chuckv 295
489 gezelter 330 real( kind = dp ) :: pot
490 gezelter 364 real( kind = dp ), dimension(:,:) :: u_l
491     real (kind=dp), dimension(:,:) :: A
492     real (kind=dp), dimension(:,:) :: f
493     real (kind=dp), dimension(:,:) :: t
494 gezelter 330
495 gezelter 329 logical, intent(inout) :: do_pot, do_stress
496 gezelter 317 integer, intent(in) :: i, j
497 chuckv 331 real ( kind = dp ), intent(inout) :: rijsq
498 gezelter 317 real ( kind = dp ) :: r
499     real ( kind = dp ), intent(inout) :: d(3)
500     logical :: is_LJ_i, is_LJ_j
501     logical :: is_DP_i, is_DP_j
502 gezelter 364 logical :: is_GB_i, is_GB_j
503 gezelter 317 logical :: is_Sticky_i, is_Sticky_j
504     integer :: me_i, me_j
505 chuckv 295
506 gezelter 330 r = sqrt(rijsq)
507    
508 gezelter 302 #ifdef IS_MPI
509    
510 gezelter 317 me_i = atid_row(i)
511     me_j = atid_col(j)
512 chuckv 295
513 gezelter 317 #else
514 chuckv 295
515 gezelter 317 me_i = atid(i)
516     me_j = atid(j)
517 gezelter 302
518 gezelter 317 #endif
519 gezelter 302
520 gezelter 329 if (FF_uses_LJ .and. SimUsesLJ()) then
521     call getElementProperty(atypes, me_i, "is_LJ", is_LJ_i)
522     call getElementProperty(atypes, me_j, "is_LJ", is_LJ_j)
523    
524     if ( is_LJ_i .and. is_LJ_j ) &
525     call do_lj_pair(i, j, d, r, rijsq, pot, f, do_pot, do_stress)
526     endif
527    
528 gezelter 330 if (FF_uses_dipoles .and. SimUsesDipoles()) then
529 gezelter 329 call getElementProperty(atypes, me_i, "is_DP", is_DP_i)
530     call getElementProperty(atypes, me_j, "is_DP", is_DP_j)
531    
532     if ( is_DP_i .and. is_DP_j ) then
533    
534 gezelter 360 call do_dipole_pair(i, j, d, r, rijsq, pot, u_l, f, t, &
535     do_pot, do_stress)
536 gezelter 329
537     if (FF_uses_RF .and. SimUsesRF()) then
538    
539     call accumulate_rf(i, j, r, u_l)
540     call rf_correct_forces(i, j, d, r, u_l, f, do_stress)
541    
542     endif
543    
544 gezelter 297 endif
545     endif
546    
547 gezelter 329 if (FF_uses_Sticky .and. SimUsesSticky()) then
548 gezelter 317
549 gezelter 329 call getElementProperty(atypes, me_i, "is_Sticky", is_Sticky_i)
550     call getElementProperty(atypes, me_j, "is_Sticky", is_Sticky_j)
551    
552     if ( is_Sticky_i .and. is_Sticky_j ) then
553     call do_sticky_pair(i, j, d, r, rijsq, A, pot, f, t, &
554     do_pot, do_stress)
555     endif
556 gezelter 297 endif
557 gezelter 364
558    
559     if (FF_uses_GB .and. SimUsesGB()) then
560    
561     call getElementProperty(atypes, me_i, "is_GB", is_GB_i)
562     call getElementProperty(atypes, me_j, "is_GB", is_GB_j)
563    
564     if ( is_GB_i .and. is_GB_j ) then
565     call do_gb_pair(i, j, d, r, rijsq, u_l, pot, f, t, &
566     do_pot, do_stress)
567     endif
568     endif
569 gezelter 309
570 chuckv 295 end subroutine do_pair
571 chuckv 292
572    
573 gezelter 317 subroutine get_interatomic_vector(q_i, q_j, d, r_sq)
574    
575 chuckv 295 real (kind = dp), dimension(3) :: q_i
576     real (kind = dp), dimension(3) :: q_j
577     real ( kind = dp ), intent(out) :: r_sq
578     real( kind = dp ) :: d(3)
579    
580     d(1:3) = q_i(1:3) - q_j(1:3)
581 gezelter 317
582     ! Wrap back into periodic box if necessary
583 gezelter 330 if ( SimUsesPBC() ) then
584     d(1:3) = d(1:3) - box(1:3) * sign(1.0_dp,box(1:3)) * &
585     int(abs(d(1:3)/box(1:3) + 0.5_dp))
586 gezelter 317 endif
587 chuckv 292
588 chuckv 295 r_sq = dot_product(d,d)
589 gezelter 317
590 chuckv 295 end subroutine get_interatomic_vector
591 gezelter 329
592     subroutine check_initialization(error)
593     integer, intent(out) :: error
594 gezelter 332
595 gezelter 329 error = 0
596     ! Make sure we are properly initialized.
597 gezelter 332 if (.not. do_forces_initialized) then
598 gezelter 329 write(default_error,*) "ERROR: do_Forces has not been initialized!"
599     error = -1
600     return
601     endif
602 gezelter 332
603 gezelter 329 #ifdef IS_MPI
604     if (.not. isMPISimSet()) then
605     write(default_error,*) "ERROR: mpiSimulation has not been initialized!"
606     error = -1
607     return
608     endif
609     #endif
610 gezelter 332
611 gezelter 329 return
612     end subroutine check_initialization
613    
614 gezelter 317
615 gezelter 325 subroutine zero_work_arrays()
616    
617     #ifdef IS_MPI
618 chuckv 292
619 gezelter 325 q_Row = 0.0_dp
620     q_Col = 0.0_dp
621 chuckv 295
622 gezelter 325 u_l_Row = 0.0_dp
623     u_l_Col = 0.0_dp
624 chuckv 295
625 gezelter 325 A_Row = 0.0_dp
626     A_Col = 0.0_dp
627 chuckv 295
628 gezelter 325 f_Row = 0.0_dp
629     f_Col = 0.0_dp
630     f_Temp = 0.0_dp
631    
632     t_Row = 0.0_dp
633     t_Col = 0.0_dp
634     t_Temp = 0.0_dp
635 chuckv 295
636 gezelter 325 pot_Row = 0.0_dp
637     pot_Col = 0.0_dp
638     pot_Temp = 0.0_dp
639 chuckv 292
640 gezelter 332 rf_Row = 0.0_dp
641     rf_Col = 0.0_dp
642     rf_Temp = 0.0_dp
643    
644 chuckv 295 #endif
645 chuckv 292
646 gezelter 332 rf = 0.0_dp
647 gezelter 325 tau_Temp = 0.0_dp
648     virial_Temp = 0.0_dp
649    
650     end subroutine zero_work_arrays
651    
652 gezelter 334 function skipThisPair(atom1, atom2) result(skip_it)
653 gezelter 332
654 gezelter 334 integer, intent(in) :: atom1
655     integer, intent(in), optional :: atom2
656     logical :: skip_it
657 gezelter 332 integer :: unique_id_1, unique_id_2
658 gezelter 334 integer :: i
659 gezelter 332
660 gezelter 334 skip_it = .false.
661    
662     !! there are a number of reasons to skip a pair or a particle
663     !! mostly we do this to exclude atoms who are involved in short
664     !! range interactions (bonds, bends, torsions), but we also need
665     !! to exclude some overcounted interactions that result from
666     !! the parallel decomposition
667 gezelter 330
668 chuckv 306 #ifdef IS_MPI
669 gezelter 334 !! in MPI, we have to look up the unique IDs for each atom
670 gezelter 332 unique_id_1 = tagRow(atom1)
671 chuckv 306 #else
672 gezelter 334 !! in the normal loop, the atom numbers are unique
673     unique_id_1 = atom1
674 chuckv 306 #endif
675 gezelter 330
676 gezelter 334 !! We were called with only one atom, so just check the global exclude
677     !! list for this atom
678 chuckv 306 if (.not. present(atom2)) then
679 gezelter 330 do i = 1, nExcludes_global
680 gezelter 332 if (excludesGlobal(i) == unique_id_1) then
681 gezelter 334 skip_it = .true.
682 chuckv 306 return
683     end if
684     end do
685 gezelter 334 return
686 chuckv 306 end if
687 gezelter 330
688 gezelter 332 #ifdef IS_MPI
689     unique_id_2 = tagColumn(atom2)
690     #else
691 gezelter 334 unique_id_2 = atom2
692 gezelter 332 #endif
693    
694 gezelter 334 #ifdef IS_MPI
695     !! this situation should only arise in MPI simulations
696 gezelter 332 if (unique_id_1 == unique_id_2) then
697 gezelter 334 skip_it = .true.
698 chuckv 295 return
699     end if
700 gezelter 330
701 gezelter 334 !! this prevents us from doing the pair on multiple processors
702 gezelter 332 if (unique_id_1 < unique_id_2) then
703 gezelter 334 if (mod(unique_id_1 + unique_id_2,2) == 0) skip_it = .true.
704 chuckv 295 return
705     else
706 gezelter 334 if (mod(unique_id_1 + unique_id_2,2) == 1) skip_it = .true.
707 chuckv 295 endif
708 gezelter 334 #endif
709    
710     !! the rest of these situations can happen in all simulations:
711     do i = 1, nExcludes_global
712     if ((excludesGlobal(i) == unique_id_1) .or. &
713     (excludesGlobal(i) == unique_id_2)) then
714     skip_it = .true.
715     return
716     endif
717     enddo
718 gezelter 332
719 gezelter 330 do i = 1, nExcludes_local
720 gezelter 334 if (excludesLocal(1,i) == unique_id_1) then
721     if (excludesLocal(2,i) == unique_id_2) then
722     skip_it = .true.
723     return
724     endif
725     else
726     if (excludesLocal(1,i) == unique_id_2) then
727     if (excludesLocal(2,i) == unique_id_1) then
728     skip_it = .true.
729     return
730     endif
731     endif
732     endif
733 chuckv 306 end do
734 gezelter 330
735 gezelter 334 return
736     end function skipThisPair
737 chuckv 306
738 gezelter 329 function FF_UsesDirectionalAtoms() result(doesit)
739     logical :: doesit
740     doesit = FF_uses_dipoles .or. FF_uses_sticky .or. &
741     FF_uses_GB .or. FF_uses_RF
742     end function FF_UsesDirectionalAtoms
743    
744     function FF_RequiresPrepairCalc() result(doesit)
745     logical :: doesit
746     doesit = FF_uses_EAM
747     end function FF_RequiresPrepairCalc
748    
749     function FF_RequiresPostpairCalc() result(doesit)
750     logical :: doesit
751     doesit = FF_uses_RF
752     end function FF_RequiresPostpairCalc
753    
754 chuckv 292 end module do_Forces