Computing the acceleration

Exercise

The acceleration vector is given by

where x_i is the x coordinate of atom i (an element of the coord array). Write the provider for V_grad_numeric, the finite-difference approximation of the derivative of the potential with respect to the coordinates:

It will be necessary to use the TOUCH keyword.

The computation of the acceleration should not depend directly on the method used to compute the gradient, so we will use V_grad in the provider for the acceleration. V_grad will be a simple copy of V_grad_numeric.

Expected output

$ ./test4 
           0 : -> provide_acceleration
           0 :  -> provide_natoms
           0 :   -> natoms
 Number of atoms?
3
           0 :   <- 0="" natoms="" 1.68999999999999879E-004="" :="" <-="" provide_natoms="" 3.50999999999999750E-004="" -=""> provide_coord
           0 :   -> coord
 For each atom: x, y, z, mass?
0 0 0 10
0 0 .3 20
.1 .2 -.3 15
           0 :   <- 0="" coord="" 2.26999999999999771E-004="" :="" <-="" provide_coord="" 3.32000000000000264E-004="" -=""> provide_v_grad
           0 :   -> provide_v_grad_numeric
           0 :    -> provide_v
           0 :     -> provide_v_lj
           0 :      -> provide_epsilon_lj
           0 :       -> epsilon_lj
 Epsilon?
0.0661
 Sigma?
.3345
           0 :       <- 0="" epsilon_lj="" 1.60999999999999685E-004="" :="" <-="" provide_epsilon_lj="" 2.52000000000000054E-004="" -=""> provide_distance
           0 :       -> distance
           0 :       <- 0="" distance="" 2.00000000000026545E-006="" :="" <-="" provide_distance="" 4.30000000000000694E-005="" -=""> v_lj
           0 :      <- 0="" v_lj="" 2.00000000000026545E-006="" :="" <-="" provide_v_lj="" 4.05999999999999677E-004="" -=""> v
           0 :     <- 0="" v="" 1.00000000000013273E-006="" :="" <-="" provide_v="" 4.78999999999999825E-004="" -=""> provide_dstep
           0 :     -> dstep
           0 :     <- 0="" dstep="" 9.99999999999699046E-007="" :="" <-="" provide_dstep="" 2.59999999999999815E-005="" -=""> v_grad_numeric
           0 :     -> touch_coord
           0 :     <- 0="" touch_coord="" 1.00000000000013273E-006="" :="" -=""> provide_v
           0 :      -> provide_v_lj
           0 :       -> provide_distance
           0 :        -> distance
           0 :        <- 0="" distance="" 1.00000000000013273E-006="" :="" <-="" provide_distance="" 2.20000000000003179E-005="" -=""> v_lj
           0 :       <- 0="" v_lj="" 9.99999999999265365E-007="" :="" <-="" provide_v_lj="" 6.70000000000002191E-005="" -=""> v
           0 :      <- 0="" v="" 9.99999999999265365E-007="" :="" <-="" provide_v="" 1.10999999999999988E-004="" -=""> touch_coord
           0 :     <- 0="" touch_coord="" 1.00000000000013273E-006="" :="" -=""> provide_v
           0 :      -> provide_v_lj
           0 :       -> provide_distance
           0 :        -> distance
           0 :        <- 0="" distance="" 1.00000000000013273E-006="" :="" <-="" provide_distance="" 2.20000000000003179E-005="" -=""> v_lj
           0 :       <- 0="" v_lj="" 1.00000000000013273E-006="" :="" <-="" provide_v_lj="" 6.29999999999996882E-005="" -=""> v
           0 :      <- 0="" v="" 1.00000000000013273E-006="" :="" <-="" provide_v="" 1.06000000000000191E-004="" -=""> touch_coord
