c
c
c     ###################################################
c     ##  COPYRIGHT (C)  1990  by  Jay William Ponder  ##
c     ##              All Rights Reserved              ##
c     ###################################################
c
c     ##################################################################
c     ##                                                              ##
c     ##  program dynamic  --  compute molecular dynamics trajectory  ##
c     ##                                                              ##
c     ##################################################################
c
c
c     "dynamic" computes a molecular dynamics trajectory in any of
c     several statistical mechanical ensembles; periodic boundaries
c     can be maintained and options are available for coupling the
c     temperature and pressure to an external bath
c
c
      program dynamic
      implicit none
      include 'sizes.i'
      include 'atmtyp.i'
      include 'atoms.i'
      include 'bath.i'
      include 'bond.i'
      include 'bound.i'
      include 'inform.i'
      include 'iounit.i'
      include 'keys.i'
      include 'potent.i'
      include 'solute.i'
      include 'usage.i'
      include 'warp.i'
      integer i,mode,ndump,nstep,istep
      integer period,next,modstep
      real*8 dt,dt2,dt_2,dt_8
      real*8 dt2_2,dt2_8,dt_dump
      real*8 ratio,def_start,def_stop
      character*6 integrate
      character*20 keyword
      character*80 record,string
      logical exist,query
c
c
c     set up the structure and mechanics calculation
c
      call initial
      call getxyz
      call mechanic
c
c     initialize the simulation length as number of time steps
c
      query = .true.
      call nextarg (string,exist)
      if (exist) then
         read (string,*,err=10,end=10)  nstep
         query = .false.
      end if
   10 continue
      if (query) then
         write (iout,20)
   20    format (/,' Enter the Number of Molecular Dynamics Steps',
     &              ' :  ',$)
         read (input,30)  nstep
   30    format (i10)
      end if
c
c     get the length of the dynamics time step to be used
c
      dt = -1.0d0
      call nextarg (string,exist)
      if (exist)  read (string,*,err=40,end=40)  dt
   40 continue
      if (dt .le. 0.0d0) then
         write (iout,50)
   50    format (/,' Enter the Time Step value in Femtoseconds',
     &              ' [1.0] :  ',$)
         read (input,60)  dt
   60    format (f20.0)
      end if
      if (dt .le. 0.0d0)  dt = 1.0d0
      dt = 1.0d-15 * dt
c
c     set the time between trajectory snapshot coordinate dumps
c
      dt_dump = -1.0d0
      call nextarg (string,exist)
      if (exist)  read (string,*,err=70,end=70)  dt_dump
   70 continue
      if (dt_dump .le. 0.0d0) then
         write (iout,80)
   80    format (/,' Enter Time between Dumps in Picoseconds',
     &              ' [0.1] :  ',$)
         read (input,90)  dt_dump
   90    format (f20.0)
      end if
      if (dt_dump .le. 0.0d0)  dt_dump = 0.1d0
      dt_dump = 1.0d-12 * dt_dump
c
c     rate of deformation change for potential surface smoothing
c
      if (use_deform) then
         def_stop = -1.0d0
         call nextarg (string,exist)
         if (exist)  read (string,*,err=100,end=100)  def_stop
  100    continue
         if (def_stop .le. 0.0d0) then
            write (iout,110)
  110       format (/,' Enter Final Desired Deformation Parameter',
     &                 ' [0.0] :  ',$)
            read (input,120)  def_stop
  120       format (f20.0)
         end if
         if (def_stop .le. 0.0d0)  def_stop = 0.0d0
         def_start = deform - def_stop
         if (def_start .le. 0.0d0)  def_start = 0.0d0
      end if
c
c     set some default parameters for the dynamics run
c
      kelvin = 0.0d0
      atmsph = 0.0d0
      isothermal = .false.
      isobaric = .false.
      integrate = 'BEEMAN'
      tautemp = 0.1d-12
      taupres = 2.0d-12
      compress = 0.000046d0
c
c     check for keywords containing any altered parameters
c
      do i = 1, nkey
         next = 1
         record = keyline(i)
         call gettext (record,keyword,next)
         call upcase (keyword)
         if (keyword(1:10) .eq. 'INTEGRATE ') then
            call getword (record,integrate,next)
            call upcase (integrate)
         else if (keyword(1:16) .eq. 'TAU-TEMPERATURE ') then
            read (record(next:80),*,err=130)  tautemp
            tautemp = 1.0d-12 * tautemp
            tautemp = max(tautemp,dt)
         else if (keyword(1:13) .eq. 'TAU-PRESSURE ') then
            read (record(next:80),*,err=130)  taupres
            taupres = 1.0d-12 * taupres
            taupres = max(taupres,dt)
         else if (keyword(1:9) .eq. 'COMPRESS ') then
            read (record(next:80),*,err=130)  compress
         end if
  130    continue
      end do
