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, 5 months ago) by chuckv
File size: 17925 byte(s)
Log Message:
A few more changes to force loop.

File Contents

# Content
1 module lj_ff
2 use simulation
3 use definitions, ONLY : dp, ndim
4 #ifdef IS_MPI
5 use mpiSimulation
6 #endif
7 implicit none
8 PRIVATE
9
10 !! Number of lj_atypes in lj_atype_list
11 integer, save :: n_lj_atypes = 0
12
13 !! Starting Size for ljMixed Array
14 integer, parameter :: ljMixed_blocksize = 10
15
16 type, public :: lj_atype
17 private
18 sequence
19 !! Unique number for place in linked list
20 integer :: atype_number = 0
21 !! Unique indentifier number (ie atomic no, etc)
22 integer :: atype_ident = 0
23 !! Mass of Particle
24 real ( kind = dp ) :: mass = 0.0_dp
25 !! Lennard-Jones epslon
26 real ( kind = dp ) :: epslon = 0.0_dp
27 !! Lennard-Jones Sigma
28 real ( kind = dp ) :: sigma = 0.0_dp
29 !! 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 type (lj_atype), pointer :: next => null()
35 end type lj_atype
36
37 !! Pointer type for atype ident array
38 type, public :: lj_atypePtr
39 type (lj_atype), pointer :: this => null()
40 end type lj_atypePtr
41
42 !! Global list of lj atypes in simulation
43 type (lj_atype), pointer :: lj_atype_list => null()
44 !! 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
49
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 public :: new_lj_atype
71 public :: do_lj_ff
72 public :: getLjPot
73
74
75
76
77
78 contains
79
80 subroutine new_lj_atype(ident,mass,epslon,sigma,status)
81 real( kind = dp ), intent(in) :: mass
82 real( kind = dp ), intent(in) :: epslon
83 real( kind = dp ), intent(in) :: sigma
84 integer, intent(in) :: ident
85 integer, intent(out) :: status
86
87 type (lj_atype), pointer :: this_lj_atype
88 type (lj_atype), pointer :: lj_atype_ptr
89
90 type (lj_atype), allocatable, dimension(:,:), pointer :: thisMix
91 type (lj_atype), allocatable, dimension(:,:), pointer :: oldMix
92 integer :: alloc_error
93 integer :: atype_counter = 0
94 integer :: alloc_size
95
96 status = 0
97
98
99
100 ! allocate a new atype
101 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 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
118
119 ! 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 ! 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
156 else ! we need to find the bottom of the list to insert new atype
157 lj_atype_ptr => lj_atype_list%next
158 atype_counter = 1
159 find_end: do
160 if (.not. associated(lj_atype_ptr%next)) then
161 exit find_end
162 end if
163 ! 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 end do find_end
186 end if
187
188
189
190
191 ! Insert new atype at end of list
192 lj_atype_ptr => this_lj_atype
193 ! 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 end subroutine new_lj_atype
212
213
214 subroutine init_ljFF()
215
216
217 #ifdef IS_MPI
218
219
220
221 #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 real ( kind = dp ), dimension(ndim,) :: q
293 real ( kind = dp ), dimension(ndim,nLRparticles) :: f
294 real ( kind = dp ) :: potE
295 logical :: do_pot
296 #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
306
307 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
314 integer :: nrow
315 integer :: ncol
316
317
318
319 #ifndef IS_MPI
320 nrow = natoms - 1
321 ncol = natoms
322 #else
323 j_start = 1
324 #endif
325
326 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 call scatter(e_row,e_tmp,plan_row)
550
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 end subroutine do_lj_ff
570
571 !! 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
587 integer, intent(out), optional :: status
588
589 ! 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 end module lj_ff