----8<-------------------------------------------------------------------- 0="" :="" <-="" touch_coord="" 1.00000000000013273E-006="" -=""> provide_v
           0 :      -> provide_v_lj
           0 :       -> provide_distance
           0 :        -> distance
           0 :        <- 0="" distance="" 1.00000000000013273E-006="" :="" <-="" provide_distance="" 2.20000000000003179E-005="" -=""> v_lj
           0 :       <- 0="" v_lj="" 1.00000000000013273E-006="" :="" <-="" provide_v_lj="" 6.39999999999998209E-005="" -=""> v
           0 :      <- 0="" v="" 1.00000000000013273E-006="" :="" <-="" provide_v="" 1.05000000000000059E-004="" -=""> touch_coord
           0 :     <- 0="" touch_coord="" 1.00000000000013273E-006="" :="" <-="" v_grad_numeric="" 2.71300000000000013E-003="" provide_v_grad_numeric="" 3.29999999999999955E-003="" -=""> v_grad
           0 :   <- 0="" v_grad="" 1.00000000000013273E-006="" :="" <-="" provide_v_grad="" 3.35400000000000021E-003="" -=""> acceleration
           0 :  <- 0="" acceleration="" 1.00000000000013273E-006="" :="" <-="" provide_acceleration="" 4.20500000000000040E-003="" -=""> test4
 -1.21434697006317371E-003 -2.42873782740904431E-003  -2.8852483886706581     
  3.77225707531847476E-004  7.54451431647651383E-004   1.4421824477394567     
  3.06597036647815457E-004  6.13223309409161033E-004  5.88995461163014712E-004
           0 : 

Solution

File test4.irp.f

ratiot4
  implicit none
  BEGIN_DOC
  ! Program testing the acceleration
  END_DOC
  integer                        :: i
  do i=1,Natoms
    print *, acceleration(:,i)
  enddo
end program

File potential.irp.f, add

BEGIN_PROVIDER [ double precision, dstep ]
  implicit none
  BEGIN_DOC
  ! Finite difference step
  END_DOC
  dstep = 1.d-4
END_PROVIDER

BEGIN_PROVIDER [ double precision, V_grad_numeric, (3,Natoms) ]
  implicit none
  BEGIN_DOC
  ! Numerical gradient of the potential
  END_DOC
  integer                        :: i, k
  do i=1,Natoms
    do k=1,3
      coord(k,i) += dstep   ! Move coordinate x_i to x_i + delta 
      TOUCH coord mass      ! Tell IRPF90 that coord has been changed
      V_grad_numeric(k,i) = V      ! V is here V(x_i + delta)
      coord(k,i) -= 2.d0*dstep     ! Move coordinate x_i to x_i - delta
      TOUCH coord mass      ! Tell IRPF90 that coord has been changed
      V_grad_numeric(k,i) -= V      ! V is here V(x_i - delta)
      V_grad_numeric(k,i) *= .5d0/dstep
      coord(k,i) += dstep   ! Put back x_i to its initial position
                            ! It is not necessary to re-touch coord since
                            ! - at the next loop iteration it will be touched
                            ! - out of the loop, it is soft-touched
    enddo
  enddo
  SOFT_TOUCH coord mass ! Does not re-provide the current entities. Here, V will
                        ! not be re-computed. This reduced the CPU time, but is
                        ! dangerous.
END_PROVIDER

BEGIN_PROVIDER [ double precision, V_grad, (3,Natoms) ]
  implicit none
  BEGIN_DOC
  ! Gradient of the potential
  END_DOC
  integer                        :: i,k
  do i=1,Natoms
    do k=1,3
      V_grad(k,i) = V_grad_numeric(k,i)
    enddo
  enddo
END_PROVIDER

BEGIN_PROVIDER [ double precision, acceleration, (3,Natoms) ]
  implicit none
  BEGIN_DOC
  ! Acceleration = - grad(V)/m
  END_DOC
  integer                        :: i, k
  do i=1,Natoms
    do k=1,3
      acceleration(k,i) = -V_grad(k,i)/mass(i)
    enddo
  enddo
END_PROVIDER