ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/UseTheForce/DarkSide/MetalNonMetal.F90
Revision: 1386
Committed: Fri Oct 23 18:41:09 2009 UTC (15 years, 9 months ago) by gezelter
File size: 24671 byte(s)
Log Message:
removing MPI responsibilities from the lowest level force routines.  This is
in preparation for migrating these routines (LJ, electrostatic, eam, suttonchen,
gay-berne, sticky) to C++

File Contents

# Content
1 !!
2 !! Copyright (c) 2007 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
43 !! Calculates Metal-Non Metal interactions.
44 !! @author Charles F. Vardeman II
45 !! @version $Id: MetalNonMetal.F90,v 1.18 2009-10-23 18:41:08 gezelter Exp $, $Date: 2009-10-23 18:41:08 $, $Name: not supported by cvs2svn $, $Revision: 1.18 $
46
47
48 module MetalNonMetal
49 use definitions
50 use atype_module
51 use vector_class
52 use simulation
53 use status
54 use fForceOptions
55 use force_globals
56
57 implicit none
58 PRIVATE
59 #define __FORTRAN90
60 #include "UseTheForce/DarkSide/fInteractionMap.h"
61 #include "UseTheForce/DarkSide/fMnMInteractions.h"
62
63 logical, save :: useGeometricDistanceMixing = .false.
64 logical, save :: haveInteractionLookup = .false.
65
66 real(kind=DP), save :: defaultCutoff = 0.0_DP
67
68 logical, save :: defaultShiftPot = .false.
69 logical, save :: defaultShiftFrc = .false.
70 logical, save :: haveDefaultCutoff = .false.
71
72 type :: MnMinteraction
73 integer :: metal_atid
74 integer :: nonmetal_atid
75 integer :: interaction_type
76 real(kind=dp) :: R0
77 real(kind=dp) :: D0
78 real(kind=dp) :: beta0
79 real(kind=dp) :: betaH
80 real(kind=dp) :: ca1
81 real(kind=dp) :: cb1
82 real(kind=dp) :: sigma
83 real(kind=dp) :: epsilon
84 real(kind=dp) :: rCut = 0.0_dp
85 logical :: rCutWasSet = .false.
86 logical :: shiftedPot = .false.
87 logical :: shiftedFrc = .false.
88 end type MnMinteraction
89
90 type :: MnMinteractionMap
91 PRIVATE
92 integer :: initialCapacity = 10
93 integer :: capacityIncrement = 0
94 integer :: interactionCount = 0
95 type(MnMinteraction), pointer :: interactions(:) => null()
96 end type MnMinteractionMap
97
98 type (MnMInteractionMap), pointer :: MnM_Map
99
100 integer, allocatable, dimension(:,:) :: MnMinteractionLookup
101
102 public :: setMnMDefaultCutoff
103 public :: addInteraction
104 public :: deleteInteractions
105 public :: MNMtype
106 public :: do_mnm_pair
107
108 contains
109
110
111 subroutine do_mnm_pair(Atom1, Atom2, atid1, atid2, D, Rij, R2, Rcut, Sw, vdwMult, &
112 Vpair, Fpair, Pot, A1, A2, f1, t1, t2, Do_pot)
113 integer, intent(in) :: atom1, atom2, atid1, atid2
114 integer :: ljt1, ljt2
115 real( kind = dp ), intent(in) :: rij, r2, rcut, vdwMult
116 real( kind = dp ) :: pot, sw, vpair
117 real( kind = dp ), intent(inout), dimension(3) :: f1
118 real (kind=dp), intent(inout), dimension(9) :: A1, A2
119 real (kind=dp), intent(inout), dimension(3) :: t1, t2
120 real( kind = dp ), intent(in), dimension(3) :: d
121 real( kind = dp ), intent(inout), dimension(3) :: fpair
122 logical, intent(in) :: do_pot
123
124 integer :: interaction_id
125 integer :: interaction_type
126
127 if(.not.haveInteractionLookup) then
128 call createInteractionLookup(MnM_MAP)
129 haveInteractionLookup =.true.
130 end if
131
132 interaction_id = MnMinteractionLookup(atid1, atid2)
133 interaction_type = MnM_Map%interactions(interaction_id)%interaction_type
134
135 select case (interaction_type)
136 case (MNM_LENNARDJONES)
137 call calc_mnm_lennardjones(Atom1, Atom2, D, Rij, R2, Rcut, Sw, &
138 vdwMult, Vpair, Fpair, Pot, f1, Do_pot, interaction_id)
139 case(MNM_REPULSIVEMORSE, MNM_SHIFTEDMORSE)
140 call calc_mnm_morse(Atom1, Atom2, D, Rij, R2, Rcut, Sw, vdwMult, &
141 Vpair, Fpair, Pot, f1, Do_pot, interaction_id, interaction_type)
142 case(MNM_MAW)
143 call calc_mnm_maw(Atom1, Atom2, atid1, atid2, D, Rij, R2, Rcut, Sw, vdwMult, &
144 Vpair, Fpair, Pot, A1, A2, f1, t1, t2, Do_pot, interaction_id)
145 case default
146 call handleError("MetalNonMetal","Unknown interaction type")
147 end select
148
149 end subroutine do_mnm_pair
150
151 subroutine calc_mnm_lennardjones(Atom1, Atom2, D, Rij, R2, Rcut, Sw, &
152 vdwMult,Vpair, Fpair, Pot, f1, Do_pot, interaction_id)
153
154 integer, intent(in) :: atom1, atom2
155 real( kind = dp ), intent(in) :: rij, r2, rcut, vdwMult
156 real( kind = dp ) :: pot, sw, vpair
157 real( kind = dp ), intent(inout), dimension(3) :: f1
158 real( kind = dp ), intent(in), dimension(3) :: d
159 real( kind = dp ), intent(inout), dimension(3) :: fpair
160 logical, intent(in) :: do_pot
161 integer, intent(in) :: interaction_id
162
163 ! local Variables
164 real( kind = dp ) :: drdx, drdy, drdz
165 real( kind = dp ) :: fx, fy, fz
166 real( kind = dp ) :: myPot, myPotC, myDeriv, myDerivC, ros, rcos
167 real( kind = dp ) :: pot_temp, dudr
168 real( kind = dp ) :: sigmai
169 real( kind = dp ) :: epsilon
170 logical :: isSoftCore, shiftedPot, shiftedFrc
171 integer :: id1, id2, localError
172
173 sigmai = 1.0_dp / MnM_Map%interactions(interaction_id)%sigma
174 epsilon = MnM_Map%interactions(interaction_id)%epsilon
175 shiftedPot = MnM_Map%interactions(interaction_id)%shiftedPot
176 shiftedFrc = MnM_Map%interactions(interaction_id)%shiftedFrc
177
178 ros = rij * sigmai
179
180 call getLJfunc(ros, myPot, myDeriv)
181
182 if (shiftedPot) then
183 rcos = rcut * sigmai
184 call getLJfunc(rcos, myPotC, myDerivC)
185 myDerivC = 0.0_dp
186 elseif (shiftedFrc) then
187 rcos = rcut * sigmai
188 call getLJfunc(rcos, myPotC, myDerivC)
189 myPotC = myPotC + myDerivC * (rij - rcut) * sigmai
190 else
191 myPotC = 0.0_dp
192 myDerivC = 0.0_dp
193 endif
194
195 pot_temp = vdwMult * epsilon * (myPot - myPotC)
196 vpair = vpair + pot_temp
197 dudr = sw * vdwMult * epsilon * (myDeriv - myDerivC) * sigmai
198
199 drdx = d(1) / rij
200 drdy = d(2) / rij
201 drdz = d(3) / rij
202
203 fx = dudr * drdx
204 fy = dudr * drdy
205 fz = dudr * drdz
206
207 pot = pot + sw*pot_temp
208 f1(1) = f1(1) + fx
209 f1(2) = f1(2) + fy
210 f1(3) = f1(3) + fz
211
212 return
213 end subroutine calc_mnm_lennardjones
214
215 subroutine calc_mnm_morse(Atom1, Atom2, D, Rij, R2, Rcut, Sw, vdwMult, &
216 Vpair, Fpair, Pot, f1, Do_pot, interaction_id, interaction_type)
217 integer, intent(in) :: atom1, atom2
218 real( kind = dp ), intent(in) :: rij, r2, rcut, vdwMult
219 real( kind = dp ) :: pot, sw, vpair
220 real( kind = dp ), intent(inout), dimension(3) :: f1
221 real( kind = dp ), intent(in), dimension(3) :: d
222 real( kind = dp ), intent(inout), dimension(3) :: fpair
223 logical, intent(in) :: do_pot
224 integer, intent(in) :: interaction_id, interaction_type
225 logical :: shiftedPot, shiftedFrc
226
227 ! Local Variables
228 real(kind=dp) :: Beta0
229 real(kind=dp) :: R0
230 real(kind=dp) :: D0
231 real(kind=dp) :: expt
232 real(kind=dp) :: expt2
233 real(kind=dp) :: expfnc
234 real(kind=dp) :: expfnc2
235 real(kind=dp) :: D_expt
236 real(kind=dp) :: D_expt2
237 real(kind=dp) :: rcos
238 real(kind=dp) :: exptC
239 real(kind=dp) :: expt2C
240 real(kind=dp) :: expfncC
241 real(kind=dp) :: expfnc2C
242 real(kind=dp) :: D_expt2C
243 real(kind=dp) :: D_exptC
244
245 real(kind=dp) :: myPot
246 real(kind=dp) :: myPotC
247 real(kind=dp) :: myDeriv
248 real(kind=dp) :: myDerivC
249 real(kind=dp) :: pot_temp
250 real(kind=dp) :: fx,fy,fz
251 real(kind=dp) :: drdx,drdy,drdz
252 real(kind=dp) :: dudr
253 integer :: id1,id2
254
255
256 D0 = MnM_Map%interactions(interaction_id)%D0
257 R0 = MnM_Map%interactions(interaction_id)%r0
258 Beta0 = MnM_Map%interactions(interaction_id)%Beta0
259 shiftedPot = MnM_Map%interactions(interaction_id)%shiftedPot
260 shiftedFrc = MnM_Map%interactions(interaction_id)%shiftedFrc
261
262 ! V(r) = D_e exp(-a(r-re)(exp(-a(r-re))-2)
263
264 expt = -beta0*(rij - R0)
265 expfnc = exp(expt)
266 expfnc2 = expfnc*expfnc
267
268 if (shiftedPot .or. shiftedFrc) then
269 exptC = -beta0*(rcut - R0)
270 expfncC = exp(exptC)
271 expfnc2C = expfncC*expfncC
272 endif
273
274 select case (interaction_type)
275 case (MNM_SHIFTEDMORSE)
276
277 myPot = D0 * (expfnc2 - 2.0_dp * expfnc)
278 myDeriv = 2.0*D0*beta0*(expfnc - expfnc2)
279
280 if (shiftedPot) then
281 myPotC = D0 * (expfnc2C - 2.0_dp * expfncC)
282 myDerivC = 0.0_dp
283 elseif (shiftedFrc) then
284 myPotC = D0 * (expfnc2C - 2.0_dp * expfncC)
285 myDerivC = 2.0*D0*beta0*(expfnc2C - expfnc2C)
286 myPotC = myPotC + myDerivC * (rij - rcut)
287 else
288 myPotC = 0.0_dp
289 myDerivC = 0.0_dp
290 endif
291
292 case (MNM_REPULSIVEMORSE)
293
294 myPot = D0 * expfnc2
295 myDeriv = -2.0_dp * D0 * beta0 * expfnc2
296
297 if (shiftedPot) then
298 myPotC = D0 * expfnc2C
299 myDerivC = 0.0_dp
300 elseif (shiftedFrc) then
301 myPotC = D0 * expfnc2C
302 myDerivC = -2.0_dp * D0* beta0 * expfnc2C
303 myPotC = myPotC + myDerivC * (rij - rcut)
304 else
305 myPotC = 0.0_dp
306 myDerivC = 0.0_dp
307 endif
308 end select
309
310 pot_temp = vdwMult * (myPot - myPotC)
311 vpair = vpair + pot_temp
312 dudr = sw * vdwMult * (myDeriv - myDerivC)
313
314 drdx = d(1) / rij
315 drdy = d(2) / rij
316 drdz = d(3) / rij
317
318 fx = dudr * drdx
319 fy = dudr * drdy
320 fz = dudr * drdz
321
322 pot = pot + sw*pot_temp
323
324 f1(1) = f1(1) + fx
325 f1(2) = f1(2) + fy
326 f1(3) = f1(3) + fz
327
328 return
329 end subroutine calc_mnm_morse
330
331 subroutine calc_mnm_maw(Atom1, Atom2, atid1, atid2, D, Rij, R2, Rcut, Sw, vdwMult, &
332 Vpair, Fpair, Pot, A1, A2, f1, t1, t2, Do_pot, interaction_id)
333 integer, intent(in) :: atom1, atom2
334 real( kind = dp ), intent(in) :: rij, r2, rcut, vdwMult
335 real( kind = dp ) :: pot, sw, vpair
336 real( kind = dp ), intent(inout), dimension(3) :: f1
337 real (kind=dp),intent(in), dimension(9) :: A1, A2
338 real (kind=dp),intent(inout), dimension(3) :: t1, t2
339
340 real( kind = dp ), intent(in), dimension(3) :: d
341 real( kind = dp ), intent(inout), dimension(3) :: fpair
342 logical, intent(in) :: do_pot
343
344 integer, intent(in) :: interaction_id
345
346 real(kind = dp) :: D0, R0, beta0, ca1, cb1, pot_temp
347 real(kind = dp) :: expt0, expfnc0, expfnc02
348 real(kind = dp) :: exptH, expfncH, expfncH2
349 real(kind = dp) :: x, y, z, x2, y2, z2, r3, r4
350 real(kind = dp) :: drdx, drdy, drdz
351 real(kind = dp) :: dvdx, dvdy, dvdz
352 real(kind = dp) :: Vang, dVangdx, dVangdy, dVangdz
353 real(kind = dp) :: dVangdux, dVangduy, dVangduz
354 real(kind = dp) :: dVmorsedr
355 real(kind = dp) :: Vmorse, dVmorsedx, dVmorsedy, dVmorsedz
356 real(kind = dp) :: ta1, b1, s
357 real(kind = dp) :: da1dx, da1dy, da1dz, da1dux, da1duy, da1duz
358 real(kind = dp) :: db1dx, db1dy, db1dz, db1dux, db1duy, db1duz
359 real(kind = dp) :: fx, fy, fz, tx, ty, tz, fxl, fyl, fzl
360 real(kind = dp), parameter :: st = sqrt(3.0_dp)
361 integer :: atid1, atid2, id1, id2
362 logical :: shiftedPot, shiftedFrc
363
364 if (atid2.eq.MnM_Map%interactions(interaction_id)%metal_atid) then
365 ! rotate the inter-particle separation into the two different
366 ! body-fixed coordinate systems:
367
368 x = A1(1)*d(1) + A1(2)*d(2) + A1(3)*d(3)
369 y = A1(4)*d(1) + A1(5)*d(2) + A1(6)*d(3)
370 z = A1(7)*d(1) + A1(8)*d(2) + A1(9)*d(3)
371 else
372 ! negative sign because this is the vector from j to i:
373
374 x = -(A2(1)*d(1) + A2(2)*d(2) + A2(3)*d(3))
375 y = -(A2(4)*d(1) + A2(5)*d(2) + A2(6)*d(3))
376 z = -(A2(7)*d(1) + A2(8)*d(2) + A2(9)*d(3))
377 endif
378
379 D0 = MnM_Map%interactions(interaction_id)%D0
380 R0 = MnM_Map%interactions(interaction_id)%r0
381 beta0 = MnM_Map%interactions(interaction_id)%beta0
382 ca1 = MnM_Map%interactions(interaction_id)%ca1
383 cb1 = MnM_Map%interactions(interaction_id)%cb1
384
385 shiftedPot = MnM_Map%interactions(interaction_id)%shiftedPot
386 shiftedFrc = MnM_Map%interactions(interaction_id)%shiftedFrc
387
388 expt0 = -beta0*(rij - R0)
389 expfnc0 = exp(expt0)
390 expfnc02 = expfnc0*expfnc0
391
392 !!$ if (shiftedPot .or. shiftedFrc) then
393 !!$ exptC0 = -beta0*(rcut - R0)
394 !!$ expfncC0 = exp(exptC0)
395 !!$ expfncC02 = expfncC0*expfncC0
396 !!$ exptCH = -betaH*(rcut - R0)
397 !!$ expfncCH = exp(exptCH)
398 !!$ expfncCH2 = expfncCH*expfncCH
399 !!$ endif
400
401 drdx = x / rij
402 drdy = y / rij
403 drdz = z / rij
404
405 x2 = x*x
406 y2 = y*y
407 z2 = z*z
408 r3 = r2*rij
409 r4 = r2*r2
410
411 Vmorse = D0 * (expfnc02 - 2.0_dp * expfnc0)
412
413 ! angular modulation of morse part of potential to approximate
414 ! the squares of the two HOMO lone pair orbitals in water:
415 !********************** old form*************************
416 ! s = 1 / (4 pi)
417 ! ta1 = (s - pz)^2 = (1 - sqrt(3)*cos(theta))^2 / (4 pi)
418 ! b1 = px^2 = 3 * (sin(theta)*cos(phi))^2 / (4 pi)
419 !********************** old form*************************
420 ! we'll leave out the 4 pi for now
421
422 ! new functional form just using the p orbitals.
423 ! Vmorse(r)*[a*p_x + b p_z + (1-a-b)]
424 ! which is
425 ! Vmorse(r)*[a sin^2(theta) cos^2(phi) + b cos(theta) + (1-a-b)]
426 ! Vmorse(r)*[a*x2/r2 + b*z/r + (1-a-b)]
427
428
429
430 s = 1.0_dp
431 ! ta1 = (1.0_dp - st * z / rij )**2
432 ! b1 = 3.0_dp * x2 / r2
433
434 ! Vang = s + ca1 * ta1 + cb1 * b1
435
436 Vang = ca1 * x2/r2 + cb1 * z/rij + (0.8_dp-ca1/3.0_dp)
437
438 pot_temp = vdwMult * Vmorse*Vang
439
440 vpair = vpair + pot_temp
441 pot = pot + pot_temp*sw
442
443 dVmorsedr = 2.0_dp*D0*beta0*(expfnc0 - expfnc02)
444
445 dVmorsedx = dVmorsedr * drdx
446 dVmorsedy = dVmorsedr * drdy
447 dVmorsedz = dVmorsedr * drdz
448
449 !da1dx = 2.0_dp * st * x * z / r3 - 6.0_dp * x * z2 / r4
450 !da1dy = 2.0_dp * st * y * z / r3 - 6.0_dp * y * z2 / r4
451 !da1dz = 2.0_dp * st * (x2 + y2) * (st * z - rij ) / r4
452
453 !db1dx = 6.0_dp * x * (1.0_dp - x2 / r2) / r2
454 !db1dy = -6.0_dp * x2 * y / r4
455 !db1dz = -6.0_dp * x2 * z / r4
456
457 !dVangdx = ca1 * da1dx + cb1 * db1dx
458 !dVangdy = ca1 * da1dy + cb1 * db1dy
459 !dVangdz = ca1 * da1dz + cb1 * db1dz
460
461 dVangdx = -2.0*ca1*x2*x/r4 + 2.0*ca1*x/r2 - cb1*x*z/r3
462 dVangdy = -2.0*ca1*x2*y/r4 - cb1*z*y/r3
463 dVangdz = -2.0*ca1*x2*z/r4 + cb1/rij - cb1*z2 /r3
464
465 ! chain rule to put these back on x, y, z
466 dvdx = Vang * dVmorsedx + Vmorse * dVangdx
467 dvdy = Vang * dVmorsedy + Vmorse * dVangdy
468 dvdz = Vang * dVmorsedz + Vmorse * dVangdz
469
470 ! Torques for Vang using method of Price:
471 ! S. L. Price, A. J. Stone, and M. Alderton, Mol. Phys. 52, 987 (1984).
472
473 !da1dux = 6.0_dp * y * z / r2 - 2.0_dp * st * y / rij
474 !da1duy = -6.0_dp * x * z / r2 + 2.0_dp * st * x / rij
475 !da1duz = 0.0_dp
476
477 !db1dux = 0.0_dp
478 !db1duy = 6.0_dp * x * z / r2
479 !db1duz = -6.0_dp * y * x / r2
480
481 !dVangdux = ca1 * da1dux + cb1 * db1dux
482 !dVangduy = ca1 * da1duy + cb1 * db1duy
483 !dVangduz = ca1 * da1duz + cb1 * db1duz
484
485 dVangdux = cb1*y/rij
486 dVangduy = 2.0*ca1*x*z/r2 - cb1*x/rij
487 dVangduz = -2.0*ca1*y*x/r2
488
489 ! do the torques first since they are easy:
490 ! remember that these are still in the body fixed axes
491
492 tx = vdwMult * Vmorse * dVangdux * sw
493 ty = vdwMult * Vmorse * dVangduy * sw
494 tz = vdwMult * Vmorse * dVangduz * sw
495
496 ! go back to lab frame using transpose of rotation matrix:
497
498 if (atid2.eq.MnM_Map%interactions(interaction_id)%metal_atid) then
499 t1(1) = t1(1) + a1(1)*tx + a1(4)*ty + a1(7)*tz
500 t1(2) = t1(2) + a1(2)*tx + a1(5)*ty + a1(8)*tz
501 t1(3) = t1(3) + a1(3)*tx + a1(6)*ty + a1(9)*tz
502 else
503 t2(1) = t2(1) + a2(1)*tx + a2(4)*ty + a2(7)*tz
504 t2(2) = t2(2) + a2(2)*tx + a2(5)*ty + a2(8)*tz
505 t2(3) = t2(3) + a2(3)*tx + a2(6)*ty + a2(9)*tz
506 endif
507
508 ! Now, on to the forces (still in body frame of water)
509
510 fx = vdwMult * dvdx * sw
511 fy = vdwMult * dvdy * sw
512 fz = vdwMult * dvdz * sw
513
514 ! rotate the terms back into the lab frame:
515
516 if (atid2.eq.MnM_Map%interactions(interaction_id)%metal_atid) then
517 fxl = a1(1)*fx + a1(4)*fy + a1(7)*fz
518 fyl = a1(2)*fx + a1(5)*fy + a1(8)*fz
519 fzl = a1(3)*fx + a1(6)*fy + a1(9)*fz
520 else
521 ! negative sign because this is the vector from j to i:
522 fxl = -(a2(1)*fx + a2(4)*fy + a2(7)*fz)
523 fyl = -(a2(2)*fx + a2(5)*fy + a2(8)*fz)
524 fzl = -(a2(3)*fx + a2(6)*fy + a2(9)*fz)
525 endif
526
527 f1(1) = f1(1) + fxl
528 f1(2) = f1(2) + fyl
529 f1(3) = f1(3) + fzl
530
531 return
532 end subroutine calc_mnm_maw
533
534
535 subroutine setMnMDefaultCutoff(thisRcut, shiftedPot, shiftedFrc)
536 real(kind=dp), intent(in) :: thisRcut
537 logical, intent(in) :: shiftedPot
538 logical, intent(in) :: shiftedFrc
539 integer i, nInteractions
540 defaultCutoff = thisRcut
541 defaultShiftPot = shiftedPot
542 defaultShiftFrc = shiftedFrc
543
544 if (associated(MnM_Map)) then
545 if(MnM_Map%interactionCount /= 0) then
546 nInteractions = MnM_Map%interactionCount
547
548 do i = 1, nInteractions
549 MnM_Map%interactions(i)%shiftedPot = shiftedPot
550 MnM_Map%interactions(i)%shiftedFrc = shiftedFrc
551 MnM_Map%interactions(i)%rCut = thisRcut
552 MnM_Map%interactions(i)%rCutWasSet = .true.
553 enddo
554 end if
555 end if
556
557 end subroutine setMnMDefaultCutoff
558
559 subroutine copyAllData(v1, v2)
560 type(MnMinteractionMap), pointer :: v1
561 type(MnMinteractionMap), pointer :: v2
562 integer :: i, j
563
564 do i = 1, v1%interactionCount
565 v2%interactions(i) = v1%interactions(i)
566 enddo
567
568 v2%interactionCount = v1%interactionCount
569 return
570 end subroutine copyAllData
571
572 subroutine addInteraction(myInteraction)
573 type(MNMtype) :: myInteraction
574 type(MnMinteraction) :: nt
575 integer :: id
576
577 nt%interaction_type = myInteraction%MNMInteractionType
578 nt%metal_atid = &
579 getFirstMatchingElement(atypes, "c_ident", myInteraction%metal_atid)
580 nt%nonmetal_atid = &
581 getFirstMatchingElement(atypes, "c_ident", myInteraction%nonmetal_atid)
582
583 select case (nt%interaction_type)
584 case (MNM_LENNARDJONES)
585 nt%sigma = myInteraction%sigma
586 nt%epsilon = myInteraction%epsilon
587 case(MNM_REPULSIVEMORSE, MNM_SHIFTEDMORSE)
588 nt%R0 = myInteraction%R0
589 nt%D0 = myInteraction%D0
590 nt%beta0 = myInteraction%beta0
591 case(MNM_MAW)
592 nt%R0 = myInteraction%R0
593 nt%D0 = myInteraction%D0
594 nt%beta0 = myInteraction%beta0
595 nt%ca1 = myInteraction%ca1
596 nt%cb1 = myInteraction%cb1
597 case default
598 call handleError("MNM", "Unknown Interaction type")
599 end select
600
601 if (.not. associated(MnM_Map)) then
602 call ensureCapacityHelper(MnM_Map, 1)
603 else
604 call ensureCapacityHelper(MnM_Map, MnM_Map%interactionCount + 1)
605 end if
606
607 MnM_Map%interactionCount = MnM_Map%interactionCount + 1
608 id = MnM_Map%interactionCount
609 MnM_Map%interactions(id) = nt
610 end subroutine addInteraction
611
612 subroutine ensureCapacityHelper(this, minCapacity)
613 type(MnMinteractionMap), pointer :: this, that
614 integer, intent(in) :: minCapacity
615 integer :: oldCapacity
616 integer :: newCapacity
617 logical :: resizeFlag
618
619 resizeFlag = .false.
620
621 ! first time: allocate a new vector with default size
622
623 if (.not. associated(this)) then
624 this => MnMinitialize(minCapacity, 0)
625 endif
626
627 oldCapacity = size(this%interactions)
628
629 if (minCapacity > oldCapacity) then
630 if (this%capacityIncrement .gt. 0) then
631 newCapacity = oldCapacity + this%capacityIncrement
632 else
633 newCapacity = oldCapacity * 2
634 endif
635 if (newCapacity .lt. minCapacity) then
636 newCapacity = minCapacity
637 endif
638 resizeFlag = .true.
639 else
640 newCapacity = oldCapacity
641 endif
642
643 if (resizeFlag) then
644 that => MnMinitialize(newCapacity, this%capacityIncrement)
645 call copyAllData(this, that)
646 this => MnMdestroy(this)
647 this => that
648 endif
649 end subroutine ensureCapacityHelper
650
651 function MnMinitialize(cap, capinc) result(this)
652 integer, intent(in) :: cap, capinc
653 integer :: error
654 type(MnMinteractionMap), pointer :: this
655
656 nullify(this)
657
658 if (cap < 0) then
659 write(*,*) 'Bogus Capacity:', cap
660 return
661 endif
662 allocate(this,stat=error)
663 if ( error /= 0 ) then
664 write(*,*) 'Could not allocate MnMinteractionMap!'
665 return
666 end if
667
668 this%initialCapacity = cap
669 this%capacityIncrement = capinc
670
671 allocate(this%interactions(this%initialCapacity), stat=error)
672 if(error /= 0) write(*,*) 'Could not allocate MnMinteraction!'
673
674 end function MnMinitialize
675
676 subroutine createInteractionLookup(this)
677 type (MnMInteractionMap),pointer :: this
678 integer :: biggestAtid, i, metal_atid, nonmetal_atid, error
679
680 biggestAtid=-1
681 do i = 1, this%interactionCount
682 metal_atid = this%interactions(i)%metal_atid
683 nonmetal_atid = this%interactions(i)%nonmetal_atid
684
685 if (metal_atid .gt. biggestAtid) biggestAtid = metal_atid
686 if (nonmetal_atid .gt. biggestAtid) biggestAtid = nonmetal_atid
687 enddo
688
689 allocate(MnMinteractionLookup(biggestAtid,biggestAtid), stat=error)
690 if (error /= 0) write(*,*) 'Could not allocate MnMinteractionLookup'
691
692 do i = 1, this%interactionCount
693 metal_atid = this%interactions(i)%metal_atid
694 nonmetal_atid = this%interactions(i)%nonmetal_atid
695
696 MnMinteractionLookup(metal_atid, nonmetal_atid) = i
697 MnMinteractionLookup(nonmetal_atid, metal_atid) = i
698 enddo
699 end subroutine createInteractionLookup
700
701 function MnMdestroy(this) result(null_this)
702 logical :: done
703 type(MnMinteractionMap), pointer :: this
704 type(MnMinteractionMap), pointer :: null_this
705
706 if (.not. associated(this)) then
707 null_this => null()
708 return
709 end if
710
711 !! Walk down the list and deallocate each of the map's components
712 if(associated(this%interactions)) then
713 deallocate(this%interactions)
714 this%interactions=>null()
715 endif
716 deallocate(this)
717 this => null()
718 null_this => null()
719 end function MnMdestroy
720
721 subroutine deleteInteractions()
722 MnM_Map => MnMdestroy(MnM_Map)
723 return
724 end subroutine deleteInteractions
725
726 subroutine getLJfunc(r, myPot, myDeriv)
727
728 real(kind=dp), intent(in) :: r
729 real(kind=dp), intent(inout) :: myPot, myDeriv
730 real(kind=dp) :: ri, ri2, ri6, ri7, ri12, ri13
731 real(kind=dp) :: a, b, c, d, dx
732 integer :: j
733
734 ri = 1.0_DP / r
735 ri2 = ri*ri
736 ri6 = ri2*ri2*ri2
737 ri7 = ri6*ri
738 ri12 = ri6*ri6
739 ri13 = ri12*ri
740
741 myPot = 4.0_DP * (ri12 - ri6)
742 myDeriv = 24.0_DP * (ri7 - 2.0_DP * ri13)
743
744 return
745 end subroutine getLJfunc
746
747 subroutine getSoftFunc(r, myPot, myDeriv)
748
749 real(kind=dp), intent(in) :: r
750 real(kind=dp), intent(inout) :: myPot, myDeriv
751 real(kind=dp) :: ri, ri2, ri6, ri7
752 real(kind=dp) :: a, b, c, d, dx
753 integer :: j
754
755 ri = 1.0_DP / r
756 ri2 = ri*ri
757 ri6 = ri2*ri2*ri2
758 ri7 = ri6*ri
759 myPot = 4.0_DP * (ri6)
760 myDeriv = - 24.0_DP * ri7
761
762 return
763 end subroutine getSoftFunc
764 end module MetalNonMetal