ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/UseTheForce/doForces.F90
Revision: 2266
Committed: Thu Jul 28 22:12:45 2005 UTC (18 years, 11 months ago) by chuckv
File size: 42028 byte(s)
Log Message:
Changed cutoffs... Segfaults nicely now...

File Contents

# User Rev Content
1 gezelter 1930 !!
2     !! Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     !!
4     !! The University of Notre Dame grants you ("Licensee") a
5     !! non-exclusive, royalty free, license to use, modify and
6     !! redistribute this software in source and binary code form, provided
7     !! that the following conditions are met:
8     !!
9     !! 1. Acknowledgement of the program authors must be made in any
10     !! publication of scientific results based in part on use of the
11     !! program. An acceptable form of acknowledgement is citation of
12     !! the article in which the program was described (Matthew
13     !! A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14     !! J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15     !! Parallel Simulation Engine for Molecular Dynamics,"
16     !! J. Comput. Chem. 26, pp. 252-271 (2005))
17     !!
18     !! 2. Redistributions of source code must retain the above copyright
19     !! notice, this list of conditions and the following disclaimer.
20     !!
21     !! 3. Redistributions in binary form must reproduce the above copyright
22     !! notice, this list of conditions and the following disclaimer in the
23     !! documentation and/or other materials provided with the
24     !! distribution.
25     !!
26     !! This software is provided "AS IS," without a warranty of any
27     !! kind. All express or implied conditions, representations and
28     !! warranties, including any implied warranty of merchantability,
29     !! fitness for a particular purpose or non-infringement, are hereby
30     !! excluded. The University of Notre Dame and its licensors shall not
31     !! be liable for any damages suffered by licensee as a result of
32     !! using, modifying or distributing the software or its
33     !! derivatives. In no event will the University of Notre Dame or its
34     !! licensors be liable for any lost revenue, profit or data, or for
35     !! direct, indirect, special, consequential, incidental or punitive
36     !! damages, however caused and regardless of the theory of liability,
37     !! arising out of the use of or inability to use software, even if the
38     !! University of Notre Dame has been advised of the possibility of
39     !! such damages.
40     !!
41    
42 gezelter 1610 !! doForces.F90
43     !! module doForces
44     !! Calculates Long Range forces.
45    
46     !! @author Charles F. Vardeman II
47     !! @author Matthew Meineke
48 chuckv 2266 !! @version $Id: doForces.F90,v 1.24 2005-07-28 22:12:45 chuckv Exp $, $Date: 2005-07-28 22:12:45 $, $Name: not supported by cvs2svn $, $Revision: 1.24 $
49 gezelter 1610
50 gezelter 1930
51 gezelter 1610 module doForces
52     use force_globals
53     use simulation
54     use definitions
55     use atype_module
56     use switcheroo
57     use neighborLists
58     use lj
59 gezelter 1930 use sticky
60 gezelter 2085 use electrostatic_module
61 gezelter 1610 use reaction_field
62     use gb_pair
63 chrisfen 1636 use shapes
64 gezelter 1610 use vector_class
65     use eam
66     use status
67     #ifdef IS_MPI
68     use mpiSimulation
69     #endif
70    
71     implicit none
72     PRIVATE
73    
74     #define __FORTRAN90
75     #include "UseTheForce/fSwitchingFunction.h"
76 gezelter 2259 #include "UseTheForce/DarkSide/fInteractionMap.h"
77 gezelter 1610
78     INTEGER, PARAMETER:: PREPAIR_LOOP = 1
79     INTEGER, PARAMETER:: PAIR_LOOP = 2
80    
81     logical, save :: haveRlist = .false.
82     logical, save :: haveNeighborList = .false.
83     logical, save :: haveSIMvariables = .false.
84     logical, save :: haveSaneForceField = .false.
85 chuckv 2262 logical, save :: haveInteractionMap = .false.
86 chrisfen 2229
87 gezelter 1634 logical, save :: FF_uses_DirectionalAtoms
88     logical, save :: FF_uses_LennardJones
89 gezelter 2085 logical, save :: FF_uses_Electrostatics
90     logical, save :: FF_uses_Charges
91     logical, save :: FF_uses_Dipoles
92     logical, save :: FF_uses_Quadrupoles
93 chrisfen 2229 logical, save :: FF_uses_Sticky
94     logical, save :: FF_uses_StickyPower
95 gezelter 1634 logical, save :: FF_uses_GayBerne
96     logical, save :: FF_uses_EAM
97     logical, save :: FF_uses_Shapes
98     logical, save :: FF_uses_FLARB
99 gezelter 1610 logical, save :: FF_uses_RF
100 gezelter 1634
101     logical, save :: SIM_uses_DirectionalAtoms
102     logical, save :: SIM_uses_LennardJones
103     logical, save :: SIM_uses_Electrostatics
104     logical, save :: SIM_uses_Charges
105     logical, save :: SIM_uses_Dipoles
106 gezelter 2085 logical, save :: SIM_uses_Quadrupoles
107 gezelter 1634 logical, save :: SIM_uses_Sticky
108 chrisfen 2229 logical, save :: SIM_uses_StickyPower
109 gezelter 1634 logical, save :: SIM_uses_GayBerne
110     logical, save :: SIM_uses_EAM
111     logical, save :: SIM_uses_Shapes
112     logical, save :: SIM_uses_FLARB
113 gezelter 1610 logical, save :: SIM_uses_RF
114     logical, save :: SIM_requires_postpair_calc
115     logical, save :: SIM_requires_prepair_calc
116     logical, save :: SIM_uses_PBC
117     logical, save :: SIM_uses_molecular_cutoffs
118    
119 chuckv 2260 !!!GO AWAY---------
120     !!!!!real(kind=dp), save :: rlist, rlistsq
121 gezelter 1610
122     public :: init_FF
123     public :: do_force_loop
124 chuckv 2260 ! public :: setRlistDF
125 chuckv 2262 !public :: addInteraction
126     !public :: setInteractionHash
127     !public :: getInteractionHash
128     public :: createInteractionMap
129     public :: createRcuts
130 gezelter 1610
131     #ifdef PROFILE
132     public :: getforcetime
133     real, save :: forceTime = 0
134     real :: forceTimeInitial, forceTimeFinal
135     integer :: nLoops
136     #endif
137    
138 chuckv 2260 type, public :: Interaction
139     integer :: InteractionHash
140 chuckv 2262 real(kind=dp) :: rList = 0.0_dp
141     real(kind=dp) :: rListSq = 0.0_dp
142 chuckv 2260 end type Interaction
143    
144 gezelter 2261 type(Interaction), dimension(:,:),allocatable :: InteractionMap
145 chuckv 2260
146 chuckv 2262
147 gezelter 2261
148 gezelter 1610 contains
149    
150 chuckv 2260
151     subroutine createInteractionMap(status)
152     integer :: nAtypes
153 chuckv 2266 integer, intent(out) :: status
154 chuckv 2260 integer :: i
155     integer :: j
156     integer :: ihash
157     real(kind=dp) :: myRcut
158     ! Test Types
159     logical :: i_is_LJ
160     logical :: i_is_Elect
161     logical :: i_is_Sticky
162     logical :: i_is_StickyP
163     logical :: i_is_GB
164     logical :: i_is_EAM
165     logical :: i_is_Shape
166     logical :: j_is_LJ
167     logical :: j_is_Elect
168     logical :: j_is_Sticky
169     logical :: j_is_StickyP
170     logical :: j_is_GB
171     logical :: j_is_EAM
172     logical :: j_is_Shape
173    
174 chuckv 2266 status = 0
175 chuckv 2260
176     if (.not. associated(atypes)) then
177     call handleError("atype", "atypes was not present before call of createDefaultInteractionMap!")
178     status = -1
179     return
180     endif
181    
182     nAtypes = getSize(atypes)
183    
184     if (nAtypes == 0) then
185     status = -1
186     return
187     end if
188 chrisfen 2229
189 chuckv 2260 if (.not. allocated(InteractionMap)) then
190     allocate(InteractionMap(nAtypes,nAtypes))
191     endif
192    
193     do i = 1, nAtypes
194     call getElementProperty(atypes, i, "is_LennardJones", i_is_LJ)
195     call getElementProperty(atypes, i, "is_Electrostatic", i_is_Elect)
196     call getElementProperty(atypes, i, "is_Sticky", i_is_Sticky)
197     call getElementProperty(atypes, i, "is_StickyPower", i_is_StickyP)
198     call getElementProperty(atypes, i, "is_GayBerne", i_is_GB)
199     call getElementProperty(atypes, i, "is_EAM", i_is_EAM)
200     call getElementProperty(atypes, i, "is_Shape", i_is_Shape)
201 gezelter 1610
202 chuckv 2260 do j = i, nAtypes
203 chrisfen 2229
204 chuckv 2260 iHash = 0
205     myRcut = 0.0_dp
206 gezelter 1610
207 chuckv 2260 call getElementProperty(atypes, j, "is_LennardJones", j_is_LJ)
208     call getElementProperty(atypes, j, "is_Electrostatic", j_is_Elect)
209     call getElementProperty(atypes, j, "is_Sticky", j_is_Sticky)
210     call getElementProperty(atypes, j, "is_StickyPower", j_is_StickyP)
211     call getElementProperty(atypes, j, "is_GayBerne", j_is_GB)
212     call getElementProperty(atypes, j, "is_EAM", j_is_EAM)
213     call getElementProperty(atypes, j, "is_Shape", j_is_Shape)
214 gezelter 1610
215 chuckv 2260 if (i_is_LJ .and. j_is_LJ) then
216 gezelter 2261 iHash = ior(iHash, LJ_PAIR)
217     endif
218    
219     if (i_is_Elect .and. j_is_Elect) then
220     iHash = ior(iHash, ELECTROSTATIC_PAIR)
221     endif
222    
223     if (i_is_Sticky .and. j_is_Sticky) then
224     iHash = ior(iHash, STICKY_PAIR)
225     endif
226 chuckv 2260
227 gezelter 2261 if (i_is_StickyP .and. j_is_StickyP) then
228     iHash = ior(iHash, STICKYPOWER_PAIR)
229     endif
230 chuckv 2260
231 gezelter 2261 if (i_is_EAM .and. j_is_EAM) then
232     iHash = ior(iHash, EAM_PAIR)
233 chuckv 2260 endif
234    
235     if (i_is_GB .and. j_is_GB) iHash = ior(iHash, GAYBERNE_PAIR)
236     if (i_is_GB .and. j_is_LJ) iHash = ior(iHash, GAYBERNE_LJ)
237     if (i_is_LJ .and. j_is_GB) iHash = ior(iHash, GAYBERNE_LJ)
238    
239     if (i_is_Shape .and. j_is_Shape) iHash = ior(iHash, SHAPE_PAIR)
240     if (i_is_Shape .and. j_is_LJ) iHash = ior(iHash, SHAPE_LJ)
241     if (i_is_LJ .and. j_is_Shape) iHash = ior(iHash, SHAPE_LJ)
242    
243    
244     InteractionMap(i,j)%InteractionHash = iHash
245     InteractionMap(j,i)%InteractionHash = iHash
246    
247     end do
248    
249     end do
250     end subroutine createInteractionMap
251    
252 chuckv 2262 ! Query each potential and return the cutoff for that potential. We build the neighbor list based on the largest cutoff value for that atype. Each potential can decide whether to calculate the force for that atype based upon it's own cutoff.
253 chuckv 2266 subroutine createRcuts(defaultRList,stat)
254 chuckv 2262 real(kind=dp), intent(in), optional :: defaultRList
255     integer :: iMap
256     integer :: map_i,map_j
257     real(kind=dp) :: thisRCut = 0.0_dp
258     real(kind=dp) :: actualCutoff = 0.0_dp
259 chuckv 2266 integer, intent(out) :: stat
260 chuckv 2262 integer :: nAtypes
261 chuckv 2266 integer :: myStatus
262 chuckv 2260
263 chuckv 2266 stat = 0
264     if (.not. haveInteractionMap) then
265 chuckv 2260
266 chuckv 2266 call createInteractionMap(myStatus)
267    
268     if (myStatus .ne. 0) then
269     write(default_error, *) 'createInteractionMap failed in doForces!'
270     stat = -1
271     return
272     endif
273     endif
274    
275    
276 chuckv 2262 nAtypes = getSize(atypes)
277     ! If we pass a default rcut, set all atypes to that cutoff distance
278     if(present(defaultRList)) then
279     InteractionMap(:,:)%rList = defaultRList
280     InteractionMap(:,:)%rListSq = defaultRList*defaultRList
281     haveRlist = .true.
282     return
283     end if
284    
285     do map_i = 1,nAtypes
286     do map_j = map_i,nAtypes
287     iMap = InteractionMap(map_i, map_j)%InteractionHash
288    
289     if ( iand(iMap, LJ_PAIR).ne.0 ) then
290     ! thisRCut = getLJCutOff(map_i,map_j)
291     if (thisRcut > actualCutoff) actualCutoff = thisRcut
292     endif
293    
294     if ( iand(iMap, ELECTROSTATIC_PAIR).ne.0 ) then
295     ! thisRCut = getElectrostaticCutOff(map_i,map_j)
296     if (thisRcut > actualCutoff) actualCutoff = thisRcut
297     endif
298    
299     if ( iand(iMap, STICKY_PAIR).ne.0 ) then
300     ! thisRCut = getStickyCutOff(map_i,map_j)
301     if (thisRcut > actualCutoff) actualCutoff = thisRcut
302     endif
303    
304     if ( iand(iMap, STICKYPOWER_PAIR).ne.0 ) then
305     ! thisRCut = getStickyPowerCutOff(map_i,map_j)
306     if (thisRcut > actualCutoff) actualCutoff = thisRcut
307     endif
308    
309     if ( iand(iMap, GAYBERNE_PAIR).ne.0 ) then
310     ! thisRCut = getGayberneCutOff(map_i,map_j)
311     if (thisRcut > actualCutoff) actualCutoff = thisRcut
312     endif
313    
314     if ( iand(iMap, GAYBERNE_LJ).ne.0 ) then
315     ! thisRCut = getGaybrneLJCutOff(map_i,map_j)
316     if (thisRcut > actualCutoff) actualCutoff = thisRcut
317     endif
318    
319     if ( iand(iMap, EAM_PAIR).ne.0 ) then
320     ! thisRCut = getEAMCutOff(map_i,map_j)
321     if (thisRcut > actualCutoff) actualCutoff = thisRcut
322     endif
323    
324     if ( iand(iMap, SHAPE_PAIR).ne.0 ) then
325     ! thisRCut = getShapeCutOff(map_i,map_j)
326     if (thisRcut > actualCutoff) actualCutoff = thisRcut
327     endif
328    
329     if ( iand(iMap, SHAPE_LJ).ne.0 ) then
330     ! thisRCut = getShapeLJCutOff(map_i,map_j)
331     if (thisRcut > actualCutoff) actualCutoff = thisRcut
332     endif
333     InteractionMap(map_i, map_j)%rList = actualCutoff
334     InteractionMap(map_i, map_j)%rListSq = actualCutoff * actualCutoff
335     end do
336     end do
337     haveRlist = .true.
338     end subroutine createRcuts
339    
340    
341 chuckv 2260 !!! THIS GOES AWAY FOR SIZE DEPENDENT CUTOFF
342     !!$ subroutine setRlistDF( this_rlist )
343     !!$
344     !!$ real(kind=dp) :: this_rlist
345     !!$
346     !!$ rlist = this_rlist
347     !!$ rlistsq = rlist * rlist
348     !!$
349     !!$ haveRlist = .true.
350     !!$
351     !!$ end subroutine setRlistDF
352    
353 gezelter 1610
354     subroutine setSimVariables()
355 gezelter 1634 SIM_uses_DirectionalAtoms = SimUsesDirectionalAtoms()
356     SIM_uses_LennardJones = SimUsesLennardJones()
357     SIM_uses_Electrostatics = SimUsesElectrostatics()
358     SIM_uses_Charges = SimUsesCharges()
359     SIM_uses_Dipoles = SimUsesDipoles()
360     SIM_uses_Sticky = SimUsesSticky()
361 chrisfen 2229 SIM_uses_StickyPower = SimUsesStickyPower()
362 gezelter 1634 SIM_uses_GayBerne = SimUsesGayBerne()
363     SIM_uses_EAM = SimUsesEAM()
364     SIM_uses_Shapes = SimUsesShapes()
365     SIM_uses_FLARB = SimUsesFLARB()
366 gezelter 1610 SIM_uses_RF = SimUsesRF()
367     SIM_requires_postpair_calc = SimRequiresPostpairCalc()
368     SIM_requires_prepair_calc = SimRequiresPrepairCalc()
369     SIM_uses_PBC = SimUsesPBC()
370    
371     haveSIMvariables = .true.
372    
373     return
374     end subroutine setSimVariables
375    
376     subroutine doReadyCheck(error)
377     integer, intent(out) :: error
378    
379     integer :: myStatus
380    
381     error = 0
382 chrisfen 2229
383 gezelter 2261 if (.not. haveInteractionMap) then
384 gezelter 1610
385     myStatus = 0
386    
387 gezelter 2261 call createInteractionMap(myStatus)
388 gezelter 1610
389     if (myStatus .ne. 0) then
390 gezelter 2261 write(default_error, *) 'createInteractionMap failed in doForces!'
391 gezelter 1610 error = -1
392     return
393     endif
394     endif
395    
396     if (.not. haveSIMvariables) then
397     call setSimVariables()
398     endif
399    
400     if (.not. haveRlist) then
401     write(default_error, *) 'rList has not been set in doForces!'
402     error = -1
403     return
404     endif
405    
406     if (.not. haveNeighborList) then
407     write(default_error, *) 'neighbor list has not been initialized in doForces!'
408     error = -1
409     return
410     end if
411    
412     if (.not. haveSaneForceField) then
413     write(default_error, *) 'Force Field is not sane in doForces!'
414     error = -1
415     return
416     end if
417    
418     #ifdef IS_MPI
419     if (.not. isMPISimSet()) then
420     write(default_error,*) "ERROR: mpiSimulation has not been initialized!"
421     error = -1
422     return
423     endif
424     #endif
425     return
426     end subroutine doReadyCheck
427    
428 chrisfen 2229
429 gezelter 1628 subroutine init_FF(use_RF_c, thisStat)
430 gezelter 1610
431     logical, intent(in) :: use_RF_c
432    
433     integer, intent(out) :: thisStat
434     integer :: my_status, nMatches
435     integer, pointer :: MatchList(:) => null()
436     real(kind=dp) :: rcut, rrf, rt, dielect
437    
438     !! assume things are copacetic, unless they aren't
439     thisStat = 0
440    
441     !! Fortran's version of a cast:
442     FF_uses_RF = use_RF_c
443 chrisfen 2229
444 gezelter 1610 !! init_FF is called *after* all of the atom types have been
445     !! defined in atype_module using the new_atype subroutine.
446     !!
447     !! this will scan through the known atypes and figure out what
448     !! interactions are used by the force field.
449 chrisfen 2229
450 gezelter 1634 FF_uses_DirectionalAtoms = .false.
451     FF_uses_LennardJones = .false.
452 gezelter 2085 FF_uses_Electrostatics = .false.
453 gezelter 1634 FF_uses_Charges = .false.
454     FF_uses_Dipoles = .false.
455     FF_uses_Sticky = .false.
456 chrisfen 2229 FF_uses_StickyPower = .false.
457 gezelter 1634 FF_uses_GayBerne = .false.
458 gezelter 1610 FF_uses_EAM = .false.
459 gezelter 1634 FF_uses_Shapes = .false.
460     FF_uses_FLARB = .false.
461 chrisfen 2229
462 gezelter 1634 call getMatchingElementList(atypes, "is_Directional", .true., &
463     nMatches, MatchList)
464     if (nMatches .gt. 0) FF_uses_DirectionalAtoms = .true.
465    
466     call getMatchingElementList(atypes, "is_LennardJones", .true., &
467     nMatches, MatchList)
468     if (nMatches .gt. 0) FF_uses_LennardJones = .true.
469 chrisfen 2229
470 gezelter 1634 call getMatchingElementList(atypes, "is_Electrostatic", .true., &
471     nMatches, MatchList)
472     if (nMatches .gt. 0) then
473 gezelter 2085 FF_uses_Electrostatics = .true.
474 gezelter 1634 endif
475    
476     call getMatchingElementList(atypes, "is_Charge", .true., &
477     nMatches, MatchList)
478     if (nMatches .gt. 0) then
479 gezelter 2085 FF_uses_Charges = .true.
480     FF_uses_Electrostatics = .true.
481 gezelter 1634 endif
482 chrisfen 2229
483 gezelter 1634 call getMatchingElementList(atypes, "is_Dipole", .true., &
484     nMatches, MatchList)
485     if (nMatches .gt. 0) then
486 gezelter 2085 FF_uses_Dipoles = .true.
487     FF_uses_Electrostatics = .true.
488 gezelter 1634 FF_uses_DirectionalAtoms = .true.
489     endif
490 gezelter 2085
491     call getMatchingElementList(atypes, "is_Quadrupole", .true., &
492     nMatches, MatchList)
493     if (nMatches .gt. 0) then
494     FF_uses_Quadrupoles = .true.
495     FF_uses_Electrostatics = .true.
496     FF_uses_DirectionalAtoms = .true.
497     endif
498 chrisfen 2229
499 gezelter 1610 call getMatchingElementList(atypes, "is_Sticky", .true., nMatches, &
500     MatchList)
501 gezelter 1634 if (nMatches .gt. 0) then
502     FF_uses_Sticky = .true.
503     FF_uses_DirectionalAtoms = .true.
504     endif
505 chrisfen 2229
506     call getMatchingElementList(atypes, "is_StickyPower", .true., nMatches, &
507     MatchList)
508     if (nMatches .gt. 0) then
509     FF_uses_StickyPower = .true.
510     FF_uses_DirectionalAtoms = .true.
511     endif
512 chrisfen 2220
513 gezelter 1634 call getMatchingElementList(atypes, "is_GayBerne", .true., &
514     nMatches, MatchList)
515     if (nMatches .gt. 0) then
516     FF_uses_GayBerne = .true.
517     FF_uses_DirectionalAtoms = .true.
518     endif
519 chrisfen 2229
520 gezelter 1610 call getMatchingElementList(atypes, "is_EAM", .true., nMatches, MatchList)
521     if (nMatches .gt. 0) FF_uses_EAM = .true.
522 chrisfen 2229
523 gezelter 1634 call getMatchingElementList(atypes, "is_Shape", .true., &
524     nMatches, MatchList)
525     if (nMatches .gt. 0) then
526     FF_uses_Shapes = .true.
527     FF_uses_DirectionalAtoms = .true.
528     endif
529    
530     call getMatchingElementList(atypes, "is_FLARB", .true., &
531     nMatches, MatchList)
532     if (nMatches .gt. 0) FF_uses_FLARB = .true.
533    
534 gezelter 1610 !! Assume sanity (for the sake of argument)
535     haveSaneForceField = .true.
536 chrisfen 2229
537 gezelter 1610 !! check to make sure the FF_uses_RF setting makes sense
538 chrisfen 2229
539 gezelter 1610 if (FF_uses_dipoles) then
540     if (FF_uses_RF) then
541     dielect = getDielect()
542     call initialize_rf(dielect)
543     endif
544     else
545     if (FF_uses_RF) then
546     write(default_error,*) 'Using Reaction Field with no dipoles? Huh?'
547     thisStat = -1
548     haveSaneForceField = .false.
549     return
550     endif
551 chrisfen 2229 endif
552 gezelter 1610
553 gezelter 1930 !sticky module does not contain check_sticky_FF anymore
554     !if (FF_uses_sticky) then
555     ! call check_sticky_FF(my_status)
556     ! if (my_status /= 0) then
557     ! thisStat = -1
558     ! haveSaneForceField = .false.
559     ! return
560     ! end if
561     !endif
562 gezelter 1610
563     if (FF_uses_EAM) then
564 chrisfen 2229 call init_EAM_FF(my_status)
565 gezelter 1610 if (my_status /= 0) then
566     write(default_error, *) "init_EAM_FF returned a bad status"
567     thisStat = -1
568     haveSaneForceField = .false.
569     return
570     end if
571     endif
572    
573 gezelter 1634 if (FF_uses_GayBerne) then
574 gezelter 1610 call check_gb_pair_FF(my_status)
575     if (my_status .ne. 0) then
576     thisStat = -1
577     haveSaneForceField = .false.
578     return
579     endif
580     endif
581    
582 gezelter 1634 if (FF_uses_GayBerne .and. FF_uses_LennardJones) then
583 gezelter 1610 endif
584 chrisfen 2229
585 gezelter 1610 if (.not. haveNeighborList) then
586     !! Create neighbor lists
587     call expandNeighborList(nLocal, my_status)
588     if (my_Status /= 0) then
589     write(default_error,*) "SimSetup: ExpandNeighborList returned error."
590     thisStat = -1
591     return
592     endif
593     haveNeighborList = .true.
594 chrisfen 2229 endif
595    
596 gezelter 1610 end subroutine init_FF
597    
598 chrisfen 2229
599 gezelter 1610 !! Does force loop over i,j pairs. Calls do_pair to calculates forces.
600     !------------------------------------------------------------->
601 gezelter 1930 subroutine do_force_loop(q, q_group, A, eFrame, f, t, tau, pot, &
602 gezelter 1610 do_pot_c, do_stress_c, error)
603     !! Position array provided by C, dimensioned by getNlocal
604     real ( kind = dp ), dimension(3, nLocal) :: q
605     !! molecular center-of-mass position array
606     real ( kind = dp ), dimension(3, nGroups) :: q_group
607     !! Rotation Matrix for each long range particle in simulation.
608     real( kind = dp), dimension(9, nLocal) :: A
609     !! Unit vectors for dipoles (lab frame)
610 gezelter 1930 real( kind = dp ), dimension(9,nLocal) :: eFrame
611 gezelter 1610 !! Force array provided by C, dimensioned by getNlocal
612     real ( kind = dp ), dimension(3,nLocal) :: f
613     !! Torsion array provided by C, dimensioned by getNlocal
614     real( kind = dp ), dimension(3,nLocal) :: t
615    
616     !! Stress Tensor
617     real( kind = dp), dimension(9) :: tau
618     real ( kind = dp ) :: pot
619     logical ( kind = 2) :: do_pot_c, do_stress_c
620     logical :: do_pot
621     logical :: do_stress
622     logical :: in_switching_region
623     #ifdef IS_MPI
624     real( kind = DP ) :: pot_local
625     integer :: nAtomsInRow
626     integer :: nAtomsInCol
627     integer :: nprocs
628     integer :: nGroupsInRow
629     integer :: nGroupsInCol
630     #endif
631     integer :: natoms
632     logical :: update_nlist
633     integer :: i, j, jstart, jend, jnab
634     integer :: istart, iend
635     integer :: ia, jb, atom1, atom2
636     integer :: nlist
637     real( kind = DP ) :: ratmsq, rgrpsq, rgrp, vpair, vij
638     real( kind = DP ) :: sw, dswdr, swderiv, mf
639     real(kind=dp),dimension(3) :: d_atm, d_grp, fpair, fij
640     real(kind=dp) :: rfpot, mu_i, virial
641     integer :: me_i, me_j, n_in_i, n_in_j
642     logical :: is_dp_i
643     integer :: neighborListSize
644     integer :: listerror, error
645     integer :: localError
646     integer :: propPack_i, propPack_j
647     integer :: loopStart, loopEnd, loop
648 chuckv 2262 integer :: iMap
649 gezelter 1610 real(kind=dp) :: listSkin = 1.0
650 chrisfen 2229
651 gezelter 1610 !! initialize local variables
652 chrisfen 2229
653 gezelter 1610 #ifdef IS_MPI
654     pot_local = 0.0_dp
655     nAtomsInRow = getNatomsInRow(plan_atom_row)
656     nAtomsInCol = getNatomsInCol(plan_atom_col)
657     nGroupsInRow = getNgroupsInRow(plan_group_row)
658     nGroupsInCol = getNgroupsInCol(plan_group_col)
659     #else
660     natoms = nlocal
661     #endif
662 chrisfen 2229
663 gezelter 1610 call doReadyCheck(localError)
664     if ( localError .ne. 0 ) then
665     call handleError("do_force_loop", "Not Initialized")
666     error = -1
667     return
668     end if
669     call zero_work_arrays()
670 chrisfen 2229
671 gezelter 1610 do_pot = do_pot_c
672     do_stress = do_stress_c
673 chrisfen 2229
674 gezelter 1610 ! Gather all information needed by all force loops:
675 chrisfen 2229
676 gezelter 1610 #ifdef IS_MPI
677 chrisfen 2229
678 gezelter 1610 call gather(q, q_Row, plan_atom_row_3d)
679     call gather(q, q_Col, plan_atom_col_3d)
680    
681     call gather(q_group, q_group_Row, plan_group_row_3d)
682     call gather(q_group, q_group_Col, plan_group_col_3d)
683 chrisfen 2229
684 gezelter 1634 if (FF_UsesDirectionalAtoms() .and. SIM_uses_DirectionalAtoms) then
685 gezelter 1930 call gather(eFrame, eFrame_Row, plan_atom_row_rotation)
686     call gather(eFrame, eFrame_Col, plan_atom_col_rotation)
687 chrisfen 2229
688 gezelter 1610 call gather(A, A_Row, plan_atom_row_rotation)
689     call gather(A, A_Col, plan_atom_col_rotation)
690     endif
691 chrisfen 2229
692 gezelter 1610 #endif
693 chrisfen 2229
694 gezelter 1610 !! Begin force loop timing:
695     #ifdef PROFILE
696     call cpu_time(forceTimeInitial)
697     nloops = nloops + 1
698     #endif
699 chrisfen 2229
700 gezelter 1610 loopEnd = PAIR_LOOP
701     if (FF_RequiresPrepairCalc() .and. SIM_requires_prepair_calc) then
702     loopStart = PREPAIR_LOOP
703     else
704     loopStart = PAIR_LOOP
705     endif
706    
707     do loop = loopStart, loopEnd
708    
709     ! See if we need to update neighbor lists
710     ! (but only on the first time through):
711     if (loop .eq. loopStart) then
712     #ifdef IS_MPI
713     call checkNeighborList(nGroupsInRow, q_group_row, listSkin, &
714 chrisfen 2229 update_nlist)
715 gezelter 1610 #else
716     call checkNeighborList(nGroups, q_group, listSkin, &
717 chrisfen 2229 update_nlist)
718 gezelter 1610 #endif
719     endif
720 chrisfen 2229
721 gezelter 1610 if (update_nlist) then
722     !! save current configuration and construct neighbor list
723     #ifdef IS_MPI
724     call saveNeighborList(nGroupsInRow, q_group_row)
725     #else
726     call saveNeighborList(nGroups, q_group)
727     #endif
728     neighborListSize = size(list)
729     nlist = 0
730     endif
731 chrisfen 2229
732 gezelter 1610 istart = 1
733     #ifdef IS_MPI
734     iend = nGroupsInRow
735     #else
736     iend = nGroups - 1
737     #endif
738     outer: do i = istart, iend
739    
740     if (update_nlist) point(i) = nlist + 1
741 chrisfen 2229
742 gezelter 1610 n_in_i = groupStartRow(i+1) - groupStartRow(i)
743 chrisfen 2229
744 gezelter 1610 if (update_nlist) then
745     #ifdef IS_MPI
746 chuckv 2266 me_i = atid_row(i)
747 gezelter 1610 jstart = 1
748     jend = nGroupsInCol
749     #else
750 chuckv 2266 me_i = atid(i)
751 gezelter 1610 jstart = i+1
752     jend = nGroups
753     #endif
754     else
755     jstart = point(i)
756     jend = point(i+1) - 1
757     ! make sure group i has neighbors
758     if (jstart .gt. jend) cycle outer
759     endif
760 chrisfen 2229
761 gezelter 1610 do jnab = jstart, jend
762     if (update_nlist) then
763     j = jnab
764     else
765     j = list(jnab)
766     endif
767    
768     #ifdef IS_MPI
769 chuckv 2266 me_j = atid_col(j)
770 gezelter 1610 call get_interatomic_vector(q_group_Row(:,i), &
771     q_group_Col(:,j), d_grp, rgrpsq)
772     #else
773 chuckv 2266 me_j = atid(j)
774 gezelter 1610 call get_interatomic_vector(q_group(:,i), &
775     q_group(:,j), d_grp, rgrpsq)
776     #endif
777    
778 chuckv 2262 if (rgrpsq < InteractionMap(me_i,me_j)%rListsq) then
779 gezelter 1610 if (update_nlist) then
780     nlist = nlist + 1
781 chrisfen 2229
782 gezelter 1610 if (nlist > neighborListSize) then
783     #ifdef IS_MPI
784     call expandNeighborList(nGroupsInRow, listerror)
785     #else
786     call expandNeighborList(nGroups, listerror)
787     #endif
788     if (listerror /= 0) then
789     error = -1
790     write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
791     return
792     end if
793     neighborListSize = size(list)
794     endif
795 chrisfen 2229
796 gezelter 1610 list(nlist) = j
797     endif
798 chrisfen 2229
799 gezelter 1610 if (loop .eq. PAIR_LOOP) then
800     vij = 0.0d0
801     fij(1:3) = 0.0d0
802     endif
803 chrisfen 2229
804 gezelter 1610 call get_switch(rgrpsq, sw, dswdr, rgrp, group_switch, &
805     in_switching_region)
806 chrisfen 2229
807 gezelter 1610 n_in_j = groupStartCol(j+1) - groupStartCol(j)
808 chrisfen 2229
809 gezelter 1610 do ia = groupStartRow(i), groupStartRow(i+1)-1
810 chrisfen 2229
811 gezelter 1610 atom1 = groupListRow(ia)
812 chrisfen 2229
813 gezelter 1610 inner: do jb = groupStartCol(j), groupStartCol(j+1)-1
814 chrisfen 2229
815 gezelter 1610 atom2 = groupListCol(jb)
816 chrisfen 2229
817 gezelter 1610 if (skipThisPair(atom1, atom2)) cycle inner
818    
819     if ((n_in_i .eq. 1).and.(n_in_j .eq. 1)) then
820     d_atm(1:3) = d_grp(1:3)
821     ratmsq = rgrpsq
822     else
823     #ifdef IS_MPI
824     call get_interatomic_vector(q_Row(:,atom1), &
825     q_Col(:,atom2), d_atm, ratmsq)
826     #else
827     call get_interatomic_vector(q(:,atom1), &
828     q(:,atom2), d_atm, ratmsq)
829     #endif
830     endif
831    
832     if (loop .eq. PREPAIR_LOOP) then
833     #ifdef IS_MPI
834     call do_prepair(atom1, atom2, ratmsq, d_atm, sw, &
835     rgrpsq, d_grp, do_pot, do_stress, &
836 gezelter 1930 eFrame, A, f, t, pot_local)
837 gezelter 1610 #else
838     call do_prepair(atom1, atom2, ratmsq, d_atm, sw, &
839     rgrpsq, d_grp, do_pot, do_stress, &
840 gezelter 1930 eFrame, A, f, t, pot)
841 gezelter 1610 #endif
842     else
843     #ifdef IS_MPI
844     call do_pair(atom1, atom2, ratmsq, d_atm, sw, &
845     do_pot, &
846 gezelter 1930 eFrame, A, f, t, pot_local, vpair, fpair)
847 gezelter 1610 #else
848     call do_pair(atom1, atom2, ratmsq, d_atm, sw, &
849     do_pot, &
850 gezelter 1930 eFrame, A, f, t, pot, vpair, fpair)
851 gezelter 1610 #endif
852    
853     vij = vij + vpair
854     fij(1:3) = fij(1:3) + fpair(1:3)
855     endif
856     enddo inner
857     enddo
858 chrisfen 2229
859 gezelter 1610 if (loop .eq. PAIR_LOOP) then
860     if (in_switching_region) then
861     swderiv = vij*dswdr/rgrp
862     fij(1) = fij(1) + swderiv*d_grp(1)
863     fij(2) = fij(2) + swderiv*d_grp(2)
864     fij(3) = fij(3) + swderiv*d_grp(3)
865 chrisfen 2229
866 gezelter 1610 do ia=groupStartRow(i), groupStartRow(i+1)-1
867     atom1=groupListRow(ia)
868     mf = mfactRow(atom1)
869     #ifdef IS_MPI
870     f_Row(1,atom1) = f_Row(1,atom1) + swderiv*d_grp(1)*mf
871     f_Row(2,atom1) = f_Row(2,atom1) + swderiv*d_grp(2)*mf
872     f_Row(3,atom1) = f_Row(3,atom1) + swderiv*d_grp(3)*mf
873     #else
874     f(1,atom1) = f(1,atom1) + swderiv*d_grp(1)*mf
875     f(2,atom1) = f(2,atom1) + swderiv*d_grp(2)*mf
876     f(3,atom1) = f(3,atom1) + swderiv*d_grp(3)*mf
877     #endif
878     enddo
879 chrisfen 2229
880 gezelter 1610 do jb=groupStartCol(j), groupStartCol(j+1)-1
881     atom2=groupListCol(jb)
882     mf = mfactCol(atom2)
883     #ifdef IS_MPI
884     f_Col(1,atom2) = f_Col(1,atom2) - swderiv*d_grp(1)*mf
885     f_Col(2,atom2) = f_Col(2,atom2) - swderiv*d_grp(2)*mf
886     f_Col(3,atom2) = f_Col(3,atom2) - swderiv*d_grp(3)*mf
887     #else
888     f(1,atom2) = f(1,atom2) - swderiv*d_grp(1)*mf
889     f(2,atom2) = f(2,atom2) - swderiv*d_grp(2)*mf
890     f(3,atom2) = f(3,atom2) - swderiv*d_grp(3)*mf
891     #endif
892     enddo
893     endif
894 chrisfen 2229
895 gezelter 1610 if (do_stress) call add_stress_tensor(d_grp, fij)
896     endif
897     end if
898     enddo
899     enddo outer
900 chrisfen 2229
901 gezelter 1610 if (update_nlist) then
902     #ifdef IS_MPI
903     point(nGroupsInRow + 1) = nlist + 1
904     #else
905     point(nGroups) = nlist + 1
906     #endif
907     if (loop .eq. PREPAIR_LOOP) then
908     ! we just did the neighbor list update on the first
909     ! pass, so we don't need to do it
910     ! again on the second pass
911     update_nlist = .false.
912     endif
913     endif
914 chrisfen 2229
915 gezelter 1610 if (loop .eq. PREPAIR_LOOP) then
916     call do_preforce(nlocal, pot)
917     endif
918 chrisfen 2229
919 gezelter 1610 enddo
920 chrisfen 2229
921 gezelter 1610 !! Do timing
922     #ifdef PROFILE
923     call cpu_time(forceTimeFinal)
924     forceTime = forceTime + forceTimeFinal - forceTimeInitial
925     #endif
926 chrisfen 2229
927 gezelter 1610 #ifdef IS_MPI
928     !!distribute forces
929 chrisfen 2229
930 gezelter 1610 f_temp = 0.0_dp
931     call scatter(f_Row,f_temp,plan_atom_row_3d)
932     do i = 1,nlocal
933     f(1:3,i) = f(1:3,i) + f_temp(1:3,i)
934     end do
935 chrisfen 2229
936 gezelter 1610 f_temp = 0.0_dp
937     call scatter(f_Col,f_temp,plan_atom_col_3d)
938     do i = 1,nlocal
939     f(1:3,i) = f(1:3,i) + f_temp(1:3,i)
940     end do
941 chrisfen 2229
942 gezelter 1634 if (FF_UsesDirectionalAtoms() .and. SIM_uses_DirectionalAtoms) then
943 gezelter 1610 t_temp = 0.0_dp
944     call scatter(t_Row,t_temp,plan_atom_row_3d)
945     do i = 1,nlocal
946     t(1:3,i) = t(1:3,i) + t_temp(1:3,i)
947     end do
948     t_temp = 0.0_dp
949     call scatter(t_Col,t_temp,plan_atom_col_3d)
950 chrisfen 2229
951 gezelter 1610 do i = 1,nlocal
952     t(1:3,i) = t(1:3,i) + t_temp(1:3,i)
953     end do
954     endif
955 chrisfen 2229
956 gezelter 1610 if (do_pot) then
957     ! scatter/gather pot_row into the members of my column
958     call scatter(pot_Row, pot_Temp, plan_atom_row)
959 chrisfen 2229
960 gezelter 1610 ! scatter/gather pot_local into all other procs
961     ! add resultant to get total pot
962     do i = 1, nlocal
963     pot_local = pot_local + pot_Temp(i)
964     enddo
965 chrisfen 2229
966 gezelter 1610 pot_Temp = 0.0_DP
967 chrisfen 2229
968 gezelter 1610 call scatter(pot_Col, pot_Temp, plan_atom_col)
969     do i = 1, nlocal
970     pot_local = pot_local + pot_Temp(i)
971     enddo
972 chrisfen 2229
973 gezelter 1610 endif
974     #endif
975 chrisfen 2229
976 gezelter 1610 if (FF_RequiresPostpairCalc() .and. SIM_requires_postpair_calc) then
977 chrisfen 2229
978 gezelter 1610 if (FF_uses_RF .and. SIM_uses_RF) then
979 chrisfen 2229
980 gezelter 1610 #ifdef IS_MPI
981     call scatter(rf_Row,rf,plan_atom_row_3d)
982     call scatter(rf_Col,rf_Temp,plan_atom_col_3d)
983     do i = 1,nlocal
984     rf(1:3,i) = rf(1:3,i) + rf_Temp(1:3,i)
985     end do
986     #endif
987 chrisfen 2229
988 gezelter 1610 do i = 1, nLocal
989 chrisfen 2229
990 gezelter 1610 rfpot = 0.0_DP
991     #ifdef IS_MPI
992     me_i = atid_row(i)
993     #else
994     me_i = atid(i)
995     #endif
996 gezelter 2261 iMap = InteractionMap(me_i, me_j)%InteractionHash
997    
998     if ( iand(iMap, ELECTROSTATIC_PAIR).ne.0 ) then
999 chrisfen 2229
1000 gezelter 1634 mu_i = getDipoleMoment(me_i)
1001 chrisfen 2229
1002 gezelter 1610 !! The reaction field needs to include a self contribution
1003     !! to the field:
1004 gezelter 1930 call accumulate_self_rf(i, mu_i, eFrame)
1005 gezelter 1610 !! Get the reaction field contribution to the
1006     !! potential and torques:
1007 gezelter 1930 call reaction_field_final(i, mu_i, eFrame, rfpot, t, do_pot)
1008 gezelter 1610 #ifdef IS_MPI
1009     pot_local = pot_local + rfpot
1010     #else
1011     pot = pot + rfpot
1012 chrisfen 2229
1013 gezelter 1610 #endif
1014 chrisfen 2229 endif
1015 gezelter 1610 enddo
1016     endif
1017     endif
1018 chrisfen 2229
1019    
1020 gezelter 1610 #ifdef IS_MPI
1021 chrisfen 2229
1022 gezelter 1610 if (do_pot) then
1023     pot = pot + pot_local
1024     !! we assume the c code will do the allreduce to get the total potential
1025     !! we could do it right here if we needed to...
1026     endif
1027 chrisfen 2229
1028 gezelter 1610 if (do_stress) then
1029     call mpi_allreduce(tau_Temp, tau, 9,mpi_double_precision,mpi_sum, &
1030     mpi_comm_world,mpi_err)
1031     call mpi_allreduce(virial_Temp, virial,1,mpi_double_precision,mpi_sum, &
1032     mpi_comm_world,mpi_err)
1033     endif
1034 chrisfen 2229
1035 gezelter 1610 #else
1036 chrisfen 2229
1037 gezelter 1610 if (do_stress) then
1038     tau = tau_Temp
1039     virial = virial_Temp
1040     endif
1041 chrisfen 2229
1042 gezelter 1610 #endif
1043 chrisfen 2229
1044 gezelter 1610 end subroutine do_force_loop
1045 chrisfen 2229
1046 gezelter 1610 subroutine do_pair(i, j, rijsq, d, sw, do_pot, &
1047 gezelter 1930 eFrame, A, f, t, pot, vpair, fpair)
1048 gezelter 1610
1049     real( kind = dp ) :: pot, vpair, sw
1050     real( kind = dp ), dimension(3) :: fpair
1051     real( kind = dp ), dimension(nLocal) :: mfact
1052 gezelter 1930 real( kind = dp ), dimension(9,nLocal) :: eFrame
1053 gezelter 1610 real( kind = dp ), dimension(9,nLocal) :: A
1054     real( kind = dp ), dimension(3,nLocal) :: f
1055     real( kind = dp ), dimension(3,nLocal) :: t
1056    
1057     logical, intent(inout) :: do_pot
1058     integer, intent(in) :: i, j
1059     real ( kind = dp ), intent(inout) :: rijsq
1060     real ( kind = dp ) :: r
1061     real ( kind = dp ), intent(inout) :: d(3)
1062 chrisfen 2231 real ( kind = dp ) :: ebalance
1063 gezelter 1610 integer :: me_i, me_j
1064    
1065 gezelter 2259 integer :: iMap
1066    
1067 gezelter 1610 r = sqrt(rijsq)
1068     vpair = 0.0d0
1069     fpair(1:3) = 0.0d0
1070    
1071     #ifdef IS_MPI
1072     me_i = atid_row(i)
1073     me_j = atid_col(j)
1074     #else
1075     me_i = atid(i)
1076     me_j = atid(j)
1077     #endif
1078 gezelter 1706
1079 gezelter 2259 iMap = InteractionMap(me_i, me_j)%InteractionHash
1080 chrisfen 2229
1081 gezelter 2259 if ( iand(iMap, LJ_PAIR).ne.0 ) then
1082     call do_lj_pair(i, j, d, r, rijsq, sw, vpair, fpair, pot, f, do_pot)
1083 gezelter 1610 endif
1084 chrisfen 2229
1085 gezelter 2259 if ( iand(iMap, ELECTROSTATIC_PAIR).ne.0 ) then
1086     call doElectrostaticPair(i, j, d, r, rijsq, sw, vpair, fpair, &
1087     pot, eFrame, f, t, do_pot)
1088 chrisfen 2229
1089 gezelter 2261 if (FF_uses_RF .and. SIM_uses_RF) then
1090    
1091     ! CHECK ME (RF needs to know about all electrostatic types)
1092     call accumulate_rf(i, j, r, eFrame, sw)
1093     call rf_correct_forces(i, j, d, r, eFrame, sw, f, fpair)
1094 gezelter 1610 endif
1095 gezelter 2261
1096 gezelter 1610 endif
1097    
1098 gezelter 2259 if ( iand(iMap, STICKY_PAIR).ne.0 ) then
1099     call do_sticky_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1100     pot, A, f, t, do_pot)
1101     endif
1102 gezelter 2085
1103 gezelter 2259 if ( iand(iMap, STICKYPOWER_PAIR).ne.0 ) then
1104     call do_sticky_power_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1105     pot, A, f, t, do_pot)
1106 gezelter 1610 endif
1107    
1108 gezelter 2259 if ( iand(iMap, GAYBERNE_PAIR).ne.0 ) then
1109     call do_gb_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1110     pot, A, f, t, do_pot)
1111 chrisfen 2229 endif
1112    
1113 gezelter 2259 if ( iand(iMap, GAYBERNE_LJ).ne.0 ) then
1114 chuckv 2262 ! call do_gblj_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1115     ! pot, A, f, t, do_pot)
1116 gezelter 2259 endif
1117 kdaily 2226
1118 gezelter 2259 if ( iand(iMap, EAM_PAIR).ne.0 ) then
1119     call do_eam_pair(i, j, d, r, rijsq, sw, vpair, fpair, pot, f, &
1120     do_pot)
1121 gezelter 1610 endif
1122 chrisfen 2229
1123 gezelter 2259 if ( iand(iMap, SHAPE_PAIR).ne.0 ) then
1124     call do_shape_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1125     pot, A, f, t, do_pot)
1126 gezelter 1610 endif
1127 gezelter 1634
1128 gezelter 2259 if ( iand(iMap, SHAPE_LJ).ne.0 ) then
1129     call do_shape_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1130     pot, A, f, t, do_pot)
1131 gezelter 1634 endif
1132 gezelter 2259
1133 gezelter 1610 end subroutine do_pair
1134    
1135     subroutine do_prepair(i, j, rijsq, d, sw, rcijsq, dc, &
1136 gezelter 1930 do_pot, do_stress, eFrame, A, f, t, pot)
1137 gezelter 1610
1138 chrisfen 2229 real( kind = dp ) :: pot, sw
1139     real( kind = dp ), dimension(9,nLocal) :: eFrame
1140     real (kind=dp), dimension(9,nLocal) :: A
1141     real (kind=dp), dimension(3,nLocal) :: f
1142     real (kind=dp), dimension(3,nLocal) :: t
1143 gezelter 1610
1144 chrisfen 2229 logical, intent(inout) :: do_pot, do_stress
1145     integer, intent(in) :: i, j
1146     real ( kind = dp ), intent(inout) :: rijsq, rcijsq
1147     real ( kind = dp ) :: r, rc
1148     real ( kind = dp ), intent(inout) :: d(3), dc(3)
1149    
1150 gezelter 2259 integer :: me_i, me_j, iMap
1151 chrisfen 2229
1152 gezelter 1610 #ifdef IS_MPI
1153 chrisfen 2229 me_i = atid_row(i)
1154     me_j = atid_col(j)
1155 gezelter 1610 #else
1156 chrisfen 2229 me_i = atid(i)
1157     me_j = atid(j)
1158 gezelter 1610 #endif
1159 chrisfen 2229
1160 gezelter 2259 iMap = InteractionMap(me_i, me_j)%InteractionHash
1161 chrisfen 2229
1162 gezelter 2259 if ( iand(iMap, EAM_PAIR).ne.0 ) then
1163 chrisfen 2229 call calc_EAM_prepair_rho(i, j, d, r, rijsq )
1164     endif
1165 gezelter 2259
1166 chrisfen 2229 end subroutine do_prepair
1167    
1168    
1169     subroutine do_preforce(nlocal,pot)
1170     integer :: nlocal
1171     real( kind = dp ) :: pot
1172    
1173     if (FF_uses_EAM .and. SIM_uses_EAM) then
1174     call calc_EAM_preforce_Frho(nlocal,pot)
1175     endif
1176    
1177    
1178     end subroutine do_preforce
1179    
1180    
1181     subroutine get_interatomic_vector(q_i, q_j, d, r_sq)
1182    
1183     real (kind = dp), dimension(3) :: q_i
1184     real (kind = dp), dimension(3) :: q_j
1185     real ( kind = dp ), intent(out) :: r_sq
1186     real( kind = dp ) :: d(3), scaled(3)
1187     integer i
1188    
1189     d(1:3) = q_j(1:3) - q_i(1:3)
1190    
1191     ! Wrap back into periodic box if necessary
1192     if ( SIM_uses_PBC ) then
1193    
1194     if( .not.boxIsOrthorhombic ) then
1195     ! calc the scaled coordinates.
1196    
1197     scaled = matmul(HmatInv, d)
1198    
1199     ! wrap the scaled coordinates
1200    
1201     scaled = scaled - anint(scaled)
1202    
1203    
1204     ! calc the wrapped real coordinates from the wrapped scaled
1205     ! coordinates
1206    
1207     d = matmul(Hmat,scaled)
1208    
1209     else
1210     ! calc the scaled coordinates.
1211    
1212     do i = 1, 3
1213     scaled(i) = d(i) * HmatInv(i,i)
1214    
1215     ! wrap the scaled coordinates
1216    
1217     scaled(i) = scaled(i) - anint(scaled(i))
1218    
1219     ! calc the wrapped real coordinates from the wrapped scaled
1220     ! coordinates
1221    
1222     d(i) = scaled(i)*Hmat(i,i)
1223     enddo
1224     endif
1225    
1226     endif
1227    
1228     r_sq = dot_product(d,d)
1229    
1230     end subroutine get_interatomic_vector
1231    
1232     subroutine zero_work_arrays()
1233    
1234 gezelter 1610 #ifdef IS_MPI
1235    
1236 chrisfen 2229 q_Row = 0.0_dp
1237     q_Col = 0.0_dp
1238    
1239     q_group_Row = 0.0_dp
1240     q_group_Col = 0.0_dp
1241    
1242     eFrame_Row = 0.0_dp
1243     eFrame_Col = 0.0_dp
1244    
1245     A_Row = 0.0_dp
1246     A_Col = 0.0_dp
1247    
1248     f_Row = 0.0_dp
1249     f_Col = 0.0_dp
1250     f_Temp = 0.0_dp
1251    
1252     t_Row = 0.0_dp
1253     t_Col = 0.0_dp
1254     t_Temp = 0.0_dp
1255    
1256     pot_Row = 0.0_dp
1257     pot_Col = 0.0_dp
1258     pot_Temp = 0.0_dp
1259    
1260     rf_Row = 0.0_dp
1261     rf_Col = 0.0_dp
1262     rf_Temp = 0.0_dp
1263    
1264 gezelter 1610 #endif
1265 chrisfen 2229
1266     if (FF_uses_EAM .and. SIM_uses_EAM) then
1267     call clean_EAM()
1268     endif
1269    
1270     rf = 0.0_dp
1271     tau_Temp = 0.0_dp
1272     virial_Temp = 0.0_dp
1273     end subroutine zero_work_arrays
1274    
1275     function skipThisPair(atom1, atom2) result(skip_it)
1276     integer, intent(in) :: atom1
1277     integer, intent(in), optional :: atom2
1278     logical :: skip_it
1279     integer :: unique_id_1, unique_id_2
1280     integer :: me_i,me_j
1281     integer :: i
1282    
1283     skip_it = .false.
1284    
1285     !! there are a number of reasons to skip a pair or a particle
1286     !! mostly we do this to exclude atoms who are involved in short
1287     !! range interactions (bonds, bends, torsions), but we also need
1288     !! to exclude some overcounted interactions that result from
1289     !! the parallel decomposition
1290    
1291 gezelter 1610 #ifdef IS_MPI
1292 chrisfen 2229 !! in MPI, we have to look up the unique IDs for each atom
1293     unique_id_1 = AtomRowToGlobal(atom1)
1294 gezelter 1610 #else
1295 chrisfen 2229 !! in the normal loop, the atom numbers are unique
1296     unique_id_1 = atom1
1297 gezelter 1610 #endif
1298 chrisfen 2229
1299     !! We were called with only one atom, so just check the global exclude
1300     !! list for this atom
1301     if (.not. present(atom2)) then
1302     do i = 1, nExcludes_global
1303     if (excludesGlobal(i) == unique_id_1) then
1304     skip_it = .true.
1305     return
1306     end if
1307     end do
1308     return
1309     end if
1310    
1311 gezelter 1610 #ifdef IS_MPI
1312 chrisfen 2229 unique_id_2 = AtomColToGlobal(atom2)
1313 gezelter 1610 #else
1314 chrisfen 2229 unique_id_2 = atom2
1315 gezelter 1610 #endif
1316 chrisfen 2229
1317 gezelter 1610 #ifdef IS_MPI
1318 chrisfen 2229 !! this situation should only arise in MPI simulations
1319     if (unique_id_1 == unique_id_2) then
1320     skip_it = .true.
1321     return
1322     end if
1323    
1324     !! this prevents us from doing the pair on multiple processors
1325     if (unique_id_1 < unique_id_2) then
1326     if (mod(unique_id_1 + unique_id_2,2) == 0) then
1327     skip_it = .true.
1328     return
1329     endif
1330     else
1331     if (mod(unique_id_1 + unique_id_2,2) == 1) then
1332     skip_it = .true.
1333     return
1334     endif
1335     endif
1336 gezelter 1610 #endif
1337 chrisfen 2229
1338     !! the rest of these situations can happen in all simulations:
1339     do i = 1, nExcludes_global
1340     if ((excludesGlobal(i) == unique_id_1) .or. &
1341     (excludesGlobal(i) == unique_id_2)) then
1342     skip_it = .true.
1343     return
1344     endif
1345     enddo
1346    
1347     do i = 1, nSkipsForAtom(atom1)
1348     if (skipsForAtom(atom1, i) .eq. unique_id_2) then
1349     skip_it = .true.
1350     return
1351     endif
1352     end do
1353    
1354     return
1355     end function skipThisPair
1356    
1357     function FF_UsesDirectionalAtoms() result(doesit)
1358     logical :: doesit
1359     doesit = FF_uses_DirectionalAtoms .or. FF_uses_Dipoles .or. &
1360     FF_uses_Quadrupoles .or. FF_uses_Sticky .or. &
1361     FF_uses_StickyPower .or. FF_uses_GayBerne .or. FF_uses_Shapes
1362     end function FF_UsesDirectionalAtoms
1363    
1364     function FF_RequiresPrepairCalc() result(doesit)
1365     logical :: doesit
1366     doesit = FF_uses_EAM
1367     end function FF_RequiresPrepairCalc
1368    
1369     function FF_RequiresPostpairCalc() result(doesit)
1370     logical :: doesit
1371     doesit = FF_uses_RF
1372     end function FF_RequiresPostpairCalc
1373    
1374 gezelter 1610 #ifdef PROFILE
1375 chrisfen 2229 function getforcetime() result(totalforcetime)
1376     real(kind=dp) :: totalforcetime
1377     totalforcetime = forcetime
1378     end function getforcetime
1379 gezelter 1610 #endif
1380    
1381 chrisfen 2229 !! This cleans componets of force arrays belonging only to fortran
1382    
1383     subroutine add_stress_tensor(dpair, fpair)
1384    
1385     real( kind = dp ), dimension(3), intent(in) :: dpair, fpair
1386    
1387     ! because the d vector is the rj - ri vector, and
1388     ! because fx, fy, fz are the force on atom i, we need a
1389     ! negative sign here:
1390    
1391     tau_Temp(1) = tau_Temp(1) - dpair(1) * fpair(1)
1392     tau_Temp(2) = tau_Temp(2) - dpair(1) * fpair(2)
1393     tau_Temp(3) = tau_Temp(3) - dpair(1) * fpair(3)
1394     tau_Temp(4) = tau_Temp(4) - dpair(2) * fpair(1)
1395     tau_Temp(5) = tau_Temp(5) - dpair(2) * fpair(2)
1396     tau_Temp(6) = tau_Temp(6) - dpair(2) * fpair(3)
1397     tau_Temp(7) = tau_Temp(7) - dpair(3) * fpair(1)
1398     tau_Temp(8) = tau_Temp(8) - dpair(3) * fpair(2)
1399     tau_Temp(9) = tau_Temp(9) - dpair(3) * fpair(3)
1400    
1401     virial_Temp = virial_Temp + &
1402     (tau_Temp(1) + tau_Temp(5) + tau_Temp(9))
1403    
1404     end subroutine add_stress_tensor
1405    
1406 gezelter 1610 end module doForces