ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/UseTheForce/doForces.F90
Revision: 2262
Committed: Sun Jul 3 20:53:43 2005 UTC (19 years ago) by chuckv
File size: 41596 byte(s)
Log Message:
Added subroutine to set cuttoff for Interaction map and function in simulation.F90 to determine if a particular atype is present in a simulation.

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