! Module to store constants
module MW_constants

   use MW_kinds, only: wp
   implicit none
   private

   ! Numbers
   real(wp), parameter, public :: pi = 3.14159265358979323_wp
   real(wp), parameter, public :: twopi = 2.0_wp*pi
   real(wp), parameter, public :: fourpi = 4.0_wp * pi
   real(wp), parameter, public :: eightpi_inv = 1.0_wp / (8.0_wp * pi)
   real(wp), parameter, public :: sqrtpi = 1.7724538509055160249_wp
   real(wp), parameter, public :: sqrt2 = sqrt(2.0_wp)

   ! Physics constant
   real(wp), parameter, public :: boltzmann_si = 1.38064852e-23_wp  !> J/K
   real(wp), parameter, public :: avogadro_si = 6.022140857e+23_wp  !> (1/mol)
   real(wp), parameter, public :: hartree_si = 4.359744650e-18_wp   !> hartree energy in J
   real(wp), parameter, public :: bohr_si = 0.52917721067e-10_wp    !> bohr radius in m
   real(wp), parameter, public :: me_si = 9.10938356e-31_wp         !> electron mass in kg

   ! Unit conversion
   ! ---------------
   !   units               SI           au           MD (Gromacs)
   !   length              m            a0           nm
   !   mass                kg           me           u
   !   time                s            hbar.Eh-1    ps
   !   charge              C            e            e
   !   temperature         K            Eh.kb-1      K
   !   energy              J            Eh           kJ.mol-1
   !   force               N (kg.m.s-2) Eh.a0-1      kJ.mol-1.nm-1
   !   pressure            Pa           Eh.a0-3      bar
   !   stress tensor       Pa           Eh.a0-3         
   !   velocity            m.s-1        a0.Eh.hbar-1 nm.ps-1
   !   dipole moment       C.m          e.a0         e.nm
   !   electric potential  V            Eh.e-1       kJ.mol-1.e-1
   !   electric field      V.m-1        Eh.e-1.a0-1  kJ.mol-1.e-1.nm-1

   real(wp), parameter, public :: boltzmann = boltzmann_si / hartree_si  !> hartree / K
   real(wp), parameter, public :: bohr2angstrom = 0.52917721067_wp
   real(wp), parameter, public :: angstrom2bohr = 1.0_wp / bohr2angstrom
   real(wp), parameter, public :: kJpermol2hartree = 1.0e+3_wp / (hartree_si*avogadro_si)
   real(wp), parameter, public :: hartree2kJpermol = hartree_si * avogadro_si * 1.0e-3_wp
   real(wp), parameter, public :: amu2me = 1.0e-3_wp / (avogadro_si*me_si)
   real(wp), parameter, public :: me2amu = 1.0e+3_wp * (avogadro_si*me_si)
   real(wp), parameter, public :: au2ps = 2.41888425E-5

#ifdef MW_CI
   ! Optimization constants for continuous integration checks
   integer, parameter, public :: cache_line_size = 8     !< size of a cache line (in number of real(wp))
   integer, parameter, public :: pair_block_size = 8   !< size of a block for pair interactions
   integer, parameter, public :: block_vector_size = 1024 !< size of a vector used for cache-blocking loops
! This will have to be uncommented when we switch to real GPUs
#elif _OPENACC
  ! Optimization constants for GPUs
   integer, parameter, public :: cache_line_size = 8       !< size of a cache line (in number of real(wp))
   integer, parameter, public :: pair_block_size = 32768    !< size of a block for pair interactions
   integer, parameter, public :: block_vector_size = 32768  !< size of a vector used for cache-blocking loops
#else
   ! Optimization constants for CPUs
   integer, parameter, public :: cache_line_size = 8     !< size of a cache line (in number of real(wp))
   integer, parameter, public :: pair_block_size = 128   !< size of a block for pair interactions
   integer, parameter, public :: block_vector_size = 1024 !< size of a vector used for cache-blocking loops
#endif
end module MW_constants
