ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/UseTheForce/DarkSide/eam.F90
Revision: 939
Committed: Thu Apr 20 18:24:24 2006 UTC (19 years, 3 months ago) by gezelter
File size: 18835 byte(s)
Log Message:
Complete rewrite of spline code and everything that uses it.

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. 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 module eam
43 use simulation
44 use force_globals
45 use status
46 use atype_module
47 use vector_class
48 use interpolation
49 #ifdef IS_MPI
50 use mpiSimulation
51 #endif
52 implicit none
53 PRIVATE
54 #define __FORTRAN90
55 #include "UseTheForce/DarkSide/fInteractionMap.h"
56
57 INTEGER, PARAMETER :: DP = selected_real_kind(15)
58
59 logical, save :: EAM_FF_initialized = .false.
60 integer, save :: EAM_Mixing_Policy
61 real(kind = dp), save :: EAM_rcut
62 logical, save :: haveRcut = .false.
63
64 character(len = statusMsgSize) :: errMesg
65 integer :: eam_err
66
67 character(len = 200) :: errMsg
68 character(len=*), parameter :: RoutineName = "EAM MODULE"
69 !! Logical that determines if eam arrays should be zeroed
70 logical :: cleanme = .true.
71
72 type, private :: EAMtype
73 integer :: eam_atype
74 real( kind = DP ) :: eam_lattice
75 real( kind = DP ) :: eam_rcut
76 integer :: eam_atype_map
77 type(cubicSpline) :: rho
78 type(cubicSpline) :: Z
79 type(cubicSpline) :: F
80 type(cubicSpline) :: phi
81 end type EAMtype
82
83 !! Arrays for derivatives used in force calculation
84 real( kind = dp), dimension(:), allocatable :: frho
85 real( kind = dp), dimension(:), allocatable :: rho
86 real( kind = dp), dimension(:), allocatable :: dfrhodrho
87
88 !! Arrays for MPI storage
89 #ifdef IS_MPI
90 real( kind = dp),save, dimension(:), allocatable :: dfrhodrho_col
91 real( kind = dp),save, dimension(:), allocatable :: dfrhodrho_row
92 real( kind = dp),save, dimension(:), allocatable :: frho_row
93 real( kind = dp),save, dimension(:), allocatable :: frho_col
94 real( kind = dp),save, dimension(:), allocatable :: rho_row
95 real( kind = dp),save, dimension(:), allocatable :: rho_col
96 real( kind = dp),save, dimension(:), allocatable :: rho_tmp
97 #endif
98
99 type, private :: EAMTypeList
100 integer :: n_eam_types = 0
101 integer :: currentAddition = 0
102
103 type (EAMtype), pointer :: EAMParams(:) => null()
104 integer, pointer :: atidToEAMType(:) => null()
105 end type EAMTypeList
106
107 type (eamTypeList), save :: EAMList
108
109 !! standard eam stuff
110
111
112 public :: init_EAM_FF
113 public :: setCutoffEAM
114 public :: do_eam_pair
115 public :: newEAMtype
116 public :: calc_eam_prepair_rho
117 public :: calc_eam_preforce_Frho
118 public :: clean_EAM
119 public :: destroyEAMTypes
120 public :: getEAMCut
121
122 contains
123
124 subroutine newEAMtype(lattice_constant,eam_nrho,eam_drho,eam_nr,&
125 eam_dr,rcut,eam_Z_r,eam_rho_r,eam_F_rho, c_ident, status)
126 real (kind = dp ) :: lattice_constant
127 integer :: eam_nrho
128 real (kind = dp ) :: eam_drho
129 integer :: eam_nr
130 real (kind = dp ) :: eam_dr
131 real (kind = dp ) :: rcut
132 real (kind = dp ), dimension(eam_nr) :: eam_Z_r, rvals
133 real (kind = dp ), dimension(eam_nr) :: eam_rho_r, eam_phi_r
134 real (kind = dp ), dimension(eam_nrho) :: eam_F_rho, rhovals
135 integer :: c_ident
136 integer :: status
137
138 integer :: nAtypes,nEAMTypes,myATID
139 integer :: maxVals
140 integer :: alloc_stat
141 integer :: current, j
142 integer,pointer :: Matchlist(:) => null()
143
144 status = 0
145
146 !! Assume that atypes has already been set and get the total number of types in atypes
147 !! Also assume that every member of atypes is a EAM model.
148
149 ! check to see if this is the first time into
150 if (.not.associated(EAMList%EAMParams)) then
151 call getMatchingElementList(atypes, "is_EAM", .true., nEAMtypes, MatchList)
152 EAMList%n_eam_types = nEAMtypes
153 allocate(EAMList%EAMParams(nEAMTypes))
154 nAtypes = getSize(atypes)
155 allocate(EAMList%atidToEAMType(nAtypes))
156 end if
157
158 EAMList%currentAddition = EAMList%currentAddition + 1
159 current = EAMList%currentAddition
160
161 myATID = getFirstMatchingElement(atypes, "c_ident", c_ident)
162 EAMList%atidToEAMType(myATID) = current
163
164 EAMList%EAMParams(current)%eam_atype = c_ident
165 EAMList%EAMParams(current)%eam_lattice = lattice_constant
166 EAMList%EAMParams(current)%eam_rcut = rcut
167
168 ! Build array of r values
169 do j = 1, eam_nr
170 rvals(j) = real(j-1,kind=dp) * eam_dr
171 end do
172
173 ! Build array of rho values
174 do j = 1, eam_nrho
175 rhovals(j) = real(j-1,kind=dp) * eam_drho
176 end do
177
178 ! convert from eV to kcal / mol:
179 do j = 1, eam_nrho
180 eam_F_rho(j) = eam_F_rho(j) * 23.06054E0_DP
181 end do
182
183 ! precompute the pair potential and get it into kcal / mol:
184 eam_phi_r(1) = 0.0E0_DP
185 do j = 2, eam_nr
186 eam_phi_r(j) = 331.999296E0_DP * (eam_Z_r(j)**2) / rvals(j)
187 enddo
188
189 call newSpline(EAMList%EAMParams(current)%rho, rvals, eam_rho_r, .true.)
190 call newSpline(EAMList%EAMParams(current)%Z, rvals, eam_Z_r, .true.)
191 call newSpline(EAMList%EAMParams(current)%F, rhovals, eam_F_rho, .true.)
192 call newSpline(EAMList%EAMParams(current)%phi, rvals, eam_phi_r, .true.)
193 end subroutine newEAMtype
194
195
196 ! kills all eam types entered and sets simulation to uninitalized
197 subroutine destroyEAMtypes()
198 integer :: i
199 type(EAMType), pointer :: tempEAMType=>null()
200
201 do i = 1, EAMList%n_eam_types
202 tempEAMType => eamList%EAMParams(i)
203 call deallocate_EAMType(tempEAMType)
204 end do
205 if(associated( eamList%EAMParams)) deallocate( eamList%EAMParams)
206 eamList%EAMParams => null()
207
208 eamList%n_eam_types = 0
209 eamList%currentAddition = 0
210 end subroutine destroyEAMtypes
211
212 function getEAMCut(atomID) result(cutValue)
213 integer, intent(in) :: atomID
214 integer :: eamID
215 real(kind=dp) :: cutValue
216
217 eamID = EAMList%atidToEAMType(atomID)
218 cutValue = EAMList%EAMParams(eamID)%eam_rcut
219 end function getEAMCut
220
221 subroutine init_EAM_FF(status)
222 integer :: status
223 integer :: i,j
224 real(kind=dp) :: current_rcut_max
225 #ifdef IS_MPI
226 integer :: nAtomsInRow
227 integer :: nAtomsInCol
228 #endif
229 integer :: alloc_stat
230 integer :: number_r, number_rho
231
232 status = 0
233 if (EAMList%currentAddition == 0) then
234 call handleError("init_EAM_FF","No members in EAMList")
235 status = -1
236 return
237 end if
238
239 !! Allocate arrays for force calculation
240
241 #ifdef IS_MPI
242 nAtomsInRow = getNatomsInRow(plan_atom_row)
243 nAtomsInCol = getNatomsInCol(plan_atom_col)
244 #endif
245
246 if (allocated(frho)) deallocate(frho)
247 allocate(frho(nlocal),stat=alloc_stat)
248 if (alloc_stat /= 0) then
249 status = -1
250 return
251 end if
252
253 if (allocated(rho)) deallocate(rho)
254 allocate(rho(nlocal),stat=alloc_stat)
255 if (alloc_stat /= 0) then
256 status = -1
257 return
258 end if
259
260 if (allocated(dfrhodrho)) deallocate(dfrhodrho)
261 allocate(dfrhodrho(nlocal),stat=alloc_stat)
262 if (alloc_stat /= 0) then
263 status = -1
264 return
265 end if
266
267 #ifdef IS_MPI
268
269 if (allocated(rho_tmp)) deallocate(rho_tmp)
270 allocate(rho_tmp(nlocal),stat=alloc_stat)
271 if (alloc_stat /= 0) then
272 status = -1
273 return
274 end if
275
276 if (allocated(frho_row)) deallocate(frho_row)
277 allocate(frho_row(nAtomsInRow),stat=alloc_stat)
278 if (alloc_stat /= 0) then
279 status = -1
280 return
281 end if
282 if (allocated(rho_row)) deallocate(rho_row)
283 allocate(rho_row(nAtomsInRow),stat=alloc_stat)
284 if (alloc_stat /= 0) then
285 status = -1
286 return
287 end if
288 if (allocated(dfrhodrho_row)) deallocate(dfrhodrho_row)
289 allocate(dfrhodrho_row(nAtomsInRow),stat=alloc_stat)
290 if (alloc_stat /= 0) then
291 status = -1
292 return
293 end if
294
295 ! Now do column arrays
296
297 if (allocated(frho_col)) deallocate(frho_col)
298 allocate(frho_col(nAtomsInCol),stat=alloc_stat)
299 if (alloc_stat /= 0) then
300 status = -1
301 return
302 end if
303 if (allocated(rho_col)) deallocate(rho_col)
304 allocate(rho_col(nAtomsInCol),stat=alloc_stat)
305 if (alloc_stat /= 0) then
306 status = -1
307 return
308 end if
309 if (allocated(dfrhodrho_col)) deallocate(dfrhodrho_col)
310 allocate(dfrhodrho_col(nAtomsInCol),stat=alloc_stat)
311 if (alloc_stat /= 0) then
312 status = -1
313 return
314 end if
315
316 #endif
317
318 end subroutine init_EAM_FF
319
320 subroutine setCutoffEAM(rcut)
321 real(kind=dp) :: rcut
322 EAM_rcut = rcut
323 end subroutine setCutoffEAM
324
325 subroutine clean_EAM()
326
327 ! clean non-IS_MPI first
328 frho = 0.0_dp
329 rho = 0.0_dp
330 dfrhodrho = 0.0_dp
331 ! clean MPI if needed
332 #ifdef IS_MPI
333 frho_row = 0.0_dp
334 frho_col = 0.0_dp
335 rho_row = 0.0_dp
336 rho_col = 0.0_dp
337 rho_tmp = 0.0_dp
338 dfrhodrho_row = 0.0_dp
339 dfrhodrho_col = 0.0_dp
340 #endif
341 end subroutine clean_EAM
342
343 subroutine deallocate_EAMType(thisEAMType)
344 type (EAMtype), pointer :: thisEAMType
345
346 call deleteSpline(thisEAMType%F)
347 call deleteSpline(thisEAMType%rho)
348 call deleteSpline(thisEAMType%phi)
349 call deleteSpline(thisEAMType%Z)
350
351 end subroutine deallocate_EAMType
352
353 !! Calculates rho_r
354 subroutine calc_eam_prepair_rho(atom1,atom2,d,r,rijsq)
355 integer :: atom1, atom2
356 real(kind = dp), dimension(3) :: d
357 real(kind = dp), intent(inout) :: r
358 real(kind = dp), intent(inout) :: rijsq
359 ! value of electron density rho do to atom i at atom j
360 real(kind = dp) :: rho_i_at_j
361 ! value of electron density rho do to atom j at atom i
362 real(kind = dp) :: rho_j_at_i
363 integer :: eam_err
364
365 integer :: atid1, atid2 ! Global atid
366 integer :: myid_atom1 ! EAM atid
367 integer :: myid_atom2
368
369 ! check to see if we need to be cleaned at the start of a force loop
370
371 #ifdef IS_MPI
372 Atid1 = Atid_row(Atom1)
373 Atid2 = Atid_col(Atom2)
374 #else
375 Atid1 = Atid(Atom1)
376 Atid2 = Atid(Atom2)
377 #endif
378
379 Myid_atom1 = Eamlist%atidtoeamtype(Atid1)
380 Myid_atom2 = Eamlist%atidtoeamtype(Atid2)
381
382 if (r.lt.EAMList%EAMParams(myid_atom1)%eam_rcut) then
383
384 call lookupUniformSpline(EAMList%EAMParams(myid_atom1)%rho, r, &
385 rho_i_at_j)
386
387 #ifdef IS_MPI
388 rho_col(atom2) = rho_col(atom2) + rho_i_at_j
389 #else
390 rho(atom2) = rho(atom2) + rho_i_at_j
391 #endif
392 endif
393
394 if (r.lt.EAMList%EAMParams(myid_atom2)%eam_rcut) then
395
396 call lookupUniformSpline(EAMList%EAMParams(myid_atom2)%rho, r, &
397 rho_j_at_i)
398
399 #ifdef IS_MPI
400 rho_row(atom1) = rho_row(atom1) + rho_j_at_i
401 #else
402 rho(atom1) = rho(atom1) + rho_j_at_i
403 #endif
404 endif
405 end subroutine calc_eam_prepair_rho
406
407
408 !! Calculate the functional F(rho) for all local atoms
409 subroutine calc_eam_preforce_Frho(nlocal, pot)
410 integer :: nlocal
411 real(kind=dp) :: pot
412 integer :: i, j
413 integer :: atom
414 real(kind=dp) :: U,U1
415 integer :: atype1
416 integer :: me, atid1
417
418 cleanme = .true.
419 !! Scatter the electron density from pre-pair calculation back to
420 !! local atoms
421 #ifdef IS_MPI
422 call scatter(rho_row,rho,plan_atom_row,eam_err)
423 if (eam_err /= 0 ) then
424 write(errMsg,*) " Error scattering rho_row into rho"
425 call handleError(RoutineName,errMesg)
426 endif
427 call scatter(rho_col,rho_tmp,plan_atom_col,eam_err)
428 if (eam_err /= 0 ) then
429 write(errMsg,*) " Error scattering rho_col into rho"
430 call handleError(RoutineName,errMesg)
431 endif
432
433 rho(1:nlocal) = rho(1:nlocal) + rho_tmp(1:nlocal)
434 #endif
435
436 !! Calculate F(rho) and derivative
437 do atom = 1, nlocal
438 atid1 = atid(atom)
439 me = eamList%atidToEAMtype(atid1)
440
441 call lookupUniformSpline1d(EAMList%EAMParams(me)%F, rho(atom), &
442 u, u1)
443
444 frho(atom) = u
445 dfrhodrho(atom) = u1
446 pot = pot + u
447
448 enddo
449
450 #ifdef IS_MPI
451 !! communicate f(rho) and derivatives back into row and column arrays
452 call gather(frho,frho_row,plan_atom_row, eam_err)
453 if (eam_err /= 0) then
454 call handleError("cal_eam_forces()","MPI gather frho_row failure")
455 endif
456 call gather(dfrhodrho,dfrhodrho_row,plan_atom_row, eam_err)
457 if (eam_err /= 0) then
458 call handleError("cal_eam_forces()","MPI gather dfrhodrho_row failure")
459 endif
460 call gather(frho,frho_col,plan_atom_col, eam_err)
461 if (eam_err /= 0) then
462 call handleError("cal_eam_forces()","MPI gather frho_col failure")
463 endif
464 call gather(dfrhodrho,dfrhodrho_col,plan_atom_col, eam_err)
465 if (eam_err /= 0) then
466 call handleError("cal_eam_forces()","MPI gather dfrhodrho_col failure")
467 endif
468 #endif
469
470
471 end subroutine calc_eam_preforce_Frho
472
473 !! Does EAM pairwise Force calculation.
474 subroutine do_eam_pair(atom1, atom2, d, rij, r2, sw, vpair, fpair, &
475 pot, f, do_pot)
476 !Arguments
477 integer, intent(in) :: atom1, atom2
478 real( kind = dp ), intent(in) :: rij, r2
479 real( kind = dp ) :: pot, sw, vpair
480 real( kind = dp ), dimension(3,nLocal) :: f
481 real( kind = dp ), intent(in), dimension(3) :: d
482 real( kind = dp ), intent(inout), dimension(3) :: fpair
483
484 logical, intent(in) :: do_pot
485
486 real( kind = dp ) :: drdx, drdy, drdz
487 real( kind = dp ) :: phab, pha, dvpdr
488 real( kind = dp ) :: rha, drha, dpha
489 real( kind = dp ) :: rhb, drhb, dphb
490 real( kind = dp ) :: dudr
491 real( kind = dp ) :: rci, rcj
492 real( kind = dp ) :: drhoidr, drhojdr
493 real( kind = dp ) :: Fx, Fy, Fz
494 real( kind = dp ) :: r, phb
495
496 integer :: id1, id2
497 integer :: mytype_atom1
498 integer :: mytype_atom2
499 integer :: atid1, atid2
500
501 phab = 0.0E0_DP
502 dvpdr = 0.0E0_DP
503
504 if (rij .lt. EAM_rcut) then
505
506 #ifdef IS_MPI
507 atid1 = atid_row(atom1)
508 atid2 = atid_col(atom2)
509 #else
510 atid1 = atid(atom1)
511 atid2 = atid(atom2)
512 #endif
513
514 mytype_atom1 = EAMList%atidToEAMType(atid1)
515 mytype_atom2 = EAMList%atidTOEAMType(atid2)
516
517
518 ! get cutoff for atom 1
519 rci = EAMList%EAMParams(mytype_atom1)%eam_rcut
520 ! get type specific cutoff for atom 2
521 rcj = EAMList%EAMParams(mytype_atom2)%eam_rcut
522
523 drdx = d(1)/rij
524 drdy = d(2)/rij
525 drdz = d(3)/rij
526
527 if (rij.lt.rci) then
528
529 ! Calculate rho and drho for atom1
530
531 call lookupUniformSpline1d(EAMList%EAMParams(mytype_atom1)%rho, &
532 rij, rha, drha)
533
534 ! Calculate Phi(r) for atom1.
535
536 call lookupUniformSpline1d(EAMList%EAMParams(mytype_atom1)%phi, &
537 rij, pha, dpha)
538
539 endif
540
541 if (rij.lt.rcj) then
542
543 ! Calculate rho and drho for atom2
544
545 call lookupUniformSpline1d(EAMList%EAMParams(mytype_atom2)%rho, &
546 rij, rhb, drhb)
547
548 ! Calculate Phi(r) for atom2.
549
550 call lookupUniformSpline1d(EAMList%EAMParams(mytype_atom2)%phi, &
551 rij, phb, dphb)
552
553 endif
554
555 if (rij.lt.rci) then
556 phab = phab + 0.5E0_DP*(rhb/rha)*pha
557 dvpdr = dvpdr + 0.5E0_DP*((rhb/rha)*dpha + &
558 pha*((drhb/rha) - (rhb*drha/rha/rha)))
559 endif
560
561 if (rij.lt.rcj) then
562 phab = phab + 0.5E0_DP*(rha/rhb)*phb
563 dvpdr = dvpdr + 0.5E0_DP*((rha/rhb)*dphb + &
564 phb*((drha/rhb) - (rha*drhb/rhb/rhb)))
565 endif
566
567 drhoidr = drha
568 drhojdr = drhb
569
570 #ifdef IS_MPI
571 dudr = drhojdr*dfrhodrho_row(atom1)+drhoidr*dfrhodrho_col(atom2) &
572 + dvpdr
573
574 #else
575 dudr = drhojdr*dfrhodrho(atom1)+drhoidr*dfrhodrho(atom2) &
576 + dvpdr
577 #endif
578
579 fx = dudr * drdx
580 fy = dudr * drdy
581 fz = dudr * drdz
582
583
584 #ifdef IS_MPI
585 if (do_pot) then
586 pot_Row(METALLIC_POT,atom1) = pot_Row(METALLIC_POT,atom1) + phab*0.5
587 pot_Col(METALLIC_POT,atom2) = pot_Col(METALLIC_POT,atom2) + phab*0.5
588 end if
589
590 f_Row(1,atom1) = f_Row(1,atom1) + fx
591 f_Row(2,atom1) = f_Row(2,atom1) + fy
592 f_Row(3,atom1) = f_Row(3,atom1) + fz
593
594 f_Col(1,atom2) = f_Col(1,atom2) - fx
595 f_Col(2,atom2) = f_Col(2,atom2) - fy
596 f_Col(3,atom2) = f_Col(3,atom2) - fz
597 #else
598
599 if(do_pot) then
600 pot = pot + phab
601 end if
602
603 f(1,atom1) = f(1,atom1) + fx
604 f(2,atom1) = f(2,atom1) + fy
605 f(3,atom1) = f(3,atom1) + fz
606
607 f(1,atom2) = f(1,atom2) - fx
608 f(2,atom2) = f(2,atom2) - fy
609 f(3,atom2) = f(3,atom2) - fz
610 #endif
611
612 vpair = vpair + phab
613
614 #ifdef IS_MPI
615 id1 = AtomRowToGlobal(atom1)
616 id2 = AtomColToGlobal(atom2)
617 #else
618 id1 = atom1
619 id2 = atom2
620 #endif
621
622 if (molMembershipList(id1) .ne. molMembershipList(id2)) then
623
624 fpair(1) = fpair(1) + fx
625 fpair(2) = fpair(2) + fy
626 fpair(3) = fpair(3) + fz
627
628 endif
629 endif
630 end subroutine do_eam_pair
631
632 end module eam