Nose-Hoover chain with arbitrary number of oscillators

This commit is contained in:
Daniel Mejia-Rodriguez 2022-04-27 23:16:54 -07:00
parent 76060f7e42
commit d98fff175f
4 changed files with 166 additions and 58 deletions

View file

@ -7,13 +7,14 @@ c
common/qmd_int/lgeom,igeom,jdebug
c
c nose-hoover thermostat parameters
integer maxchain
parameter (maxchain = 2)
integer maxchain,maxnsy,nnhos,nnhsy
parameter (maxchain = 10, maxnsy = 7)
logical do_nosehoover
double precision r_nh(maxchain) ! chain positions
double precision v_nh(maxchain) ! chain velocities
double precision v_nh(maxchain) ! chain velocities
double precision m_nh(maxchain) ! chain masses
double precision g_nh(maxchain) ! bath couplings
double precision syw_nh(maxnsy) ! Suzuki-Yoshida weights
c
c berendsen thermostat
logical do_berendsen
@ -31,7 +32,8 @@ c stochastic velocity rescaling
logical do_svr
c
common/qmd_thermostats/do_berendsen,tau,
& do_nosehoover,r_nh,v_nh,m_nh,g_nh,
& do_nosehoover,r_nh,v_nh,m_nh,g_nh,syw_nh,
& nnhos, nnhsy,
& do_langevin,friction,
& do_rescale,idum,
& do_svr

View file

