! Lennard-Jones Potential
! -----------------------
!
! Proposed by Sir John Edward Lennard-Jones, the Lennard-Jones
! potential describes the potential energy of interaction between two
! non-bonding atoms or molecules based on their distance of
! separation. The potential equation accounts for the difference
! between attractive forces (dipole-dipole, dipole-induced dipole, and
! London interactions) and repulsive forces.
!
! The Lennard-Jones model consists of two 'parts'; a steep repulsive
! term, and smoother attractive term, representing the London dispersion
! forces. Apart from being an important model in itself, the
! Lennard-Jones potential frequently forms one of 'building blocks' of
! many force fields. It is worth mentioning that the 12-6 Lennard-Jones
! model is not the most faithful representation of the potential energy
! surface, but rather its use is widespread due to its computational
! expediency.The Lennard-Jones Potential is given by the following
! equation:
!
!   V(r) = 4 * epsilon * [(sigma/r)^12 - (sigma/r)^6]
!
! or
!
!   V(r) = A/(r^12) - B/(r^6)
!
! where:
!
!   * V is the intermolecular potential between the two atoms or
!       molecules.
!   * epsilon is the well depth and a measure of how strongly the two
!             particles attract each other
!   * sigma is the distance at which the intermolecular potential
!           between the two particles is zero. sigma gives a
!           measurement of how close two nonbonding particles can get
!           and is thus referred to as the van der Waals radius. It is
!           equal to one-half of the internuclear distance between
!           nonbonding particles.
!   * r is the distance of separation between both particles (measured
!       from the center of one particle to the center of the other
!       particle).
!   * A = 4*epsilon*(sigma^12), B = 4*epsilon*(sigma^6)
!
! Reference
! ---------
!
! John Edward Lennard-Jones "On the Determination of Molecular
! Fields. I. From the Variation of the Viscosity of a Gas with
! Temperature", Proceedings of the Royal Society of London. Series A,
! Containing Papers of a Mathematical and Physical Character 106
! pp. 441-462 (1924)
!
! John Edward Lennard-Jones "On the Determination of Molecular
! Fields. II. From the Equation of State of a Gas", Proceedings of the
! Royal Society of London. Series A, Containing Papers of a Mathematical
! and Physical Character 106 pp. 463-477 (1924)

!
module MW_lennard_jones
#ifndef MW_SERIAL
   use MPI
#endif
   use MW_kinds, only: wp
   use MW_box, only: MW_box_t
   use MW_ewald, only: MW_ewald_t
   use MW_box, only: MW_box_t
   use MW_electrode, only: MW_electrode_t
   use MW_ion, only: MW_ion_t
   use MW_timers
   use MW_localwork, only: MW_localwork_t
   use MW_parallel, only: MW_COMM_WORLD
   use MW_molecule, only: MW_molecule_t
   implicit none
   private

   ! Public type
   ! -----------
   public :: MW_lennard_jones_t

   ! Public subroutines
   ! ------------------
   public :: define_type
   public :: copy_type
   public :: void_type
   public :: print_type
   public :: set_rcut
   public :: set_parameters
   public :: lorentz_berthelot_mixing_rule
   public :: melt_forces
   public :: stress_tensor_tail_correction
   public :: energy
   public :: melt_fix_molecule_forces
   public :: fix_molecule_energy

   ! Data structure to handle Lennard-Jones potentials
   ! V(r) = A/(r^12) - B/(r^6)
   type MW_lennard_jones_t
      integer :: num_species = 0                    ! number of species
      real(wp) :: rcut = 0.0_wp                     ! cut-off parameter
      real(wp) :: rcutsq = 0.0_wp                     ! cut-off parameter squared
      real(wp), dimension(:,:), allocatable :: A    ! (num_species,num_species)
      real(wp), dimension(:,:), allocatable :: B    ! (num_species,num_species)
      real(wp), dimension(:,:), allocatable :: shift ! (num_species,num_species)
      real(wp), dimension(:,:), allocatable :: alpha ! (num_species,num_species)
      logical :: lj_3D_tail_correction = .false.         !< flag to turn on the LJ flat tail correction in 3D
    end type MW_lennard_jones_t

   integer, parameter :: ION_NAME_LEN = 8