c
c     get choice of statistical ensemble for periodic system
c
      if (use_bounds) then
         mode = 0
         call nextarg (string,exist)
         if (exist)  read (string,*,err=140,end=140)  mode
  140    continue
         if (mode.lt.1 .or. mode.gt.4) then
            write (iout,150)
  150       format (/,' Possible Statistical Mechanical Ensembles :',
     &              /,'   (1) Microcanonical (NVE)',
     &              /,'   (2) Canonical (NVT)',
     &              /,'   (3) Isoenthalpic-Isobaric (NPH)',
     &              /,'   (4) Isothermal-Isobaric (NPT)',
     &              /,' Enter the Number of the Desired Choice',
     &                 ' [1] :  ',$)
            read (input,160)  mode
  160       format (i10)
         end if
         if (mode.eq.2 .or. mode.eq.4) then
            isothermal = .true.
            kelvin = -1.0d0
            call nextarg (string,exist)
            if (exist)  read (string,*,err=170,end=170)  kelvin
  170       continue
            if (kelvin .le. 0.0d0) then
               write (iout,180)
  180          format (/,' Enter the Desired Temperature in Degrees',
     &                    ' K [300] :  ',$)
               read (input,190)  kelvin
  190          format (f20.0)
            end if
            if (kelvin .le. 0.0d0)  kelvin = 300.0d0
         end if
         if (mode.eq.3 .or. mode.eq.4) then
            isobaric = .true.
            atmsph = -1.0d0
            call nextarg (string,exist)
            if (exist)  read (string,*,err=200,end=200)  kelvin
  200       continue
            if (atmsph .le. 0.0d0) then
               write (iout,210)
  210          format (/,' Enter the Desired Pressure in Atm',
     &                    ' [1.0] :  ',$)
               read (input,220)  atmsph
  220          format (f20.0)
            end if
            if (atmsph .le. 0.0d0)  atmsph = 1.0d0
         end if
      end if
c
c     get desired temperature for nonperiodic system
c
      if (.not. use_bounds) then
         isothermal = .true.
         kelvin = -1.0d0
         call nextarg (string,exist)
         if (exist)  read (string,*,err=230,end=230)  kelvin
  230    continue
         if (kelvin .le. 0.0d0) then
            write (iout,240)
  240       format (/,' Enter the Desired Temperature in Degrees',
     &                 ' K [300] :  ',$)
            read (input,250)  kelvin
  250       format (f20.0)
         end if
         if (kelvin .le. 0.0d0)  kelvin = 300.0d0
      end if
c
c     set time constants for the dynamics integration
c
      dt2 = dt * dt
      dt_2 = dt / 2.0d0
      dt_8 = dt / 8.0d0
      dt2_2 = dt2 / 2.0d0
      dt2_8 = dt2 / 8.0d0
      ndump = nint(dt_dump/dt)
c
c     make sure all atoms have a mass of at least one
c
      do i = 1, n
         if (use(i)) then
            mass(i) = max(mass(i),1.0d0)
         end if
      end do
c
c     set initial velocities and check various options
c
      call mdinit
c
c     initialize any constraints for the rattle algorithm
c
      call shakeup
c
c     set Born radii update frequency for GB/SA solvation
c
      if (use_gbsa) then
         if (reborn .eq. 1) then
            call born
            reborn = 100
         end if
      end if
c
c     print out a header line for the computation
c
      if (integrate .eq. 'VERLET') then
         write (iout,260)
  260    format (/,' Molecular Dynamics Trajectory via',
     &              ' Velocity Verlet Algorithm')
      else
         write (iout,270)
  270    format (/,' Molecular Dynamics Trajectory via',
     &              ' Modified Beeman Algorithm')
      end if
c
c     take the desired number of molecular dynamics steps
c
      period = 100
      do istep = 1, nstep
         modstep = mod(istep,period)
         if (verbose .and. modstep.eq.1) then
            if (isobaric) then
               write (iout,280)
  280          format (/,'    MD Step      E Total   E Potential',
     &                   '   E Kinetic       Temp       Pres',/)
            else
               write (iout,290)
  290          format (/,'    MD Step      E Total   E Potential',
     &                   '   E Kinetic       Temp',/)
            end if
         end if
         if (use_deform) then
            ratio = (1.0d0-dble(istep)/dble(nstep))**3
            deform = def_stop + ratio*def_start
         end if
         if (integrate .eq. 'VERLET') then
            call verlet (istep,dt,dt_2,dt2_2,ndump)
         else
            call beeman (istep,dt,dt_8,dt2_8,ndump)
         end if
         if (nuse.eq.n .and. modstep.eq.0)  call mdrest
      end do
      end
