ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/mdtools/md_code/lj_FF.F90
Revision: 232
Committed: Fri Jan 10 17:27:28 2003 UTC (21 years, 6 months ago) by chuckv
File size: 17925 byte(s)
Log Message:
A few more changes to force loop.

File Contents

# User Rev Content
1 chuckv 215 module lj_ff
2     use simulation
3     use definitions, ONLY : dp, ndim
4 chuckv 230 #ifdef IS_MPI
5     use mpiSimulation
6     #endif
7 chuckv 215 implicit none
8 chuckv 230 PRIVATE
9 chuckv 215
10 chuckv 230 !! Number of lj_atypes in lj_atype_list
11 chuckv 215 integer, save :: n_lj_atypes = 0
12    
13 chuckv 230 !! Starting Size for ljMixed Array
14     integer, parameter :: ljMixed_blocksize = 10
15    
16 chuckv 215 type, public :: lj_atype
17     private
18     sequence
19 chuckv 230 !! Unique number for place in linked list
20     integer :: atype_number = 0
21     !! Unique indentifier number (ie atomic no, etc)
22 chuckv 215 integer :: atype_ident = 0
23 chuckv 230 !! Mass of Particle
24 chuckv 215 real ( kind = dp ) :: mass = 0.0_dp
25 chuckv 230 !! Lennard-Jones epslon
26 chuckv 215 real ( kind = dp ) :: epslon = 0.0_dp
27 chuckv 230 !! Lennard-Jones Sigma
28 chuckv 215 real ( kind = dp ) :: sigma = 0.0_dp
29 chuckv 230 !! Lennard-Jones Sigma Squared
30     real ( kind = dp ) :: sigma2 = 0.0_dp
31     !! Lennard-Jones Sigma to sixth
32     real ( kind = dp ) :: sigma6 = 0.0_dp
33     !! Pointer for linked list creation
34 chuckv 215 type (lj_atype), pointer :: next => null()
35     end type lj_atype
36    
37 chuckv 230 !! Pointer type for atype ident array
38 chuckv 232 type, public :: lj_atypePtr
39 chuckv 230 type (lj_atype), pointer :: this => null()
40     end type lj_atypePtr
41    
42     !! Global list of lj atypes in simulation
43 chuckv 215 type (lj_atype), pointer :: lj_atype_list => null()
44 chuckv 230 !! LJ mixing array
45     type (lj_atype), dimension(:,:), allocatable, pointer :: ljMixed =>null()
46     !! identity pointer list for force loop.
47     type (lj_atypePtr), dimension(:), allocatable :: identPtrList
48 chuckv 215
49 chuckv 230
50     !! Neighbor list and commom arrays
51     integer, allocatable, dimension(:) :: point
52     integer, allocatable, dimension(:) :: list
53    
54     #ifdef IS_MPI
55     ! Universal routines: All types of force calculations will need these arrays
56     ! Arrays specific to a type of force calculation should be declared in that module.
57     real( kind = dp ), allocatable, dimension(:,:) :: qRow
58     real( kind = dp ), allocatable, dimension(:,:) :: qColumn
59    
60     real( kind = dp ), allocatable, dimension(:,:) :: fRow
61     real( kind = dp ), allocatable, dimension(:,:) :: fColumn
62     #endif
63    
64    
65    
66    
67    
68    
69     !! Public methods and data
70 chuckv 215 public :: new_lj_atype
71 chuckv 230 public :: do_lj_ff
72     public :: getLjPot
73    
74 chuckv 215
75 chuckv 230
76    
77    
78 chuckv 215 contains
79    
80 chuckv 231 subroutine new_lj_atype(ident,mass,epslon,sigma,status)
81 chuckv 215 real( kind = dp ), intent(in) :: mass
82     real( kind = dp ), intent(in) :: epslon
83 chuckv 230 real( kind = dp ), intent(in) :: sigma
84     integer, intent(in) :: ident
85 chuckv 215 integer, intent(out) :: status
86    
87 chuckv 216 type (lj_atype), pointer :: this_lj_atype
88     type (lj_atype), pointer :: lj_atype_ptr
89    
90 chuckv 230 type (lj_atype), allocatable, dimension(:,:), pointer :: thisMix
91     type (lj_atype), allocatable, dimension(:,:), pointer :: oldMix
92 chuckv 216 integer :: alloc_error
93     integer :: atype_counter = 0
94 chuckv 230 integer :: alloc_size
95 chuckv 216
96 chuckv 215 status = 0
97    
98 chuckv 230
99    
100     ! allocate a new atype
101 chuckv 216 allocate(this_lj_atype,stat=alloc_error)
102     if (alloc_error /= 0 ) then
103     status = -1
104     return
105     end if
106    
107     ! assign our new lj_atype information
108     this_lj_atype%mass = mass
109     this_lj_atype%epslon = epslon
110     this_lj_atype%sigma = sigma
111 chuckv 230 this_lj_atype%sigma2 = sigma * sigma
112     this_lj_atype%sigma6 = this_lj_atype%sigma2 * this_lj_atype%sigma2 &
113     * this_lj_atype%sigma2
114     ! assume that this atype will be successfully added
115     this_lj_atype%atype_ident = ident
116     this_lj_atype%number = n_lj_atypes + 1
117 chuckv 216
118    
119 chuckv 230 ! First time through allocate a array of size ljMixed_blocksize
120     if(.not. associated(ljMixed)) then
121     allocate(thisMix(ljMixed_blocksize,ljMixed_blocksize))
122     if (alloc_error /= 0 ) then
123     status = -1
124     return
125     end if
126     ljMixed => thisMix
127     ! If we have outgrown ljMixed_blocksize, allocate a new matrix twice the size and
128     ! point ljMix at the new matrix.
129     else if( (n_lj_atypes + 1) > size(ljMixed)) then
130     alloc_size = 2*size(ljMix)
131     allocate(thisMix(alloc_size,alloc_size))
132     if (alloc_error /= 0 ) then
133     status = -1
134     return
135     end if
136     ! point oldMix at old ljMixed array
137     oldMix => ljMixed
138     ! Copy oldMix into new Mixed array
139     thisMix = oldMix
140     ! Point ljMixed at new array
141     ljMixed => thisMix
142     ! Free old array so we don't have a memory leak
143     deallocate(oldMix)
144     endif
145    
146    
147    
148    
149    
150     ! Find bottom of atype master list
151 chuckv 216 ! if lj_atype_list is null then we are at the top of the list.
152     if (.not. associated(lj_atype_list)) then
153     lj_atype_ptr => this_lj_atype
154     atype_counter = 1
155 chuckv 230
156     else ! we need to find the bottom of the list to insert new atype
157 chuckv 216 lj_atype_ptr => lj_atype_list%next
158 chuckv 230 atype_counter = 1
159 chuckv 216 find_end: do
160     if (.not. associated(lj_atype_ptr%next)) then
161     exit find_end
162     end if
163 chuckv 230 ! Set up mixing for new atype and current atype in list
164     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma = &
165     calcLJMix("sigma",this_lj_atype%sigma, &
166     lj_atype_prt%sigma)
167    
168     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma2 = &
169     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma &
170     * ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma
171    
172     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma6 = &
173     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma2 &
174     * ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma2 &
175     * ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%sigma2
176    
177     ljMix(this_lj_atype%atype_number,lj_atype_ptr%atype_number)%epslon = &
178     calcLJMix("epslon",this_lj_atype%epslon, &
179     lj_atype_prt%epslon)
180    
181     ! Advance to next pointer
182     lj_atype_ptr => lj_atype_ptr%next
183     atype_counter = atype_counter + 1
184    
185 chuckv 216 end do find_end
186     end if
187 chuckv 230
188    
189    
190 chuckv 216
191 chuckv 230 ! Insert new atype at end of list
192 chuckv 216 lj_atype_ptr => this_lj_atype
193 chuckv 230 ! Increment number of atypes
194    
195     n_lj_atypes = n_lj_atypes + 1
196    
197     ! Set up self mixing
198    
199     ljMix(n_lj_atypes,n_lj_atypes)%sigma = this_lj_atype%sigma
200    
201     ljMix(n_lj_atypes,n_lj_atypes)%sigma2 = ljMix(n_lj_atypes,n_lj_atypes)%sigma &
202     * ljMix(n_lj_atypes,n_lj_atypes)%sigma
203    
204     ljMix(n_lj_atypes,n_lj_atypes)%sigma6 = ljMix(n_lj_atypes,n_lj_atypes)%sigma2 &
205     * ljMix(n_lj_atypes,n_lj_atypes)%sigma2 &
206     * ljMix(n_lj_atypes,n_lj_atypes)%sigma2
207    
208     ljMix(n_lj_atypes,n_lj_atypes)%epslon = this_lj_atype%epslon
209    
210    
211 chuckv 215 end subroutine new_lj_atype
212    
213    
214 chuckv 230 subroutine init_ljFF()
215 chuckv 215
216    
217 chuckv 230 #ifdef IS_MPI
218 chuckv 215
219 chuckv 230
220 chuckv 215
221 chuckv 230 #endif
222    
223     end subroutine init_ljFF
224    
225     !! Takes an ident array and creates an atype pointer list
226     !! based on those identities
227     subroutine new_ljatypePtrList(mysize,ident,PtrList,status)
228     integer, intent(in) :: mysize
229     integer, intent(in) :: ident
230     integer, optional :: status
231     type(lj_atypePtr), dimension(:) :: PtrList
232    
233     integer :: thisIdent
234     integer :: i
235     integer :: alloc_error
236     type (lj_atype), pointer :: tmpPtr
237    
238     if (present(status)) status = 0
239    
240     ! First time through, allocate list
241     if (.not.(allocated)) then
242     allocate(PtrList(mysize))
243     else
244     ! We want to creat a new ident list so free old list
245     deallocate(PrtList)
246     allocate(PtrList(mysize))
247     endif
248    
249     ! Match pointer list
250     do i = 1, mysize
251     thisIdent = ident(i)
252     call getLJatype(thisIdent,tmpPtr)
253    
254     if (.not. associated(tmpPtr)) then
255     status = -1
256     return
257     endif
258    
259     PtrList(i)%this => tmpPtr
260     end do
261    
262     end subroutine new_ljatypePtrList
263    
264     !! Finds a lj_atype based upon numerical ident
265     !! returns a null pointer if error
266     subroutine getLJatype(ident,ljAtypePtr)
267     integer, intent(in) :: ident
268     type (lj_atype), intent(out),pointer :: ljAtypePtr => null()
269    
270     type (lj_atype), pointer :: tmplj_atype_ptr => null()
271    
272     if(.not. associated(lj_atype_list)) return
273    
274     ! Point at head of list.
275     tmplj_atype_ptr => lj_atype_list
276     find_ident: do
277     if (.not.associated(tmplj_atype_ptr)) then
278     exit find_ident
279     else if( lj_atype_ptr%atype_ident == ident)
280     ljAtypePtr => tmplj_atype_ptr
281     exit find_ident
282     endif
283     tmplj_atype_ptr => tmplj_atype_ptr%next
284     end do find_ident
285    
286     end subroutine getLJatype
287    
288    
289     ! FORCE routine
290     !------------------------------------------------------------->
291     subroutine do_lj_ff(q,f,potE,do_pot)
292 chuckv 222 real ( kind = dp ), dimension(ndim,) :: q
293     real ( kind = dp ), dimension(ndim,nLRparticles) :: f
294     real ( kind = dp ) :: potE
295 chuckv 232 logical :: do_pot
296 chuckv 230 #ifdef MPI
297     real( kind = DP ), dimension(3,ncol) :: efr
298     real( kind = DP ) :: pot_local
299     #else
300     ! real( kind = DP ), dimension(3,natoms) :: efr
301     #endif
302    
303     real( kind = DP ) :: pe
304     logical, :: update_nlist
305 chuckv 216
306 chuckv 232
307 chuckv 230 integer :: i, j, jbeg, jend, jnab, idim, jdim, idim2, jdim2, dim, dim2
308     integer :: nlist
309     integer :: j_start
310     integer :: tag_i,tag_j
311     real( kind = DP ) :: r, pot, ftmp, dudr, d2, drdx1, kt1, kt2, kt3, ktmp
312     real( kind = DP ) :: rxi, ryi, rzi, rxij, ryij, rzij, rijsq
313 chuckv 222
314 chuckv 230 integer :: nrow
315     integer :: ncol
316 chuckv 222
317    
318    
319 chuckv 230 #ifndef IS_MPI
320     nrow = natoms - 1
321     ncol = natoms
322     #else
323     j_start = 1
324     #endif
325 chuckv 222
326 chuckv 230 call check(update_nlist)
327    
328     #ifndef IS_MPI
329     nloops = nloops + 1
330     pot = 0.0E0_DP
331     f = 0.0E0_DP
332     e = 0.0E0_DP
333     #else
334     f_row = 0.0E0_DP
335     f_col = 0.0E0_DP
336    
337     pot_local = 0.0E0_DP
338    
339     e_row = 0.0E0_DP
340     e_col = 0.0E0_DP
341     e_tmp = 0.0E0_DP
342     #endif
343     efr = 0.0E0_DP
344    
345     ! communicate MPI positions
346     #ifdef MPI
347     call gather(q,q_row,plan_row3)
348     call gather(q,q_col,plan_col3)
349     #endif
350    
351     #ifndef MPI
352    
353     #endif
354    
355     if (update_nlist) then
356    
357     ! save current configuration, contruct neighbor list,
358     ! and calculate forces
359     call save_nlist()
360    
361     nlist = 0
362    
363    
364    
365     do i = 1, nrow
366     point(i) = nlist + 1
367     #ifdef MPI
368     tag_i = tag_row(i)
369     rxi = q_row(1,i)
370     ryi = q_row(2,i)
371     rzi = q_row(3,i)
372     #else
373     j_start = i + 1
374     rxi = q(1,i)
375     ryi = q(2,i)
376     rzi = q(3,i)
377     #endif
378    
379     inner: do j = j_start, ncol
380     #ifdef MPI
381     tag_j = tag_col(j)
382     if (newtons_thrd) then
383     if (tag_i <= tag_j) then
384     if (mod(tag_i + tag_j,2) == 0) cycle inner
385     else
386     if (mod(tag_i + tag_j,2) == 1) cycle inner
387     endif
388     endif
389    
390     rxij = wrap(rxi - q_col(1,j), 1)
391     ryij = wrap(ryi - q_col(2,j), 2)
392     rzij = wrap(rzi - q_col(3,j), 3)
393     #else
394    
395     rxij = wrap(rxi - q(1,j), 1)
396     ryij = wrap(ryi - q(2,j), 2)
397     rzij = wrap(rzi - q(3,j), 3)
398    
399     #endif
400     rijsq = rxij*rxij + ryij*ryij + rzij*rzij
401    
402     #ifdef MPI
403     if (rijsq <= rlstsq .AND. &
404     tag_j /= tag_i) then
405     #else
406     if (rijsq < rlstsq) then
407     #endif
408    
409     nlist = nlist + 1
410     if (nlist > size(list)) then
411     call info("FORCE_LJ","error size list smaller then nlist")
412     write(msg,*) "nlist size(list)", nlist, size(list)
413     call info("FORCE_LJ",msg)
414     #ifdef MPI
415     call mpi_abort(MPI_COMM_WORLD,mpi_err)
416     #endif
417     stop
418     endif
419     list(nlist) = j
420    
421    
422     if (rijsq < rcutsq) then
423    
424     r = dsqrt(rijsq)
425    
426     call LJ_mix(r,pot,dudr,d2,i,j)
427    
428     #ifdef MPI
429     e_row(i) = e_row(i) + pot*0.5
430     e_col(i) = e_col(i) + pot*0.5
431     #else
432     pe = pe + pot
433     #endif
434    
435     efr(1,j) = -rxij
436     efr(2,j) = -ryij
437     efr(3,j) = -rzij
438    
439     do dim = 1, 3
440    
441    
442     drdx1 = efr(dim,j) / r
443     ftmp = dudr * drdx1
444    
445    
446     #ifdef MPI
447     f_col(dim,j) = f_col(dim,j) - ftmp
448     f_row(dim,i) = f_row(dim,i) + ftmp
449     #else
450    
451     f(dim,j) = f(dim,j) - ftmp
452     f(dim,i) = f(dim,i) + ftmp
453    
454     #endif
455     enddo
456     endif
457     endif
458     enddo inner
459     enddo
460    
461     #ifdef MPI
462     point(nrow + 1) = nlist + 1
463     #else
464     point(natoms) = nlist + 1
465     #endif
466    
467     else
468    
469     ! use the list to find the neighbors
470     do i = 1, nrow
471     JBEG = POINT(i)
472     JEND = POINT(i+1) - 1
473     ! check thiat molecule i has neighbors
474     if (jbeg .le. jend) then
475     #ifdef MPI
476     rxi = q_row(1,i)
477     ryi = q_row(2,i)
478     rzi = q_row(3,i)
479     #else
480     rxi = q(1,i)
481     ryi = q(2,i)
482     rzi = q(3,i)
483     #endif
484     do jnab = jbeg, jend
485     j = list(jnab)
486     #ifdef MPI
487     rxij = wrap(rxi - q_col(1,j), 1)
488     ryij = wrap(ryi - q_col(2,j), 2)
489     rzij = wrap(rzi - q_col(3,j), 3)
490     #else
491     rxij = wrap(rxi - q(1,j), 1)
492     ryij = wrap(ryi - q(2,j), 2)
493     rzij = wrap(rzi - q(3,j), 3)
494     #endif
495     rijsq = rxij*rxij + ryij*ryij + rzij*rzij
496    
497     if (rijsq < rcutsq) then
498    
499     r = dsqrt(rijsq)
500    
501     call LJ_mix(r,pot,dudr,d2,i,j)
502     #ifdef MPI
503     e_row(i) = e_row(i) + pot*0.5
504     e_col(i) = e_col(i) + pot*0.5
505     #else
506     if (do_pot) pe = pe + pot
507     #endif
508    
509    
510     efr(1,j) = -rxij
511     efr(2,j) = -ryij
512     efr(3,j) = -rzij
513    
514     do dim = 1, 3
515    
516     drdx1 = efr(dim,j) / r
517     ftmp = dudr * drdx1
518     #ifdef MPI
519     f_col(dim,j) = f_col(dim,j) - ftmp
520     f_row(dim,i) = f_row(dim,i) + ftmp
521     #else
522     f(dim,j) = f(dim,j) - ftmp
523     f(dim,i) = f(dim,i) + ftmp
524     #endif
525     enddo
526     endif
527     enddo
528     endif
529     enddo
530     endif
531    
532    
533    
534     #ifdef MPI
535     !!distribute forces
536     call scatter(f_row,f,plan_row3)
537    
538     call scatter(f_col,f_tmp,plan_col3)
539     do i = 1,nlocal
540     do dim = 1,3
541     f(dim,i) = f(dim,i) + f_tmp(dim,i)
542     end do
543     end do
544    
545    
546    
547     if (do_pot) then
548     ! scatter/gather pot_row into the members of my column
549 chuckv 232 call scatter(e_row,e_tmp,plan_row)
550 chuckv 230
551     ! scatter/gather pot_local into all other procs
552     ! add resultant to get total pot
553     do i = 1, nlocal
554     pot_local = pot_local + e_tmp(i)
555     enddo
556     if (newtons_thrd) then
557     e_tmp = 0.0E0_DP
558     call scatter(e_col,e_tmp,plan_col)
559     do i = 1, nlocal
560     pot_local = pot_local + e_tmp(i)
561     enddo
562     endif
563     endif
564     #endif
565    
566    
567    
568    
569 chuckv 222 end subroutine do_lj_ff
570    
571 chuckv 230 !! Calculates the potential between two lj particles, optionally returns second
572     !! derivatives.
573     subroutine getLjPot(r,pot,dudr,atype1,atype2,d2,status)
574     ! arguments
575     !! Length of vector between particles
576     real( kind = dp ), intent(in) :: r
577     !! Potential Energy
578     real( kind = dp ), intent(out) :: pot
579     !! Derivatve wrt postion
580     real( kind = dp ), intent(out) :: dudr
581     !! Second Derivative, optional, used mainly for normal mode calculations.
582     real( kind = dp ), intent(out), optional :: d2
583    
584     type (lj_atype), intent(in) :: atype1
585     type (lj_atype), intent(in) :: atype2
586 chuckv 222
587 chuckv 230 integer, intent(out), optional :: status
588 chuckv 222
589 chuckv 230 ! local Variables
590     real( kind = dp ) :: sigma
591     real( kind = dp ) :: sigma2
592     real( kind = dp ) :: sigma6
593     real( kind = dp ) :: epslon
594    
595     real( kind = dp ) :: rcut
596     real( kind = dp ) :: rcut2
597     real( kind = dp ) :: rcut6
598     real( kind = dp ) :: r2
599     real( kind = dp ) :: r6
600    
601     real( kind = dp ) :: t6
602     real( kind = dp ) :: t12
603     real( kind = dp ) :: tp6
604     real( kind = dp ) :: tp12
605     real( kind = dp ) :: delta
606    
607     logical :: doSec = .false.
608    
609     integer :: errorStat
610    
611     !! Optional Argument Checking
612     ! Check to see if we need to do second derivatives
613    
614     if (present(d2)) doSec = .true.
615     if (present(status)) status = 0
616    
617     ! Look up the correct parameters in the mixing matrix
618     sigma = ljMixed(atype1%atype_ident,atype2_atype_ident)%sigma
619     sigma2 = ljMixed(atype1%atype_ident,atype2_atype_ident)%sigma2
620     sigma6 = ljMixed(atype1%atype_ident,atype2_atype_ident)%sigma6
621     epslon = ljMixed(atype1%atype_ident,atype2_atype_ident)%epslon
622    
623    
624    
625     call getRcut(rcut,rcut2=rcut2,rcut6=rcut6,status=errorStat)
626    
627     r2 = r * r
628     r6 = r2 * r2 * r2
629    
630     t6 = sigma6/ r6
631     t12 = t6 * t6
632    
633    
634    
635     tp6 = sigma6 / rcut6
636     tp12 = tp6*tp6
637    
638     delta = -4.0E0_DP*epsilon * (tp12 - tp6)
639    
640     if (r.le.rcut) then
641     u = 4.0E0_DP * epsilon * (t12 - t6) + delta
642     dudr = 24.0E0_DP * epsilon * (t6 - 2.0E0_DP*t12) / r
643     if(doSec) d2 = 24.0E0_DP * epsilon * (26.0E0_DP*t12 - 7.0E0_DP*t6)/r/r
644     else
645     u = 0.0E0_DP
646     dudr = 0.0E0_DP
647     if(doSec) d2 = 0.0E0_DP
648     endif
649    
650     return
651    
652    
653    
654     end subroutine getLjPot
655    
656    
657     !! Calculates the mixing for sigma or epslon based on character string
658     function calcLJMix(thisParam,param1,param2,status) result(myMixParam)
659     character(len=*) :: thisParam
660     real(kind = dp) :: param1
661     real(kind = dp) :: param2
662     real(kind = dp ) :: myMixParam
663     integer, optional :: status
664    
665    
666     myMixParam = 0.0_dp
667    
668     if (present(status)) status = 0
669    
670     select case (thisParam)
671    
672     case ("sigma")
673     myMixParam = 0.5_dp * (param1 + param2)
674     case ("epslon")
675     myMixParam = sqrt(param1 * param2)
676     case default
677     status = -1
678     end select
679    
680     end function calcLJMix
681    
682    
683    
684 chuckv 215 end module lj_ff