ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/UseTheForce/doForces.F90
Revision: 567
Committed: Thu Jul 28 22:12:45 2005 UTC (19 years, 9 months ago) by chuckv
Original Path: trunk/src/UseTheForce/doForces.F90
File size: 42028 byte(s)
Log Message:
Changed cutoffs... Segfaults nicely now...

File Contents

# User Rev Content
1 gezelter 246 !!
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 117 !! doForces.F90
43     !! module doForces
44     !! Calculates Long Range forces.
45    
46     !! @author Charles F. Vardeman II
47     !! @author Matthew Meineke
48 chuckv 567 !! @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 117
50 gezelter 246
51 gezelter 117 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 246 use sticky
60 gezelter 401 use electrostatic_module
61 gezelter 117 use reaction_field
62     use gb_pair
63 chrisfen 143 use shapes
64 gezelter 117 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 560 #include "UseTheForce/DarkSide/fInteractionMap.h"
77 gezelter 117
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 563 logical, save :: haveInteractionMap = .false.
86 chrisfen 532
87 gezelter 141 logical, save :: FF_uses_DirectionalAtoms
88     logical, save :: FF_uses_LennardJones
89 gezelter 401 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 532 logical, save :: FF_uses_Sticky
94     logical, save :: FF_uses_StickyPower
95 gezelter 141 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 117 logical, save :: FF_uses_RF
100 gezelter 141
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 401 logical, save :: SIM_uses_Quadrupoles
107 gezelter 141 logical, save :: SIM_uses_Sticky
108 chrisfen 532 logical, save :: SIM_uses_StickyPower
109 gezelter 141 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 117 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 561 !!!GO AWAY---------
120     !!!!!real(kind=dp), save :: rlist, rlistsq
121 gezelter 117
122     public :: init_FF
123     public :: do_force_loop
124 chuckv 561 ! public :: setRlistDF
125 chuckv 563 !public :: addInteraction
126     !public :: setInteractionHash
127     !public :: getInteractionHash
128     public :: createInteractionMap
129     public :: createRcuts
130 gezelter 117
131     #ifdef PROFILE
132     public :: getforcetime
133     real, save :: forceTime = 0
134     real :: forceTimeInitial, forceTimeFinal
135     integer :: nLoops
136     #endif
137    
138 chuckv 561 type, public :: Interaction
139     integer :: InteractionHash
140 chuckv 563 real(kind=dp) :: rList = 0.0_dp
141     real(kind=dp) :: rListSq = 0.0_dp
142 chuckv 561 end type Interaction
143    
144 gezelter 562 type(Interaction), dimension(:,:),allocatable :: InteractionMap
145 chuckv 561
146 chuckv 563
147 gezelter 562
148 gezelter 117 contains
149    
150 chuckv 561
151     subroutine createInteractionMap(status)
152     integer :: nAtypes
153 chuckv 567 integer, intent(out) :: status
154 chuckv 561 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 567 status = 0
175 chuckv 561
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 532
189 chuckv 561 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 117
202 chuckv 561 do j = i, nAtypes
203 chrisfen 532
204 chuckv 561 iHash = 0
205     myRcut = 0.0_dp
206 gezelter 117
207 chuckv 561 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 117
215 chuckv 561 if (i_is_LJ .and. j_is_LJ) then
216 gezelter 562 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 561
227 gezelter 562 if (i_is_StickyP .and. j_is_StickyP) then
228     iHash = ior(iHash, STICKYPOWER_PAIR)
229     endif
230 chuckv 561
231 gezelter 562 if (i_is_EAM .and. j_is_EAM) then
232     iHash = ior(iHash, EAM_PAIR)
233 chuckv 561 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 563 ! 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 567 subroutine createRcuts(defaultRList,stat)
254 chuckv 563 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 567 integer, intent(out) :: stat
260 chuckv 563 integer :: nAtypes
261 chuckv 567 integer :: myStatus
262 chuckv 561
263 chuckv 567 stat = 0
264     if (.not. haveInteractionMap) then
265 chuckv 561
266 chuckv 567 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 563 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 561 !!! 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 117
354     subroutine setSimVariables()
355 gezelter 141 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 532 SIM_uses_StickyPower = SimUsesStickyPower()
362 gezelter 141 SIM_uses_GayBerne = SimUsesGayBerne()
363     SIM_uses_EAM = SimUsesEAM()
364     SIM_uses_Shapes = SimUsesShapes()
365     SIM_uses_FLARB = SimUsesFLARB()
366 gezelter 117 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 532
383 gezelter 562 if (.not. haveInteractionMap) then
384 gezelter 117
385     myStatus = 0
386    
387 gezelter 562 call createInteractionMap(myStatus)
388 gezelter 117
389     if (myStatus .ne. 0) then
390 gezelter 562 write(default_error, *) 'createInteractionMap failed in doForces!'
391 gezelter 117 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 532
429 gezelter 135 subroutine init_FF(use_RF_c, thisStat)
430 gezelter 117
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 532
444 gezelter 117 !! 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 532
450 gezelter 141 FF_uses_DirectionalAtoms = .false.
451     FF_uses_LennardJones = .false.
452 gezelter 401 FF_uses_Electrostatics = .false.
453 gezelter 141 FF_uses_Charges = .false.
454     FF_uses_Dipoles = .false.
455     FF_uses_Sticky = .false.
456 chrisfen 532 FF_uses_StickyPower = .false.
457 gezelter 141 FF_uses_GayBerne = .false.
458 gezelter 117 FF_uses_EAM = .false.
459 gezelter 141 FF_uses_Shapes = .false.
460     FF_uses_FLARB = .false.
461 chrisfen 532
462 gezelter 141 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 532
470 gezelter 141 call getMatchingElementList(atypes, "is_Electrostatic", .true., &
471     nMatches, MatchList)
472     if (nMatches .gt. 0) then
473 gezelter 401 FF_uses_Electrostatics = .true.
474 gezelter 141 endif
475    
476     call getMatchingElementList(atypes, "is_Charge", .true., &
477     nMatches, MatchList)
478     if (nMatches .gt. 0) then
479 gezelter 401 FF_uses_Charges = .true.
480     FF_uses_Electrostatics = .true.
481 gezelter 141 endif
482 chrisfen 532
483 gezelter 141 call getMatchingElementList(atypes, "is_Dipole", .true., &
484     nMatches, MatchList)
485     if (nMatches .gt. 0) then
486 gezelter 401 FF_uses_Dipoles = .true.
487     FF_uses_Electrostatics = .true.
488 gezelter 141 FF_uses_DirectionalAtoms = .true.
489     endif
490 gezelter 401
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 532
499 gezelter 117 call getMatchingElementList(atypes, "is_Sticky", .true., nMatches, &
500     MatchList)
501 gezelter 141 if (nMatches .gt. 0) then
502     FF_uses_Sticky = .true.
503     FF_uses_DirectionalAtoms = .true.
504     endif
505 chrisfen 532
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 523
513 gezelter 141 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 532
520 gezelter 117 call getMatchingElementList(atypes, "is_EAM", .true., nMatches, MatchList)
521     if (nMatches .gt. 0) FF_uses_EAM = .true.
522 chrisfen 532
523 gezelter 141 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 117 !! Assume sanity (for the sake of argument)
535     haveSaneForceField = .true.
536 chrisfen 532
537 gezelter 117 !! check to make sure the FF_uses_RF setting makes sense
538 chrisfen 532
539 gezelter 117 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 532 endif
552 gezelter 117
553 gezelter 246 !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 117
563     if (FF_uses_EAM) then
564 chrisfen 532 call init_EAM_FF(my_status)
565 gezelter 117 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 141 if (FF_uses_GayBerne) then
574 gezelter 117 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 141 if (FF_uses_GayBerne .and. FF_uses_LennardJones) then
583 gezelter 117 endif
584 chrisfen 532
585 gezelter 117 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 532 endif
595    
596 gezelter 117 end subroutine init_FF
597    
598 chrisfen 532
599 gezelter 117 !! Does force loop over i,j pairs. Calls do_pair to calculates forces.
600     !------------------------------------------------------------->
601 gezelter 246 subroutine do_force_loop(q, q_group, A, eFrame, f, t, tau, pot, &
602 gezelter 117 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 246 real( kind = dp ), dimension(9,nLocal) :: eFrame
611 gezelter 117 !! 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 563 integer :: iMap
649 gezelter 117 real(kind=dp) :: listSkin = 1.0
650 chrisfen 532
651 gezelter 117 !! initialize local variables
652 chrisfen 532
653 gezelter 117 #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 532
663 gezelter 117 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 532
671 gezelter 117 do_pot = do_pot_c
672     do_stress = do_stress_c
673 chrisfen 532
674 gezelter 117 ! Gather all information needed by all force loops:
675 chrisfen 532
676 gezelter 117 #ifdef IS_MPI
677 chrisfen 532
678 gezelter 117 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 532
684 gezelter 141 if (FF_UsesDirectionalAtoms() .and. SIM_uses_DirectionalAtoms) then
685 gezelter 246 call gather(eFrame, eFrame_Row, plan_atom_row_rotation)
686     call gather(eFrame, eFrame_Col, plan_atom_col_rotation)
687 chrisfen 532
688 gezelter 117 call gather(A, A_Row, plan_atom_row_rotation)
689     call gather(A, A_Col, plan_atom_col_rotation)
690     endif
691 chrisfen 532
692 gezelter 117 #endif
693 chrisfen 532
694 gezelter 117 !! Begin force loop timing:
695     #ifdef PROFILE
696     call cpu_time(forceTimeInitial)
697     nloops = nloops + 1
698     #endif
699 chrisfen 532
700 gezelter 117 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 532 update_nlist)
715 gezelter 117 #else
716     call checkNeighborList(nGroups, q_group, listSkin, &
717 chrisfen 532 update_nlist)
718 gezelter 117 #endif
719     endif
720 chrisfen 532
721 gezelter 117 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 532
732 gezelter 117 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 532
742 gezelter 117 n_in_i = groupStartRow(i+1) - groupStartRow(i)
743 chrisfen 532
744 gezelter 117 if (update_nlist) then
745     #ifdef IS_MPI
746 chuckv 567 me_i = atid_row(i)
747 gezelter 117 jstart = 1
748     jend = nGroupsInCol
749     #else
750 chuckv 567 me_i = atid(i)
751 gezelter 117 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 532
761 gezelter 117 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 567 me_j = atid_col(j)
770 gezelter 117 call get_interatomic_vector(q_group_Row(:,i), &
771     q_group_Col(:,j), d_grp, rgrpsq)
772     #else
773 chuckv 567 me_j = atid(j)
774 gezelter 117 call get_interatomic_vector(q_group(:,i), &
775     q_group(:,j), d_grp, rgrpsq)
776     #endif
777    
778 chuckv 563 if (rgrpsq < InteractionMap(me_i,me_j)%rListsq) then
779 gezelter 117 if (update_nlist) then
780     nlist = nlist + 1
781 chrisfen 532
782 gezelter 117 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 532
796 gezelter 117 list(nlist) = j
797     endif
798 chrisfen 532
799 gezelter 117 if (loop .eq. PAIR_LOOP) then
800     vij = 0.0d0
801     fij(1:3) = 0.0d0
802     endif
803 chrisfen 532
804 gezelter 117 call get_switch(rgrpsq, sw, dswdr, rgrp, group_switch, &
805     in_switching_region)
806 chrisfen 532
807 gezelter 117 n_in_j = groupStartCol(j+1) - groupStartCol(j)
808 chrisfen 532
809 gezelter 117 do ia = groupStartRow(i), groupStartRow(i+1)-1
810 chrisfen 532
811 gezelter 117 atom1 = groupListRow(ia)
812 chrisfen 532
813 gezelter 117 inner: do jb = groupStartCol(j), groupStartCol(j+1)-1
814 chrisfen 532
815 gezelter 117 atom2 = groupListCol(jb)
816 chrisfen 532
817 gezelter 117 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 246 eFrame, A, f, t, pot_local)
837 gezelter 117 #else
838     call do_prepair(atom1, atom2, ratmsq, d_atm, sw, &
839     rgrpsq, d_grp, do_pot, do_stress, &
840 gezelter 246 eFrame, A, f, t, pot)
841 gezelter 117 #endif
842     else
843     #ifdef IS_MPI
844     call do_pair(atom1, atom2, ratmsq, d_atm, sw, &
845     do_pot, &
846 gezelter 246 eFrame, A, f, t, pot_local, vpair, fpair)
847 gezelter 117 #else
848     call do_pair(atom1, atom2, ratmsq, d_atm, sw, &
849     do_pot, &
850 gezelter 246 eFrame, A, f, t, pot, vpair, fpair)
851 gezelter 117 #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 532
859 gezelter 117 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 532
866 gezelter 117 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 532
880 gezelter 117 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 532
895 gezelter 117 if (do_stress) call add_stress_tensor(d_grp, fij)
896     endif
897     end if
898     enddo
899     enddo outer
900 chrisfen 532
901 gezelter 117 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 532
915 gezelter 117 if (loop .eq. PREPAIR_LOOP) then
916     call do_preforce(nlocal, pot)
917     endif
918 chrisfen 532
919 gezelter 117 enddo
920 chrisfen 532
921 gezelter 117 !! Do timing
922     #ifdef PROFILE
923     call cpu_time(forceTimeFinal)
924     forceTime = forceTime + forceTimeFinal - forceTimeInitial
925     #endif
926 chrisfen 532
927 gezelter 117 #ifdef IS_MPI
928     !!distribute forces
929 chrisfen 532
930 gezelter 117 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 532
936 gezelter 117 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 532
942 gezelter 141 if (FF_UsesDirectionalAtoms() .and. SIM_uses_DirectionalAtoms) then
943 gezelter 117 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 532
951 gezelter 117 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 532
956 gezelter 117 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 532
960 gezelter 117 ! 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 532
966 gezelter 117 pot_Temp = 0.0_DP
967 chrisfen 532
968 gezelter 117 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 532
973 gezelter 117 endif
974     #endif
975 chrisfen 532
976 gezelter 117 if (FF_RequiresPostpairCalc() .and. SIM_requires_postpair_calc) then
977 chrisfen 532
978 gezelter 117 if (FF_uses_RF .and. SIM_uses_RF) then
979 chrisfen 532
980 gezelter 117 #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 532
988 gezelter 117 do i = 1, nLocal
989 chrisfen 532
990 gezelter 117 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 562 iMap = InteractionMap(me_i, me_j)%InteractionHash
997    
998     if ( iand(iMap, ELECTROSTATIC_PAIR).ne.0 ) then
999 chrisfen 532
1000 gezelter 141 mu_i = getDipoleMoment(me_i)
1001 chrisfen 532
1002 gezelter 117 !! The reaction field needs to include a self contribution
1003     !! to the field:
1004 gezelter 246 call accumulate_self_rf(i, mu_i, eFrame)
1005 gezelter 117 !! Get the reaction field contribution to the
1006     !! potential and torques:
1007 gezelter 246 call reaction_field_final(i, mu_i, eFrame, rfpot, t, do_pot)
1008 gezelter 117 #ifdef IS_MPI
1009     pot_local = pot_local + rfpot
1010     #else
1011     pot = pot + rfpot
1012 chrisfen 532
1013 gezelter 117 #endif
1014 chrisfen 532 endif
1015 gezelter 117 enddo
1016     endif
1017     endif
1018 chrisfen 532
1019    
1020 gezelter 117 #ifdef IS_MPI
1021 chrisfen 532
1022 gezelter 117 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 532
1028 gezelter 117 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 532
1035 gezelter 117 #else
1036 chrisfen 532
1037 gezelter 117 if (do_stress) then
1038     tau = tau_Temp
1039     virial = virial_Temp
1040     endif
1041 chrisfen 532
1042 gezelter 117 #endif
1043 chrisfen 532
1044 gezelter 117 end subroutine do_force_loop
1045 chrisfen 532
1046 gezelter 117 subroutine do_pair(i, j, rijsq, d, sw, do_pot, &
1047 gezelter 246 eFrame, A, f, t, pot, vpair, fpair)
1048 gezelter 117
1049     real( kind = dp ) :: pot, vpair, sw
1050     real( kind = dp ), dimension(3) :: fpair
1051     real( kind = dp ), dimension(nLocal) :: mfact
1052 gezelter 246 real( kind = dp ), dimension(9,nLocal) :: eFrame
1053 gezelter 117 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 534 real ( kind = dp ) :: ebalance
1063 gezelter 117 integer :: me_i, me_j
1064    
1065 gezelter 560 integer :: iMap
1066    
1067 gezelter 117 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 202
1079 gezelter 560 iMap = InteractionMap(me_i, me_j)%InteractionHash
1080 chrisfen 532
1081 gezelter 560 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 117 endif
1084 chrisfen 532
1085 gezelter 560 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 532
1089 gezelter 562 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 117 endif
1095 gezelter 562
1096 gezelter 117 endif
1097    
1098 gezelter 560 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 401
1103 gezelter 560 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 117 endif
1107    
1108 gezelter 560 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 532 endif
1112    
1113 gezelter 560 if ( iand(iMap, GAYBERNE_LJ).ne.0 ) then
1114 chuckv 563 ! call do_gblj_pair(i, j, d, r, rijsq, sw, vpair, fpair, &
1115     ! pot, A, f, t, do_pot)
1116 gezelter 560 endif
1117 kdaily 529
1118 gezelter 560 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 117 endif
1122 chrisfen 532
1123 gezelter 560 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 117 endif
1127 gezelter 141
1128 gezelter 560 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 141 endif
1132 gezelter 560
1133 gezelter 117 end subroutine do_pair
1134    
1135     subroutine do_prepair(i, j, rijsq, d, sw, rcijsq, dc, &
1136 gezelter 246 do_pot, do_stress, eFrame, A, f, t, pot)
1137 gezelter 117
1138 chrisfen 532 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 117
1144 chrisfen 532 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 560 integer :: me_i, me_j, iMap
1151 chrisfen 532
1152 gezelter 117 #ifdef IS_MPI
1153 chrisfen 532 me_i = atid_row(i)
1154     me_j = atid_col(j)
1155 gezelter 117 #else
1156 chrisfen 532 me_i = atid(i)
1157     me_j = atid(j)
1158 gezelter 117 #endif
1159 chrisfen 532
1160 gezelter 560 iMap = InteractionMap(me_i, me_j)%InteractionHash
1161 chrisfen 532
1162 gezelter 560 if ( iand(iMap, EAM_PAIR).ne.0 ) then
1163 chrisfen 532 call calc_EAM_prepair_rho(i, j, d, r, rijsq )
1164     endif
1165 gezelter 560
1166 chrisfen 532 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 117 #ifdef IS_MPI
1235    
1236 chrisfen 532 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 117 #endif
1265 chrisfen 532
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 117 #ifdef IS_MPI
1292 chrisfen 532 !! in MPI, we have to look up the unique IDs for each atom
1293     unique_id_1 = AtomRowToGlobal(atom1)
1294 gezelter 117 #else
1295 chrisfen 532 !! in the normal loop, the atom numbers are unique
1296     unique_id_1 = atom1
1297 gezelter 117 #endif
1298 chrisfen 532
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 117 #ifdef IS_MPI
1312 chrisfen 532 unique_id_2 = AtomColToGlobal(atom2)
1313 gezelter 117 #else
1314 chrisfen 532 unique_id_2 = atom2
1315 gezelter 117 #endif
1316 chrisfen 532
1317 gezelter 117 #ifdef IS_MPI
1318 chrisfen 532 !! 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 117 #endif
1337 chrisfen 532
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 117 #ifdef PROFILE
1375 chrisfen 532 function getforcetime() result(totalforcetime)
1376     real(kind=dp) :: totalforcetime
1377     totalforcetime = forcetime
1378     end function getforcetime
1379 gezelter 117 #endif
1380    
1381 chrisfen 532 !! 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 117 end module doForces