contains

   !================================================================================
   ! Define the data structure
   subroutine define_type(this, num_species, rcut)
      use MW_errors, only: &
            MW_errors_allocate_error => allocate_error, &
            MW_errors_parameter_error => parameter_error
      implicit none
      ! Parameters
      ! ---------_
      type(MW_lennard_jones_t), intent(inout) :: this      !> structure to be defined
      integer, intent(in) :: num_species                    !> number of species
      real(wp), intent(in) :: rcut

      ! Local
      ! -----
      integer :: ierr

      call set_rcut(this, rcut)

      if (num_species <= 0) then
         call MW_errors_parameter_error("define_type", "lennard_jones.f90",&
               "num_species", num_species)
      end if

      this%num_species = num_species

      allocate(this%A(num_species,num_species), stat=ierr)
      if (ierr /= 0) &
            call MW_errors_allocate_error("define_type", "lennard_jones.f90", ierr)
      this%A(:,:) = 0.0_wp

      allocate(this%B(num_species,num_species), stat=ierr)
      if (ierr /= 0) &
            call MW_errors_allocate_error("define_type", "lennard_jones.f90", ierr)
      this%B(:,:) = 0.0_wp

      allocate(this%shift(num_species,num_species), stat=ierr)
      if (ierr /= 0) &
            call MW_errors_allocate_error("define_type", "lennard_jones.f90", ierr)
      this%shift(:,:) = 0.0_wp

      allocate(this%alpha(num_species,num_species), stat=ierr)
      if (ierr /= 0) &
            call MW_errors_allocate_error("define_type", "lennard_jones.f90", ierr)
      this%alpha(:,:) = 0.0_wp

   end subroutine define_type

   !================================================================================
   subroutine copy_type(this, copy)
      implicit none

      type(MW_lennard_jones_t), intent(in) :: this
      type(MW_lennard_jones_t), intent(out) :: copy

      ! Local
      ! -----
      integer :: i, j

      call define_type(copy, this%num_species, this%rcut)

      do i=1, copy%num_species
         do j=1, copy%num_species
            copy%A(i,j) = this%A(i,j)
            copy%B(i,j) = this%B(i,j)
            copy%shift(i,j) = this%shift(i,j)
            copy%alpha(i,j) = this%alpha(i,j)
         end do
      end do

   end subroutine copy_type

   !================================================================================
   ! Void the data structure
   subroutine void_type(this)
      use MW_errors, only: MW_errors_deallocate_error => deallocate_error
      implicit none
      type(MW_lennard_jones_t), intent(inout) :: this

      integer :: ierr

      if (allocated(this%B)) then
         deallocate(this%B, stat=ierr)
         if (ierr /= 0) then
            call MW_errors_deallocate_error("void_type", "lennard_jones.f90", ierr)
         end if
      end if

      if (allocated(this%A)) then
         deallocate(this%A, stat=ierr)
         if (ierr /= 0) then
            call MW_errors_deallocate_error("void_type", "lennard_jones.f90", ierr)
         end if
      end if

      if (allocated(this%shift)) then
         deallocate(this%shift, stat=ierr)
         if (ierr /= 0) then
            call MW_errors_deallocate_error("void_type", "lennard_jones.f90", ierr)
         end if
      end if

      if (allocated(this%alpha)) then
         deallocate(this%alpha, stat=ierr)
         if (ierr /= 0) then
            call MW_errors_deallocate_error("void_type", "lennard_jones.f90", ierr)
         end if
      end if

      this%num_species = 0
      this%rcut = 0.0_wp
      this%rcutsq = 0.0_wp
   end subroutine void_type

   ! ================================================================================
   ! set rcut value
   subroutine set_rcut(this, rcut)
      implicit none
      type(MW_lennard_jones_t), intent(inout) :: this
      real(wp), intent(in) :: rcut

      this%rcut = rcut
      this%rcutsq = rcut*rcut
   end subroutine set_rcut

   ! ================================================================================
   ! set rcut value
   subroutine set_parameters(this, typeA, typeB, lj_eps, lj_sig)
      use MW_constants, only: kJpermol2hartree, angstrom2bohr
      implicit none
      type(MW_lennard_jones_t), intent(inout) :: this
      integer, intent(in) :: typeA
      integer, intent(in) :: typeB
      real(wp), intent(in) :: lj_eps ! kJ per mol
      real(wp), intent(in) :: lj_sig ! angstrom

      ! Local
      real(wp) :: lj_A, lj_B, lj_epsilon, lj_sigma

      ! Convert lj_eps from kJ/mol to atomic unit
      lj_epsilon = kJpermol2hartree * lj_eps
      ! convert lj_sig from Angstrom to atomic unit
      lj_sigma = angstrom2bohr * lj_sig

      ! Convert (eps,sig) to (A,B)
      lj_A = 4.0_wp * lj_epsilon * lj_sigma**12
      lj_B = 4.0_wp * lj_epsilon * lj_sigma**6

      this%A(typeA,typeB) = lj_A
      this%A(typeB,typeA) = lj_A

      this%B(typeA,typeB) = lj_B
      this%B(typeB,typeA) = lj_B

      this%shift(typeA,typeB) = lj_sigma**6
      this%shift(typeB,typeA) = lj_sigma**6

   end subroutine set_parameters

   ! ================================================================================
   ! set rcut value
   subroutine lorentz_berthelot_mixing_rule(this)
      implicit none
      type(MW_lennard_jones_t), intent(inout) :: this

      ! Local
      integer :: itype, jtype
      real(wp) :: lj_sig1, lj_sig2, lj_eps1, lj_eps2

      do itype = 1, this%num_species
         do jtype = itype+1, this%num_species
            if (this%A(itype,itype)>0 .and. this%A(jtype,jtype)>0) then
               lj_sig1 = this%shift(itype,itype)**(1.0_wp/6.0_wp)
               lj_sig2 = this%shift(jtype,jtype)**(1.0_wp/6.0_wp)
               lj_eps1 = this%B(itype,itype)*this%B(itype,itype) / this%A(itype,itype) / 4.0_wp
               lj_eps2 = this%B(jtype,jtype)*this%B(jtype,jtype) / this%A(jtype,jtype) / 4.0_wp
               this%A(itype,jtype) = 4.0_wp * sqrt(lj_eps1 * lj_eps2) * ((lj_sig1 + lj_sig2)/2.0_wp)**12
               this%A(jtype,itype) = 4.0_wp * sqrt(lj_eps1 * lj_eps2) * ((lj_sig1 + lj_sig2)/2.0_wp)**12
               this%B(itype,jtype) = 4.0_wp * sqrt(lj_eps1 * lj_eps2) * ((lj_sig1 + lj_sig2)/2.0_wp)**6
               this%B(jtype,itype) = 4.0_wp * sqrt(lj_eps1 * lj_eps2) * ((lj_sig1 + lj_sig2)/2.0_wp)**6
               this%shift(itype,jtype) = ((lj_sig1+lj_sig2)/2.0_wp)**6
               this%shift(jtype,itype) = ((lj_sig1+lj_sig2)/2.0_wp)**6
            end if
         end do
      end do

   end subroutine lorentz_berthelot_mixing_rule

   !================================================================================
   ! Print the data structure to ounit
   subroutine print_type(this, species_names, ounit)
      use MW_kinds, only: PARTICLE_NAME_LEN
      implicit none
      type(MW_lennard_jones_t), intent(in) :: this               ! structure to be printed
      character(PARTICLE_NAME_LEN),   intent(in) :: species_names(:)   ! names of the species
      integer,                   intent(in) :: ounit              ! output unit

      integer :: i, j

      write(ounit, '("|lennard-jones| cut-off distance: ",es12.5)') this%rcut
      write(ounit, '("|lennard-jones| ",8x,1x,8x,1x,"     A      ",1x,"     B      ")')

      do j = 1, this%num_species
         do i = j, this%num_species
            write(ounit, '("|lennard-jones| ",a8,1x,a8,1x,es12.5,1x,es12.5)') &
                  species_names(i), species_names(j), this%A(i,j), this%B(i,j)
         end do
      end do

   end subroutine print_type

   ! ==============================================================================
   ! Compute Lennard-Jones forces felt by melt ions
   subroutine melt_forces(num_pbc, localwork, lj, box, ions, xyz_ions, type_ions, &
         electrodes, xyz_elec, force, stress_tensor,  compute_force, soft)
      implicit none

      ! Parameters in
      ! -------------
      integer, intent(in) :: num_pbc                !< Number of periodic boundary conditions
      type(MW_localwork_t), intent(in) :: localwork !< Local work assignment
      type(MW_lennard_jones_t), intent(in) :: lj    !< Lennard-Jones potential parameters
      type(MW_box_t),   intent(in) :: box           !< Simulation box parameters

      type(MW_ion_t), intent(in) :: ions(:)         !< Ions parameters
      real(wp),       intent(in) :: xyz_ions(:,:)   !< Ions xyz positions
      integer,        intent(in) :: type_ions(:)    !< Ion types

      type(MW_electrode_t), intent(inout) :: electrodes(:)  !< electrode parameters
      real(wp),             intent(in) :: xyz_elec(:,:)  !< electrode atoms xyz positions
      logical,              intent(in) :: compute_force !< compute_force on electrodes
      logical,             intent(in) :: soft

      ! Parameters out
      ! --------------
      real(wp), intent(inout) :: force(:,:) !< LJ force on ions
      real(wp), intent(inout) :: stress_tensor(:,:) !< LJ stress

      ! Local
      ! -----
      integer :: ierr, i
      integer :: count, num_elec_types
      select case(num_pbc)
      case(2)
         if (soft) then
            call melt_forces_soft_core_2DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_elec, force, stress_tensor)
         else
            call melt_forces_2DPBC(localwork, lj, box, ions, xyz_ions, type_ions, &
                  electrodes, xyz_elec, force, stress_tensor)
         end if
      case(3)
         if (soft) then
            call melt_forces_soft_core_3DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_elec, force, stress_tensor)
         else
            call melt_forces_3DPBC(localwork, lj, box, ions, xyz_ions, type_ions, &
                  electrodes, xyz_elec, force, stress_tensor)
         end if
      end select
