
   ! ================================================================================
   
   subroutine compute_fourth_site_position_@PBC@(molecules, xyz_ions, box, ions)
      use MW_molecule, only: MW_molecule_t
      use MW_ion, only: MW_ion_t
      use MW_box, only: MW_box_t

      implicit none

      ! Passed in/out
      real(wp), intent(inout) :: xyz_ions(:,:)  !< ions xyz positions

      ! Passed in
      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

      ! Local
      integer :: num_molecule_types
      integer :: mol_type, imol, num_mol
      integer :: Oion, Oion_type, Oion_type_offset
      integer :: H1ion, H1ion_type, H1ion_type_offset
      integer :: H2ion, H2ion_type, H2ion_type_offset
      integer :: Mion, Mion_type, Mion_type_offset
      real(wp) :: a, b, c, OMdist
      real(wp) :: dx1, dy1, dz1, drnorm2_1, dx, dy, dz
      real(wp) :: dx2, dy2, dz2, drnorm2_2, dnorm2, factor

      a = box%length(1)
      b = box%length(2)
      c = box%length(3)

      num_molecule_types = size(molecules,1)
      do mol_type = 1, num_molecule_types
         if (molecules(mol_type)%fourth_site) then
            num_mol = molecules(mol_type)%n

            Oion_type = molecules(mol_type)%sites(1)
            H1ion_type = molecules(mol_type)%sites(2)
            H2ion_type = molecules(mol_type)%sites(3)
            Mion_type = molecules(mol_type)%sites(4)
          
            Oion_type_offset = ions(Oion_type)%offset
            H1ion_type_offset = ions(H1ion_type)%offset
            H2ion_type_offset = ions(H2ion_type)%offset
            Mion_type_offset = ions(Mion_type)%offset
          
            OMdist = molecules(mol_type)%fourth_distance
          
            do imol = 1, num_mol
               Oion = imol + Oion_type_offset
               H1ion = imol + H1ion_type_offset
               H2ion = imol + H2ion_type_offset
               Mion = imol + Mion_type_offset

               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(Oion,1), xyz_ions(Oion,2), xyz_ions(Oion,3), &
                     xyz_ions(H1ion,1), xyz_ions(H1ion,2), xyz_ions(H1ion,3), &
                     dx1, dy1, dz1, drnorm2_1)

               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(Oion,1), xyz_ions(Oion,2), xyz_ions(Oion,3), &
                     xyz_ions(H2ion,1), xyz_ions(H2ion,2), xyz_ions(H2ion,3), &
                     dx2, dy2, dz2, drnorm2_2)

               dx = (dx1 + dx2)
               dy = (dy1 + dy2)
               dz = (dz1 + dz2)
               dnorm2 = dx*dx + dy*dy + dz*dz
               factor = OMdist / sqrt(dnorm2) !< if rigid could be precomputed

               xyz_ions(Mion,1) = xyz_ions(Oion,1) + factor * dx
               xyz_ions(Mion,2) = xyz_ions(Oion,2) + factor * dy
               xyz_ions(Mion,3) = xyz_ions(Oion,3) + factor * dz
            end do
         end if
      end do

   end subroutine compute_fourth_site_position_@PBC@
   ! ================================================================================
   
   subroutine redistribute_force_@PBC@(localwork, molecules, xyz_ions, forces_ions, box,&
         ions, force_to_distribute, stress_to_distribute)
      use MW_localwork, only: MW_localwork_t
      use MW_molecule, only: MW_molecule_t
      use MW_ion, only: MW_ion_t
      use MW_box, only: MW_box_t

      implicit none

      ! Passed in/out
      real(wp), intent(inout) :: force_to_distribute(:,:)  !< ions forces to redistribute
      real(wp), intent(inout) :: stress_to_distribute(:,:)  !< ions forces to redistribute

      ! Passed in
      real(wp), intent(in) :: xyz_ions(:,:)  !< ions xyz positions
      real(wp), intent(in) :: forces_ions(:,:)  !< ions forces
      type(MW_localwork_t), intent(in) :: localwork !< Local work assignment
      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

      ! Local
      integer :: num_molecule_types
      integer :: mol_type, imol, num_mol
      integer :: Oion, Oion_type, Oion_type_offset
      integer :: H1ion, H1ion_type, H1ion_type_offset
      integer :: H2ion, H2ion_type, H2ion_type_offset
      integer :: Mion, Mion_type, Mion_type_offset
      real(wp) :: a, b, c, OMdist, alpha, gamm
      real(wp) :: dx1, dy1, dz1, drnorm2_1, dx, dy, dz
      real(wp) :: dx2, dy2, dz2, drnorm2_2, dnorm2
      real(wp) :: dxOM, dyOM, dzOM, drnorm2_OM, fxM, fyM, fzm, fx1, fy1, fz1, rOM_x_fM
      real(wp) :: dxH1M, dyH1M, dzH1M, drnorm2_H1M, dxH2M, dyH2M, dzH2M, drnorm2_H2M

      a = box%length(1)
      b = box%length(2)
      c = box%length(3)

      num_molecule_types = size(molecules,1)
      do mol_type = 1, num_molecule_types
         if (molecules(mol_type)%fourth_site) then
            num_mol = molecules(mol_type)%n

            Oion_type = molecules(mol_type)%sites(1)
            H1ion_type = molecules(mol_type)%sites(2)
            H2ion_type = molecules(mol_type)%sites(3)
            Mion_type = molecules(mol_type)%sites(4)
          
            Oion_type_offset = ions(Oion_type)%offset
            H1ion_type_offset = ions(H1ion_type)%offset
            H2ion_type_offset = ions(H2ion_type)%offset
            Mion_type_offset = ions(Mion_type)%offset
          
            OMdist = molecules(mol_type)%fourth_distance
          
            alpha = molecules(mol_type)%alpha
          
            do imol = localwork%molecules_istart(mol_type), localwork%molecules_iend(mol_type)
            !do imol = 1, num_mol
               Oion = imol + Oion_type_offset
               H1ion = imol + H1ion_type_offset
               H2ion = imol + H2ion_type_offset
               Mion = imol + Mion_type_offset

               ! compute gamma
               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(Oion,1), xyz_ions(Oion,2), xyz_ions(Oion,3), &
                     xyz_ions(H1ion,1), xyz_ions(H1ion,2), xyz_ions(H1ion,3), &
                     dx1, dy1, dz1, drnorm2_1)

               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(H1ion,1), xyz_ions(H1ion,2), xyz_ions(H1ion,3), &
                     xyz_ions(H2ion,1), xyz_ions(H2ion,2), xyz_ions(H2ion,3), &
                     dx2, dy2, dz2, drnorm2_2)

               dx = (dx1 + alpha*dx2)
               dy = (dy1 + alpha*dy2)
               dz = (dz1 + alpha*dz2)
               dnorm2 = dx*dx + dy*dy + dz*dz
               gamm = OMdist / sqrt(dnorm2)  !< it is usually fixed... precompute it?

               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(Oion,1), xyz_ions(Oion,2), xyz_ions(Oion,3), &
                     xyz_ions(Mion,1), xyz_ions(Mion,2), xyz_ions(Mion,3), &
                     dxOM, dyOM, dzOM, drnorm2_OM)

               fxM = forces_ions(Mion,1)
               fyM = forces_ions(Mion,2)
               fzM = forces_ions(Mion,3)

               force_to_distribute(Mion,1) = -fxM
               force_to_distribute(Mion,2) = -fyM
               force_to_distribute(Mion,3) = -fzM

               rOM_x_fM = dxOM*fxM + dyOM*fyM + dzOM*fzM
               fx1 = rOM_x_fM / drnorm2_OM * dxOM
               fy1 = rOM_x_fM / drnorm2_OM * dyOM
               fz1 = rOM_x_fM / drnorm2_OM * dzOM

               force_to_distribute(Oion,1) = fxM - gamm*(fxm-fx1)
               force_to_distribute(Oion,2) = fyM - gamm*(fym-fy1)
               force_to_distribute(Oion,3) = fzM - gamm*(fzm-fz1)

               force_to_distribute(H1ion,1) = (1-alpha)*gamm*(fxm-fx1)
               force_to_distribute(H1ion,2) = (1-alpha)*gamm*(fym-fy1)
               force_to_distribute(H1ion,3) = (1-alpha)*gamm*(fzm-fz1)

               force_to_distribute(H2ion,1) = alpha*gamm*(fxm-fx1)
               force_to_distribute(H2ion,2) = alpha*gamm*(fym-fy1)
               force_to_distribute(H2ion,3) = alpha*gamm*(fzm-fz1)

