ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/do_Forces.F90
Revision: 657
Committed: Wed Jul 30 21:17:01 2003 UTC (20 years, 11 months ago) by chuckv
File size: 28380 byte(s)
Log Message:
More bug fixes for eam.

File Contents

# Content
1 !! do_Forces.F90
2 !! module do_Forces
3 !! Calculates Long Range forces.
4
5 !! @author Charles F. Vardeman II
6 !! @author Matthew Meineke
7 !! @version $Id: do_Forces.F90,v 1.26 2003-07-30 21:17:01 chuckv Exp $, $Date: 2003-07-30 21:17:01 $, $Name: not supported by cvs2svn $, $Revision: 1.26 $
8
9 module do_Forces
10 use force_globals
11 use simulation
12 use definitions
13 use atype_module
14 use neighborLists
15 use lj
16 use sticky_pair
17 use dipole_dipole
18 use reaction_field
19 use gb_pair
20 use vector_class
21 use eam
22 use status
23 #ifdef IS_MPI
24 use mpiSimulation
25 #endif
26
27 implicit none
28 PRIVATE
29
30 #define __FORTRAN90
31 #include "fForceField.h"
32
33 logical, save :: do_forces_initialized = .false., haveRlist = .false.
34 logical, save :: havePolicies = .false.
35 logical, save :: FF_uses_LJ
36 logical, save :: FF_uses_sticky
37 logical, save :: FF_uses_dipoles
38 logical, save :: FF_uses_RF
39 logical, save :: FF_uses_GB
40 logical, save :: FF_uses_EAM
41
42 real(kind=dp), save :: rlist, rlistsq
43
44 public :: init_FF
45 public :: do_force_loop
46 public :: setRlistDF
47
48 contains
49
50 subroutine setRlistDF( this_rlist )
51
52 real(kind=dp) :: this_rlist
53
54 rlist = this_rlist
55 rlistsq = rlist * rlist
56
57 haveRlist = .true.
58 if( havePolicies ) do_forces_initialized = .true.
59
60 end subroutine setRlistDF
61
62 subroutine init_FF(LJMIXPOLICY, use_RF_c, thisStat)
63
64 integer, intent(in) :: LJMIXPOLICY
65 logical, intent(in) :: use_RF_c
66
67 integer, intent(out) :: thisStat
68 integer :: my_status, nMatches
69 integer, pointer :: MatchList(:) => null()
70 real(kind=dp) :: rcut, rrf, rt, dielect
71
72 !! assume things are copacetic, unless they aren't
73 thisStat = 0
74
75 !! Fortran's version of a cast:
76 FF_uses_RF = use_RF_c
77
78 !! init_FF is called *after* all of the atom types have been
79 !! defined in atype_module using the new_atype subroutine.
80 !!
81 !! this will scan through the known atypes and figure out what
82 !! interactions are used by the force field.
83
84 FF_uses_LJ = .false.
85 FF_uses_sticky = .false.
86 FF_uses_dipoles = .false.
87 FF_uses_GB = .false.
88 FF_uses_EAM = .false.
89
90 call getMatchingElementList(atypes, "is_LJ", .true., nMatches, MatchList)
91 if (nMatches .gt. 0) FF_uses_LJ = .true.
92
93 call getMatchingElementList(atypes, "is_DP", .true., nMatches, MatchList)
94 if (nMatches .gt. 0) FF_uses_dipoles = .true.
95
96 call getMatchingElementList(atypes, "is_Sticky", .true., nMatches, &
97 MatchList)
98 if (nMatches .gt. 0) FF_uses_Sticky = .true.
99
100 call getMatchingElementList(atypes, "is_GB", .true., nMatches, MatchList)
101 if (nMatches .gt. 0) FF_uses_GB = .true.
102
103 call getMatchingElementList(atypes, "is_EAM", .true., nMatches, MatchList)
104 if (nMatches .gt. 0) FF_uses_EAM = .true.
105
106 !! check to make sure the FF_uses_RF setting makes sense
107
108 if (FF_uses_dipoles) then
109 if (FF_uses_RF) then
110 dielect = getDielect()
111 call initialize_rf(dielect)
112 endif
113 else
114 if (FF_uses_RF) then
115 write(default_error,*) 'Using Reaction Field with no dipoles? Huh?'
116 thisStat = -1
117 return
118 endif
119 endif
120
121 if (FF_uses_LJ) then
122
123 select case (LJMIXPOLICY)
124 case (LB_MIXING_RULE)
125 call init_lj_FF(LB_MIXING_RULE, my_status)
126 case (EXPLICIT_MIXING_RULE)
127 call init_lj_FF(EXPLICIT_MIXING_RULE, my_status)
128 case default
129 write(default_error,*) 'unknown LJ Mixing Policy!'
130 thisStat = -1
131 return
132 end select
133 if (my_status /= 0) then
134 thisStat = -1
135 return
136 end if
137 endif
138
139 if (FF_uses_sticky) then
140 call check_sticky_FF(my_status)
141 if (my_status /= 0) then
142 thisStat = -1
143 return
144 end if
145 endif
146
147
148 if (FF_uses_EAM) then
149 call init_EAM_FF(my_status)
150 if (my_status /= 0) then
151 thisStat = -1
152 return
153 end if
154 endif
155
156
157
158 if (FF_uses_GB) then
159 call check_gb_pair_FF(my_status)
160 if (my_status .ne. 0) then
161 thisStat = -1
162 return
163 endif
164 endif
165
166 if (FF_uses_GB .and. FF_uses_LJ) then
167 endif
168 if (.not. do_forces_initialized) then
169 !! Create neighbor lists
170 call expandNeighborList(getNlocal(), my_status)
171 if (my_Status /= 0) then
172 write(default_error,*) "SimSetup: ExpandNeighborList returned error."
173 thisStat = -1
174 return
175 endif
176 endif
177
178
179 havePolicies = .true.
180 if( haveRlist ) do_forces_initialized = .true.
181
182 end subroutine init_FF
183
184
185 !! Does force loop over i,j pairs. Calls do_pair to calculates forces.
186 !------------------------------------------------------------->
187 subroutine do_force_loop(q, A, u_l, f, t, tau, pot, do_pot_c, do_stress_c, &
188 error)
189 !! Position array provided by C, dimensioned by getNlocal
190 real ( kind = dp ), dimension(3,getNlocal()) :: q
191 !! Rotation Matrix for each long range particle in simulation.
192 real( kind = dp), dimension(9,getNlocal()) :: A
193 !! Unit vectors for dipoles (lab frame)
194 real( kind = dp ), dimension(3,getNlocal()) :: u_l
195 !! Force array provided by C, dimensioned by getNlocal
196 real ( kind = dp ), dimension(3,getNlocal()) :: f
197 !! Torsion array provided by C, dimensioned by getNlocal
198 real( kind = dp ), dimension(3,getNlocal()) :: t
199 !! Stress Tensor
200 real( kind = dp), dimension(9) :: tau
201 real ( kind = dp ) :: pot
202 logical ( kind = 2) :: do_pot_c, do_stress_c
203 logical :: do_pot
204 logical :: do_stress
205 #ifdef IS_MPI
206 real( kind = DP ) :: pot_local
207 integer :: nrow
208 integer :: ncol
209 #endif
210 integer :: nlocal
211 integer :: natoms
212 logical :: update_nlist
213 integer :: i, j, jbeg, jend, jnab
214 integer :: nlist
215 real( kind = DP ) :: rijsq
216 real(kind=dp),dimension(3) :: d
217 real(kind=dp) :: rfpot, mu_i, virial
218 integer :: me_i
219 logical :: is_dp_i
220 integer :: neighborListSize
221 integer :: listerror, error
222 integer :: localError
223
224 real(kind=dp) :: listSkin = 1.0
225
226
227 !! initialize local variables
228
229 #ifdef IS_MPI
230 pot_local = 0.0_dp
231 nlocal = getNlocal()
232 nrow = getNrow(plan_row)
233 ncol = getNcol(plan_col)
234 #else
235 nlocal = getNlocal()
236 natoms = nlocal
237 #endif
238 write(*,*) "Inside do_Force Loop"
239 call check_initialization(localError)
240 if ( localError .ne. 0 ) then
241 call handleError("do_force_loop","Not Initialized")
242 error = -1
243 return
244 end if
245 call zero_work_arrays()
246
247 do_pot = do_pot_c
248 do_stress = do_stress_c
249
250 ! Gather all information needed by all force loops:
251
252 #ifdef IS_MPI
253
254 call gather(q,q_Row,plan_row3d)
255 call gather(q,q_Col,plan_col3d)
256
257 if (FF_UsesDirectionalAtoms() .and. SimUsesDirectionalAtoms()) then
258 call gather(u_l,u_l_Row,plan_row3d)
259 call gather(u_l,u_l_Col,plan_col3d)
260
261 call gather(A,A_Row,plan_row_rotation)
262 call gather(A,A_Col,plan_col_rotation)
263 endif
264
265 #endif
266
267 if (FF_RequiresPrepairCalc() .and. SimRequiresPrepairCalc()) then
268 !! See if we need to update neighbor lists
269 call checkNeighborList(nlocal, q, listSkin, update_nlist)
270 !! if_mpi_gather_stuff_for_prepair
271 !! do_prepair_loop_if_needed
272 !! if_mpi_scatter_stuff_from_prepair
273 !! if_mpi_gather_stuff_from_prepair_to_main_loop
274
275 !--------------------PREFORCE LOOP----------->>>>>>>>>>>>>>>>>>>>>>>>>>>
276 #ifdef IS_MPI
277
278 if (update_nlist) then
279
280 !! save current configuration, construct neighbor list,
281 !! and calculate forces
282 call saveNeighborList(nlocal, q)
283
284 neighborListSize = size(list)
285 nlist = 0
286
287 do i = 1, nrow
288 point(i) = nlist + 1
289
290 prepair_inner: do j = 1, ncol
291
292 if (skipThisPair(i,j)) cycle prepair_inner
293
294 call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
295
296 if (rijsq < rlistsq) then
297
298 nlist = nlist + 1
299
300 if (nlist > neighborListSize) then
301 call expandNeighborList(nlocal, listerror)
302 if (listerror /= 0) then
303 error = -1
304 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
305 return
306 end if
307 neighborListSize = size(list)
308 endif
309
310 list(nlist) = j
311 call do_prepair(i, j, rijsq, d, do_pot, do_stress, u_l, A, f, t, pot_local)
312 endif
313 enddo prepair_inner
314 enddo
315
316 point(nrow + 1) = nlist + 1
317
318 else !! (of update_check)
319
320 ! use the list to find the neighbors
321 do i = 1, nrow
322 JBEG = POINT(i)
323 JEND = POINT(i+1) - 1
324 ! check thiat molecule i has neighbors
325 if (jbeg .le. jend) then
326
327 do jnab = jbeg, jend
328 j = list(jnab)
329
330 call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
331 call do_prepair(i, j, rijsq, d, do_pot, do_stress, &
332 u_l, A, f, t, pot_local)
333
334 enddo
335 endif
336 enddo
337 endif
338
339 #else
340
341 if (update_nlist) then
342
343 ! save current configuration, contruct neighbor list,
344 ! and calculate forces
345 call saveNeighborList(natoms, q)
346
347 neighborListSize = size(list)
348
349 nlist = 0
350
351 do i = 1, natoms-1
352 point(i) = nlist + 1
353
354 prepair_inner: do j = i+1, natoms
355
356 if (skipThisPair(i,j)) cycle prepair_inner
357
358 call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
359
360
361 if (rijsq < rlistsq) then
362
363 nlist = nlist + 1
364
365 if (nlist > neighborListSize) then
366 call expandNeighborList(natoms, listerror)
367 if (listerror /= 0) then
368 error = -1
369 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
370 return
371 end if
372 neighborListSize = size(list)
373 endif
374
375 list(nlist) = j
376
377 call do_prepair(i, j, rijsq, d, do_pot, do_stress, &
378 u_l, A, f, t, pot)
379
380 endif
381 enddo prepair_inner
382 enddo
383
384 point(natoms) = nlist + 1
385
386 else !! (update)
387
388 ! use the list to find the neighbors
389 do i = 1, natoms-1
390 JBEG = POINT(i)
391 JEND = POINT(i+1) - 1
392 ! check thiat molecule i has neighbors
393 if (jbeg .le. jend) then
394
395 do jnab = jbeg, jend
396 j = list(jnab)
397
398 call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
399 call do_prepair(i, j, rijsq, d, do_pot, do_stress, &
400 u_l, A, f, t, pot)
401
402 enddo
403 endif
404 enddo
405 endif
406 #endif
407 !! Do rest of preforce calculations
408 call do_preforce(nlocal,pot)
409 else
410 !! See if we need to update neighbor lists for non pre-pair
411 call checkNeighborList(nlocal, q, listSkin, update_nlist)
412 endif
413
414
415
416
417
418 !---------------------------------MAIN Pair LOOP->>>>>>>>>>>>>>>>>>>>>>>>>>>>
419
420
421
422
423
424 #ifdef IS_MPI
425
426 if (update_nlist) then
427
428 !! save current configuration, construct neighbor list,
429 !! and calculate forces
430 call saveNeighborList(nlocal, q)
431
432 neighborListSize = size(list)
433 nlist = 0
434
435 do i = 1, nrow
436 point(i) = nlist + 1
437
438 inner: do j = 1, ncol
439
440 if (skipThisPair(i,j)) cycle inner
441
442 call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
443
444 if (rijsq < rlistsq) then
445
446 nlist = nlist + 1
447
448 if (nlist > neighborListSize) then
449 call expandNeighborList(nlocal, listerror)
450 if (listerror /= 0) then
451 error = -1
452 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
453 return
454 end if
455 neighborListSize = size(list)
456 endif
457
458 list(nlist) = j
459
460 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
461 u_l, A, f, t, pot_local)
462
463 endif
464 enddo inner
465 enddo
466
467 point(nrow + 1) = nlist + 1
468
469 else !! (of update_check)
470
471 ! use the list to find the neighbors
472 do i = 1, nrow
473 JBEG = POINT(i)
474 JEND = POINT(i+1) - 1
475 ! check thiat molecule i has neighbors
476 if (jbeg .le. jend) then
477
478 do jnab = jbeg, jend
479 j = list(jnab)
480
481 call get_interatomic_vector(q_Row(:,i), q_Col(:,j), d, rijsq)
482 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
483 u_l, A, f, t, pot_local)
484
485 enddo
486 endif
487 enddo
488 endif
489
490 #else
491
492 if (update_nlist) then
493
494 ! save current configuration, contruct neighbor list,
495 ! and calculate forces
496 call saveNeighborList(natoms, q)
497
498 neighborListSize = size(list)
499
500 nlist = 0
501
502 do i = 1, natoms-1
503 point(i) = nlist + 1
504
505 inner: do j = i+1, natoms
506
507 if (skipThisPair(i,j)) cycle inner
508
509 call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
510
511
512 if (rijsq < rlistsq) then
513
514 nlist = nlist + 1
515
516 if (nlist > neighborListSize) then
517 call expandNeighborList(natoms, listerror)
518 if (listerror /= 0) then
519 error = -1
520 write(DEFAULT_ERROR,*) "ERROR: nlist > list size and max allocations exceeded."
521 return
522 end if
523 neighborListSize = size(list)
524 endif
525
526 list(nlist) = j
527
528 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
529 u_l, A, f, t, pot)
530
531 endif
532 enddo inner
533 enddo
534
535 point(natoms) = nlist + 1
536
537 else !! (update)
538
539 ! use the list to find the neighbors
540 do i = 1, natoms-1
541 JBEG = POINT(i)
542 JEND = POINT(i+1) - 1
543 ! check thiat molecule i has neighbors
544 if (jbeg .le. jend) then
545
546 do jnab = jbeg, jend
547 j = list(jnab)
548
549 call get_interatomic_vector(q(:,i), q(:,j), d, rijsq)
550 call do_pair(i, j, rijsq, d, do_pot, do_stress, &
551 u_l, A, f, t, pot)
552
553 enddo
554 endif
555 enddo
556 endif
557
558 #endif
559
560 ! phew, done with main loop.
561
562 #ifdef IS_MPI
563 !!distribute forces
564
565 f_temp = 0.0_dp
566 call scatter(f_Row,f_temp,plan_row3d)
567 do i = 1,nlocal
568 f(1:3,i) = f(1:3,i) + f_temp(1:3,i)
569 end do
570
571 f_temp = 0.0_dp
572 call scatter(f_Col,f_temp,plan_col3d)
573 do i = 1,nlocal
574 f(1:3,i) = f(1:3,i) + f_temp(1:3,i)
575 end do
576
577 if (FF_UsesDirectionalAtoms() .and. SimUsesDirectionalAtoms()) then
578 t_temp = 0.0_dp
579 call scatter(t_Row,t_temp,plan_row3d)
580 do i = 1,nlocal
581 t(1:3,i) = t(1:3,i) + t_temp(1:3,i)
582 end do
583 t_temp = 0.0_dp
584 call scatter(t_Col,t_temp,plan_col3d)
585
586 do i = 1,nlocal
587 t(1:3,i) = t(1:3,i) + t_temp(1:3,i)
588 end do
589 endif
590
591 if (do_pot) then
592 ! scatter/gather pot_row into the members of my column
593 call scatter(pot_Row, pot_Temp, plan_row)
594
595 ! scatter/gather pot_local into all other procs
596 ! add resultant to get total pot
597 do i = 1, nlocal
598 pot_local = pot_local + pot_Temp(i)
599 enddo
600
601 pot_Temp = 0.0_DP
602
603 call scatter(pot_Col, pot_Temp, plan_col)
604 do i = 1, nlocal
605 pot_local = pot_local + pot_Temp(i)
606 enddo
607
608 endif
609 #endif
610
611 if (FF_RequiresPostpairCalc() .and. SimRequiresPostpairCalc()) then
612
613 if (FF_uses_RF .and. SimUsesRF()) then
614
615 #ifdef IS_MPI
616 call scatter(rf_Row,rf,plan_row3d)
617 call scatter(rf_Col,rf_Temp,plan_col3d)
618 do i = 1,nlocal
619 rf(1:3,i) = rf(1:3,i) + rf_Temp(1:3,i)
620 end do
621 #endif
622
623 do i = 1, getNlocal()
624
625 rfpot = 0.0_DP
626 #ifdef IS_MPI
627 me_i = atid_row(i)
628 #else
629 me_i = atid(i)
630 #endif
631 call getElementProperty(atypes, me_i, "is_DP", is_DP_i)
632 if ( is_DP_i ) then
633 call getElementProperty(atypes, me_i, "dipole_moment", mu_i)
634 !! The reaction field needs to include a self contribution
635 !! to the field:
636 call accumulate_self_rf(i, mu_i, u_l)
637 !! Get the reaction field contribution to the
638 !! potential and torques:
639 call reaction_field_final(i, mu_i, u_l, rfpot, t, do_pot)
640 #ifdef IS_MPI
641 pot_local = pot_local + rfpot
642 #else
643 pot = pot + rfpot
644
645 #endif
646 endif
647 enddo
648 endif
649 endif
650
651
652 #ifdef IS_MPI
653
654 if (do_pot) then
655 pot = pot + pot_local
656 !! we assume the c code will do the allreduce to get the total potential
657 !! we could do it right here if we needed to...
658 endif
659
660 if (do_stress) then
661 call mpi_allreduce(tau_Temp, tau, 9,mpi_double_precision,mpi_sum, &
662 mpi_comm_world,mpi_err)
663 call mpi_allreduce(virial_Temp, virial,1,mpi_double_precision,mpi_sum, &
664 mpi_comm_world,mpi_err)
665 endif
666
667 #else
668
669 if (do_stress) then
670 tau = tau_Temp
671 virial = virial_Temp
672 endif
673
674 #endif
675
676 end subroutine do_force_loop
677
678 subroutine do_pair(i, j, rijsq, d, do_pot, do_stress, u_l, A, f, t, pot)
679
680 real( kind = dp ) :: pot
681 real( kind = dp ), dimension(3,getNlocal()) :: u_l
682 real (kind=dp), dimension(9,getNlocal()) :: A
683 real (kind=dp), dimension(3,getNlocal()) :: f
684 real (kind=dp), dimension(3,getNlocal()) :: t
685
686 logical, intent(inout) :: do_pot, do_stress
687 integer, intent(in) :: i, j
688 real ( kind = dp ), intent(inout) :: rijsq
689 real ( kind = dp ) :: r
690 real ( kind = dp ), intent(inout) :: d(3)
691 logical :: is_LJ_i, is_LJ_j
692 logical :: is_DP_i, is_DP_j
693 logical :: is_GB_i, is_GB_j
694 logical :: is_EAM_i,is_EAM_j
695 logical :: is_Sticky_i, is_Sticky_j
696 integer :: me_i, me_j
697
698 r = sqrt(rijsq)
699
700 #ifdef IS_MPI
701 if (tagRow(i) .eq. tagColumn(j)) then
702 write(0,*) 'do_pair is doing', i , j, tagRow(i), tagColumn(j)
703 endif
704
705 me_i = atid_row(i)
706 me_j = atid_col(j)
707
708 #else
709
710 me_i = atid(i)
711 me_j = atid(j)
712
713 #endif
714
715 if (FF_uses_LJ .and. SimUsesLJ()) then
716 call getElementProperty(atypes, me_i, "is_LJ", is_LJ_i)
717 call getElementProperty(atypes, me_j, "is_LJ", is_LJ_j)
718
719 if ( is_LJ_i .and. is_LJ_j ) &
720 call do_lj_pair(i, j, d, r, rijsq, pot, f, do_pot, do_stress)
721 endif
722
723 if (FF_uses_dipoles .and. SimUsesDipoles()) then
724 call getElementProperty(atypes, me_i, "is_DP", is_DP_i)
725 call getElementProperty(atypes, me_j, "is_DP", is_DP_j)
726
727 if ( is_DP_i .and. is_DP_j ) then
728
729 call do_dipole_pair(i, j, d, r, rijsq, pot, u_l, f, t, &
730 do_pot, do_stress)
731 if (FF_uses_RF .and. SimUsesRF()) then
732 call accumulate_rf(i, j, r, u_l)
733 call rf_correct_forces(i, j, d, r, u_l, f, do_stress)
734 endif
735
736 endif
737 endif
738
739 if (FF_uses_Sticky .and. SimUsesSticky()) then
740
741 call getElementProperty(atypes, me_i, "is_Sticky", is_Sticky_i)
742 call getElementProperty(atypes, me_j, "is_Sticky", is_Sticky_j)
743
744 if ( is_Sticky_i .and. is_Sticky_j ) then
745 call do_sticky_pair(i, j, d, r, rijsq, A, pot, f, t, &
746 do_pot, do_stress)
747 endif
748 endif
749
750
751 if (FF_uses_GB .and. SimUsesGB()) then
752
753 call getElementProperty(atypes, me_i, "is_GB", is_GB_i)
754 call getElementProperty(atypes, me_j, "is_GB", is_GB_j)
755
756 if ( is_GB_i .and. is_GB_j ) then
757 call do_gb_pair(i, j, d, r, rijsq, u_l, pot, f, t, &
758 do_pot, do_stress)
759 endif
760 endif
761
762
763
764 if (FF_uses_EAM .and. SimUsesEAM()) then
765 call getElementProperty(atypes, me_i, "is_EAM", is_EAM_i)
766 call getElementProperty(atypes, me_j, "is_EAM", is_EAM_j)
767
768 if ( is_EAM_i .and. is_EAM_j ) &
769 call do_eam_pair(i, j, d, r, rijsq, pot, f, do_pot, do_stress)
770 endif
771
772
773
774
775 end subroutine do_pair
776
777
778
779 subroutine do_prepair(i, j, rijsq, d, do_pot, do_stress, u_l, A, f, t, pot)
780 real( kind = dp ) :: pot
781 real( kind = dp ), dimension(3,getNlocal()) :: u_l
782 real (kind=dp), dimension(9,getNlocal()) :: A
783 real (kind=dp), dimension(3,getNlocal()) :: f
784 real (kind=dp), dimension(3,getNlocal()) :: t
785
786 logical, intent(inout) :: do_pot, do_stress
787 integer, intent(in) :: i, j
788 real ( kind = dp ), intent(inout) :: rijsq
789 real ( kind = dp ) :: r
790 real ( kind = dp ), intent(inout) :: d(3)
791
792 logical :: is_EAM_i, is_EAM_j
793
794 integer :: me_i, me_j
795
796 r = sqrt(rijsq)
797
798 #ifdef IS_MPI
799 if (tagRow(i) .eq. tagColumn(j)) then
800 write(0,*) 'do_pair is doing', i , j, tagRow(i), tagColumn(j)
801 endif
802
803 me_i = atid_row(i)
804 me_j = atid_col(j)
805
806 #else
807
808 me_i = atid(i)
809 me_j = atid(j)
810
811 #endif
812
813 if (FF_uses_EAM .and. SimUsesEAM()) then
814 call getElementProperty(atypes, me_i, "is_EAM", is_EAM_i)
815 call getElementProperty(atypes, me_j, "is_EAM", is_EAM_j)
816
817 if ( is_EAM_i .and. is_EAM_j ) &
818 call calc_EAM_prepair_rho(i, j, d, r, rijsq )
819 endif
820 end subroutine do_prepair
821
822
823
824
825 subroutine do_preforce(nlocal,pot)
826 integer :: nlocal
827 real( kind = dp ) :: pot
828
829 if (FF_uses_EAM .and. SimUsesEAM()) then
830 call calc_EAM_preforce_Frho(nlocal,pot)
831 endif
832
833
834 end subroutine do_preforce
835
836
837 subroutine get_interatomic_vector(q_i, q_j, d, r_sq)
838
839 real (kind = dp), dimension(3) :: q_i
840 real (kind = dp), dimension(3) :: q_j
841 real ( kind = dp ), intent(out) :: r_sq
842 real( kind = dp ) :: d(3), scaled(3)
843 integer i
844
845 d(1:3) = q_j(1:3) - q_i(1:3)
846
847 ! Wrap back into periodic box if necessary
848 if ( SimUsesPBC() ) then
849
850 if( .not.boxIsOrthorhombic ) then
851 ! calc the scaled coordinates.
852
853 scaled = matmul(HmatInv, d)
854
855 ! wrap the scaled coordinates
856
857 scaled = scaled - anint(scaled)
858
859
860 ! calc the wrapped real coordinates from the wrapped scaled
861 ! coordinates
862
863 d = matmul(Hmat,scaled)
864
865 else
866 ! calc the scaled coordinates.
867
868 do i = 1, 3
869 scaled(i) = d(i) * HmatInv(i,i)
870
871 ! wrap the scaled coordinates
872
873 scaled(i) = scaled(i) - anint(scaled(i))
874
875 ! calc the wrapped real coordinates from the wrapped scaled
876 ! coordinates
877
878 d(i) = scaled(i)*Hmat(i,i)
879 enddo
880 endif
881
882 endif
883
884 r_sq = dot_product(d,d)
885
886 end subroutine get_interatomic_vector
887
888 subroutine check_initialization(error)
889 integer, intent(out) :: error
890
891 error = 0
892 ! Make sure we are properly initialized.
893 if (.not. do_forces_initialized) then
894 write(*,*) "Forces not initialized"
895 error = -1
896 return
897 endif
898
899 #ifdef IS_MPI
900 if (.not. isMPISimSet()) then
901 write(default_error,*) "ERROR: mpiSimulation has not been initialized!"
902 error = -1
903 return
904 endif
905 #endif
906
907 return
908 end subroutine check_initialization
909
910
911 subroutine zero_work_arrays()
912
913 #ifdef IS_MPI
914
915 q_Row = 0.0_dp
916 q_Col = 0.0_dp
917
918 u_l_Row = 0.0_dp
919 u_l_Col = 0.0_dp
920
921 A_Row = 0.0_dp
922 A_Col = 0.0_dp
923
924 f_Row = 0.0_dp
925 f_Col = 0.0_dp
926 f_Temp = 0.0_dp
927
928 t_Row = 0.0_dp
929 t_Col = 0.0_dp
930 t_Temp = 0.0_dp
931
932 pot_Row = 0.0_dp
933 pot_Col = 0.0_dp
934 pot_Temp = 0.0_dp
935
936 rf_Row = 0.0_dp
937 rf_Col = 0.0_dp
938 rf_Temp = 0.0_dp
939
940 #endif
941
942 rf = 0.0_dp
943 tau_Temp = 0.0_dp
944 virial_Temp = 0.0_dp
945 end subroutine zero_work_arrays
946
947 function skipThisPair(atom1, atom2) result(skip_it)
948 integer, intent(in) :: atom1
949 integer, intent(in), optional :: atom2
950 logical :: skip_it
951 integer :: unique_id_1, unique_id_2
952 integer :: me_i,me_j
953 integer :: i
954
955 skip_it = .false.
956
957 !! there are a number of reasons to skip a pair or a particle
958 !! mostly we do this to exclude atoms who are involved in short
959 !! range interactions (bonds, bends, torsions), but we also need
960 !! to exclude some overcounted interactions that result from
961 !! the parallel decomposition
962
963 #ifdef IS_MPI
964 !! in MPI, we have to look up the unique IDs for each atom
965 unique_id_1 = tagRow(atom1)
966 #else
967 !! in the normal loop, the atom numbers are unique
968 unique_id_1 = atom1
969 #endif
970
971 !! We were called with only one atom, so just check the global exclude
972 !! list for this atom
973 if (.not. present(atom2)) then
974 do i = 1, nExcludes_global
975 if (excludesGlobal(i) == unique_id_1) then
976 skip_it = .true.
977 return
978 end if
979 end do
980 return
981 end if
982
983 #ifdef IS_MPI
984 unique_id_2 = tagColumn(atom2)
985 #else
986 unique_id_2 = atom2
987 #endif
988
989 #ifdef IS_MPI
990 !! this situation should only arise in MPI simulations
991 if (unique_id_1 == unique_id_2) then
992 skip_it = .true.
993 return
994 end if
995
996 !! this prevents us from doing the pair on multiple processors
997 if (unique_id_1 < unique_id_2) then
998 if (mod(unique_id_1 + unique_id_2,2) == 0) then
999 skip_it = .true.
1000 return
1001 endif
1002 else
1003 if (mod(unique_id_1 + unique_id_2,2) == 1) then
1004 skip_it = .true.
1005 return
1006 endif
1007 endif
1008 #endif
1009
1010 !! the rest of these situations can happen in all simulations:
1011 do i = 1, nExcludes_global
1012 if ((excludesGlobal(i) == unique_id_1) .or. &
1013 (excludesGlobal(i) == unique_id_2)) then
1014 skip_it = .true.
1015 return
1016 endif
1017 enddo
1018
1019 do i = 1, nExcludes_local
1020 if (excludesLocal(1,i) == unique_id_1) then
1021 if (excludesLocal(2,i) == unique_id_2) then
1022 skip_it = .true.
1023 return
1024 endif
1025 else
1026 if (excludesLocal(1,i) == unique_id_2) then
1027 if (excludesLocal(2,i) == unique_id_1) then
1028 skip_it = .true.
1029 return
1030 endif
1031 endif
1032 endif
1033 end do
1034
1035 return
1036 end function skipThisPair
1037
1038 function FF_UsesDirectionalAtoms() result(doesit)
1039 logical :: doesit
1040 doesit = FF_uses_dipoles .or. FF_uses_sticky .or. &
1041 FF_uses_GB .or. FF_uses_RF
1042 end function FF_UsesDirectionalAtoms
1043
1044 function FF_RequiresPrepairCalc() result(doesit)
1045 logical :: doesit
1046 doesit = FF_uses_EAM
1047 end function FF_RequiresPrepairCalc
1048
1049 function FF_RequiresPostpairCalc() result(doesit)
1050 logical :: doesit
1051 doesit = FF_uses_RF
1052 end function FF_RequiresPostpairCalc
1053
1054 end module do_Forces