#ifndef MW_SERIAL
      count = size(force,1)*size(force,2)
      call MPI_Allreduce(MPI_IN_PLACE, force, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)

      count = size(stress_tensor,1)*size(stress_tensor,2)      ! this should always be 9
      call MPI_Allreduce(MPI_IN_PLACE, stress_tensor, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)


      if (compute_force) then
         num_elec_types = size(electrodes, 1)
         do i = 1, num_elec_types
            call MPI_Allreduce(MPI_IN_PLACE, electrodes(i)%force_ions(:,7), 3, &
                  MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)
         end do
      end if
#endif
   end subroutine melt_forces

   ! ==============================================================================
   ! Compute tail correction to the stress tensor 
   subroutine stress_tensor_tail_correction(lj, box, ions,tail_correction)
      use MW_constants, only : pi     
      implicit none

      ! Parameters in
      ! -------------
      type(MW_lennard_jones_t), intent(in) :: lj      !< Lennard-Jones potential parameters
      type(MW_box_t),   intent(in) :: box     !< Simulation box parameters

      type(MW_ion_t), intent(in) :: ions(:)        !< ions parameters

      ! Parameters out
      ! --------------
      real(wp), intent(inout) :: tail_correction !< tail correction to the stress tensor

      ! Local
      ! -----
      integer :: itype,jtype,num_ion_types
      integer :: count_n,count_m
      real(wp) :: rcutsq,rcut,A_ij,B_ij

      num_ion_types = size(ions,1)

      rcutsq = lj%rcutsq
      rcut=sqrt(rcutsq)
      tail_correction=0.0_wp
      do itype = 1, num_ion_types
         count_n = ions(itype)%count
