ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/nano_mpi/src/velocity_module.F90
Revision: 9
Committed: Mon Jul 1 15:27:33 2002 UTC (22 years, 2 months ago) by chuckv
File size: 13752 byte(s)
Log Message:
nose hoover chains added

File Contents

# User Rev Content
1 chuckv 4 module velocity
2     use parameter
3     use simulation
4     use definitions, ONLY: DP, NDIM
5     use status, ONLY: error,info,warning
6     #ifdef MPI
7     use mpi_module
8     #endif
9     implicit none
10     PRIVATE
11    
12    
13    
14     public :: calc_temp
15     public :: quench
16     public :: scale_velocities
17     public :: randomize_velocities
18     public :: remove_cm_momentum
19     public :: remove_angular_momentum
20     public :: get_com
21     public :: get_com_all
22    
23     contains
24    
25     subroutine quench()
26    
27     v = 0.0E0_DP
28    
29     call remove_cm_momentum()
30     call remove_angular_momentum()
31    
32     return
33     end subroutine quench
34    
35     subroutine scale_velocities(target_t)
36    
37    
38     real( kind = DP ), intent(in) :: target_t
39     integer :: i, dim
40     real( kind = DP ) :: temperature
41     real( kind = DP ) :: scaling
42    
43    
44     call calc_temp(temperature)
45    
46     scaling = dsqrt(target_t / temperature)
47    
48     do i = 1, nlocal
49     do dim = 1, ndim
50     v(dim,i) = v(dim,i) * scaling
51     end do
52     end do
53    
54     call remove_cm_momentum()
55     call remove_angular_momentum()
56    
57     end subroutine scale_velocities
58    
59     !. ===============================================================================
60     subroutine randomize_velocities(temperature)
61     use model_module
62     use constants, ONLY : twopi,pi
63     use sprng_mod, ONLY : random_gauss
64     real( kind = DP ), intent(in) :: temperature
65    
66     integer :: i, dim
67     integer :: ntmp
68    
69     real( kind = DP ), allocatable, dimension(:) :: vbar
70    
71     real( kind = DP ) :: mtmp,vbtmp
72     real( kind = DP ) :: vrand
73    
74    
75    
76    
77     allocate(vbar(natypes))
78    
79    
80     do i = 1, natypes
81     if (is_atype(i)) then
82     mtmp = atype_mass(i)
83     vbar(i) = get_vbar(mtmp,temperature)
84     endif
85     enddo
86    
87    
88    
89     ! pick random velocity from gaussian distribution
90     do i = 1, nlocal
91     vbtmp = vbar(ident(i))
92     v(1:ndim,i) = vbtmp * random_gauss()
93     end do
94    
95    
96    
97     call remove_cm_momentum()
98     call print_angular_momentum()
99     call remove_angular_momentum()
100     call print_angular_momentum()
101    
102     deallocate(vbar)
103     end subroutine randomize_velocities
104    
105     !.============================================================================================
106     ! . write total angular momentum
107     subroutine print_angular_momentum()
108     use vectors, ONLY : cross_product
109     ! . variables for 2-d angular momentum
110    
111     ! . varibles for 3-d angular momentum
112     real( kind = DP ), dimension( ndim ) :: ltot
113     real( kind = DP ), dimension( ndim ) :: l
114     real( kind = DP ), dimension( ndim ) :: l_local
115     real( kind = DP ), dimension( ndim ) :: r
116     real( kind = DP ), dimension( ndim ) :: p
117    
118     real( kind = DP ), dimension( ndim ) :: com
119    
120    
121     integer :: i
122     character(len=80) :: msg
123    
124     ! . for single version natoms = nlocal
125    
126     ! . zero variables
127     ltot = 0.0_DP
128     l_local = 0.0_DP
129     com = 0.0_DP
130    
131     ! . get center of mass
132     com = get_com()
133    
134     if (ndim /= 3) return
135    
136     ! . find angular momentum
137    
138     ! . handle 3-d case first
139     ! . result is a vector
140    
141     do i = 1, nlocal
142     r(1:ndim) = q(1:ndim,i) - com(1:ndim)
143     p(1:ndim) = v(1:ndim,i)*mass(i)
144    
145     l = cross_product(r,p)
146    
147     l_local(1:ndim) = l_local(1:ndim) + l(1:ndim)
148     end do
149    
150     #ifdef MPI
151     call mpi_allreduce(l_local,ltot,ndim,mpi_double_precision, &
152     mpi_sum,mpi_comm_world,mpi_err)
153     if (mpi_err /= 0) then
154     call error("PRINT_ANGULAR_MOMENTUM", "MPI allreduce lx_local failed")
155     endif
156     #else
157     ltot = l_local
158     #endif
159     write(msg,'(a6,3es12.3)') 'L = ', &
160     ltot(1), ltot(2), ltot(3)
161     call info('PRINT_ANGULAR_MOMENTUM',trim(msg))
162    
163     return
164    
165    
166     end subroutine print_angular_momentum
167    
168     !. =======================================================================================
169     ! . Removes center of mass momentum
170     subroutine remove_cm_momentum()
171     integer :: i
172     real( kind = dp ), dimension( ndim ) :: com_v
173    
174    
175    
176     ! . initialize center of mass velocity
177     com_v = 0.0E0_DP
178    
179     ! . call get_com_v to get center of mass velocity
180     com_v = get_com_v()
181    
182     ! . subtract center of mass momentum from velocity
183     do i = 1, nlocal
184     v(1:ndim,i) = v(1:ndim,i) - com_v(1:ndim)
185     enddo
186    
187     return
188     end subroutine remove_cm_momentum
189    
190    
191    
192    
193     subroutine remove_angular_momentum()
194     use f95_lapack, only: la_getrf,la_getri
195     use vectors, only: cross_product
196     integer :: i, j, k
197     integer :: ifail,la_info
198 chuckv 9 character(len=80) :: junk
199 chuckv 4 real( kind = DP ) :: xx, yy, zz
200     real( kind = DP ) :: xy, xz, yz
201    
202     real( kind = DP ),dimension(3,3) :: inertia, inertia_save, identity
203     real( kind = DP ),dimension(3,3) :: inertia_inverse
204     integer ,dimension(3) :: ipiv
205     real( kind = DP), dimension(3) :: angmom, omega, angmom_local
206     real( kind = DP ),dimension(3) :: this_q, this_v
207     real( kind = DP ),dimension(9) :: inertia_vec_local
208     real( kind = DP ),dimension(9) :: inertia_vec
209     real( kind = DP ),dimension(3) :: com, com_v
210     real( kind = DP ),dimension(3,nlocal) :: q_adj_com, v_adj_com
211    
212     ! . if were not in 3-d, don't even bother
213    
214     if (ndim /= 3) then
215     return
216     end if
217    
218     !. initialize center of mass
219     !. and velocity center of mass
220     com = 0.0E0_DP
221     com_v = 0.0E0_DP
222    
223     ! com = get_com()
224     ! com_v = get_com_v()
225    
226     ! The get_com_all subroutine to avoid looping twice
227    
228     call get_com_all(com, com_v)
229    
230     ! . initialize components for inertia tensor
231     xx=0.0_DP
232     yy=0.0_DP
233     zz=0.0_DP
234     xy=0.0_DP
235     xz=0.0_DP
236     yz=0.0_DP
237    
238     ! . build components of Inertia tensor
239     !
240     ! [ Ixx -Ixy -Ixz ]
241     ! J = | -Iyx Iyy -Iyz |
242     ! [ -Izx -Iyz Izz ]
243     ! See Fowles and Cassidy Chapter 9
244     ! or Goldstein Chapter 5
245    
246     !
247     do i = 1, nlocal
248     ! get components for this atom i.
249     this_q(1:3) = q(1:3,i) - com(1:3)
250     this_v(1:3) = v(1:3,i) - com_v(1:3)
251    
252     q_adj_com(1:3,i) = this_q(1:3)
253     v_adj_com(1:3,i) = this_v(1:3)
254    
255     ! . compute moment of inertia coefficents
256     xx = xx + &
257     this_q(1)*this_q(1)*mass(i)
258     yy = yy + &
259     this_q(2)*this_q(2)*mass(i)
260     zz = zz + &
261     this_q(3)*this_q(3)*mass(i)
262     ! . compute products of inertia
263     xy = xy + &
264     this_q(1)*this_q(2)*mass(i)
265     xz = xz + &
266     this_q(1)*this_q(3)*mass(i)
267     yz = yz + &
268     this_q(2)*this_q(3)*mass(i)
269    
270     angmom_local = angmom_local + &
271     cross_product(this_q,this_v) * mass(i)
272     enddo
273    
274     ! . form the local inertia vector
275     ! . f90 mpi won't allow a rank > 1 array in allreduce
276     ! . so we make a vector length 9 and transfer it back
277     ! . to a tensor after the allreduce
278     inertia_vec_local(1)=yy+zz
279     inertia_vec_local(2)=-xy
280     inertia_vec_local(3)=-xz
281     inertia_vec_local(4)=-xy
282     inertia_vec_local(5)=xx+zz
283     inertia_vec_local(6)=-yz
284     inertia_vec_local(7)=-xz
285     inertia_vec_local(8)=-yz
286     inertia_vec_local(9)=xx+yy
287    
288     ! . Sum and distribute inertia and angmom arrays
289     #ifdef MPI
290     call mpi_allreduce(inertia_vec_local,inertia_vec,9,mpi_double_precision, &
291     mpi_sum,mpi_comm_world,mpi_err)
292     if (mpi_err /= 0) then
293     call error("REMOVE_ANGULAR_MOMENTUM", "MPI allreduce inertia_vec_local failed")
294     endif
295    
296     call mpi_allreduce(angmom_local,angmom,3,mpi_double_precision, &
297     mpi_sum,mpi_comm_world,mpi_err)
298     if (mpi_err /= 0) then
299     call error("REMOVE_ANGULAR_MOMENTUM", "MPI allreduce angmom_local failed")
300     endif
301    
302     inertia(1,1) = inertia_vec(1)
303     inertia(2,1) = inertia_vec(2)
304     inertia(3,1) = inertia_vec(3)
305     inertia(1,2) = inertia_vec(4)
306     inertia(2,2) = inertia_vec(5)
307     inertia(3,2) = inertia_vec(6)
308     inertia(1,3) = inertia_vec(7)
309     inertia(2,3) = inertia_vec(8)
310     inertia(3,3) = inertia_vec(9)
311    
312     #else
313     inertia(1,1) = inertia_vec_local(1)
314     inertia(2,1) = inertia_vec_local(2)
315     inertia(3,1) = inertia_vec_local(3)
316     inertia(1,2) = inertia_vec_local(4)
317     inertia(2,2) = inertia_vec_local(5)
318     inertia(3,2) = inertia_vec_local(6)
319     inertia(1,3) = inertia_vec_local(7)
320     inertia(2,3) = inertia_vec_local(8)
321     inertia(3,3) = inertia_vec_local(9)
322    
323     angmom = angmom_local
324     #endif
325    
326     ! invert the moment of inertia tensor by LU-decomposition / backsolving:
327    
328 chuckv 9 call la_getrf(inertia, ipiv, INFO=la_info)
329 chuckv 4 if (la_info /= 0) then
330 chuckv 9 write(junk,*) 'LA_GETRF error in LU-Decomposition ',la_info
331 chuckv 4 call error('REMOVE_ANGULAR_MOMENTUM', &
332 chuckv 9 junk)
333    
334 chuckv 4 end if
335    
336     call la_getri(inertia, ipiv, INFO=la_info)
337     if (la_info /= 0) then
338     call error('REMOVE_ANGULAR_MOMENTUM', &
339     'LA_GETRI error in Inverting Moment of Inertia tensor')
340     end if
341    
342     inertia_inverse = inertia
343    
344     ! calculate the angular velocities: omega = I^-1 . L
345    
346     omega = matmul(inertia_inverse, angmom)
347    
348     ! subtract out center of mass velocity and angular momentum from
349     ! particle velocities
350    
351     do i = 1, nlocal
352     this_q(1:3) = q_adj_com(1:3,i)
353     v(1:3,i) = v_adj_com(1:3,i) - cross_product(omega, this_q)
354     enddo
355    
356     return
357     end subroutine remove_angular_momentum
358    
359     ! ======================================================================================
360     !. functions
361     function get_vbar(mass, this_temp) result(vbar)
362    
363     real( kind = DP ) :: vbar
364     real( kind = DP ),intent(in) :: this_temp, mass
365     real( kind = DP ), parameter :: kb = 1.381E-23_DP
366     real( kind = DP ) :: kebar, vbar2
367    
368    
369     kebar = 3.0E0_DP * kb * this_temp / 2.0E0_DP
370    
371     vbar2 = 2.0E0_DP * kebar / (mass * 1.661E-27_DP)
372    
373     vbar = dsqrt(vbar2/3.0E0_DP) * 1.0E-5_DP
374    
375     return
376     end function get_vbar
377    
378     subroutine calc_temp(this_temp,ke)
379     use constants
380     integer i, dim
381     real( kind = DP ), intent(out) :: this_temp
382     real( kind = DP ), intent(out), optional :: ke
383     real( kind = DP ) :: ktmp, converter, kebar, kb
384     real( kind = DP ) :: ke_local
385     real( kind = DP ) :: ke_global
386     logical :: do_ke
387    
388     do_ke = .false.
389     if (present(ke)) do_ke = .true.
390    
391     converter = 1.0E0_DP/2.390664d3
392    
393     if (do_ke) ke = 0.0E0_DP
394     ke_local = 0.0E0_DP
395     this_temp = 0.0E0_DP
396     ke_global = 0.0E0_DP
397    
398 chuckv 9 ! write(*,*) 'ndim: ',ndim
399     ! write(*,*) 'nlocal: ',nlocal
400    
401 chuckv 4 do i = 1, nlocal
402     ktmp = 0.0E0_DP
403     do dim = 1, ndim
404     ktmp = ktmp + v(dim,i)**2
405     end do
406     ke_local = ke_local + 0.5E0_DP * mass(i) * ktmp
407     end do
408    
409    
410    
411     #ifdef MPI
412     call mpi_allreduce(ke_local,ke_global,1,mpi_double_precision, &
413     mpi_sum,mpi_comm_world,mpi_err)
414     #else
415     ke_global = ke_local
416     #endif
417    
418     ke_global = ke_global * AMUA2FS2_TO_KCALMOL
419    
420     ! ke_global = ke_global/converter
421    
422     kebar = kcal_to_kj*1000.0E0_DP * ke_global / dble(natoms) / NAVOGADRO
423     ! kebar = 4.184E3_DP * ke_global / dble(natoms) / NAVOGADRO
424     this_temp = 2.0E0_DP * kebar / (3.0E0_DP * K_BOLTZ)
425    
426     if (do_ke) ke = ke_global
427     ! write(*,*) 'ke, kb, temp = ', ke, kb, temp
428    
429     return
430     end subroutine calc_temp
431    
432     function get_com() result(com)
433     real( kind = DP ), dimension( ndim ) :: com_local
434     real( kind = DP ), dimension( ndim ) :: com
435     integer :: i
436    
437     com = 0.0E0_DP
438     com_local = 0.0E0_DP
439    
440     do i = 1, nlocal
441     com_local(1:ndim) = com_local(1:ndim) + mass(i)*q(1:ndim,i)
442     enddo
443    
444     #ifdef MPI
445     call mpi_allreduce(com_local,com,ndim,mpi_double_precision, &
446     mpi_sum,mpi_comm_world,mpi_err)
447     if (mpi_err /= 0) then
448     call error("PRINT_ANGULAR_MOMENTUM", "MPI allreduce com failed")
449     endif
450     #else
451     com = com_local
452     #endif
453    
454     com(1:ndim) = com(1:ndim)/total_mass
455    
456    
457     return
458    
459     end function get_com
460    
461    
462     ! . =============================================================================
463     function get_com_v() result(com_v)
464     !. =============================================================================
465     !. returns center of mass velocity
466    
467     real( kind = DP ), dimension( ndim ) :: com_p_local
468     real( kind = DP ), dimension( ndim ) :: com_p
469     real( kind = DP ), dimension( ndim ) :: com_v
470     integer :: i
471    
472     com_p = 0.0E0_DP
473     com_p_local = 0.0E0_DP
474    
475     do i = 1, nlocal
476     com_p_local(1:ndim) = com_p_local(1:ndim) + mass(i)*v(1:ndim,i)
477     enddo
478    
479     #ifdef MPI
480     call mpi_allreduce(com_p_local,com_p,ndim,mpi_double_precision, &
481     mpi_sum,mpi_comm_world,mpi_err)
482     if (mpi_err /= 0) then
483     call error("PRINT_ANGULAR_MOMENTUM", "MPI allreduce com failed")
484     endif
485     #else
486     com_p = com_p_local
487     #endif
488    
489     do i = 1, ndim
490     com_v(i) = com_p(i)/total_mass
491     enddo
492    
493     return
494    
495     end function get_com_v
496    
497    
498     !Maybe a subroutine to get com and com_v without looping twice
499    
500     subroutine get_com_all(com, com_v)
501    
502     real( kind = DP ), dimension( ndim ) :: com_local
503     real( kind = DP ), dimension( ndim ),intent(out) :: com
504     real( kind = DP ), dimension( ndim ) :: com_p_local
505     real( kind = DP ), dimension( ndim ) :: com_p
506     real( kind = DP ), dimension( ndim ),intent(out) :: com_v
507     integer :: i
508    
509     com = 0.0E0_DP
510     com_local = 0.0E0_DP
511     com_p = 0.0E0_DP
512     com_p_local = 0.0E0_DP
513    
514     do i = 1, nlocal
515     com_local(1:ndim) = com_local(1:ndim) + mass(i)*q(1:ndim,i)
516     com_p_local(1:ndim) = com_p_local(1:ndim) + mass(i)*v(1:ndim,i)
517     enddo
518    
519     #ifdef MPI
520     call mpi_allreduce(com_local,com,ndim,mpi_double_precision, &
521     mpi_sum,mpi_comm_world,mpi_err)
522     if (mpi_err /= 0) then
523     call error("PRINT_ANGULAR_MOMENTUM", "MPI allreduce com failed")
524     endif
525    
526     call mpi_allreduce(com_p_local,com_p,ndim,mpi_double_precision, &
527     mpi_sum,mpi_comm_world,mpi_err)
528     if (mpi_err /= 0) then
529     call error("PRINT_ANGULAR_MOMENTUM", "MPI allreduce com failed")
530     endif
531     #else
532     com = com_local
533     com_p = com_p_local
534     #endif
535    
536     com(1:ndim) = com(1:ndim)/total_mass
537     com_v(1:ndim) = com_p(1:ndim)/total_mass
538    
539     return
540    
541     end subroutine get_com_all
542    
543     end module velocity