ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/UseTheForce/DarkSide/electrostatic.F90
Revision: 1486
Committed: Thu Jul 29 17:31:39 2010 UTC (14 years, 11 months ago) by gezelter
File size: 48936 byte(s)
Log Message:
simple fix for calls to getCharge for non-charge atoms (triggered by
shifted pot / shifted force computations of self-self interactions
with out point charges on topologically connected molecules).


File Contents

# Content
1 !!
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. Redistributions of source code must retain the above copyright
10 !! notice, this list of conditions and the following disclaimer.
11 !!
12 !! 2. Redistributions in binary form must reproduce the above copyright
13 !! notice, this list of conditions and the following disclaimer in the
14 !! documentation and/or other materials provided with the
15 !! distribution.
16 !!
17 !! This software is provided "AS IS," without a warranty of any
18 !! kind. All express or implied conditions, representations and
19 !! warranties, including any implied warranty of merchantability,
20 !! fitness for a particular purpose or non-infringement, are hereby
21 !! excluded. The University of Notre Dame and its licensors shall not
22 !! be liable for any damages suffered by licensee as a result of
23 !! using, modifying or distributing the software or its
24 !! derivatives. In no event will the University of Notre Dame or its
25 !! licensors be liable for any lost revenue, profit or data, or for
26 !! direct, indirect, special, consequential, incidental or punitive
27 !! damages, however caused and regardless of the theory of liability,
28 !! arising out of the use of or inability to use software, even if the
29 !! University of Notre Dame has been advised of the possibility of
30 !! such damages.
31 !!
32 !! SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 !! research, please cite the appropriate papers when you publish your
34 !! work. Good starting points are:
35 !!
36 !! [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 !! [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 !! [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 !! [4] Vardeman & Gezelter, in progress (2009).
40 !!
41
42 module electrostatic_module
43
44 use force_globals
45 use definitions
46 use atype_module
47 use vector_class
48 use simulation
49 use status
50 use interpolation
51 implicit none
52
53 PRIVATE
54
55
56 #define __FORTRAN90
57 #include "UseTheForce/DarkSide/fInteractionMap.h"
58 #include "UseTheForce/DarkSide/fElectrostaticSummationMethod.h"
59 #include "UseTheForce/DarkSide/fElectrostaticScreeningMethod.h"
60
61
62 !! these prefactors convert the multipole interactions into kcal / mol
63 !! all were computed assuming distances are measured in angstroms
64 !! Charge-Charge, assuming charges are measured in electrons
65 real(kind=dp), parameter :: pre11 = 332.0637778_dp
66 !! Charge-Dipole, assuming charges are measured in electrons, and
67 !! dipoles are measured in debyes
68 real(kind=dp), parameter :: pre12 = 69.13373_dp
69 !! Dipole-Dipole, assuming dipoles are measured in debyes
70 real(kind=dp), parameter :: pre22 = 14.39325_dp
71 !! Charge-Quadrupole, assuming charges are measured in electrons, and
72 !! quadrupoles are measured in 10^-26 esu cm^2
73 !! This unit is also known affectionately as an esu centi-barn.
74 real(kind=dp), parameter :: pre14 = 69.13373_dp
75
76 real(kind=dp), parameter :: zero = 0.0_dp
77
78 !! conversions for the simulation box dipole moment
79 real(kind=dp), parameter :: chargeToC = 1.60217733e-19_dp
80 real(kind=dp), parameter :: angstromToM = 1.0e-10_dp
81 real(kind=dp), parameter :: debyeToCm = 3.33564095198e-30_dp
82
83 !! number of points for electrostatic splines
84 integer, parameter :: np = 100
85
86 !! variables to handle different summation methods for long-range
87 !! electrostatics:
88 integer, save :: summationMethod = NONE
89 integer, save :: screeningMethod = UNDAMPED
90 logical, save :: summationMethodChecked = .false.
91 real(kind=DP), save :: defaultCutoff = 0.0_DP
92 real(kind=DP), save :: defaultCutoff2 = 0.0_DP
93 logical, save :: haveDefaultCutoff = .false.
94 real(kind=DP), save :: dampingAlpha = 0.0_DP
95 real(kind=DP), save :: alpha2 = 0.0_DP
96 real(kind=DP), save :: alpha4 = 0.0_DP
97 real(kind=DP), save :: alpha6 = 0.0_DP
98 real(kind=DP), save :: alpha8 = 0.0_DP
99 logical, save :: haveDampingAlpha = .false.
100 real(kind=DP), save :: dielectric = 1.0_DP
101 logical, save :: haveDielectric = .false.
102 real(kind=DP), save :: constEXP = 0.0_DP
103 real(kind=dp), save :: rcuti = 0.0_DP
104 real(kind=dp), save :: rcuti2 = 0.0_DP
105 real(kind=dp), save :: rcuti3 = 0.0_DP
106 real(kind=dp), save :: rcuti4 = 0.0_DP
107 real(kind=dp), save :: alphaPi = 0.0_DP
108 real(kind=dp), save :: invRootPi = 0.0_DP
109 real(kind=dp), save :: rrf = 1.0_DP
110 real(kind=dp), save :: rt = 1.0_DP
111 real(kind=dp), save :: rrfsq = 1.0_DP
112 real(kind=dp), save :: preRF = 0.0_DP
113 real(kind=dp), save :: preRF2 = 0.0_DP
114 real(kind=dp), save :: erfcVal = 1.0_DP
115 real(kind=dp), save :: derfcVal = 0.0_DP
116 type(cubicSpline), save :: erfcSpline
117 logical, save :: haveElectroSpline = .false.
118 real(kind=dp), save :: c1 = 1.0_DP
119 real(kind=dp), save :: c2 = 1.0_DP
120 real(kind=dp), save :: c3 = 0.0_DP
121 real(kind=dp), save :: c4 = 0.0_DP
122 real(kind=dp), save :: c5 = 0.0_DP
123 real(kind=dp), save :: c6 = 0.0_DP
124 real(kind=dp), save :: c1c = 1.0_DP
125 real(kind=dp), save :: c2c = 1.0_DP
126 real(kind=dp), save :: c3c = 0.0_DP
127 real(kind=dp), save :: c4c = 0.0_DP
128 real(kind=dp), save :: c5c = 0.0_DP
129 real(kind=dp), save :: c6c = 0.0_DP
130 real(kind=dp), save :: one_third = 1.0_DP / 3.0_DP
131
132 #if defined(__IFC) || defined(__PGI)
133 ! error function for ifc version > 7.
134 real(kind=dp), external :: erfc
135 #endif
136
137 public :: setElectrostaticSummationMethod
138 public :: setScreeningMethod
139 public :: setElectrostaticCutoffRadius
140 public :: setDampingAlpha
141 public :: setReactionFieldDielectric
142 public :: buildElectroSpline
143 public :: newElectrostaticType
144 public :: setCharge
145 public :: setDipoleMoment
146 public :: setSplitDipoleDistance
147 public :: setQuadrupoleMoments
148 public :: doElectrostaticPair
149 public :: getCharge
150 public :: getDipoleMoment
151 public :: destroyElectrostaticTypes
152 public :: self_self
153 public :: rf_self_excludes
154 public :: accumulate_box_dipole
155
156 type :: Electrostatic
157 integer :: c_ident
158 logical :: is_Charge = .false.
159 logical :: is_Dipole = .false.
160 logical :: is_SplitDipole = .false.
161 logical :: is_Quadrupole = .false.
162 logical :: is_Tap = .false.
163 real(kind=DP) :: charge = 0.0_DP
164 real(kind=DP) :: dipole_moment = 0.0_DP
165 real(kind=DP) :: split_dipole_distance = 0.0_DP
166 real(kind=DP), dimension(3) :: quadrupole_moments = 0.0_DP
167 end type Electrostatic
168
169 type(Electrostatic), dimension(:), allocatable :: ElectrostaticMap
170
171 logical, save :: hasElectrostaticMap
172
173 contains
174
175 subroutine setElectrostaticSummationMethod(the_ESM)
176 integer, intent(in) :: the_ESM
177
178 if ((the_ESM .le. 0) .or. (the_ESM .gt. REACTION_FIELD)) then
179 call handleError("setElectrostaticSummationMethod", "Unsupported Summation Method")
180 endif
181
182 summationMethod = the_ESM
183
184 end subroutine setElectrostaticSummationMethod
185
186 subroutine setScreeningMethod(the_SM)
187 integer, intent(in) :: the_SM
188 screeningMethod = the_SM
189 end subroutine setScreeningMethod
190
191 subroutine setElectrostaticCutoffRadius(thisRcut, thisRsw)
192 real(kind=dp), intent(in) :: thisRcut
193 real(kind=dp), intent(in) :: thisRsw
194 defaultCutoff = thisRcut
195 defaultCutoff2 = defaultCutoff*defaultCutoff
196 rrf = defaultCutoff
197 rt = thisRsw
198 haveDefaultCutoff = .true.
199 end subroutine setElectrostaticCutoffRadius
200
201 subroutine setDampingAlpha(thisAlpha)
202 real(kind=dp), intent(in) :: thisAlpha
203 dampingAlpha = thisAlpha
204 alpha2 = dampingAlpha*dampingAlpha
205 alpha4 = alpha2*alpha2
206 alpha6 = alpha4*alpha2
207 alpha8 = alpha4*alpha4
208 haveDampingAlpha = .true.
209 end subroutine setDampingAlpha
210
211 subroutine setReactionFieldDielectric(thisDielectric)
212 real(kind=dp), intent(in) :: thisDielectric
213 dielectric = thisDielectric
214 haveDielectric = .true.
215 end subroutine setReactionFieldDielectric
216
217 subroutine buildElectroSpline()
218 real( kind = dp ), dimension(np) :: xvals, yvals
219 real( kind = dp ) :: dx, rmin, rval
220 integer :: i
221
222 rmin = 0.0_dp
223
224 dx = (defaultCutoff-rmin) / dble(np-1)
225
226 do i = 1, np
227 rval = rmin + dble(i-1)*dx
228 xvals(i) = rval
229 yvals(i) = erfc(dampingAlpha*rval)
230 enddo
231
232 call newSpline(erfcSpline, xvals, yvals, .true.)
233
234 haveElectroSpline = .true.
235 end subroutine buildElectroSpline
236
237 subroutine newElectrostaticType(c_ident, is_Charge, is_Dipole, &
238 is_SplitDipole, is_Quadrupole, is_Tap, status)
239
240 integer, intent(in) :: c_ident
241 logical, intent(in) :: is_Charge
242 logical, intent(in) :: is_Dipole
243 logical, intent(in) :: is_SplitDipole
244 logical, intent(in) :: is_Quadrupole
245 logical, intent(in) :: is_Tap
246 integer, intent(out) :: status
247 integer :: nAtypes, myATID, i, j
248
249 status = 0
250 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
251
252 !! Be simple-minded and assume that we need an ElectrostaticMap that
253 !! is the same size as the total number of atom types
254
255 if (.not.allocated(ElectrostaticMap)) then
256
257 nAtypes = getSize(atypes)
258
259 if (nAtypes == 0) then
260 status = -1
261 return
262 end if
263
264 allocate(ElectrostaticMap(nAtypes))
265
266 end if
267
268 if (myATID .gt. size(ElectrostaticMap)) then
269 status = -1
270 return
271 endif
272
273 ! set the values for ElectrostaticMap for this atom type:
274
275 ElectrostaticMap(myATID)%c_ident = c_ident
276 ElectrostaticMap(myATID)%is_Charge = is_Charge
277 ElectrostaticMap(myATID)%is_Dipole = is_Dipole
278 ElectrostaticMap(myATID)%is_SplitDipole = is_SplitDipole
279 ElectrostaticMap(myATID)%is_Quadrupole = is_Quadrupole
280 ElectrostaticMap(myATID)%is_Tap = is_Tap
281
282 hasElectrostaticMap = .true.
283
284 end subroutine newElectrostaticType
285
286 subroutine setCharge(c_ident, charge, status)
287 integer, intent(in) :: c_ident
288 real(kind=dp), intent(in) :: charge
289 integer, intent(out) :: status
290 integer :: myATID
291
292 status = 0
293 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
294
295 if (.not.hasElectrostaticMap) then
296 call handleError("electrostatic", "no ElectrostaticMap was present before first call of setCharge!")
297 status = -1
298 return
299 end if
300
301 if (myATID .gt. size(ElectrostaticMap)) then
302 call handleError("electrostatic", "ElectrostaticMap was found to be too small during setCharge!")
303 status = -1
304 return
305 endif
306
307 if (.not.ElectrostaticMap(myATID)%is_Charge) then
308 call handleError("electrostatic", "Attempt to setCharge of an atom type that is not a charge!")
309 status = -1
310 return
311 endif
312
313 ElectrostaticMap(myATID)%charge = charge
314 end subroutine setCharge
315
316 subroutine setDipoleMoment(c_ident, dipole_moment, status)
317 integer, intent(in) :: c_ident
318 real(kind=dp), intent(in) :: dipole_moment
319 integer, intent(out) :: status
320 integer :: myATID
321
322 status = 0
323 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
324
325 if (.not.hasElectrostaticMap) then
326 call handleError("electrostatic", "no ElectrostaticMap was present before first call of setDipoleMoment!")
327 status = -1
328 return
329 end if
330
331 if (myATID .gt. size(ElectrostaticMap)) then
332 call handleError("electrostatic", "ElectrostaticMap was found to be too small during setDipoleMoment!")
333 status = -1
334 return
335 endif
336
337 if (.not.ElectrostaticMap(myATID)%is_Dipole) then
338 call handleError("electrostatic", "Attempt to setDipoleMoment of an atom type that is not a dipole!")
339 status = -1
340 return
341 endif
342
343 ElectrostaticMap(myATID)%dipole_moment = dipole_moment
344 end subroutine setDipoleMoment
345
346 subroutine setSplitDipoleDistance(c_ident, split_dipole_distance, status)
347 integer, intent(in) :: c_ident
348 real(kind=dp), intent(in) :: split_dipole_distance
349 integer, intent(out) :: status
350 integer :: myATID
351
352 status = 0
353 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
354
355 if (.not.hasElectrostaticMap) then
356 call handleError("electrostatic", "no ElectrostaticMap was present before first call of setSplitDipoleDistance!")
357 status = -1
358 return
359 end if
360
361 if (myATID .gt. size(ElectrostaticMap)) then
362 call handleError("electrostatic", "ElectrostaticMap was found to be too small during setSplitDipoleDistance!")
363 status = -1
364 return
365 endif
366
367 if (.not.ElectrostaticMap(myATID)%is_SplitDipole) then
368 call handleError("electrostatic", "Attempt to setSplitDipoleDistance of an atom type that is not a splitDipole!")
369 status = -1
370 return
371 endif
372
373 ElectrostaticMap(myATID)%split_dipole_distance = split_dipole_distance
374 end subroutine setSplitDipoleDistance
375
376 subroutine setQuadrupoleMoments(c_ident, quadrupole_moments, status)
377 integer, intent(in) :: c_ident
378 real(kind=dp), intent(in), dimension(3) :: quadrupole_moments
379 integer, intent(out) :: status
380 integer :: myATID, i, j
381
382 status = 0
383 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
384
385 if (.not.hasElectrostaticMap) then
386 call handleError("electrostatic", "no ElectrostaticMap was present before first call of setQuadrupoleMoments!")
387 status = -1
388 return
389 end if
390
391 if (myATID .gt. size(ElectrostaticMap)) then
392 call handleError("electrostatic", "ElectrostaticMap was found to be too small during setQuadrupoleMoments!")
393 status = -1
394 return
395 endif
396
397 if (.not.ElectrostaticMap(myATID)%is_Quadrupole) then
398 call handleError("electrostatic", "Attempt to setQuadrupoleMoments of an atom type that is not a quadrupole!")
399 status = -1
400 return
401 endif
402
403 do i = 1, 3
404 ElectrostaticMap(myATID)%quadrupole_moments(i) = &
405 quadrupole_moments(i)
406 enddo
407
408 end subroutine setQuadrupoleMoments
409
410
411 function getCharge(atid) result (c)
412 integer, intent(in) :: atid
413 integer :: localError
414 real(kind=dp) :: c
415
416 if (.not.hasElectrostaticMap) then
417 call handleError("electrostatic", "no ElectrostaticMap was present before first call of getCharge!")
418 return
419 end if
420
421 if (.not.ElectrostaticMap(atid)%is_Charge) then
422 c = 0.0_dp
423 return
424 endif
425
426 c = ElectrostaticMap(atid)%charge
427 end function getCharge
428
429 function getDipoleMoment(atid) result (dm)
430 integer, intent(in) :: atid
431 integer :: localError
432 real(kind=dp) :: dm
433
434 if (.not.hasElectrostaticMap) then
435 call handleError("electrostatic", "no ElectrostaticMap was present before first call of getDipoleMoment!")
436 return
437 end if
438
439 if (.not.ElectrostaticMap(atid)%is_Dipole) then
440 call handleError("electrostatic", "getDipoleMoment was called for an atom type that isn't a dipole!")
441 return
442 endif
443
444 dm = ElectrostaticMap(atid)%dipole_moment
445 end function getDipoleMoment
446
447 subroutine checkSummationMethod()
448
449 if (.not.haveDefaultCutoff) then
450 call handleError("checkSummationMethod", "no Default Cutoff set!")
451 endif
452
453 rcuti = 1.0_dp / defaultCutoff
454 rcuti2 = rcuti*rcuti
455 rcuti3 = rcuti2*rcuti
456 rcuti4 = rcuti2*rcuti2
457
458 if (screeningMethod .eq. DAMPED) then
459 if (.not.haveDampingAlpha) then
460 call handleError("checkSummationMethod", "no Damping Alpha set!")
461 endif
462
463 if (.not.haveDefaultCutoff) then
464 call handleError("checkSummationMethod", "no Default Cutoff set!")
465 endif
466
467 constEXP = exp(-alpha2*defaultCutoff2)
468 invRootPi = 0.56418958354775628695_dp
469 alphaPi = 2.0_dp*dampingAlpha*invRootPi
470
471 c1c = erfc(dampingAlpha*defaultCutoff) * rcuti
472 c2c = alphaPi*constEXP*rcuti + c1c*rcuti
473 c3c = 2.0_dp*alphaPi*alpha2 + 3.0_dp*c2c*rcuti
474 c4c = 4.0_dp*alphaPi*alpha4 + 5.0_dp*c3c*rcuti2
475 c5c = 8.0_dp*alphaPi*alpha6 + 7.0_dp*c4c*rcuti2
476 c6c = 16.0_dp*alphaPi*alpha8 + 9.0_dp*c5c*rcuti2
477 else
478 c1c = rcuti
479 c2c = c1c*rcuti
480 c3c = 3.0_dp*c2c*rcuti
481 c4c = 5.0_dp*c3c*rcuti2
482 c5c = 7.0_dp*c4c*rcuti2
483 c6c = 9.0_dp*c5c*rcuti2
484 endif
485
486 if (summationMethod .eq. REACTION_FIELD) then
487 if (haveDielectric) then
488 defaultCutoff2 = defaultCutoff*defaultCutoff
489 preRF = (dielectric-1.0_dp) / &
490 ((2.0_dp*dielectric+1.0_dp)*defaultCutoff2*defaultCutoff)
491 preRF2 = 2.0_dp*preRF
492 else
493 call handleError("checkSummationMethod", "Dielectric not set")
494 endif
495
496 endif
497
498 if (.not.haveElectroSpline) then
499 call buildElectroSpline()
500 end if
501
502 summationMethodChecked = .true.
503 end subroutine checkSummationMethod
504
505
506 subroutine doElectrostaticPair(me1, me2, d, rij, r2, rcut, sw, &
507 electroMult, vpair, fpair, pot, eF1, eF2, f1, t1, t2)
508
509 integer, intent(in) :: me1, me2
510 integer :: localError
511
512 real(kind=dp), intent(in) :: rij, r2, sw, rcut, electroMult
513 real(kind=dp), intent(in), dimension(3) :: d
514 real(kind=dp), intent(inout) :: vpair
515 real(kind=dp), intent(inout), dimension(3) :: fpair
516
517 real( kind = dp ) :: pot
518 real( kind = dp ), dimension(9) :: eF1, eF2 ! eFrame = electroFrame
519 real( kind = dp ), dimension(3) :: f1
520 real( kind = dp ), dimension(3,nLocal) :: felec
521 real( kind = dp ), dimension(3) :: t1, t2
522
523 real (kind = dp), dimension(3) :: ux_i, uy_i, uz_i
524 real (kind = dp), dimension(3) :: ux_j, uy_j, uz_j
525 real (kind = dp), dimension(3) :: dudux_i, duduy_i, duduz_i
526 real (kind = dp), dimension(3) :: dudux_j, duduy_j, duduz_j
527
528 logical :: i_is_Charge, i_is_Dipole, i_is_SplitDipole, i_is_Quadrupole
529 logical :: j_is_Charge, j_is_Dipole, j_is_SplitDipole, j_is_Quadrupole
530 logical :: i_is_Tap, j_is_Tap
531 integer :: id1, id2
532 real (kind=dp) :: q_i, q_j, mu_i, mu_j, d_i, d_j
533 real (kind=dp) :: qxx_i, qyy_i, qzz_i
534 real (kind=dp) :: qxx_j, qyy_j, qzz_j
535 real (kind=dp) :: cx_i, cy_i, cz_i
536 real (kind=dp) :: cx_j, cy_j, cz_j
537 real (kind=dp) :: cx2, cy2, cz2
538 real (kind=dp) :: ct_i, ct_j, ct_ij, a0, a1
539 real (kind=dp) :: riji, ri, ri2, ri3, ri4
540 real (kind=dp) :: pref, vterm, epot, dudr, vterm1, vterm2
541 real (kind=dp) :: xhat, yhat, zhat
542 real (kind=dp) :: dudx, dudy, dudz
543 real (kind=dp) :: scale, sc2, bigR
544 real (kind=dp) :: varEXP
545 real (kind=dp) :: pot_term
546 real (kind=dp) :: preVal, rfVal
547 real (kind=dp) :: c2ri, c3ri, c4rij
548 real (kind=dp) :: cti3, ctj3, ctidotj
549 real (kind=dp) :: preSw, preSwSc
550 real (kind=dp) :: xhatdot2, yhatdot2, zhatdot2
551 real (kind=dp) :: xhatc4, yhatc4, zhatc4
552
553 if (.not.summationMethodChecked) then
554 call checkSummationMethod()
555 endif
556
557 !! some variables we'll need independent of electrostatic type:
558
559 riji = 1.0_dp / rij
560
561 xhat = d(1) * riji
562 yhat = d(2) * riji
563 zhat = d(3) * riji
564
565 !! logicals
566 i_is_Charge = ElectrostaticMap(me1)%is_Charge
567 i_is_Dipole = ElectrostaticMap(me1)%is_Dipole
568 i_is_SplitDipole = ElectrostaticMap(me1)%is_SplitDipole
569 i_is_Quadrupole = ElectrostaticMap(me1)%is_Quadrupole
570 i_is_Tap = ElectrostaticMap(me1)%is_Tap
571
572 j_is_Charge = ElectrostaticMap(me2)%is_Charge
573 j_is_Dipole = ElectrostaticMap(me2)%is_Dipole
574 j_is_SplitDipole = ElectrostaticMap(me2)%is_SplitDipole
575 j_is_Quadrupole = ElectrostaticMap(me2)%is_Quadrupole
576 j_is_Tap = ElectrostaticMap(me2)%is_Tap
577
578 if (i_is_Charge) then
579 q_i = ElectrostaticMap(me1)%charge
580 endif
581
582 if (i_is_Dipole) then
583 mu_i = ElectrostaticMap(me1)%dipole_moment
584
585 uz_i(1) = eF1(3)
586 uz_i(2) = eF1(6)
587 uz_i(3) = eF1(9)
588
589 ct_i = uz_i(1)*xhat + uz_i(2)*yhat + uz_i(3)*zhat
590
591 if (i_is_SplitDipole) then
592 d_i = ElectrostaticMap(me1)%split_dipole_distance
593 endif
594 duduz_i = zero
595 endif
596
597 if (i_is_Quadrupole) then
598 qxx_i = ElectrostaticMap(me1)%quadrupole_moments(1)
599 qyy_i = ElectrostaticMap(me1)%quadrupole_moments(2)
600 qzz_i = ElectrostaticMap(me1)%quadrupole_moments(3)
601
602 ux_i(1) = eF1(1)
603 ux_i(2) = eF1(4)
604 ux_i(3) = eF1(7)
605 uy_i(1) = eF1(2)
606 uy_i(2) = eF1(5)
607 uy_i(3) = eF1(8)
608 uz_i(1) = eF1(3)
609 uz_i(2) = eF1(6)
610 uz_i(3) = eF1(9)
611
612 cx_i = ux_i(1)*xhat + ux_i(2)*yhat + ux_i(3)*zhat
613 cy_i = uy_i(1)*xhat + uy_i(2)*yhat + uy_i(3)*zhat
614 cz_i = uz_i(1)*xhat + uz_i(2)*yhat + uz_i(3)*zhat
615 dudux_i = zero
616 duduy_i = zero
617 duduz_i = zero
618 endif
619
620 if (j_is_Charge) then
621 q_j = ElectrostaticMap(me2)%charge
622 endif
623
624 if (j_is_Dipole) then
625 mu_j = ElectrostaticMap(me2)%dipole_moment
626
627 uz_j(1) = eF2(3)
628 uz_j(2) = eF2(6)
629 uz_j(3) = eF2(9)
630
631 ct_j = uz_j(1)*xhat + uz_j(2)*yhat + uz_j(3)*zhat
632
633 if (j_is_SplitDipole) then
634 d_j = ElectrostaticMap(me2)%split_dipole_distance
635 endif
636 duduz_j = zero
637 endif
638
639 if (j_is_Quadrupole) then
640 qxx_j = ElectrostaticMap(me2)%quadrupole_moments(1)
641 qyy_j = ElectrostaticMap(me2)%quadrupole_moments(2)
642 qzz_j = ElectrostaticMap(me2)%quadrupole_moments(3)
643
644 ux_j(1) = eF2(1)
645 ux_j(2) = eF2(4)
646 ux_j(3) = eF2(7)
647 uy_j(1) = eF2(2)
648 uy_j(2) = eF2(5)
649 uy_j(3) = eF2(8)
650 uz_j(1) = eF2(3)
651 uz_j(2) = eF2(6)
652 uz_j(3) = eF2(9)
653
654 cx_j = ux_j(1)*xhat + ux_j(2)*yhat + ux_j(3)*zhat
655 cy_j = uy_j(1)*xhat + uy_j(2)*yhat + uy_j(3)*zhat
656 cz_j = uz_j(1)*xhat + uz_j(2)*yhat + uz_j(3)*zhat
657 dudux_j = zero
658 duduy_j = zero
659 duduz_j = zero
660 endif
661
662 epot = zero
663 dudx = zero
664 dudy = zero
665 dudz = zero
666
667 if (i_is_Charge) then
668
669 if (j_is_Charge) then
670 if (screeningMethod .eq. DAMPED) then
671 ! assemble the damping variables
672 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
673 c1 = erfcVal*riji
674 c2 = (-derfcVal + c1)*riji
675 else
676 c1 = riji
677 c2 = c1*riji
678 endif
679
680 preVal = electroMult * pre11 * q_i * q_j
681
682 if (summationMethod .eq. SHIFTED_POTENTIAL) then
683 vterm = preVal * (c1 - c1c)
684
685 dudr = -sw * preVal * c2
686
687 elseif (summationMethod .eq. SHIFTED_FORCE) then
688 vterm = preVal * ( c1 - c1c + c2c*(rij - defaultCutoff) )
689
690 dudr = sw * preVal * (c2c - c2)
691
692 elseif (summationMethod .eq. REACTION_FIELD) then
693 rfVal = electroMult * preRF*rij*rij
694 vterm = preVal * ( riji + rfVal )
695
696 dudr = sw * preVal * ( 2.0_dp*rfVal - riji )*riji
697
698 else
699 vterm = preVal * riji*erfcVal
700
701 dudr = - sw * preVal * c2
702
703 endif
704
705 vpair = vpair + vterm
706 epot = epot + sw*vterm
707
708 dudx = dudx + dudr * xhat
709 dudy = dudy + dudr * yhat
710 dudz = dudz + dudr * zhat
711
712 endif
713
714 if (j_is_Dipole) then
715 ! pref is used by all the possible methods
716 pref = electroMult * pre12 * q_i * mu_j
717 preSw = sw*pref
718
719 if (summationMethod .eq. REACTION_FIELD) then
720 ri2 = riji * riji
721 ri3 = ri2 * riji
722
723 vterm = - pref * ct_j * ( ri2 - preRF2*rij )
724 vpair = vpair + vterm
725 epot = epot + sw*vterm
726
727 dudx = dudx - preSw*( ri3*(uz_j(1) - 3.0_dp*ct_j*xhat) - &
728 preRF2*uz_j(1) )
729 dudy = dudy - preSw*( ri3*(uz_j(2) - 3.0_dp*ct_j*yhat) - &
730 preRF2*uz_j(2) )
731 dudz = dudz - preSw*( ri3*(uz_j(3) - 3.0_dp*ct_j*zhat) - &
732 preRF2*uz_j(3) )
733 duduz_j(1) = duduz_j(1) - preSw * xhat * ( ri2 - preRF2*rij )
734 duduz_j(2) = duduz_j(2) - preSw * yhat * ( ri2 - preRF2*rij )
735 duduz_j(3) = duduz_j(3) - preSw * zhat * ( ri2 - preRF2*rij )
736
737 else
738 ! determine the inverse r used if we have split dipoles
739 if (j_is_SplitDipole) then
740 BigR = sqrt(r2 + 0.25_dp * d_j * d_j)
741 ri = 1.0_dp / BigR
742 scale = rij * ri
743 else
744 ri = riji
745 scale = 1.0_dp
746 endif
747
748 sc2 = scale * scale
749
750 if (screeningMethod .eq. DAMPED) then
751 ! assemble the damping variables
752 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
753 c1 = erfcVal*ri
754 c2 = (-derfcVal + c1)*ri
755 c3 = -2.0_dp*derfcVal*alpha2 + 3.0_dp*c2*ri
756 else
757 c1 = ri
758 c2 = c1*ri
759 c3 = 3.0_dp*c2*ri
760 endif
761
762 c2ri = c2*ri
763
764 ! calculate the potential
765 pot_term = scale * c2
766 vterm = -pref * ct_j * pot_term
767 vpair = vpair + vterm
768 epot = epot + sw*vterm
769
770 ! calculate derivatives for forces and torques
771 dudx = dudx - preSw*( uz_j(1)*c2ri - ct_j*xhat*sc2*c3 )
772 dudy = dudy - preSw*( uz_j(2)*c2ri - ct_j*yhat*sc2*c3 )
773 dudz = dudz - preSw*( uz_j(3)*c2ri - ct_j*zhat*sc2*c3 )
774
775 duduz_j(1) = duduz_j(1) - preSw * pot_term * xhat
776 duduz_j(2) = duduz_j(2) - preSw * pot_term * yhat
777 duduz_j(3) = duduz_j(3) - preSw * pot_term * zhat
778
779 endif
780 endif
781
782 if (j_is_Quadrupole) then
783 ! first precalculate some necessary variables
784 cx2 = cx_j * cx_j
785 cy2 = cy_j * cy_j
786 cz2 = cz_j * cz_j
787 pref = electroMult * pre14 * q_i * one_third
788
789 if (screeningMethod .eq. DAMPED) then
790 ! assemble the damping variables
791 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
792 c1 = erfcVal*riji
793 c2 = (-derfcVal + c1)*riji
794 c3 = -2.0_dp*derfcVal*alpha2 + 3.0_dp*c2*riji
795 c4 = -4.0_dp*derfcVal*alpha4 + 5.0_dp*c3*riji*riji
796 else
797 c1 = riji
798 c2 = c1*riji
799 c3 = 3.0_dp*c2*riji
800 c4 = 5.0_dp*c3*riji*riji
801 endif
802
803 ! precompute variables for convenience
804 preSw = sw*pref
805 c2ri = c2*riji
806 c3ri = c3*riji
807 c4rij = c4*rij
808 xhatdot2 = 2.0_dp*xhat*c3
809 yhatdot2 = 2.0_dp*yhat*c3
810 zhatdot2 = 2.0_dp*zhat*c3
811 xhatc4 = xhat*c4rij
812 yhatc4 = yhat*c4rij
813 zhatc4 = zhat*c4rij
814
815 ! calculate the potential
816 pot_term = ( qxx_j*(cx2*c3 - c2ri) + qyy_j*(cy2*c3 - c2ri) + &
817 qzz_j*(cz2*c3 - c2ri) )
818 vterm = pref * pot_term
819 vpair = vpair + vterm
820 epot = epot + sw*vterm
821
822 ! calculate derivatives for the forces and torques
823 dudx = dudx - preSw * ( &
824 qxx_j*(cx2*xhatc4 - (2.0_dp*cx_j*ux_j(1) + xhat)*c3ri) + &
825 qyy_j*(cy2*xhatc4 - (2.0_dp*cy_j*uy_j(1) + xhat)*c3ri) + &
826 qzz_j*(cz2*xhatc4 - (2.0_dp*cz_j*uz_j(1) + xhat)*c3ri) )
827 dudy = dudy - preSw * ( &
828 qxx_j*(cx2*yhatc4 - (2.0_dp*cx_j*ux_j(2) + yhat)*c3ri) + &
829 qyy_j*(cy2*yhatc4 - (2.0_dp*cy_j*uy_j(2) + yhat)*c3ri) + &
830 qzz_j*(cz2*yhatc4 - (2.0_dp*cz_j*uz_j(2) + yhat)*c3ri) )
831 dudz = dudz - preSw * ( &
832 qxx_j*(cx2*zhatc4 - (2.0_dp*cx_j*ux_j(3) + zhat)*c3ri) + &
833 qyy_j*(cy2*zhatc4 - (2.0_dp*cy_j*uy_j(3) + zhat)*c3ri) + &
834 qzz_j*(cz2*zhatc4 - (2.0_dp*cz_j*uz_j(3) + zhat)*c3ri) )
835
836 dudux_j(1) = dudux_j(1) + preSw*(qxx_j*cx_j*xhatdot2)
837 dudux_j(2) = dudux_j(2) + preSw*(qxx_j*cx_j*yhatdot2)
838 dudux_j(3) = dudux_j(3) + preSw*(qxx_j*cx_j*zhatdot2)
839
840 duduy_j(1) = duduy_j(1) + preSw*(qyy_j*cy_j*xhatdot2)
841 duduy_j(2) = duduy_j(2) + preSw*(qyy_j*cy_j*yhatdot2)
842 duduy_j(3) = duduy_j(3) + preSw*(qyy_j*cy_j*zhatdot2)
843
844 duduz_j(1) = duduz_j(1) + preSw*(qzz_j*cz_j*xhatdot2)
845 duduz_j(2) = duduz_j(2) + preSw*(qzz_j*cz_j*yhatdot2)
846 duduz_j(3) = duduz_j(3) + preSw*(qzz_j*cz_j*zhatdot2)
847
848
849 endif
850 endif
851
852 if (i_is_Dipole) then
853
854 if (j_is_Charge) then
855 ! variables used by all the methods
856 pref = electroMult * pre12 * q_j * mu_i
857 preSw = sw*pref
858
859 if (summationMethod .eq. REACTION_FIELD) then
860
861 ri2 = riji * riji
862 ri3 = ri2 * riji
863
864 vterm = pref * ct_i * ( ri2 - preRF2*rij )
865 vpair = vpair + vterm
866 epot = epot + sw*vterm
867
868 dudx = dudx + preSw * ( ri3*(uz_i(1) - 3.0_dp*ct_i*xhat) - &
869 preRF2*uz_i(1) )
870 dudy = dudy + preSw * ( ri3*(uz_i(2) - 3.0_dp*ct_i*yhat) - &
871 preRF2*uz_i(2) )
872 dudz = dudz + preSw * ( ri3*(uz_i(3) - 3.0_dp*ct_i*zhat) - &
873 preRF2*uz_i(3) )
874
875 duduz_i(1) = duduz_i(1) + preSw * xhat * ( ri2 - preRF2*rij )
876 duduz_i(2) = duduz_i(2) + preSw * yhat * ( ri2 - preRF2*rij )
877 duduz_i(3) = duduz_i(3) + preSw * zhat * ( ri2 - preRF2*rij )
878
879 else
880 ! determine inverse r if we are using split dipoles
881 if (i_is_SplitDipole) then
882 BigR = sqrt(r2 + 0.25_dp * d_i * d_i)
883 ri = 1.0_dp / BigR
884 scale = rij * ri
885 else
886 ri = riji
887 scale = 1.0_dp
888 endif
889
890 sc2 = scale * scale
891
892 if (screeningMethod .eq. DAMPED) then
893 ! assemble the damping variables
894 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
895 c1 = erfcVal*ri
896 c2 = (-derfcVal + c1)*ri
897 c3 = -2.0_dp*derfcVal*alpha2 + 3.0_dp*c2*ri
898 else
899 c1 = ri
900 c2 = c1*ri
901 c3 = 3.0_dp*c2*ri
902 endif
903
904 c2ri = c2*ri
905
906 ! calculate the potential
907 pot_term = c2 * scale
908 vterm = pref * ct_i * pot_term
909 vpair = vpair + vterm
910 epot = epot + sw*vterm
911
912 ! calculate derivatives for the forces and torques
913 dudx = dudx + preSw * ( uz_i(1)*c2ri - ct_i*xhat*sc2*c3 )
914 dudy = dudy + preSw * ( uz_i(2)*c2ri - ct_i*yhat*sc2*c3 )
915 dudz = dudz + preSw * ( uz_i(3)*c2ri - ct_i*zhat*sc2*c3 )
916
917 duduz_i(1) = duduz_i(1) + preSw * pot_term * xhat
918 duduz_i(2) = duduz_i(2) + preSw * pot_term * yhat
919 duduz_i(3) = duduz_i(3) + preSw * pot_term * zhat
920
921 endif
922 endif
923
924 if (j_is_Dipole) then
925 ! variables used by all methods
926 ct_ij = uz_i(1)*uz_j(1) + uz_i(2)*uz_j(2) + uz_i(3)*uz_j(3)
927 pref = electroMult * pre22 * mu_i * mu_j
928 preSw = sw*pref
929
930 if (summationMethod .eq. REACTION_FIELD) then
931 ri2 = riji * riji
932 ri3 = ri2 * riji
933 ri4 = ri2 * ri2
934
935 vterm = pref*( ri3*(ct_ij - 3.0_dp * ct_i * ct_j) - &
936 preRF2*ct_ij )
937 vpair = vpair + vterm
938 epot = epot + sw*vterm
939
940 a1 = 5.0_dp * ct_i * ct_j - ct_ij
941
942 dudx = dudx + preSw*3.0_dp*ri4*(a1*xhat-ct_i*uz_j(1)-ct_j*uz_i(1))
943 dudy = dudy + preSw*3.0_dp*ri4*(a1*yhat-ct_i*uz_j(2)-ct_j*uz_i(2))
944 dudz = dudz + preSw*3.0_dp*ri4*(a1*zhat-ct_i*uz_j(3)-ct_j*uz_i(3))
945
946 duduz_i(1) = duduz_i(1) + preSw*(ri3*(uz_j(1)-3.0_dp*ct_j*xhat) &
947 - preRF2*uz_j(1))
948 duduz_i(2) = duduz_i(2) + preSw*(ri3*(uz_j(2)-3.0_dp*ct_j*yhat) &
949 - preRF2*uz_j(2))
950 duduz_i(3) = duduz_i(3) + preSw*(ri3*(uz_j(3)-3.0_dp*ct_j*zhat) &
951 - preRF2*uz_j(3))
952 duduz_j(1) = duduz_j(1) + preSw*(ri3*(uz_i(1)-3.0_dp*ct_i*xhat) &
953 - preRF2*uz_i(1))
954 duduz_j(2) = duduz_j(2) + preSw*(ri3*(uz_i(2)-3.0_dp*ct_i*yhat) &
955 - preRF2*uz_i(2))
956 duduz_j(3) = duduz_j(3) + preSw*(ri3*(uz_i(3)-3.0_dp*ct_i*zhat) &
957 - preRF2*uz_i(3))
958
959 else
960 if (i_is_SplitDipole) then
961 if (j_is_SplitDipole) then
962 BigR = sqrt(r2 + 0.25_dp * d_i * d_i + 0.25_dp * d_j * d_j)
963 else
964 BigR = sqrt(r2 + 0.25_dp * d_i * d_i)
965 endif
966 ri = 1.0_dp / BigR
967 scale = rij * ri
968 else
969 if (j_is_SplitDipole) then
970 BigR = sqrt(r2 + 0.25_dp * d_j * d_j)
971 ri = 1.0_dp / BigR
972 scale = rij * ri
973 else
974 ri = riji
975 scale = 1.0_dp
976 endif
977 endif
978
979 if (screeningMethod .eq. DAMPED) then
980 ! assemble the damping variables
981 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
982 c1 = erfcVal*ri
983 c2 = (-derfcVal + c1)*ri
984 c3 = -2.0_dp*derfcVal*alpha2 + 3.0_dp*c2*ri
985 c4 = -4.0_dp*derfcVal*alpha4 + 5.0_dp*c3*ri*ri
986 else
987 c1 = ri
988 c2 = c1*ri
989 c3 = 3.0_dp*c2*ri
990 c4 = 5.0_dp*c3*ri*ri
991 endif
992
993 ! precompute variables for convenience
994 sc2 = scale * scale
995 cti3 = ct_i*sc2*c3
996 ctj3 = ct_j*sc2*c3
997 ctidotj = ct_i * ct_j * sc2
998 preSwSc = preSw*scale
999 c2ri = c2*ri
1000 c3ri = c3*ri
1001 c4rij = c4*rij
1002
1003
1004 ! calculate the potential
1005 pot_term = (ct_ij*c2ri - ctidotj*c3)
1006 vterm = pref * pot_term
1007 vpair = vpair + vterm
1008 epot = epot + sw*vterm
1009
1010 ! calculate derivatives for the forces and torques
1011 dudx = dudx + preSwSc * ( ctidotj*xhat*c4rij - &
1012 (ct_i*uz_j(1) + ct_j*uz_i(1) + ct_ij*xhat)*c3ri )
1013 dudy = dudy + preSwSc * ( ctidotj*yhat*c4rij - &
1014 (ct_i*uz_j(2) + ct_j*uz_i(2) + ct_ij*yhat)*c3ri )
1015 dudz = dudz + preSwSc * ( ctidotj*zhat*c4rij - &
1016 (ct_i*uz_j(3) + ct_j*uz_i(3) + ct_ij*zhat)*c3ri )
1017
1018 duduz_i(1) = duduz_i(1) + preSw * ( uz_j(1)*c2ri - ctj3*xhat )
1019 duduz_i(2) = duduz_i(2) + preSw * ( uz_j(2)*c2ri - ctj3*yhat )
1020 duduz_i(3) = duduz_i(3) + preSw * ( uz_j(3)*c2ri - ctj3*zhat )
1021
1022 duduz_j(1) = duduz_j(1) + preSw * ( uz_i(1)*c2ri - cti3*xhat )
1023 duduz_j(2) = duduz_j(2) + preSw * ( uz_i(2)*c2ri - cti3*yhat )
1024 duduz_j(3) = duduz_j(3) + preSw * ( uz_i(3)*c2ri - cti3*zhat )
1025
1026 endif
1027 endif
1028 endif
1029
1030 if (i_is_Quadrupole) then
1031 if (j_is_Charge) then
1032 ! precompute some necessary variables
1033 cx2 = cx_i * cx_i
1034 cy2 = cy_i * cy_i
1035 cz2 = cz_i * cz_i
1036 pref = electroMult * pre14 * q_j * one_third
1037
1038 if (screeningMethod .eq. DAMPED) then
1039 ! assemble the damping variables
1040 call lookupUniformSpline1d(erfcSpline, rij, erfcVal, derfcVal)
1041 c1 = erfcVal*riji
1042 c2 = (-derfcVal + c1)*riji
1043 c3 = -2.0_dp*derfcVal*alpha2 + 3.0_dp*c2*riji
1044 c4 = -4.0_dp*derfcVal*alpha4 + 5.0_dp*c3*riji*riji
1045 else
1046 c1 = riji
1047 c2 = c1*riji
1048 c3 = 3.0_dp*c2*riji
1049 c4 = 5.0_dp*c3*riji*riji
1050 endif
1051
1052 ! precompute some variables for convenience
1053 preSw = sw*pref
1054 c2ri = c2*riji
1055 c3ri = c3*riji
1056 c4rij = c4*rij
1057 xhatdot2 = 2.0_dp*xhat*c3
1058 yhatdot2 = 2.0_dp*yhat*c3
1059 zhatdot2 = 2.0_dp*zhat*c3
1060 xhatc4 = xhat*c4rij
1061 yhatc4 = yhat*c4rij
1062 zhatc4 = zhat*c4rij
1063
1064 ! calculate the potential
1065 pot_term = ( qxx_i * (cx2*c3 - c2ri) + qyy_i * (cy2*c3 - c2ri) + &
1066 qzz_i * (cz2*c3 - c2ri) )
1067
1068 vterm = pref * pot_term
1069 vpair = vpair + vterm
1070 epot = epot + sw*vterm
1071
1072 ! calculate the derivatives for the forces and torques
1073 dudx = dudx - preSw * ( &
1074 qxx_i*(cx2*xhatc4 - (2.0_dp*cx_i*ux_i(1) + xhat)*c3ri) + &
1075 qyy_i*(cy2*xhatc4 - (2.0_dp*cy_i*uy_i(1) + xhat)*c3ri) + &
1076 qzz_i*(cz2*xhatc4 - (2.0_dp*cz_i*uz_i(1) + xhat)*c3ri) )
1077 dudy = dudy - preSw * ( &
1078 qxx_i*(cx2*yhatc4 - (2.0_dp*cx_i*ux_i(2) + yhat)*c3ri) + &
1079 qyy_i*(cy2*yhatc4 - (2.0_dp*cy_i*uy_i(2) + yhat)*c3ri) + &
1080 qzz_i*(cz2*yhatc4 - (2.0_dp*cz_i*uz_i(2) + yhat)*c3ri) )
1081 dudz = dudz - preSw * ( &
1082 qxx_i*(cx2*zhatc4 - (2.0_dp*cx_i*ux_i(3) + zhat)*c3ri) + &
1083 qyy_i*(cy2*zhatc4 - (2.0_dp*cy_i*uy_i(3) + zhat)*c3ri) + &
1084 qzz_i*(cz2*zhatc4 - (2.0_dp*cz_i*uz_i(3) + zhat)*c3ri) )
1085
1086 dudux_i(1) = dudux_i(1) + preSw*(qxx_i*cx_i*xhatdot2)
1087 dudux_i(2) = dudux_i(2) + preSw*(qxx_i*cx_i*yhatdot2)
1088 dudux_i(3) = dudux_i(3) + preSw*(qxx_i*cx_i*zhatdot2)
1089
1090 duduy_i(1) = duduy_i(1) + preSw*(qyy_i*cy_i*xhatdot2)
1091 duduy_i(2) = duduy_i(2) + preSw*(qyy_i*cy_i*yhatdot2)
1092 duduy_i(3) = duduy_i(3) + preSw*(qyy_i*cy_i*zhatdot2)
1093
1094 duduz_i(1) = duduz_i(1) + preSw*(qzz_i*cz_i*xhatdot2)
1095 duduz_i(2) = duduz_i(2) + preSw*(qzz_i*cz_i*yhatdot2)
1096 duduz_i(3) = duduz_i(3) + preSw*(qzz_i*cz_i*zhatdot2)
1097 endif
1098 endif
1099
1100 pot = pot + epot
1101
1102 f1(1) = f1(1) + dudx
1103 f1(2) = f1(2) + dudy
1104 f1(3) = f1(3) + dudz
1105
1106 if (i_is_Dipole .or. i_is_Quadrupole) then
1107 t1(1) = t1(1) - uz_i(2)*duduz_i(3) + uz_i(3)*duduz_i(2)
1108 t1(2) = t1(2) - uz_i(3)*duduz_i(1) + uz_i(1)*duduz_i(3)
1109 t1(3) = t1(3) - uz_i(1)*duduz_i(2) + uz_i(2)*duduz_i(1)
1110 endif
1111 if (i_is_Quadrupole) then
1112 t1(1) = t1(1) - ux_i(2)*dudux_i(3) + ux_i(3)*dudux_i(2)
1113 t1(2) = t1(2) - ux_i(3)*dudux_i(1) + ux_i(1)*dudux_i(3)
1114 t1(3) = t1(3) - ux_i(1)*dudux_i(2) + ux_i(2)*dudux_i(1)
1115
1116 t1(1) = t1(1) - uy_i(2)*duduy_i(3) + uy_i(3)*duduy_i(2)
1117 t1(2) = t1(2) - uy_i(3)*duduy_i(1) + uy_i(1)*duduy_i(3)
1118 t1(3) = t1(3) - uy_i(1)*duduy_i(2) + uy_i(2)*duduy_i(1)
1119 endif
1120
1121 if (j_is_Dipole .or. j_is_Quadrupole) then
1122 t2(1) = t2(1) - uz_j(2)*duduz_j(3) + uz_j(3)*duduz_j(2)
1123 t2(2) = t2(2) - uz_j(3)*duduz_j(1) + uz_j(1)*duduz_j(3)
1124 t2(3) = t2(3) - uz_j(1)*duduz_j(2) + uz_j(2)*duduz_j(1)
1125 endif
1126 if (j_is_Quadrupole) then
1127 t2(1) = t2(1) - ux_j(2)*dudux_j(3) + ux_j(3)*dudux_j(2)
1128 t2(2) = t2(2) - ux_j(3)*dudux_j(1) + ux_j(1)*dudux_j(3)
1129 t2(3) = t2(3) - ux_j(1)*dudux_j(2) + ux_j(2)*dudux_j(1)
1130
1131 t2(1) = t2(1) - uy_j(2)*duduy_j(3) + uy_j(3)*duduy_j(2)
1132 t2(2) = t2(2) - uy_j(3)*duduy_j(1) + uy_j(1)*duduy_j(3)
1133 t2(3) = t2(3) - uy_j(1)*duduy_j(2) + uy_j(2)*duduy_j(1)
1134 endif
1135
1136 return
1137 end subroutine doElectrostaticPair
1138
1139 subroutine destroyElectrostaticTypes()
1140
1141 if(allocated(ElectrostaticMap)) deallocate(ElectrostaticMap)
1142
1143 end subroutine destroyElectrostaticTypes
1144
1145 subroutine self_self(atom1, eFrame, skch, mypot, t)
1146 integer, intent(in) :: atom1
1147 integer :: atid1
1148 real(kind=dp), dimension(9,nLocal) :: eFrame
1149 real(kind=dp), dimension(3,nLocal) :: t
1150 real(kind=dp) :: mu1, chg1, c1e
1151 real(kind=dp) :: preVal, epot, mypot, skch
1152 real(kind=dp) :: eix, eiy, eiz, self
1153
1154 ! this is a local only array, so we use the local atom type id's:
1155 atid1 = atid(atom1)
1156
1157 if (.not.summationMethodChecked) then
1158 call checkSummationMethod()
1159 endif
1160
1161 if (summationMethod .eq. REACTION_FIELD) then
1162 if (ElectrostaticMap(atid1)%is_Dipole) then
1163 mu1 = getDipoleMoment(atid1)
1164
1165 preVal = pre22 * preRF2 * mu1*mu1
1166 mypot = mypot - 0.5_dp*preVal
1167
1168 ! The self-correction term adds into the reaction field vector
1169
1170 eix = preVal * eFrame(3,atom1)
1171 eiy = preVal * eFrame(6,atom1)
1172 eiz = preVal * eFrame(9,atom1)
1173
1174 ! once again, this is self-self, so only the local arrays are needed
1175 ! even for MPI jobs:
1176
1177 t(1,atom1)=t(1,atom1) - eFrame(6,atom1)*eiz + &
1178 eFrame(9,atom1)*eiy
1179 t(2,atom1)=t(2,atom1) - eFrame(9,atom1)*eix + &
1180 eFrame(3,atom1)*eiz
1181 t(3,atom1)=t(3,atom1) - eFrame(3,atom1)*eiy + &
1182 eFrame(6,atom1)*eix
1183
1184 endif
1185
1186 elseif ( (summationMethod .eq. SHIFTED_FORCE) .or. &
1187 (summationMethod .eq. SHIFTED_POTENTIAL) ) then
1188 if (ElectrostaticMap(atid1)%is_Charge) then
1189 chg1 = getCharge(atid1)
1190 if (screeningMethod .eq. DAMPED) then
1191 self = - 0.5_dp * (c1c+alphaPi) * chg1 * (chg1+skch) * pre11
1192 else
1193 self = - 0.5_dp * rcuti * chg1 * (chg1+skch) * pre11
1194 endif
1195
1196 mypot = mypot + self
1197 endif
1198 endif
1199
1200
1201
1202 return
1203 end subroutine self_self
1204
1205 subroutine rf_self_excludes(atom1, atom2, sw, electroMult, eFrame, d, &
1206 rij, vpair, myPot, f, t)
1207 integer, intent(in) :: atom1
1208 integer, intent(in) :: atom2
1209 logical :: i_is_Charge, j_is_Charge
1210 logical :: i_is_Dipole, j_is_Dipole
1211 integer :: atid1
1212 integer :: atid2
1213 real(kind=dp), intent(in) :: rij
1214 real(kind=dp), intent(in) :: sw, electroMult
1215 real(kind=dp), intent(in), dimension(3) :: d
1216 real(kind=dp), intent(inout) :: vpair
1217 real(kind=dp), dimension(9,nLocal) :: eFrame
1218 real(kind=dp), dimension(3,nLocal) :: f
1219 real(kind=dp), dimension(3,nLocal) :: t
1220 real (kind = dp), dimension(3) :: duduz_i
1221 real (kind = dp), dimension(3) :: duduz_j
1222 real (kind = dp), dimension(3) :: uz_i
1223 real (kind = dp), dimension(3) :: uz_j
1224 real(kind=dp) :: q_i, q_j, mu_i, mu_j
1225 real(kind=dp) :: xhat, yhat, zhat
1226 real(kind=dp) :: ct_i, ct_j
1227 real(kind=dp) :: ri2, ri3, riji, vterm
1228 real(kind=dp) :: pref, preVal, rfVal, myPot
1229 real(kind=dp) :: dudx, dudy, dudz, dudr
1230
1231 if (.not.summationMethodChecked) then
1232 call checkSummationMethod()
1233 endif
1234
1235 dudx = zero
1236 dudy = zero
1237 dudz = zero
1238
1239 riji = 1.0_dp/rij
1240
1241 xhat = d(1) * riji
1242 yhat = d(2) * riji
1243 zhat = d(3) * riji
1244
1245 ! this is a local only array, so we use the local atom type id's:
1246 atid1 = atid(atom1)
1247 atid2 = atid(atom2)
1248 i_is_Charge = ElectrostaticMap(atid1)%is_Charge
1249 j_is_Charge = ElectrostaticMap(atid2)%is_Charge
1250 i_is_Dipole = ElectrostaticMap(atid1)%is_Dipole
1251 j_is_Dipole = ElectrostaticMap(atid2)%is_Dipole
1252
1253 if (i_is_Charge.and.j_is_Charge) then
1254 q_i = ElectrostaticMap(atid1)%charge
1255 q_j = ElectrostaticMap(atid2)%charge
1256
1257 preVal = electroMult * pre11 * q_i * q_j
1258 rfVal = preRF*rij*rij
1259 vterm = preVal * rfVal
1260
1261 myPot = myPot + sw*vterm
1262
1263 dudr = sw*preVal * 2.0_dp*rfVal*riji
1264
1265 dudx = dudx + dudr * xhat
1266 dudy = dudy + dudr * yhat
1267 dudz = dudz + dudr * zhat
1268
1269 elseif (i_is_Charge.and.j_is_Dipole) then
1270 q_i = ElectrostaticMap(atid1)%charge
1271 mu_j = ElectrostaticMap(atid2)%dipole_moment
1272 uz_j(1) = eFrame(3,atom2)
1273 uz_j(2) = eFrame(6,atom2)
1274 uz_j(3) = eFrame(9,atom2)
1275 ct_j = uz_j(1)*xhat + uz_j(2)*yhat + uz_j(3)*zhat
1276
1277 ri2 = riji * riji
1278 ri3 = ri2 * riji
1279
1280 pref = electroMult * pre12 * q_i * mu_j
1281 vterm = - pref * ct_j * ( ri2 - preRF2*rij )
1282 myPot = myPot + sw*vterm
1283
1284 dudx = dudx - sw*pref*( ri3*(uz_j(1)-3.0_dp*ct_j*xhat) &
1285 - preRF2*uz_j(1) )
1286 dudy = dudy - sw*pref*( ri3*(uz_j(2)-3.0_dp*ct_j*yhat) &
1287 - preRF2*uz_j(2) )
1288 dudz = dudz - sw*pref*( ri3*(uz_j(3)-3.0_dp*ct_j*zhat) &
1289 - preRF2*uz_j(3) )
1290
1291 duduz_j(1) = duduz_j(1) - sw * pref * xhat * ( ri2 - preRF2*rij )
1292 duduz_j(2) = duduz_j(2) - sw * pref * yhat * ( ri2 - preRF2*rij )
1293 duduz_j(3) = duduz_j(3) - sw * pref * zhat * ( ri2 - preRF2*rij )
1294
1295 elseif (i_is_Dipole.and.j_is_Charge) then
1296 mu_i = ElectrostaticMap(atid1)%dipole_moment
1297 q_j = ElectrostaticMap(atid2)%charge
1298 uz_i(1) = eFrame(3,atom1)
1299 uz_i(2) = eFrame(6,atom1)
1300 uz_i(3) = eFrame(9,atom1)
1301 ct_i = uz_i(1)*xhat + uz_i(2)*yhat + uz_i(3)*zhat
1302
1303 ri2 = riji * riji
1304 ri3 = ri2 * riji
1305
1306 pref = electroMult * pre12 * q_j * mu_i
1307 vterm = pref * ct_i * ( ri2 - preRF2*rij )
1308 myPot = myPot + sw*vterm
1309
1310 dudx = dudx + sw*pref*( ri3*(uz_i(1)-3.0_dp*ct_i*xhat) &
1311 - preRF2*uz_i(1) )
1312 dudy = dudy + sw*pref*( ri3*(uz_i(2)-3.0_dp*ct_i*yhat) &
1313 - preRF2*uz_i(2) )
1314 dudz = dudz + sw*pref*( ri3*(uz_i(3)-3.0_dp*ct_i*zhat) &
1315 - preRF2*uz_i(3) )
1316
1317 duduz_i(1) = duduz_i(1) + sw * pref * xhat * ( ri2 - preRF2*rij )
1318 duduz_i(2) = duduz_i(2) + sw * pref * yhat * ( ri2 - preRF2*rij )
1319 duduz_i(3) = duduz_i(3) + sw * pref * zhat * ( ri2 - preRF2*rij )
1320
1321 endif
1322
1323
1324 ! accumulate the forces and torques resulting from the self term
1325 f(1,atom1) = f(1,atom1) + dudx
1326 f(2,atom1) = f(2,atom1) + dudy
1327 f(3,atom1) = f(3,atom1) + dudz
1328
1329 f(1,atom2) = f(1,atom2) - dudx
1330 f(2,atom2) = f(2,atom2) - dudy
1331 f(3,atom2) = f(3,atom2) - dudz
1332
1333 if (i_is_Dipole) then
1334 t(1,atom1)=t(1,atom1) - uz_i(2)*duduz_i(3) + uz_i(3)*duduz_i(2)
1335 t(2,atom1)=t(2,atom1) - uz_i(3)*duduz_i(1) + uz_i(1)*duduz_i(3)
1336 t(3,atom1)=t(3,atom1) - uz_i(1)*duduz_i(2) + uz_i(2)*duduz_i(1)
1337 elseif (j_is_Dipole) then
1338 t(1,atom2)=t(1,atom2) - uz_j(2)*duduz_j(3) + uz_j(3)*duduz_j(2)
1339 t(2,atom2)=t(2,atom2) - uz_j(3)*duduz_j(1) + uz_j(1)*duduz_j(3)
1340 t(3,atom2)=t(3,atom2) - uz_j(1)*duduz_j(2) + uz_j(2)*duduz_j(1)
1341 endif
1342
1343 return
1344 end subroutine rf_self_excludes
1345
1346 subroutine accumulate_box_dipole(atom1, eFrame, d, pChg, nChg, pChgPos, &
1347 nChgPos, dipVec, pChgCount, nChgCount)
1348 integer, intent(in) :: atom1
1349 logical :: i_is_Charge
1350 logical :: i_is_Dipole
1351 integer :: atid1
1352 integer :: pChgCount
1353 integer :: nChgCount
1354 real(kind=dp), intent(in), dimension(3) :: d
1355 real(kind=dp), dimension(9,nLocal) :: eFrame
1356 real(kind=dp) :: pChg
1357 real(kind=dp) :: nChg
1358 real(kind=dp), dimension(3) :: pChgPos
1359 real(kind=dp), dimension(3) :: nChgPos
1360 real(kind=dp), dimension(3) :: dipVec
1361 real(kind=dp), dimension(3) :: uz_i
1362 real(kind=dp), dimension(3) :: pos
1363 real(kind=dp) :: q_i, mu_i
1364 real(kind=dp) :: pref, preVal
1365
1366 if (.not.summationMethodChecked) then
1367 call checkSummationMethod()
1368 endif
1369
1370 ! this is a local only array, so we use the local atom type id's:
1371 atid1 = atid(atom1)
1372 i_is_Charge = ElectrostaticMap(atid1)%is_Charge
1373 i_is_Dipole = ElectrostaticMap(atid1)%is_Dipole
1374
1375 if (i_is_Charge) then
1376 q_i = ElectrostaticMap(atid1)%charge
1377 ! convert to the proper units
1378 q_i = q_i * chargeToC
1379 pos = d * angstromToM
1380
1381 if (q_i.le.0.0_dp) then
1382 nChg = nChg - q_i
1383 nChgPos(1) = nChgPos(1) + pos(1)
1384 nChgPos(2) = nChgPos(2) + pos(2)
1385 nChgPos(3) = nChgPos(3) + pos(3)
1386 nChgCount = nChgCount + 1
1387
1388 else
1389 pChg = pChg + q_i
1390 pChgPos(1) = pChgPos(1) + pos(1)
1391 pChgPos(2) = pChgPos(2) + pos(2)
1392 pChgPos(3) = pChgPos(3) + pos(3)
1393 pChgCount = pChgCount + 1
1394
1395 endif
1396
1397 endif
1398
1399 if (i_is_Dipole) then
1400 mu_i = ElectrostaticMap(atid1)%dipole_moment
1401 uz_i(1) = eFrame(3,atom1)
1402 uz_i(2) = eFrame(6,atom1)
1403 uz_i(3) = eFrame(9,atom1)
1404 ! convert to the proper units
1405 mu_i = mu_i * debyeToCm
1406
1407 dipVec(1) = dipVec(1) + uz_i(1)*mu_i
1408 dipVec(2) = dipVec(2) + uz_i(2)*mu_i
1409 dipVec(3) = dipVec(3) + uz_i(3)*mu_i
1410
1411 endif
1412
1413 return
1414 end subroutine accumulate_box_dipole
1415
1416 end module electrostatic_module

Properties

Name Value
svn:keywords Author Id Revision Date