@ -19,6 +19,7 @@ c
#include "msgids.fh"
#include "stdio.fh"
#include "msgtypesf.h"
#include "util_params.fh"
c
#include "qmd_common.fh"
c
@ -41,7 +42,7 @@ c
character*32 integrator_nucl ! nuclear md integrator
character*32 integrator_elec ! electronic dynamics integrator
integer ichain
double precision nh_mass(2) ! nose-hoover mass
double precision nhfreq ! nose-hoover mass
logical do_none
logical restart
logical do_namd
@ -131,19 +132,38 @@ c thermostat
end if
c
c nose-hoover mass parameter
if (.not.rtdb_get(rtdb,'qmd:nh_mass',mt_dbl,2,nh_mass))
if (.not.rtdb_get(rtdb,'qmd:nhfreq',mt_dbl,1,nhfreq))
& call errquit(pname//'failed to read nh_mass',0,RTDB_ERR)
if (.not.rtdb_get(rtdb,'qmd:nnhos',mt_int,1,nnhos))
& call errquit(pname//'failed to read nh_nchain',0,RTDB_ERR)
if (.not.rtdb_get(rtdb,'qmd:nnhsy',mt_int,1,nnhsy))
& call errquit(pname//'failed to read nh_nsy',0,RTDB_ERR)
if (do_nosehoover) then
do ichain = 1,maxchain
r_nh(ichain) = 0.d0 ! position of chains
v_nh(ichain) = 0.d0 ! velocity of chains
m_nh(ichain) = nh_mass(ichain) ! mass of chains
g_nh(ichain) = 0.d0 ! bath coupling
end do
do ichain = 1,nnhos
r_nh(ichain) = 0.d0 ! position of chains
m_nh(ichain) = kb_au*targ_temp/nhfreq**2 ! mass of chains
v_nh(ichain) = 0.d0 ! velocity of chains
g_nh(ichain) = 0.d0 ! bath coupling
end do
if (nnhsy.eq.1) then
syw_nh(1) = 1d0
elseif (nnhsy.eq.3) then
syw_nh(1) = 1d0/(2d0 - 2d0**(1d0/3d0))
syw_nh(2) = 1 - 2*syw_nh(1)
syw_nh(3) = syw_nh(1)
elseif (nnhsy.eq.7) then
syw_nh(1) = 0.784513610477560d0
syw_nh(2) = 0.235573213359357d0
syw_nh(3) = -1.17767998417887d0
syw_nh(4) = 1d0 - 2*sum(syw_nh(1:3))
syw_nh(5) = syw_nh(3)
syw_nh(6) = syw_nh(2)
syw_nh(7) = syw_nh(1)
endif
if (ga_nodeid().eq.0)
& write(luout,130) "NH mass(1):",nh_mass(1)
if (ga_nodeid().eq.0)
& write(luout,130) "NH mass(2):",nh_mass(2)
& write(luout,130) "NH frequency:",nhfreq
end if
c
c langevin friction parameter

View file

@ -31,9 +31,9 @@ c
integer tvals(8)
double precision targ_temp
double precision friction
integer idum
integer idum, nnhos, nnhsy
double precision tau
double precision nh_mass(2)
double precision nh_freq
character*32 test
character*32 thermostat
character*32 integrator_nucl
@ -83,10 +83,15 @@ c Berendsen tau parameter, also used for svr
& call errquit(pname//'failed to write tau',0,RTDB_ERR)
c
c Nose-Hoover mass parameter
nh_mass(1)=0.1d0
nh_mass(2)=0.1d0
if (.not.rtdb_put(rtdb,'qmd:nh_mass',mt_dbl,2,nh_mass(1)))
& call errquit(pname//'failed to write nh_mass',0,RTDB_ERR)
nh_freq = 0.013669d0
nnhos = 3
nnhsy = 3
if (.not.rtdb_put(rtdb,'qmd:nhfreq',mt_dbl,1,nh_freq))
& call errquit(pname//'failed to write tau',0,RTDB_ERR)
if (.not.rtdb_put(rtdb,'qmd:nnhos',mt_dbl,1,nnhos))
& call errquit(pname//'failed to write tau',0,RTDB_ERR)
if (.not.rtdb_put(rtdb,'qmd:nnhsy',mt_dbl,1,nnhsy))
& call errquit(pname//'failed to write tau',0,RTDB_ERR)
c
c Nuclear MD integrator
integrator_nucl='velocity-verlet'
@ -199,10 +204,48 @@ c Nuclear thermostat
1 call errquit(pname//'failed to write thermostat',0,RTDB_ERR)
c Nose-Hoover: get masses
if (thermostat.eq.'nose-hoover') then
if (.not.inp_f(nh_mass(1))) nh_mass(1) = 0.1d0
if (.not.inp_f(nh_mass(2))) nh_mass(2) = 0.1d0
if (.not.rtdb_put(rtdb,'qmd:nh_mass',mt_dbl,2,nh_mass(1)))
& call errquit(pname//'failed to write nh_mass',0,RTDB_ERR)
200 if (.not.inp_a(test)) goto 10
201 if (inp_compare(.false.,'nnhos',test)) then
if (.not.inp_i(nnhos))
& call errquit(pname//'failed to read number of oscillators',
& 0,INPUT_ERR)
if (.not.rtdb_put(rtdb,'qmd:nnhos',mt_int,1,nnhos))
& call errquit(pname//'failed to write nnhos',0,RTDB_ERR)
goto 200
elseif(inp_compare(.false.,'frequency',test)) then
if (.not.inp_f(nh_freq))
& call errquit(pname//'failed to read frequency',0,INPUT_ERR)
if (.not.rtdb_put(rtdb,'qmd:nhfreq',mt_dbl,1,nh_freq))
& call errquit(pname//'failed to write nhfreq',0,RTDB_ERR)
if (.not.inp_a(test)) goto 10
if (inp_compare(.false.,'1/cm',test)) then
nh_freq = nh_freq*4.5563352529120d-6
elseif (inp_compare(.false.,'cm^-1',test)) then
nh_freq = nh_freq*4.5563352529120d-6
elseif (inp_compare(.false.,'ev',test)) then
nh_freq = nh_freq*3.6749322175655d-2
elseif (inp_compare(.false.,'au',test)) then
nh_freq = nh_freq
elseif (inp_compare(.false.,'ha',test)) then
nh_freq = nh_freq
else
goto 201
endif
if (.not.rtdb_put(rtdb,'qmd:nhfreq',mt_dbl,1,nh_freq))
& call errquit(pname//'failed to write nnhos',0,RTDB_ERR)
goto 200
elseif(inp_compare(.false.,'nsy',test)) then
if (.not.inp_i(nnhsy))
& call errquit(pname//'failed to number of Suzuki-Yoshida'//
& ' points',0,INPUT_ERR)
if (.not.rtdb_put(rtdb,'qmd:nnhsy',mt_int,1,nnhsy))
& call errquit(pname//'failed to write nnhsy',0,RTDB_ERR)
goto 200
else
call errquit(pname//'unknown nose-hoover option '//
$ trim(test),0,INPUT_ERR)
endif
c Berendsen or svr (Bussi, Donadio, Parrinello 2007): get tau
else if (thermostat.eq.'berendsen'.or.thermostat.eq.'svr') then
if (.not.inp_f(tau)) tau = 1.d3
@ -342,10 +385,10 @@ c $Id$
#include "mafdecls.fh"
#include "errquit.fh"
c
integer nstep_nucl
integer nstep_nucl, nnhos, nnhsy
double precision dt_nucl
double precision targ_temp
double precision nh_mass(2)
double precision nhfreq
double precision tau
character*32 thermostat
character*32 integrator_nucl
@ -378,11 +421,22 @@ c Nuclear thermostat
& call errquit(pname//'failed to write thermostat',0,RTDB_ERR)
endif
c Nose-Hoover mass parameter
if (.not.rtdb_get(rtdb,'qmd:nh_mass',mt_dbl,2,nh_mass(1)))then
nh_mass(1)=0.1d0
nh_mass(2)=0.1d0
if (.not.rtdb_put(rtdb,'qmd:nh_mass',mt_dbl,2,nh_mass(1)))
& call errquit(pname//'failed to write nh_mass',0,RTDB_ERR)
if (.not.rtdb_get(rtdb,'qmd:nhfreq',mt_dbl,1,nhfreq))then
nhfreq = 0.013669d0
if (.not.rtdb_put(rtdb,'qmd:nhfreq',mt_dbl,1,nhfreq))
& call errquit(pname//'failed to write nhfreq',0,RTDB_ERR)
endif
c Nose-Hoover number of oscillators
if (.not.rtdb_get(rtdb,'qmd:nnhos',mt_int,1,nnhos))then
nnhos = 3
if (.not.rtdb_put(rtdb,'qmd:nnhos',mt_int,1,nnhos))
& call errquit(pname//'failed to write nnhos',0,RTDB_ERR)
endif
c Nose-Hoover number of Suzuki-Yoshida points
if (.not.rtdb_get(rtdb,'qmd:nnhsy',mt_int,1,nnhsy))then
nnhsy = 3
if (.not.rtdb_put(rtdb,'qmd:nnhsy',mt_int,1,nnhsy))
& call errquit(pname//'failed to write nnhsy',0,RTDB_ERR)
endif
c Berendsen tau parameter, also used for svr
if (.not.rtdb_get(rtdb,'qmd:tau',mt_dbl,1,tau)) then

View file

@ -69,9 +69,9 @@ c
c
double precision dt2,dt4,dt8
c
integer i,j
double precision scalefac
double precision kbt
integer i,j,ios,isy,ims,mdeg
double precision scalefac,aa,kbt
c
character*30 pname
c
@ -81,43 +81,75 @@ c preliminaries
dt4 = 0.25d0*dt
dt8 = 0.125d0*dt
kbt = kb_au*targ_temp
mdeg = ndeg + 6
if (do_linear) mdeg = mdeg - 1
scalefac = 1d0
m_nh(1) = m_nh(1)*mdeg
g_nh(1) = (2d0*KE_in - mdeg*kbt)/m_nh(1)
do ims=1,3
do isy=1,nnhsy
v_nh(nnhos) = v_nh(nnhos) + g_nh(nnhos)*dt4*syw_nh(isy)/3
do ios=1,nnhos-1
aa = dexp(-dt8*syw_nh(isy)*v_nh(nnhos+1-ios)/3)
v_nh(nnhos-ios) = v_nh(nnhos-ios)*aa**2 +
$ dt4*syw_nh(isy)*g_nh(nnhos-ios)*aa/3
enddo
aa = dexp(-dt2*syw_nh(isy)*v_nh(1)/3)
scalefac = scalefac*aa
g_nh(1) = (2d0*KE_in*scalefac**2 - mdeg*kbt)/m_nh(1)
do ios=1,nnhos
r_nh(ios) = r_nh(ios) + v_nh(ios)*dt2*syw_nh(isy)/3
enddo
do ios=1,nnhos-1
aa = dexp(-dt8*syw_nh(isy)*v_nh(ios+1)/3)
v_nh(ios) = v_nh(ios)*aa**2 + dt4*syw_nh(isy)*g_nh(ios)*aa/3
g_nh(ios+1) = (m_nh(ios)*v_nh(ios)**2 - kbt)/m_nh(ios+1)
enddo
v_nh(nnhos) = v_nh(nnhos) + g_nh(nnhos)*dt4*syw_nh(isy)/3
enddo
enddo
do i=1,n
v(1:3,i) = scalefac*v(1:3,i)
enddo
m_nh(1) = m_nh(1)/mdeg
c
c nose-hoover 2 chain formula: Frenkel & Smit
g_nh(2) = (m_nh(1)*v_nh(1)*v_nh(1)-kbt)/m_nh(2)
c g_nh(2) = (m_nh(1)*v_nh(1)*v_nh(1)-kbt)/m_nh(2)
c
v_nh(2) = v_nh(2) + g_nh(2)*dt4
v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c v_nh(2) = v_nh(2) + g_nh(2)*dt4
c v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c
g_nh(1) = (2.0d0*KE_in - ndeg*kbt)/m_nh(1)
c g_nh(1) = (2.0d0*KE_in - ndeg*kbt)/m_nh(1)
c
v_nh(1) = v_nh(1) + g_nh(1)*dt4
v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c v_nh(1) = v_nh(1) + g_nh(1)*dt4
c v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c
r_nh(1) = r_nh(1) + v_nh(1)*dt2
r_nh(2) = r_nh(2) + v_nh(2)*dt2
c r_nh(1) = r_nh(1) + v_nh(1)*dt2
c r_nh(2) = r_nh(2) + v_nh(2)*dt2
c
scalefac = dexp(-v_nh(1)*dt2)
c scalefac = dexp(-v_nh(1)*dt2)
c
c scale kinetic energy
KE_in = KE_in*scalefac*scalefac
c KE_in = KE_in*scalefac*scalefac
c
c nose-hoover 2 chain formula: Frenkel & Smit
g_nh(1) = (2.0d0*KE_in - ndeg*kbt)/m_nh(1)
c g_nh(1) = (2.0d0*KE_in - ndeg*kbt)/m_nh(1)
c
v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
v_nh(1) = v_nh(1) + g_nh(1)*dt4
v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c v_nh(1) = v_nh(1) + g_nh(1)*dt4
c v_nh(1) = v_nh(1) * dexp(-v_nh(2)*dt8)
c
g_nh(2) = (m_nh(1)*v_nh(1)*v_nh(1)-kbt)/m_nh(2)
c g_nh(2) = (m_nh(1)*v_nh(1)*v_nh(1)-kbt)/m_nh(2)
c
v_nh(2) = v_nh(2) + g_nh(2)*dt4
c
c scale velocity
do i = 1,n
v(1,i) = scalefac*v(1,i)
v(2,i) = scalefac*v(2,i)
v(3,i) = scalefac*v(3,i)
end do
c v_nh(2) = v_nh(2) + g_nh(2)*dt4
c
return
end