!        do jtype =  itype, num_ion_types
         do jtype =  1, num_ion_types
            count_m = ions(jtype)%count
            A_ij = lj%A(itype, jtype)
            B_ij = lj%B(itype, jtype)
            !Analytical LJ 3D correction from Frenkel Smit book,
            tail_correction=tail_correction- &
                    2.0*pi*count_m*count_n/product(box%length(:))*(-4.0*A_ij/(3.0*rcut**9.0)+B_ij*2.0/(rcut**3.0))
         end do
      end do

   end subroutine stress_tensor_tail_correction        

   ! ==============================================================================
   ! Compute Lennard-Jones potential felt by melt ions
   subroutine energy(num_pbc, localwork, lj, box, ions, xyz_ions, &
         electrodes, xyz_atoms, h, soft)
      implicit none

      ! Parameters in
      ! -------------
      integer, intent(in) :: num_pbc !< number of periodic boundary conditions
      type(MW_localwork_t), intent(in) :: localwork !< Local work assignment
      type(MW_lennard_jones_t), intent(in) :: lj      !< Lennard-Jones potential parameters
      type(MW_box_t),   intent(in) :: box     !< Simulation box parameters

      type(MW_ion_t), intent(in) :: ions(:)        !< ions parameters
      real(wp),       intent(in) :: xyz_ions(:,:)  !< ions xyz positions

      type(MW_electrode_t), intent(in) :: electrodes(:)  !< electrode parameters
      real(wp),             intent(in) :: xyz_atoms(:,:)  !< electrode atoms xyz positions

      logical,             intent(in) :: soft

      ! Parameters out
      ! --------------
      real(wp), intent(inout) :: h(:)       !< Potential energy due to L-J interactions

      ! Local
      ! -----
      integer :: ierr, count

      select case(num_pbc)
      case(2)
         if (soft) then
            call energy_soft_core_2DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_atoms, h)
         else
            call energy_2DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_atoms, h)
         end if
      case(3)
         if (soft) then
            call energy_soft_core_3DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_atoms, h)
         else
            call energy_3DPBC(localwork, lj, box, ions, xyz_ions, &
                  electrodes, xyz_atoms, h)
         end if
      end select