!               ! Redistribute stress_tensor using the virial sum(fi*ri): -vM + vO + vH1 + vH2
!               stress_to_distribute(1,1) = stress_to_distribute(1,1) - xyz_ions(Mion,1)*fxM
!               stress_to_distribute(2,2) = stress_to_distribute(2,2) - xyz_ions(Mion,2)*fyM
!               stress_to_distribute(3,3) = stress_to_distribute(3,3) - xyz_ions(Mion,3)*fzM
!               stress_to_distribute(1,2) = stress_to_distribute(1,2) - xyz_ions(Mion,1)*fyM
!               stress_to_distribute(1,3) = stress_to_distribute(1,3) - xyz_ions(Mion,1)*fzM
!               stress_to_distribute(2,3) = stress_to_distribute(2,3) - xyz_ions(Mion,2)*fzM
!
!               stress_to_distribute(1,1) = stress_to_distribute(1,1) + xyz_ions(Oion,1)*force_to_distribute(Oion,1) &
!                     + xyz_ions(H1ion,1)*force_to_distribute(H1ion,1) + xyz_ions(H2ion,1)*force_to_distribute(H2ion,1)
!               stress_to_distribute(2,2) = stress_to_distribute(2,2) + xyz_ions(Oion,2)*force_to_distribute(Oion,2) &
!                     + xyz_ions(H1ion,2)*force_to_distribute(H1ion,2) + xyz_ions(H2ion,2)*force_to_distribute(H2ion,2)
!               stress_to_distribute(3,3) = stress_to_distribute(3,3) + xyz_ions(Oion,3)*force_to_distribute(Oion,3) &
!                     + xyz_ions(H1ion,3)*force_to_distribute(H1ion,3) + xyz_ions(H2ion,3)*force_to_distribute(H2ion,3)
!               stress_to_distribute(1,2) = stress_to_distribute(1,2) + xyz_ions(Oion,1)*force_to_distribute(Oion,2) &
!                     + xyz_ions(H1ion,1)*force_to_distribute(H1ion,2) + xyz_ions(H2ion,1)*force_to_distribute(H2ion,2)
!               stress_to_distribute(1,3) = stress_to_distribute(1,3) + xyz_ions(Oion,1)*force_to_distribute(Oion,3) &
!                     + xyz_ions(H1ion,1)*force_to_distribute(H1ion,3) + xyz_ions(H2ion,1)*force_to_distribute(H2ion,3)
!               stress_to_distribute(2,3) = stress_to_distribute(2,3) + xyz_ions(Oion,2)*force_to_distribute(Oion,3) &
!                     + xyz_ions(H1ion,2)*force_to_distribute(H1ion,3) + xyz_ions(H2ion,2)*force_to_distribute(H2ion,3)
!
!
               ! Redistribute stress_tensor using 'pair-wise' technique to reset the force in O
               ! Minimum displacement M-H1
               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(H1ion,1), xyz_ions(H1ion,2), xyz_ions(H1ion,3),  &
                     xyz_ions(Mion,1),  xyz_ions(Mion,2),  xyz_ions(Mion,3), &
                     dxH1M, dyH1M, dzH1M, drnorm2_H1M)
               ! Minimum displacements M-H2
               call minimum_image_displacement_@PBC@(a, b, c, &
                     xyz_ions(H2ion,1), xyz_ions(H2ion,2), xyz_ions(H2ion,3),  &
                     xyz_ions(Mion,1),  xyz_ions(Mion,2),  xyz_ions(Mion,3), &
                     dxH2M, dyH2M, dzH2M, drnorm2_H2M)
               stress_to_distribute(1,1) = stress_to_distribute(1,1) - dxOM*force_to_distribute(Oion,1) &
                     - dxH1M*force_to_distribute(H1ion,1) - dxH2M*force_to_distribute(H2ion,1)
               stress_to_distribute(2,2) = stress_to_distribute(2,2) - dyOM*force_to_distribute(Oion,2) &
                     - dyH1M*force_to_distribute(H1ion,2) - dyH2M*force_to_distribute(H2ion,2)
               stress_to_distribute(3,3) = stress_to_distribute(3,3) - dzOM*force_to_distribute(Oion,3) &
                     - dzH1M*force_to_distribute(H1ion,3) - dzH2M*force_to_distribute(H2ion,3)
               stress_to_distribute(1,2) = stress_to_distribute(1,2) - dxOM*force_to_distribute(Oion,2) &
                     - dxH1M*force_to_distribute(H1ion,2) - dxH2M*force_to_distribute(H2ion,2)
               stress_to_distribute(1,3) = stress_to_distribute(1,3) - dxOM*force_to_distribute(Oion,3) &
                     - dxH1M*force_to_distribute(H1ion,3) - dxH2M*force_to_distribute(H2ion,3)
               stress_to_distribute(2,3) = stress_to_distribute(2,3) - dyOM*force_to_distribute(Oion,3) &
                     - dyH1M*force_to_distribute(H1ion,3) - dyH2M*force_to_distribute(H2ion,3)

            end do
         end if
      end do

   end subroutine redistribute_force_@PBC@