#ifndef MW_SERIAL
      count = size(h,1)
      call MPI_Allreduce(MPI_IN_PLACE, h, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)
#endif
   end subroutine energy

   ! ================================================================================
   ! Remove contribution from same molecule particles
   !
   subroutine melt_fix_molecule_forces(num_pbc, localwork, lj, molecules, box, ions, &
         xyz_ions, force, stress_tensor, soft)
      implicit none
      ! Parameters
      ! ----------
      integer, intent(in) :: num_pbc !< number of periodic boundary conditions
      type(MW_localwork_t), intent(in) :: localwork
      type(MW_lennard_jones_t), intent(in) :: lj      !< Lennard-Jones potential parameters
      type(MW_molecule_t), intent(in) :: molecules(:) !< molecules parameters
      type(MW_box_t), intent(in) :: box !< box parameters
      type(MW_ion_t), intent(in) :: ions(:) !< ions parameters
      real(wp), intent(in) :: xyz_ions(:,:) !< melt particles coordinates
      real(wp), intent(inout) :: force(:,:) !< force on melt particles
      real(wp), intent(inout) :: stress_tensor(:,:) !< stress tensor contribution
      logical,             intent(in) :: soft

      ! Local
      ! -----
      integer :: ierr
      integer :: count
      select case(num_pbc)
      case(2)
         if (soft) then
            call melt_fix_molecule_forces_soft_core_2DPBC(localwork, lj, molecules, box, ions, &
                  xyz_ions, force, stress_tensor)
         else
            call melt_fix_molecule_forces_2DPBC(localwork, lj, molecules, box, ions, &
                  xyz_ions, force, stress_tensor)
         end if
      case(3)
         if (soft) then
            call melt_fix_molecule_forces_soft_core_3DPBC(localwork, lj, molecules, box, ions, &
                  xyz_ions, force, stress_tensor)
         else
            call melt_fix_molecule_forces_3DPBC(localwork, lj, molecules, box, ions, &
                  xyz_ions, force, stress_tensor)
         end if
      end select
#ifndef MW_SERIAL
      count = size(force,1)*size(force,2)
      call MPI_Allreduce(MPI_IN_PLACE, force, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)

      count = size(stress_tensor,1)*size(stress_tensor,2)      ! this should always be 9
      call MPI_Allreduce(MPI_IN_PLACE, stress_tensor, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)
#endif
   end subroutine melt_fix_molecule_forces

   ! ================================================================================
   ! Remove contribution from same molecule particles
   !
   subroutine fix_molecule_energy(num_pbc, localwork, lj, molecules, box, ions, &
         xyz_ions, h, soft)
      implicit none
      ! Parameters
      ! ----------
      integer, intent(in) :: num_pbc !< number of periodic boundary conditions
      type(MW_localwork_t), intent(in) :: localwork
      type(MW_lennard_jones_t), intent(in) :: lj      !< Lennard-Jones potential parameters
      type(MW_molecule_t), intent(in) :: molecules(:) !< molecules parameters
      type(MW_box_t), intent(in) :: box !< box parameters
      type(MW_ion_t), intent(in) :: ions(:) !< melt particle parameters
      real(wp), intent(in) :: xyz_ions(:,:) !< melt particles coordinates
      real(wp), intent(inout) :: h(:) !< potential on melt particles
      logical,             intent(in) :: soft

      ! Local
      ! -----
      integer :: ierr, count

      select case(num_pbc)
      case(2)
         if (soft) then
            call fix_molecule_energy_soft_core_2DPBC(localwork, lj, molecules, box, ions, &
               xyz_ions, h)
         else
            call fix_molecule_energy_2DPBC(localwork, lj, molecules, box, ions, &
               xyz_ions, h)
         end if
      case(3)
         if (soft) then
            call fix_molecule_energy_soft_core_3DPBC(localwork, lj, molecules, box, ions, &
               xyz_ions, h)
         else
            call fix_molecule_energy_3DPBC(localwork, lj, molecules, box, ions, &
               xyz_ions, h)
         end if
      end select

#ifndef MW_SERIAL
      count = size(h,1)
      call MPI_Allreduce(MPI_IN_PLACE, h, count, MPI_DOUBLE_PRECISION, MPI_SUM, MW_COMM_WORLD, ierr)
#endif
   end subroutine fix_molecule_energy

   ! ================================================================================
   ! Function to compute force coeffcient between 2 particles
   !
   ! lj_ij = (dV(r_ij) / dr_ij) * (1/ r_ij)
   function force_ij(drnorm2, A_ij, B_ij) result(lj_ij)
      implicit none
      ! Passed in
      ! ---------
      real(wp), intent(in) :: drnorm2
      real(wp), intent(in) :: A_ij
      real(wp), intent(in) :: B_ij

      ! Result
      ! ------
      real(wp) :: lj_ij

      ! Local
      ! -----

      real(wp) :: drnorm2rec, drnorm6rec, drnorm8rec

      drnorm2rec = 1.0_wp / drnorm2
      drnorm6rec = drnorm2rec * drnorm2rec * drnorm2rec
      drnorm8rec = drnorm2rec * drnorm6rec
      lj_ij = (-12.0_wp*A_ij*drnorm6rec + 6.0_wp*B_ij)*drnorm8rec
   end function force_ij

   ! ================================================================================
   ! Function to compute the potential felt between 2 particles
   !
   ! lj_ij = V(r_ij) - V(r_cut)
   function potential_ij(drnorm2, A_ij, B_ij) result(lj_ij)
      implicit none
      ! Passed in
      ! ---------
      real(wp), intent(in) :: drnorm2
      real(wp), intent(in) :: A_ij
      real(wp), intent(in) :: B_ij

      ! Result
      ! ------
      real(wp) :: lj_ij

      ! Local
      ! -----
      real(wp) :: drnorm2rec, drnorm6rec, drnorm12rec

      drnorm2rec = 1.0_wp / drnorm2
      drnorm6rec = drnorm2rec * drnorm2rec * drnorm2rec
      drnorm12rec = drnorm6rec * drnorm6rec

      lj_ij = A_ij * drnorm12rec - B_ij * drnorm6rec
   end function potential_ij

   ! ================================================================================
   include 'lennard_jones_2DPBC.inc'
   include 'lennard_jones_3DPBC.inc'
   include 'lennard_jones_soft_core_2DPBC.inc'
   include 'lennard_jones_soft_core_3DPBC.inc'
   ! ================================================================================
   include 'minimum_image_displacement_2DPBC.inc'
   include 'minimum_image_displacement_3DPBC.inc'
   include 'minimum_image_distance_2DPBC.inc'
   include 'minimum_image_distance_3DPBC.inc'
   ! ================================================================================
   include 'update_diag_block_boundaries.inc'
   include 'update_tri_block_boundaries.inc'
   include 'update_other_block_boundaries.inc'

end module MW_lennard_jones
