!--------------------------------------------------------------------------------------------------!
!   CP2K: A general program to perform molecular dynamics simulations                              !
!   Copyright (C) 2000 - 2018  CP2K developers group                                               !
!--------------------------------------------------------------------------------------------------!

! **************************************************************************************************
!> \brief Initialize the collective variables types
!> \par History
!>      5.2004 created [fawzi and alessandro]
!>      1.2009 Fabio Sterpone : added the population COLVAR
!> \author Teodoro Laino
! **************************************************************************************************
MODULE colvar_types

   USE input_section_types,             ONLY: section_vals_type
   USE kinds,                           ONLY: default_path_length,&
                                              default_string_length,&
                                              dp
   USE particle_types,                  ONLY: particle_type
#include "../base/base_uses.f90"

   IMPLICIT NONE

   PRIVATE

   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'colvar_types'

   INTEGER, PARAMETER, PUBLIC               :: plane_def_atoms = 0, &
                                               plane_def_vec = 1

   INTEGER, PARAMETER, PUBLIC               :: do_clv_geo_center = 0, &
                                               do_clv_fix_point = 1, &
                                               do_clv_xyz = 0, &
                                               do_clv_x = 1, &
                                               do_clv_y = 2, &
                                               do_clv_z = 3, &
                                               do_clv_xy = 4, &
                                               do_clv_xz = 5, &
                                               do_clv_yz = 6
   PUBLIC :: colvar_type, &
             colvar_p_type, &
             colvar_p_reallocate, &
             colvar_p_release, &
             colvar_create, &
             colvar_clone, &
             colvar_setup, &
             colvar_release, &
             colvar_counters, &
             eval_point_der, &
             eval_point_pos, &
             eval_point_mass, &
             diff_colvar

   INTEGER, PARAMETER, PUBLIC :: no_colvar_id = -2, &
                                 dist_colvar_id = 1, &
                                 coord_colvar_id = 2, &
                                 torsion_colvar_id = 3, &
                                 angle_colvar_id = 4, &
                                 plane_distance_colvar_id = 5, &
                                 rotation_colvar_id = 6, &
                                 dfunct_colvar_id = 7, &
                                 qparm_colvar_id = 8, &
                                 hydronium_shell_colvar_id = 9, &
                                 reaction_path_colvar_id = 10, &
                                 combine_colvar_id = 11, &
                                 population_colvar_id = 12, &
                                 plane_plane_angle_colvar_id = 13, &
                                 gyration_colvar_id = 14, &
                                 rmsd_colvar_id = 15, &
                                 distance_from_path_colvar_id = 16, &
                                 xyz_diag_colvar_id = 17, &
                                 xyz_outerdiag_colvar_id = 18, &
                                 u_colvar_id = 19, &
                                 Wc_colvar_id = 20, &
                                 hbp_colvar_id = 21, &
                                 ring_puckering_colvar_id = 22, &
                                 mindist_colvar_id = 23, &
                                 acid_hyd_dist_colvar_id = 24, &
                                 acid_hyd_shell_colvar_id = 25, &
                                 hydronium_dist_colvar_id = 26

! **************************************************************************************************
!> \brief parameters for the distance collective variable
!> \param i_at ,j_at: indexes of the two atoms between which you calculate
!>        the distance
!> \author alessandro laio and fawzi mohamed
! **************************************************************************************************
   TYPE dist_colvar_type
      INTEGER       :: i_at, j_at, axis_id
   END TYPE dist_colvar_type

! **************************************************************************************************
   TYPE coord_colvar_type
      LOGICAL                    :: do_chain, use_kinds_from, use_kinds_to, &
                                    use_kinds_to_b
      INTEGER                         :: n_atoms_to, &
                                         n_atoms_from, &
                                         nncrd, &
                                         ndcrd, &
                                         n_atoms_to_b, &
                                         nncrd_b, &
                                         ndcrd_b
      INTEGER, POINTER, DIMENSION(:) :: i_at_from, &
                                        i_at_to, &
                                        i_at_to_b
      CHARACTER(LEN=default_string_length), DIMENSION(:), POINTER :: c_kinds_from, &
                                                                     c_kinds_to, &
                                                                     c_kinds_to_b
      REAL(KIND=dp)                   :: r_0, r_0_b
   END TYPE coord_colvar_type

! **************************************************************************************************
   TYPE population_colvar_type
      LOGICAL                         :: use_kinds_from, use_kinds_to
      INTEGER                         :: n_atoms_to, &
                                         n_atoms_from, &
                                         nncrd, &
                                         ndcrd, &
                                         n0
      INTEGER, POINTER, DIMENSION(:) :: i_at_from, &
                                        i_at_to
      CHARACTER(LEN=default_string_length), DIMENSION(:), POINTER :: c_kinds_from, &
                                                                     c_kinds_to
      REAL(KIND=dp)                   :: r_0, sigma
   END TYPE population_colvar_type

! **************************************************************************************************
   TYPE gyration_colvar_type
      LOGICAL                         :: use_kinds
      INTEGER                         :: n_atoms
      INTEGER, POINTER, DIMENSION(:) :: i_at
      CHARACTER(LEN=default_string_length), DIMENSION(:), POINTER :: c_kinds
   END TYPE gyration_colvar_type

! **************************************************************************************************
   TYPE torsion_colvar_type
      REAL(KIND=dp)                   :: o0
      INTEGER, DIMENSION(4)          :: i_at_tors
   END TYPE torsion_colvar_type

! **************************************************************************************************
   TYPE plane_distance_colvar_type
      LOGICAL               :: use_pbc
      INTEGER, DIMENSION(3) :: plane
      INTEGER               :: point
   END TYPE plane_distance_colvar_type

! **************************************************************************************************
   TYPE plane_def_type
      INTEGER                     :: type_of_def
      INTEGER, DIMENSION(3)       :: points
      REAL(KIND=dp), DIMENSION(3) :: normal_vec
   END TYPE plane_def_type

   TYPE plane_plane_angle_colvar_type
      TYPE(plane_def_type)        :: plane1, plane2
   END TYPE plane_plane_angle_colvar_type

! **************************************************************************************************
   TYPE angle_colvar_type
      INTEGER, DIMENSION(3) :: i_at_angle
   END TYPE angle_colvar_type

! **************************************************************************************************
   TYPE rotation_colvar_type
      INTEGER :: i_at1_bond1, &
                 i_at2_bond1, &
                 i_at1_bond2, &
                 i_at2_bond2
   END TYPE rotation_colvar_type

! **************************************************************************************************
   TYPE dfunct_colvar_type
      INTEGER, DIMENSION(4)         :: i_at_dfunct
      LOGICAL                       :: use_pbc
      REAL(KIND=dp)                 :: coeff
   END TYPE dfunct_colvar_type

! **************************************************************************************************
   TYPE qparm_colvar_type
      INTEGER                         :: l
      INTEGER                         :: n_atoms_to, &
                                         n_atoms_from
      INTEGER, POINTER, DIMENSION(:) :: i_at_from, &
                                        i_at_to
      REAL(KIND=dp)                   :: rcut, rstart
      LOGICAL                         :: include_images
   END TYPE qparm_colvar_type

! **************************************************************************************************
   TYPE hydronium_shell_colvar_type
      INTEGER                         :: n_oxygens, &
                                         n_hydrogens, &
                                         poh, qoh, poo, qoo, &
                                         pm, qm
      INTEGER, POINTER, DIMENSION(:)  :: i_oxygens, &
                                         i_hydrogens
      REAL(KIND=dp)                   :: roo, roh, lambda, nh
   END TYPE hydronium_shell_colvar_type

! **************************************************************************************************
   TYPE hydronium_dist_colvar_type
      INTEGER                         :: n_oxygens, &
                                         n_hydrogens, &
                                         poh, qoh, &
                                         pf, qf, pm, qm
      INTEGER, POINTER, DIMENSION(:)  :: i_oxygens, &
                                         i_hydrogens
      REAL(KIND=dp)                   :: roh, lambda, nh, nn
   END TYPE hydronium_dist_colvar_type

! **************************************************************************************************
   TYPE acid_hyd_dist_colvar_type
      INTEGER                         :: n_oxygens_water, &
                                         n_oxygens_acid, &
                                         n_hydrogens, &
                                         pwoh, qwoh, paoh, qaoh, pcut, qcut
      INTEGER, POINTER, DIMENSION(:)  :: i_oxygens_water, i_oxygens_acid, &
                                         i_hydrogens
      REAL(KIND=dp)                   :: rwoh, raoh, lambda, nc
   END TYPE acid_hyd_dist_colvar_type

! **************************************************************************************************
   TYPE acid_hyd_shell_colvar_type
      INTEGER                         :: n_oxygens_water, &
                                         n_oxygens_acid, &
                                         n_hydrogens, &
                                         pwoh, qwoh, paoh, qaoh, &
                                         poo, qoo, pcut, qcut, pm, qm
      INTEGER, POINTER, DIMENSION(:)  :: i_oxygens_water, i_oxygens_acid, &
                                         i_hydrogens
      REAL(KIND=dp)                   :: rwoh, raoh, roo, lambda, nc, nh
   END TYPE acid_hyd_shell_colvar_type

! **************************************************************************************************
   TYPE reaction_path_colvar_type
      INTEGER                                  :: type_id
      INTEGER                                  :: n_components, nr_frames, subset
      INTEGER, DIMENSION(2)                     :: function_bounds
      INTEGER, POINTER, DIMENSION(:)          :: i_rmsd
      LOGICAL                                  :: align_frames, dist_rmsd, rmsd
      REAL(KIND=dp), DIMENSION(:, :), POINTER  :: f_vals
      REAL(KIND=dp), DIMENSION(:, :), POINTER   :: r_ref
      REAL(KIND=dp)                            :: lambda
      REAL(KIND=dp)                            :: step_size
      TYPE(colvar_p_type), POINTER, DIMENSION(:) :: colvar_p
   END TYPE reaction_path_colvar_type

! **************************************************************************************************
   TYPE combine_colvar_type
      INTEGER                                  :: type_id
      TYPE(colvar_p_type), POINTER, DIMENSION(:) :: colvar_p
      REAL(KIND=dp)                            :: lerr, dx
      CHARACTER(LEN=default_path_length)       :: FUNCTION
      CHARACTER(LEN=default_string_length), &
         DIMENSION(:), POINTER               :: c_parameters, variables
      REAL(KIND=dp), DIMENSION(:), POINTER     :: v_parameters
   END TYPE combine_colvar_type
! **************************************************************************************************
   TYPE rmsd_colvar_type
      INTEGER                                  :: n_atoms, nr_frames, subset
      INTEGER, POINTER, DIMENSION(:)          :: i_rmsd
      LOGICAL                                  :: align_frames
      REAL(KIND=dp), DIMENSION(:), POINTER     :: weights
      REAL(KIND=dp), DIMENSION(:, :), POINTER   :: r_ref
   END TYPE rmsd_colvar_type

! **************************************************************************************************
   TYPE point_type
      INTEGER :: type_id
      INTEGER, DIMENSION(:), POINTER          :: atoms
      REAL(KIND=dp), DIMENSION(:), POINTER    :: weights
      REAL(KIND=dp), DIMENSION(3)              :: r
   END TYPE point_type

! **************************************************************************************************
   TYPE xyz_diag_colvar_type
      LOGICAL                                  :: use_pbc
      LOGICAL                                  :: use_absolute_position
      INTEGER                                  :: i_atom
      INTEGER                                  :: component
      REAL(KIND=dp), DIMENSION(3)              :: r0
   END TYPE xyz_diag_colvar_type

! **************************************************************************************************
   TYPE xyz_outerdiag_colvar_type
      LOGICAL                                  :: use_pbc
      INTEGER, DIMENSION(2)                    :: i_atoms
      INTEGER, DIMENSION(2)                    :: components
      REAL(KIND=dp), DIMENSION(3, 2)            :: r0
   END TYPE xyz_outerdiag_colvar_type

! **************************************************************************************************
   TYPE u_colvar_type
      TYPE(section_vals_type), POINTER         :: mixed_energy_section
      INTEGER       :: natom
   END TYPE u_colvar_type

! **************************************************************************************************
   TYPE Wc_colvar_type
      INTEGER                         :: ids(3) ! first is the Od, second the H, third the Oa
      REAL(KIND=dp)                   :: ewc
      REAL(KIND=dp)                   :: rcut
   END TYPE Wc_colvar_type

! **************************************************************************************************
   TYPE HBP_colvar_type
      INTEGER                         :: nPoints ! number of the points in the path
      INTEGER, POINTER                :: ids(:, :) ! first is the Od, second the H,
      ! third the Oa and contains a row for each intermediate point in the path
      REAL(KIND=dp), POINTER           :: ewc(:) ! one for each point in the path
      REAL(KIND=dp)                   :: rcut
      REAL(KIND=dp)                   :: shift ! shift applied for each term in the collective variable
   END TYPE HBP_colvar_type

! **************************************************************************************************
   TYPE ring_puckering_colvar_type
      INTEGER                         :: nring
      INTEGER, POINTER, DIMENSION(:) :: atoms
      INTEGER                         :: iq
   END TYPE ring_puckering_colvar_type

! **************************************************************************************************
   TYPE mindist_colvar_type
      LOGICAL                    :: use_kinds_from, use_kinds_to
      INTEGER                         :: n_coord_to, &
                                         n_coord_from, &
                                         n_dist_from, &
                                         p_exp, &
                                         q_exp
      INTEGER, POINTER, DIMENSION(:) :: i_coord_from, &
                                        i_coord_to, &
                                        i_dist_from
      CHARACTER(LEN=default_string_length), DIMENSION(:), POINTER :: k_coord_from, &
                                                                     k_coord_to
      REAL(KIND=dp)                   :: lambda, r_cut
   END TYPE mindist_colvar_type

! **************************************************************************************************
!> \brief parameters for a collective variable
!> \author alessandro laio and fawzi mohamed
! **************************************************************************************************
   TYPE colvar_type
      INTEGER                                     :: type_id
      LOGICAL                                     :: use_points
      REAL(kind=dp)                               :: ss ! Value of the colvar
      REAL(kind=dp), DIMENSION(:, :), POINTER     :: dsdr ! Derivative of colvar (3,:)
      INTEGER, DIMENSION(:), POINTER              :: i_atom ! Mapping of dsdr
      INTEGER                                     :: n_atom_s
      ! Available COLVAR types
      TYPE(dist_colvar_type), POINTER              :: dist_param
      TYPE(coord_colvar_type), POINTER             :: coord_param
      TYPE(population_colvar_type), POINTER        :: population_param
      TYPE(gyration_colvar_type), POINTER          :: gyration_param
      TYPE(torsion_colvar_type), POINTER           :: torsion_param
      TYPE(angle_colvar_type), POINTER             :: angle_param
      TYPE(plane_distance_colvar_type), POINTER    :: plane_distance_param
      TYPE(plane_plane_angle_colvar_type), POINTER :: plane_plane_angle_param
      TYPE(rotation_colvar_type), POINTER          :: rotation_param
      TYPE(dfunct_colvar_type), POINTER            :: dfunct_param
      TYPE(qparm_colvar_type), POINTER             :: qparm_param
      TYPE(hydronium_shell_colvar_type), POINTER   :: hydronium_shell_param
      TYPE(hydronium_dist_colvar_type), POINTER    :: hydronium_dist_param
      TYPE(acid_hyd_dist_colvar_type), POINTER     :: acid_hyd_dist_param
      TYPE(acid_hyd_shell_colvar_type), POINTER    :: acid_hyd_shell_param
      TYPE(reaction_path_colvar_type), POINTER     :: reaction_path_param
      TYPE(combine_colvar_type), POINTER           :: combine_cvs_param
      TYPE(rmsd_colvar_type), POINTER              :: rmsd_param
      TYPE(xyz_diag_colvar_type), POINTER          :: xyz_diag_param
      TYPE(xyz_outerdiag_colvar_type), POINTER     :: xyz_outerdiag_param
      TYPE(u_colvar_type), POINTER                 :: u_param
      TYPE(point_type), DIMENSION(:), POINTER      :: points
      TYPE(Wc_colvar_type), POINTER                :: Wc
      TYPE(HBP_colvar_type), POINTER               :: HBP
      TYPE(ring_puckering_colvar_type), POINTER    :: ring_puckering_param
      TYPE(mindist_colvar_type), POINTER           :: mindist_param
   END TYPE colvar_type

! **************************************************************************************************
   TYPE colvar_p_type
      TYPE(colvar_type), POINTER :: colvar
   END TYPE colvar_p_type

! **************************************************************************************************
   TYPE colvar_counters
      INTEGER :: ndist
      INTEGER :: nangle
      INTEGER :: ntorsion
      INTEGER :: ncoord
      INTEGER :: nplane_dist
      INTEGER :: nplane_angle
      INTEGER :: nrot
      INTEGER :: ndfunct
      INTEGER :: nqparm
      INTEGER :: nhydronium_shell
      INTEGER :: nhydronium_dist
      INTEGER :: nacid_hyd_dist
      INTEGER :: nacid_hyd_shell
      INTEGER :: nreactionpath
      INTEGER :: ncombinecvs
      INTEGER :: nrestraint
      INTEGER :: npopulation
      INTEGER :: ngyration
      INTEGER :: nrmsd
      INTEGER :: nxyz_diag
      INTEGER :: nxyz_outerdiag
      INTEGER :: ntot
      INTEGER :: nWc
      INTEGER :: nHBP
      INTEGER :: nring_puckering
   END TYPE colvar_counters

CONTAINS

! **************************************************************************************************
!> \brief initializes a colvar_param type
!> \param colvar the colvat to initialize
!> \param colvar_id ...
!> \author alessandro laio and fawzi mohamed
! **************************************************************************************************
   SUBROUTINE colvar_create(colvar, colvar_id)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(in)                                :: colvar_id

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_create', routineP = moduleN//':'//routineN

      CPASSERT(.NOT. ASSOCIATED(colvar))
      ALLOCATE (colvar)
      ! Nullify all available COLVAR types
      NULLIFY (colvar%dist_param)
      NULLIFY (colvar%angle_param)
      NULLIFY (colvar%torsion_param)
      NULLIFY (colvar%plane_distance_param)
      NULLIFY (colvar%plane_plane_angle_param)
      NULLIFY (colvar%rotation_param)
      NULLIFY (colvar%dfunct_param)
      NULLIFY (colvar%coord_param)
      NULLIFY (colvar%population_param)
      NULLIFY (colvar%gyration_param)
      NULLIFY (colvar%qparm_param)
      NULLIFY (colvar%xyz_diag_param)
      NULLIFY (colvar%xyz_outerdiag_param)
      NULLIFY (colvar%u_param)
      NULLIFY (colvar%hydronium_shell_param)
      NULLIFY (colvar%hydronium_dist_param)
      NULLIFY (colvar%acid_hyd_dist_param)
      NULLIFY (colvar%acid_hyd_shell_param)
      NULLIFY (colvar%reaction_path_param)
      NULLIFY (colvar%combine_cvs_param)
      NULLIFY (colvar%rmsd_param)
      ! More types to nullify
      NULLIFY (colvar%points)
      NULLIFY (colvar%dsdr)
      NULLIFY (colvar%i_atom)
      NULLIFY (colvar%Wc)
      NULLIFY (colvar%ring_puckering_param)
      NULLIFY (colvar%mindist_param)
      colvar%type_id = colvar_id
      colvar%use_points = .FALSE.
      SELECT CASE (colvar_id)
      CASE (dist_colvar_id)
         ALLOCATE (colvar%dist_param)
         colvar%dist_param%axis_id = do_clv_xyz
      CASE (coord_colvar_id)
         ALLOCATE (colvar%coord_param)
      CASE (population_colvar_id)
         ALLOCATE (colvar%population_param)
      CASE (gyration_colvar_id)
         ALLOCATE (colvar%gyration_param)
      CASE (angle_colvar_id)
         ALLOCATE (colvar%angle_param)
      CASE (torsion_colvar_id)
         ALLOCATE (colvar%torsion_param)
      CASE (plane_distance_colvar_id)
         ALLOCATE (colvar%plane_distance_param)
      CASE (plane_plane_angle_colvar_id)
         ALLOCATE (colvar%plane_plane_angle_param)
      CASE (rotation_colvar_id)
         ALLOCATE (colvar%rotation_param)
      CASE (dfunct_colvar_id)
         ALLOCATE (colvar%dfunct_param)
      CASE (qparm_colvar_id)
         ALLOCATE (colvar%qparm_param)
      CASE (xyz_diag_colvar_id)
         ALLOCATE (colvar%xyz_diag_param)
         ! Initialize r0 with dummy..
         colvar%xyz_diag_param%r0 = HUGE(0.0_dp)
      CASE (xyz_outerdiag_colvar_id)
         ALLOCATE (colvar%xyz_outerdiag_param)
         ! Initialize r0 with dummy..
         colvar%xyz_outerdiag_param%r0 = HUGE(0.0_dp)
      CASE (u_colvar_id)
         ALLOCATE (colvar%u_param)
         NULLIFY (colvar%u_param%mixed_energy_section)
      CASE (hydronium_shell_colvar_id)
         ALLOCATE (colvar%hydronium_shell_param)
      CASE (hydronium_dist_colvar_id)
         ALLOCATE (colvar%hydronium_dist_param)
      CASE (acid_hyd_dist_colvar_id)
         ALLOCATE (colvar%acid_hyd_dist_param)
      CASE (acid_hyd_shell_colvar_id)
         ALLOCATE (colvar%acid_hyd_shell_param)
      CASE (reaction_path_colvar_id)
         ALLOCATE (colvar%reaction_path_param)
      CASE (distance_from_path_colvar_id)
         ALLOCATE (colvar%reaction_path_param)
      CASE (combine_colvar_id)
         ALLOCATE (colvar%combine_cvs_param)
      CASE (rmsd_colvar_id)
         ALLOCATE (colvar%rmsd_param)
      CASE (Wc_colvar_id)
         ALLOCATE (colvar%Wc)
      CASE (HBP_colvar_id)
         ALLOCATE (colvar%HBP)
      CASE (ring_puckering_colvar_id)
         ALLOCATE (colvar%ring_puckering_param)
      CASE (mindist_colvar_id)
         ALLOCATE (colvar%mindist_param)
      CASE (no_colvar_id)
         ! Do nothing
      CASE DEFAULT
         CPABORT("")
      END SELECT

   END SUBROUTINE colvar_create

! **************************************************************************************************
!> \brief Finalize the setup of the collective variable
!> \param colvar the colvar to initialize
!> \author Teodoro Laino, [teo] 09.03.2006
! **************************************************************************************************
   SUBROUTINE colvar_setup(colvar)
      TYPE(colvar_type), POINTER                         :: colvar

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_setup', routineP = moduleN//':'//routineN

      INTEGER                                            :: i, idum, iend, ii, istart, j, np, stat
      INTEGER, DIMENSION(:), POINTER                     :: list

      CPASSERT(ASSOCIATED(colvar))
      SELECT CASE (colvar%type_id)
      CASE (dist_colvar_id)
         np = 2
         i = colvar%dist_param%i_at
         j = colvar%dist_param%j_at
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = COLV_SIZE(colvar, i)+ &
                           COLV_SIZE(colvar, j)
         ! Create a List of points...
         ALLOCATE (list(np))
         list(1) = colvar%dist_param%i_at
         list(2) = colvar%dist_param%j_at
      CASE (coord_colvar_id)
         np = colvar%coord_param%n_atoms_from+colvar%coord_param%n_atoms_to &
              +colvar%coord_param%n_atoms_to_b
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%coord_param%n_atoms_from
            i = colvar%coord_param%i_at_from(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         DO ii = 1, colvar%coord_param%n_atoms_to
            i = colvar%coord_param%i_at_to(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         IF (colvar%coord_param%n_atoms_to_b /= 0) THEN
            DO ii = 1, colvar%coord_param%n_atoms_to_b
               i = colvar%coord_param%i_at_to_b(ii)
               colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
            ENDDO
         END IF
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%coord_param%n_atoms_from
            idum = idum+1
            i = colvar%coord_param%i_at_from(ii)
            list(idum) = i
         ENDDO
         DO ii = 1, colvar%coord_param%n_atoms_to
            idum = idum+1
            i = colvar%coord_param%i_at_to(ii)
            list(idum) = i
         ENDDO
         IF (colvar%coord_param%n_atoms_to_b /= 0) THEN
            DO ii = 1, colvar%coord_param%n_atoms_to_b
               idum = idum+1
               i = colvar%coord_param%i_at_to_b(ii)
               list(idum) = i
            ENDDO
         END IF
         CPASSERT(idum == np)
      CASE (population_colvar_id)
         np = colvar%population_param%n_atoms_from+colvar%population_param%n_atoms_to
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%population_param%n_atoms_from
            i = colvar%population_param%i_at_from(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         DO ii = 1, colvar%population_param%n_atoms_to
            i = colvar%population_param%i_at_to(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%population_param%n_atoms_from
            idum = idum+1
            i = colvar%population_param%i_at_from(ii)
            list(idum) = i
         ENDDO
         DO ii = 1, colvar%population_param%n_atoms_to
            idum = idum+1
            i = colvar%population_param%i_at_to(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (gyration_colvar_id)
         np = colvar%gyration_param%n_atoms
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%gyration_param%n_atoms
            i = colvar%gyration_param%i_at(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%gyration_param%n_atoms
            idum = idum+1
            i = colvar%gyration_param%i_at(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (angle_colvar_id)
         np = 3
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, 3
            i = colvar%angle_param%i_at_angle(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, 3
            idum = idum+1
            i = colvar%angle_param%i_at_angle(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (torsion_colvar_id)
         np = 4
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, 4
            i = colvar%torsion_param%i_at_tors(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, 4
            idum = idum+1
            i = colvar%torsion_param%i_at_tors(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (plane_distance_colvar_id)
         np = 4
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, 3
            i = colvar%plane_distance_param%plane(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         i = colvar%plane_distance_param%point
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, 3
            idum = idum+1
            i = colvar%plane_distance_param%plane(ii)
            list(idum) = i
         ENDDO
         i = colvar%plane_distance_param%point
         list(4) = i
         idum = idum+1
         CPASSERT(idum == np)
      CASE (plane_plane_angle_colvar_id)
         np = 0
         IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) np = np+3
         IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) np = np+3
         ! if np is equal to zero this means that this is not a COLLECTIVE variable..
         IF (np == 0) &
            CALL cp_abort(__LOCATION__, &
                          "PLANE_PLANE_ANGLE Colvar defined using two normal vectors! This is "// &
                          "not a COLLECTIVE VARIABLE! One of the two planes must be defined "// &
                          "using atomic positions.")

         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) THEN
            DO ii = 1, 3
               i = colvar%plane_plane_angle_param%plane1%points(ii)
               colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
            ENDDO
         END IF
         IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) THEN
            DO ii = 1, 3
               i = colvar%plane_plane_angle_param%plane2%points(ii)
               colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
            ENDDO
         END IF

         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) THEN
            DO ii = 1, 3
               idum = idum+1
               i = colvar%plane_plane_angle_param%plane1%points(ii)
               list(idum) = i
            ENDDO
         END IF
         IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) THEN
            DO ii = 1, 3
               idum = idum+1
               i = colvar%plane_plane_angle_param%plane2%points(ii)
               list(idum) = i
            ENDDO
         END IF
         CPASSERT(idum == np)
      CASE (dfunct_colvar_id)
         np = 4
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, 4
            i = colvar%dfunct_param%i_at_dfunct(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, 4
            idum = idum+1
            i = colvar%dfunct_param%i_at_dfunct(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (rotation_colvar_id)
         np = 4
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         i = colvar%rotation_param%i_at1_bond1
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         i = colvar%rotation_param%i_at2_bond1
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         i = colvar%rotation_param%i_at1_bond2
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         i = colvar%rotation_param%i_at2_bond2
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ! Create a List of points...
         ALLOCATE (list(np))
         i = colvar%rotation_param%i_at1_bond1
         list(1) = i
         i = colvar%rotation_param%i_at2_bond1
         list(2) = i
         i = colvar%rotation_param%i_at1_bond2
         list(3) = i
         i = colvar%rotation_param%i_at2_bond2
         list(4) = i
      CASE (qparm_colvar_id)
         np = colvar%qparm_param%n_atoms_from+colvar%qparm_param%n_atoms_to
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%qparm_param%n_atoms_from
            i = colvar%qparm_param%i_at_from(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         DO ii = 1, colvar%qparm_param%n_atoms_to
            i = colvar%qparm_param%i_at_to(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%qparm_param%n_atoms_from
            idum = idum+1
            i = colvar%qparm_param%i_at_from(ii)
            list(idum) = i
         ENDDO
         DO ii = 1, colvar%qparm_param%n_atoms_to
            idum = idum+1
            i = colvar%qparm_param%i_at_to(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (hydronium_shell_colvar_id)
         np = colvar%hydronium_shell_param%n_oxygens+colvar%hydronium_shell_param%n_hydrogens
         ALLOCATE (list(np))
         CALL setup_hydronium_colvars(colvar, hydronium_shell_colvar_id, list)
      CASE (hydronium_dist_colvar_id)
         np = colvar%hydronium_dist_param%n_oxygens+colvar%hydronium_dist_param%n_hydrogens
         ALLOCATE (list(np))
         CALL setup_hydronium_colvars(colvar, hydronium_dist_colvar_id, list)
      CASE (acid_hyd_dist_colvar_id)
         np = colvar%acid_hyd_dist_param%n_oxygens_water &
              +colvar%acid_hyd_dist_param%n_oxygens_acid &
              +colvar%acid_hyd_dist_param%n_hydrogens
         ALLOCATE (list(np))
         CALL setup_acid_hydronium_colvars(colvar, acid_hyd_dist_colvar_id, list)
      CASE (acid_hyd_shell_colvar_id)
         np = colvar%acid_hyd_shell_param%n_oxygens_water &
              +colvar%acid_hyd_shell_param%n_oxygens_acid &
              +colvar%acid_hyd_shell_param%n_hydrogens
         ALLOCATE (list(np))
         CALL setup_acid_hydronium_colvars(colvar, acid_hyd_shell_colvar_id, list)
      CASE (rmsd_colvar_id)
         np = colvar%rmsd_param%n_atoms
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%rmsd_param%n_atoms
            i = colvar%rmsd_param%i_rmsd(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%rmsd_param%n_atoms
            idum = idum+1
            i = colvar%rmsd_param%i_rmsd(ii)
            list(idum) = i
         END DO
      CASE (reaction_path_colvar_id, distance_from_path_colvar_id)
         colvar%n_atom_s = 0
         IF (colvar%reaction_path_param%dist_rmsd .OR. colvar%reaction_path_param%rmsd) THEN
            colvar%n_atom_s = colvar%reaction_path_param%n_components
         ELSE
            DO ii = 1, SIZE(colvar%reaction_path_param%colvar_p)
               colvar%n_atom_s = colvar%n_atom_s+colvar%reaction_path_param%colvar_p(ii)%colvar%n_atom_s
            END DO
         END IF
         ALLOCATE (list(colvar%n_atom_s))
         idum = 0
         IF (colvar%reaction_path_param%dist_rmsd .OR. colvar%reaction_path_param%rmsd) THEN
            DO ii = 1, SIZE(colvar%reaction_path_param%i_rmsd)
               idum = idum+1
               i = colvar%reaction_path_param%i_rmsd(ii)
               list(idum) = i
            END DO
         ELSE
            DO ii = 1, SIZE(colvar%reaction_path_param%colvar_p)
               DO j = 1, colvar%reaction_path_param%colvar_p(ii)%colvar%n_atom_s
                  idum = idum+1
                  list(idum) = colvar%reaction_path_param%colvar_p(ii)%colvar%i_atom(j)
               END DO
            END DO
         END IF
      CASE (xyz_diag_colvar_id)
         np = 1
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         i = colvar%xyz_diag_param%i_atom
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ! Create a List of points...
         ALLOCATE (list(np))
         i = colvar%xyz_diag_param%i_atom
         list(1) = i
      CASE (xyz_outerdiag_colvar_id)
         np = 2
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         i = colvar%xyz_outerdiag_param%i_atoms(1)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         i = colvar%xyz_outerdiag_param%i_atoms(2)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ! Create a List of points...
         ALLOCATE (list(np))
         i = colvar%xyz_outerdiag_param%i_atoms(1)
         list(1) = i
         i = colvar%xyz_outerdiag_param%i_atoms(2)
         list(2) = i
      CASE (u_colvar_id)
         np = 1; ALLOCATE (list(np), stat=stat)
         CPASSERT(stat == 0)
         colvar%n_atom_s = np; list(1) = 1
      CASE (Wc_colvar_id)
         np = 3
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, 3
            i = colvar%Wc%ids(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, 3
            idum = idum+1
            i = colvar%Wc%ids(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (HBP_colvar_id)
         np = 3*colvar%HBP%nPoints
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO j = 1, colvar%HBP%nPoints
            DO ii = 1, 3
               i = colvar%HBP%ids(j, ii)
               colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
            ENDDO
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO j = 1, colvar%HBP%nPoints
            DO ii = 1, 3
               idum = idum+1
               i = colvar%HBP%ids(j, ii)
               list(idum) = i
            ENDDO
         ENDDO
         CPASSERT(idum == np)
      CASE (ring_puckering_colvar_id)
         np = colvar%ring_puckering_param%nring
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%ring_puckering_param%nring
            i = colvar%ring_puckering_param%atoms(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%ring_puckering_param%nring
            idum = idum+1
            i = colvar%ring_puckering_param%atoms(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (mindist_colvar_id)
         np = colvar%mindist_param%n_dist_from+ &
              colvar%mindist_param%n_coord_from+colvar%mindist_param%n_coord_to
         ! Number of real atoms involved in the colvar
         colvar%n_atom_s = 0
         DO ii = 1, colvar%mindist_param%n_dist_from
            i = colvar%mindist_param%i_dist_from(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         DO ii = 1, colvar%mindist_param%n_coord_from
            i = colvar%mindist_param%i_coord_from(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         DO ii = 1, colvar%mindist_param%n_coord_to
            i = colvar%mindist_param%i_coord_to(ii)
            colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
         ENDDO
         ! Create a List of points...
         ALLOCATE (list(np))
         idum = 0
         DO ii = 1, colvar%mindist_param%n_dist_from
            idum = idum+1
            i = colvar%mindist_param%i_dist_from(ii)
            list(idum) = i
         ENDDO
         DO ii = 1, colvar%mindist_param%n_coord_from
            idum = idum+1
            i = colvar%mindist_param%i_coord_from(ii)
            list(idum) = i
         ENDDO
         DO ii = 1, colvar%mindist_param%n_coord_to
            idum = idum+1
            i = colvar%mindist_param%i_coord_to(ii)
            list(idum) = i
         ENDDO
         CPASSERT(idum == np)
      CASE (combine_colvar_id)
         colvar%n_atom_s = 0
         DO ii = 1, SIZE(colvar%combine_cvs_param%colvar_p)
            colvar%n_atom_s = colvar%n_atom_s+colvar%combine_cvs_param%colvar_p(ii)%colvar%n_atom_s
         END DO
         ALLOCATE (list(colvar%n_atom_s))
         idum = 0
         DO ii = 1, SIZE(colvar%combine_cvs_param%colvar_p)
            DO j = 1, colvar%combine_cvs_param%colvar_p(ii)%colvar%n_atom_s
               idum = idum+1
               list(idum) = colvar%combine_cvs_param%colvar_p(ii)%colvar%i_atom(j)
            END DO
         END DO
      END SELECT

      IF (ASSOCIATED(colvar%dsdr)) THEN
         DEALLOCATE (colvar%dsdr)
      END IF
      IF (ASSOCIATED(colvar%i_atom)) THEN
         DEALLOCATE (colvar%i_atom)
      END IF
      ALLOCATE (colvar%dsdr(3, colvar%n_atom_s))
      ALLOCATE (colvar%i_atom(colvar%n_atom_s))
      ! And now map real atoms
      istart = 0
      iend = 0
      DO i = 1, SIZE(list)
         IF (.NOT. colvar%use_points) THEN
            ! No point centers
            colvar%i_atom(i) = list(i)
            iend = iend+1
         ELSE
            IF (ASSOCIATED(colvar%points(list(i))%atoms)) THEN
               iend = istart+SIZE(colvar%points(list(i))%atoms)
               colvar%i_atom(istart+1:iend) = colvar%points(list(i))%atoms
               istart = iend
            END IF
         END IF
      END DO
      CPASSERT(iend == colvar%n_atom_s)
      DEALLOCATE (list)

   END SUBROUTINE colvar_setup

! **************************************************************************************************
!> \brief Finalize the setup of the collective variable for the autoionization of water
!> \param colvar the colvar to initialize
!> \param colvar_id ...
!> \param list ...
!> \author Dorothea Golze
! **************************************************************************************************
   SUBROUTINE setup_hydronium_colvars(colvar, colvar_id, list)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: colvar_id
      INTEGER, DIMENSION(:), INTENT(INOUT)               :: list

      CHARACTER(len=*), PARAMETER :: routineN = 'setup_hydronium_colvars', &
         routineP = moduleN//':'//routineN

      INTEGER                                            :: i, idum, ii, n_hydrogens, n_oxygens, np
      INTEGER, DIMENSION(:), POINTER                     :: i_hydrogens, i_oxygens

      NULLIFY (i_oxygens, i_hydrogens)

      SELECT CASE (colvar_id)
      CASE (hydronium_shell_colvar_id)
         n_oxygens = colvar%hydronium_shell_param%n_oxygens
         n_hydrogens = colvar%hydronium_shell_param%n_hydrogens
         i_oxygens => colvar%hydronium_shell_param%i_oxygens
         i_hydrogens => colvar%hydronium_shell_param%i_hydrogens
      CASE (hydronium_dist_colvar_id)
         n_oxygens = colvar%hydronium_dist_param%n_oxygens
         n_hydrogens = colvar%hydronium_dist_param%n_hydrogens
         i_oxygens => colvar%hydronium_dist_param%i_oxygens
         i_hydrogens => colvar%hydronium_dist_param%i_hydrogens
      END SELECT

      np = n_oxygens+n_hydrogens
      ! Number of real atoms involved in the colvar
      colvar%n_atom_s = 0
      DO ii = 1, n_oxygens
         i = i_oxygens(ii)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
      ENDDO
      DO ii = 1, n_hydrogens
         i = i_hydrogens(ii)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
      ENDDO
      idum = 0
      DO ii = 1, n_oxygens
         idum = idum+1
         i = i_oxygens(ii)
         list(idum) = i
         IF (ANY(i_hydrogens == i)) &
            CPABORT("COLVAR: atoms doubled in OXYGENS and HYDROGENS list")
      ENDDO
      DO ii = 1, n_hydrogens
         idum = idum+1
         i = i_hydrogens(ii)
         list(idum) = i
      ENDDO
      CPASSERT(idum == np)
      DO i = 1, np
         DO ii = i+1, np
            IF (list(i) == list(ii)) THEN
               IF (i <= n_oxygens) &
                  CPABORT("atoms doubled in OXYGENS list")
               IF (i > n_oxygens) &
                  CPABORT("atoms doubled in HYDROGENS list")
            ENDIF
         ENDDO
      ENDDO

   END SUBROUTINE setup_hydronium_colvars

! **************************************************************************************************
!> \brief Finalize the setup of the collective variable for the dissociation
!>        of a carboxylic acid in water
!> \param colvar the colvar to initialize
!> \param colvar_id ...
!> \param list ...
!> \author Dorothea Golze
! **************************************************************************************************
   SUBROUTINE setup_acid_hydronium_colvars(colvar, colvar_id, list)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: colvar_id
      INTEGER, DIMENSION(:), INTENT(INOUT)               :: list

      CHARACTER(len=*), PARAMETER :: routineN = 'setup_acid_hydronium_colvars', &
         routineP = moduleN//':'//routineN

      INTEGER                                            :: i, idum, ii, n_hydrogens, &
                                                            n_oxygens_acid, n_oxygens_water, np
      INTEGER, DIMENSION(:), POINTER                     :: i_hydrogens, i_oxygens_acid, &
                                                            i_oxygens_water

      NULLIFY (i_oxygens_water, i_oxygens_acid, i_hydrogens)

      SELECT CASE (colvar_id)
      CASE (acid_hyd_dist_colvar_id)
         n_oxygens_water = colvar%acid_hyd_dist_param%n_oxygens_water
         n_oxygens_acid = colvar%acid_hyd_dist_param%n_oxygens_acid
         n_hydrogens = colvar%acid_hyd_dist_param%n_hydrogens
         i_oxygens_water => colvar%acid_hyd_dist_param%i_oxygens_water
         i_oxygens_acid => colvar%acid_hyd_dist_param%i_oxygens_acid
         i_hydrogens => colvar%acid_hyd_dist_param%i_hydrogens
      CASE (acid_hyd_shell_colvar_id)
         n_oxygens_water = colvar%acid_hyd_shell_param%n_oxygens_water
         n_oxygens_acid = colvar%acid_hyd_shell_param%n_oxygens_acid
         n_hydrogens = colvar%acid_hyd_shell_param%n_hydrogens
         i_oxygens_water => colvar%acid_hyd_shell_param%i_oxygens_water
         i_oxygens_acid => colvar%acid_hyd_shell_param%i_oxygens_acid
         i_hydrogens => colvar%acid_hyd_shell_param%i_hydrogens
      END SELECT

      np = n_oxygens_water+n_oxygens_acid+n_hydrogens
      ! Number of real atoms involved in the colvar
      colvar%n_atom_s = 0
      DO ii = 1, n_oxygens_water
         i = i_oxygens_water(ii)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
      ENDDO
      DO ii = 1, n_oxygens_acid
         i = i_oxygens_acid(ii)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
      ENDDO
      DO ii = 1, n_hydrogens
         i = i_hydrogens(ii)
         colvar%n_atom_s = colvar%n_atom_s+COLV_SIZE(colvar, i)
      ENDDO
      idum = 0
      DO ii = 1, n_oxygens_water
         idum = idum+1
         i = i_oxygens_water(ii)
         list(idum) = i
         IF (ANY(i_hydrogens == i)) &
            CPABORT("COLVAR: atoms doubled in OXYGENS_WATER and HYDROGENS list")
         IF (ANY(i_oxygens_acid == i)) &
            CPABORT("COLVAR: atoms doubled in OXYGENS_WATER and OXYGENS_ACID list")
      ENDDO
      DO ii = 1, n_oxygens_acid
         idum = idum+1
         i = i_oxygens_acid(ii)
         list(idum) = i
         IF (ANY(i_hydrogens == i)) &
            CPABORT("COLVAR: atoms doubled in OXYGENS_ACID and HYDROGENS list")
      ENDDO
      DO ii = 1, n_hydrogens
         idum = idum+1
         i = i_hydrogens(ii)
         list(idum) = i
      ENDDO
      CPASSERT(idum == np)
      DO i = 1, np
         DO ii = i+1, np
            IF (list(i) == list(ii)) THEN
               IF (i <= n_oxygens_water) &
                  CPABORT("atoms doubled in OXYGENS_WATER list")
               IF (i > n_oxygens_water .AND. i <= n_oxygens_water+n_oxygens_acid) &
                  CPABORT("atoms doubled in OXYGENS_ACID list")
               IF (i > n_oxygens_water+n_oxygens_acid) &
                  CPABORT("atoms doubled in HYDROGENS list")
            ENDIF
         ENDDO
      ENDDO

   END SUBROUTINE setup_acid_hydronium_colvars

! **************************************************************************************************
!> \brief Gives back the size of an array of integer. If not associated gives back 1
!> \param colvar ...
!> \param i ...
!> \return ...
!> \author Teodoro Laino - 03.2007
! **************************************************************************************************
   FUNCTION colv_size(colvar, i) RESULT(my_size)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER                                            :: i, my_size

      my_size = 1
      IF (ASSOCIATED(colvar%points)) THEN
         IF (ASSOCIATED(colvar%points(i)%atoms)) THEN
            my_size = SIZE(colvar%points(i)%atoms)
         ELSE
            my_size = 0
         END IF
      END IF
   END FUNCTION colv_size

! **************************************************************************************************
!> \brief releases the memory that might have been allocated by the colvar
!> \param colvar the colvar to deallocate
!> \author alessandro laio and fawzi mohamed
! **************************************************************************************************
   RECURSIVE SUBROUTINE colvar_release(colvar)
      TYPE(colvar_type), POINTER                         :: colvar

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_release', routineP = moduleN//':'//routineN

      INTEGER                                            :: i

      CPASSERT(ASSOCIATED(colvar))
      IF (ASSOCIATED(colvar%dsdr)) THEN
         DEALLOCATE (colvar%dsdr)
      END IF
      IF (ASSOCIATED(colvar%i_atom)) THEN
         DEALLOCATE (colvar%i_atom)
      END IF
      IF (ASSOCIATED(colvar%points)) THEN
         DO i = 1, SIZE(colvar%points)
            IF (ASSOCIATED(colvar%points(i)%atoms)) THEN
               DEALLOCATE (colvar%points(i)%atoms)
            END IF
            IF (ASSOCIATED(colvar%points(i)%weights)) THEN
               DEALLOCATE (colvar%points(i)%weights)
            END IF
         END DO
         DEALLOCATE (colvar%points)
      END IF
      SELECT CASE (colvar%type_id)
      CASE (dist_colvar_id)
         DEALLOCATE (colvar%dist_param)
      CASE (coord_colvar_id)
         IF (ASSOCIATED(colvar%coord_param%i_at_from)) THEN
            DEALLOCATE (colvar%coord_param%i_at_from)
         END IF
         IF (ASSOCIATED(colvar%coord_param%i_at_to)) THEN
            DEALLOCATE (colvar%coord_param%i_at_to)
         END IF
         IF (ASSOCIATED(colvar%coord_param%c_kinds_from)) THEN
            DEALLOCATE (colvar%coord_param%c_kinds_from)
         END IF
         IF (ASSOCIATED(colvar%coord_param%c_kinds_to)) THEN
            DEALLOCATE (colvar%coord_param%c_kinds_to)
         END IF
         IF (ASSOCIATED(colvar%coord_param%i_at_to_b)) THEN
            DEALLOCATE (colvar%coord_param%i_at_to_b)
         END IF
         IF (ASSOCIATED(colvar%coord_param%c_kinds_to_b)) THEN
            DEALLOCATE (colvar%coord_param%c_kinds_to_b)
         END IF
         DEALLOCATE (colvar%coord_param)
      CASE (population_colvar_id)
         IF (ASSOCIATED(colvar%population_param%i_at_from)) THEN
            DEALLOCATE (colvar%population_param%i_at_from)
         END IF
         IF (ASSOCIATED(colvar%population_param%i_at_to)) THEN
            DEALLOCATE (colvar%population_param%i_at_to)
         END IF
         IF (ASSOCIATED(colvar%population_param%c_kinds_from)) THEN
            DEALLOCATE (colvar%population_param%c_kinds_from)
         END IF
         IF (ASSOCIATED(colvar%population_param%c_kinds_to)) THEN
            DEALLOCATE (colvar%population_param%c_kinds_to)
         END IF
         DEALLOCATE (colvar%population_param)
      CASE (gyration_colvar_id)
         IF (ASSOCIATED(colvar%gyration_param%i_at)) THEN
            DEALLOCATE (colvar%gyration_param%i_at)
         END IF
         IF (ASSOCIATED(colvar%gyration_param%c_kinds)) THEN
            DEALLOCATE (colvar%gyration_param%c_kinds)
         END IF
         DEALLOCATE (colvar%gyration_param)
      CASE (angle_colvar_id)
         DEALLOCATE (colvar%angle_param)
      CASE (torsion_colvar_id)
         DEALLOCATE (colvar%torsion_param)
      CASE (plane_distance_colvar_id)
         DEALLOCATE (colvar%plane_distance_param)
      CASE (plane_plane_angle_colvar_id)
         DEALLOCATE (colvar%plane_plane_angle_param)
      CASE (dfunct_colvar_id)
         DEALLOCATE (colvar%dfunct_param)
      CASE (rotation_colvar_id)
         DEALLOCATE (colvar%rotation_param)
      CASE (qparm_colvar_id)
         DEALLOCATE (colvar%qparm_param%i_at_from)
         DEALLOCATE (colvar%qparm_param%i_at_to)
         DEALLOCATE (colvar%qparm_param)
      CASE (xyz_diag_colvar_id)
         DEALLOCATE (colvar%xyz_diag_param)
      CASE (xyz_outerdiag_colvar_id)
         DEALLOCATE (colvar%xyz_outerdiag_param)
      CASE (u_colvar_id)
         NULLIFY (colvar%u_param%mixed_energy_section)
         DEALLOCATE (colvar%u_param)
      CASE (hydronium_shell_colvar_id)
         DEALLOCATE (colvar%hydronium_shell_param%i_oxygens)
         DEALLOCATE (colvar%hydronium_shell_param%i_hydrogens)
         DEALLOCATE (colvar%hydronium_shell_param)
      CASE (hydronium_dist_colvar_id)
         DEALLOCATE (colvar%hydronium_dist_param%i_oxygens)
         DEALLOCATE (colvar%hydronium_dist_param%i_hydrogens)
         DEALLOCATE (colvar%hydronium_dist_param)
      CASE (acid_hyd_dist_colvar_id)
         DEALLOCATE (colvar%acid_hyd_dist_param%i_oxygens_water)
         DEALLOCATE (colvar%acid_hyd_dist_param%i_oxygens_acid)
         DEALLOCATE (colvar%acid_hyd_dist_param%i_hydrogens)
         DEALLOCATE (colvar%acid_hyd_dist_param)
      CASE (acid_hyd_shell_colvar_id)
         DEALLOCATE (colvar%acid_hyd_shell_param%i_oxygens_water)
         DEALLOCATE (colvar%acid_hyd_shell_param%i_oxygens_acid)
         DEALLOCATE (colvar%acid_hyd_shell_param%i_hydrogens)
         DEALLOCATE (colvar%acid_hyd_shell_param)
      CASE (reaction_path_colvar_id, distance_from_path_colvar_id)
         IF (colvar%reaction_path_param%dist_rmsd .OR. colvar%reaction_path_param%rmsd) THEN
            DEALLOCATE (colvar%reaction_path_param%r_ref)
            DEALLOCATE (colvar%reaction_path_param%i_rmsd)
         ELSE
            DO i = 1, SIZE(colvar%reaction_path_param%colvar_p)
               CALL colvar_release(colvar%reaction_path_param%colvar_p(i)%colvar)
            END DO
            DEALLOCATE (colvar%reaction_path_param%colvar_p)
            DEALLOCATE (colvar%reaction_path_param%f_vals)
         END IF
         DEALLOCATE (colvar%reaction_path_param)
      CASE (combine_colvar_id)
         DO i = 1, SIZE(colvar%combine_cvs_param%colvar_p)
            CALL colvar_release(colvar%combine_cvs_param%colvar_p(i)%colvar)
         END DO
         DEALLOCATE (colvar%combine_cvs_param%colvar_p)
         DEALLOCATE (colvar%combine_cvs_param%c_parameters)
         DEALLOCATE (colvar%combine_cvs_param%v_parameters)
         DEALLOCATE (colvar%combine_cvs_param%variables)
         DEALLOCATE (colvar%combine_cvs_param)
      CASE (rmsd_colvar_id)
         DEALLOCATE (colvar%rmsd_param%weights)
         DEALLOCATE (colvar%rmsd_param%r_ref)
         DEALLOCATE (colvar%rmsd_param%i_rmsd)
         DEALLOCATE (colvar%rmsd_param)
      CASE (Wc_colvar_id)
         DEALLOCATE (colvar%Wc)
      CASE (HBP_colvar_id)
         DEALLOCATE (colvar%HBP%ewc)
         DEALLOCATE (colvar%HBP%ids)
         DEALLOCATE (colvar%HBP)
      CASE (ring_puckering_colvar_id)
         DEALLOCATE (colvar%ring_puckering_param%atoms)
         DEALLOCATE (colvar%ring_puckering_param)
      CASE (mindist_colvar_id)
         IF (ASSOCIATED(colvar%mindist_param%i_dist_from)) THEN
            DEALLOCATE (colvar%mindist_param%i_dist_from)
         END IF
         IF (ASSOCIATED(colvar%mindist_param%i_coord_from)) THEN
            DEALLOCATE (colvar%mindist_param%i_coord_from)
         END IF
         IF (ASSOCIATED(colvar%mindist_param%i_coord_to)) THEN
            DEALLOCATE (colvar%mindist_param%i_coord_to)
         END IF
         IF (ASSOCIATED(colvar%mindist_param%k_coord_from)) THEN
            DEALLOCATE (colvar%mindist_param%k_coord_from)
         END IF
         IF (ASSOCIATED(colvar%mindist_param%k_coord_to)) THEN
            DEALLOCATE (colvar%mindist_param%k_coord_to)
         END IF
         DEALLOCATE (colvar%mindist_param)
      CASE (no_colvar_id)
         ! Do nothing
      CASE default
         CPABORT("")
      END SELECT
      DEALLOCATE (colvar)

   END SUBROUTINE colvar_release

! **************************************************************************************************
!> \brief Clone a colvar type
!> \param colvar_out ...
!> \param colvar_in the colvar to deallocate
!> \param i_atom_offset ...
!> \author Teodoro Laino [tlaino] 04.2006
! **************************************************************************************************
   RECURSIVE SUBROUTINE colvar_clone(colvar_out, colvar_in, i_atom_offset)
      TYPE(colvar_type), POINTER                         :: colvar_out, colvar_in
      INTEGER, INTENT(IN), OPTIONAL                      :: i_atom_offset

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_clone', routineP = moduleN//':'//routineN

      INTEGER                                            :: i, my_offset, ndim, ndim2, stat

      my_offset = 0
      CPASSERT(ASSOCIATED(colvar_in))
      CPASSERT(.NOT. ASSOCIATED(colvar_out))
      IF (PRESENT(i_atom_offset)) my_offset = i_atom_offset
      CALL colvar_create(colvar_out, colvar_in%type_id)
      CALL colvar_clone_points(colvar_out, colvar_in, my_offset)
      IF (colvar_in%use_points) my_offset = 0
      SELECT CASE (colvar_out%type_id)
      CASE (dist_colvar_id)
         colvar_out%dist_param%i_at = colvar_in%dist_param%i_at+my_offset
         colvar_out%dist_param%j_at = colvar_in%dist_param%j_at+my_offset
         colvar_out%dist_param%axis_id = colvar_in%dist_param%axis_id
      CASE (coord_colvar_id)
         colvar_out%coord_param%n_atoms_to = colvar_in%coord_param%n_atoms_to
         colvar_out%coord_param%n_atoms_to_b = colvar_in%coord_param%n_atoms_to_b
         colvar_out%coord_param%n_atoms_from = colvar_in%coord_param%n_atoms_from
         colvar_out%coord_param%nncrd = colvar_in%coord_param%nncrd
         colvar_out%coord_param%ndcrd = colvar_in%coord_param%ndcrd
         colvar_out%coord_param%r_0 = colvar_in%coord_param%r_0
         colvar_out%coord_param%nncrd_b = colvar_in%coord_param%nncrd_b
         colvar_out%coord_param%ndcrd_b = colvar_in%coord_param%ndcrd_b
         colvar_out%coord_param%r_0_b = colvar_in%coord_param%r_0_b
         colvar_out%coord_param%use_kinds_from = colvar_in%coord_param%use_kinds_from
         colvar_out%coord_param%use_kinds_to = colvar_in%coord_param%use_kinds_to
         colvar_out%coord_param%use_kinds_to_b = colvar_in%coord_param%use_kinds_to_b
         NULLIFY (colvar_out%coord_param%c_kinds_from, colvar_out%coord_param%i_at_from)
         NULLIFY (colvar_out%coord_param%c_kinds_to, colvar_out%coord_param%i_at_to)
         NULLIFY (colvar_out%coord_param%c_kinds_to_b, colvar_out%coord_param%i_at_to_b)
         IF (colvar_in%coord_param%use_kinds_from) THEN
            ! KINDS
            ndim = SIZE(colvar_in%coord_param%c_kinds_from)
            ALLOCATE (colvar_out%coord_param%c_kinds_from(ndim))
            colvar_out%coord_param%c_kinds_from = colvar_in%coord_param%c_kinds_from
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%coord_param%i_at_from)
            ALLOCATE (colvar_out%coord_param%i_at_from(ndim))
            colvar_out%coord_param%i_at_from = colvar_in%coord_param%i_at_from+my_offset
         END IF
         IF (colvar_in%coord_param%use_kinds_to) THEN
            ! KINDS
            ndim = SIZE(colvar_in%coord_param%c_kinds_to)
            ALLOCATE (colvar_out%coord_param%c_kinds_to(ndim))
            colvar_out%coord_param%c_kinds_to = colvar_in%coord_param%c_kinds_to
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%coord_param%i_at_to)
            ALLOCATE (colvar_out%coord_param%i_at_to(ndim))
            colvar_out%coord_param%i_at_to = colvar_in%coord_param%i_at_to+my_offset
         END IF
         IF (colvar_in%coord_param%use_kinds_to_b) THEN
            ! KINDS
            ndim = SIZE(colvar_in%coord_param%c_kinds_to_b)
            ALLOCATE (colvar_out%coord_param%c_kinds_to_b(ndim))
            colvar_out%coord_param%c_kinds_to_b = colvar_in%coord_param%c_kinds_to_b
         ELSEIF (ASSOCIATED(colvar_in%coord_param%i_at_to_b)) THEN
            ! INDEX
            ndim = SIZE(colvar_in%coord_param%i_at_to_b)
            ALLOCATE (colvar_out%coord_param%i_at_to_b(ndim))
            colvar_out%coord_param%i_at_to_b = colvar_in%coord_param%i_at_to_b+my_offset
         END IF

      CASE (population_colvar_id)
         colvar_out%population_param%n_atoms_to = colvar_in%population_param%n_atoms_to
         colvar_out%population_param%n_atoms_from = colvar_in%population_param%n_atoms_from
         colvar_out%population_param%nncrd = colvar_in%population_param%nncrd
         colvar_out%population_param%ndcrd = colvar_in%population_param%ndcrd
         colvar_out%population_param%r_0 = colvar_in%population_param%r_0
         colvar_out%population_param%use_kinds_from = colvar_in%population_param%use_kinds_from
         colvar_out%population_param%use_kinds_to = colvar_in%population_param%use_kinds_to
         NULLIFY (colvar_out%population_param%c_kinds_from, colvar_out%population_param%i_at_from)
         NULLIFY (colvar_out%population_param%c_kinds_to, colvar_out%population_param%i_at_to)
         IF (colvar_in%population_param%use_kinds_from) THEN
            ! KINDS
            ndim = SIZE(colvar_in%population_param%c_kinds_from)
            ALLOCATE (colvar_out%population_param%c_kinds_from(ndim))
            colvar_out%population_param%c_kinds_from = colvar_in%population_param%c_kinds_from
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%population_param%i_at_from)
            ALLOCATE (colvar_out%population_param%i_at_from(ndim))
            colvar_out%population_param%i_at_from = colvar_in%population_param%i_at_from+my_offset
         END IF
         IF (colvar_in%population_param%use_kinds_to) THEN
            ! KINDS
            ndim = SIZE(colvar_in%population_param%c_kinds_to)
            ALLOCATE (colvar_out%population_param%c_kinds_to(ndim))
            colvar_out%population_param%c_kinds_to = colvar_in%population_param%c_kinds_to
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%population_param%i_at_to)
            ALLOCATE (colvar_out%population_param%i_at_to(ndim))
            colvar_out%population_param%i_at_to = colvar_in%population_param%i_at_to+my_offset
         END IF

      CASE (gyration_colvar_id)
         colvar_out%gyration_param%n_atoms = colvar_in%gyration_param%n_atoms
         colvar_out%gyration_param%use_kinds = colvar_in%gyration_param%use_kinds
         NULLIFY (colvar_out%gyration_param%c_kinds, colvar_out%gyration_param%i_at)
         IF (colvar_in%gyration_param%use_kinds) THEN
            ! KINDS
            ndim = SIZE(colvar_in%gyration_param%c_kinds)
            ALLOCATE (colvar_out%gyration_param%c_kinds(ndim))
            colvar_out%gyration_param%c_kinds = colvar_in%gyration_param%c_kinds
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%gyration_param%i_at)
            ALLOCATE (colvar_out%gyration_param%i_at(ndim))
            colvar_out%gyration_param%i_at = colvar_in%gyration_param%i_at+my_offset
         END IF
      CASE (angle_colvar_id)
         colvar_out%angle_param%i_at_angle = colvar_in%angle_param%i_at_angle+my_offset
      CASE (torsion_colvar_id)
         colvar_out%torsion_param%i_at_tors = colvar_in%torsion_param%i_at_tors+my_offset
         colvar_out%torsion_param%o0 = colvar_in%torsion_param%o0
      CASE (plane_distance_colvar_id)
         colvar_out%plane_distance_param%use_pbc = colvar_in%plane_distance_param%use_pbc
         colvar_out%plane_distance_param%plane = colvar_in%plane_distance_param%plane+my_offset
         colvar_out%plane_distance_param%point = colvar_in%plane_distance_param%point+my_offset
      CASE (plane_plane_angle_colvar_id)
         colvar_out%plane_plane_angle_param%plane1%type_of_def = colvar_in%plane_plane_angle_param%plane1%type_of_def
         IF (colvar_out%plane_plane_angle_param%plane1%type_of_def == plane_def_vec) THEN
            colvar_out%plane_plane_angle_param%plane1%normal_vec = colvar_in%plane_plane_angle_param%plane1%normal_vec
         ELSE
            colvar_out%plane_plane_angle_param%plane1%points = colvar_in%plane_plane_angle_param%plane1%points+my_offset
         END IF

         colvar_out%plane_plane_angle_param%plane2%type_of_def = colvar_in%plane_plane_angle_param%plane2%type_of_def
         IF (colvar_out%plane_plane_angle_param%plane2%type_of_def == plane_def_vec) THEN
            colvar_out%plane_plane_angle_param%plane2%normal_vec = colvar_in%plane_plane_angle_param%plane2%normal_vec
         ELSE
            colvar_out%plane_plane_angle_param%plane2%points = colvar_in%plane_plane_angle_param%plane2%points+my_offset
         END IF
      CASE (rotation_colvar_id)
         colvar_out%rotation_param%i_at1_bond1 = colvar_in%rotation_param%i_at1_bond1+my_offset
         colvar_out%rotation_param%i_at2_bond1 = colvar_in%rotation_param%i_at2_bond1+my_offset
         colvar_out%rotation_param%i_at1_bond2 = colvar_in%rotation_param%i_at1_bond2+my_offset
         colvar_out%rotation_param%i_at2_bond2 = colvar_in%rotation_param%i_at2_bond2+my_offset
      CASE (dfunct_colvar_id)
         colvar_out%dfunct_param%i_at_dfunct = colvar_in%dfunct_param%i_at_dfunct+my_offset
         colvar_out%dfunct_param%coeff = colvar_in%dfunct_param%coeff
         colvar_out%dfunct_param%use_pbc = colvar_in%dfunct_param%use_pbc
      CASE (qparm_colvar_id)
         colvar_out%qparm_param%n_atoms_to = colvar_in%qparm_param%n_atoms_to
         colvar_out%qparm_param%n_atoms_from = colvar_in%qparm_param%n_atoms_from
         colvar_out%qparm_param%rcut = colvar_in%qparm_param%rcut
         colvar_out%qparm_param%l = colvar_in%qparm_param%l
         colvar_out%qparm_param%rstart = colvar_in%qparm_param%rstart
         colvar_out%qparm_param%include_images = colvar_in%qparm_param%include_images
         ndim = SIZE(colvar_in%qparm_param%i_at_from)
         ALLOCATE (colvar_out%qparm_param%i_at_from(ndim))
         ndim = SIZE(colvar_in%qparm_param%i_at_to)
         ALLOCATE (colvar_out%qparm_param%i_at_to(ndim))
         colvar_out%qparm_param%i_at_from = colvar_in%qparm_param%i_at_from+my_offset
         colvar_out%qparm_param%i_at_to = colvar_in%qparm_param%i_at_from+my_offset
      CASE (xyz_diag_colvar_id)
         colvar_out%xyz_diag_param%i_atom = colvar_in%xyz_diag_param%i_atom+my_offset
         colvar_out%xyz_diag_param%component = colvar_in%xyz_diag_param%component
         colvar_out%xyz_diag_param%r0 = colvar_in%xyz_diag_param%r0
         colvar_out%xyz_diag_param%use_pbc = colvar_in%xyz_diag_param%use_pbc
         colvar_out%xyz_diag_param%use_absolute_position = colvar_in%xyz_diag_param%use_absolute_position
      CASE (xyz_outerdiag_colvar_id)
         colvar_out%xyz_outerdiag_param%i_atoms = colvar_in%xyz_outerdiag_param%i_atoms+my_offset
         colvar_out%xyz_outerdiag_param%components = colvar_in%xyz_outerdiag_param%components
         colvar_out%xyz_outerdiag_param%r0 = colvar_in%xyz_outerdiag_param%r0
         colvar_out%xyz_outerdiag_param%use_pbc = colvar_in%xyz_outerdiag_param%use_pbc
      CASE (u_colvar_id)
         colvar_out%u_param%natom = colvar_in%u_param%natom
      CASE (hydronium_shell_colvar_id)
         colvar_out%hydronium_shell_param%n_hydrogens = colvar_in%hydronium_shell_param%n_hydrogens
         colvar_out%hydronium_shell_param%n_oxygens = colvar_in%hydronium_shell_param%n_oxygens
         colvar_out%hydronium_shell_param%nh = colvar_in%hydronium_shell_param%nh
         colvar_out%hydronium_shell_param%poh = colvar_in%hydronium_shell_param%poh
         colvar_out%hydronium_shell_param%poo = colvar_in%hydronium_shell_param%poo
         colvar_out%hydronium_shell_param%qoh = colvar_in%hydronium_shell_param%qoh
         colvar_out%hydronium_shell_param%qoo = colvar_in%hydronium_shell_param%qoo
         colvar_out%hydronium_shell_param%pm = colvar_in%hydronium_shell_param%pm
         colvar_out%hydronium_shell_param%qm = colvar_in%hydronium_shell_param%qm
         colvar_out%hydronium_shell_param%roo = colvar_in%hydronium_shell_param%roo
         colvar_out%hydronium_shell_param%roh = colvar_in%hydronium_shell_param%roh
         colvar_out%hydronium_shell_param%lambda = colvar_in%hydronium_shell_param%lambda
         ndim = SIZE(colvar_in%hydronium_shell_param%i_oxygens)
         ALLOCATE (colvar_out%hydronium_shell_param%i_oxygens(ndim))
         ndim = SIZE(colvar_in%hydronium_shell_param%i_hydrogens)
         ALLOCATE (colvar_out%hydronium_shell_param%i_hydrogens(ndim))
         colvar_out%hydronium_shell_param%i_oxygens = colvar_in%hydronium_shell_param%i_oxygens+my_offset
         colvar_out%hydronium_shell_param%i_hydrogens = colvar_in%hydronium_shell_param%i_hydrogens+my_offset
      CASE (hydronium_dist_colvar_id)
         colvar_out%hydronium_dist_param%n_hydrogens = colvar_in%hydronium_dist_param%n_hydrogens
         colvar_out%hydronium_dist_param%n_oxygens = colvar_in%hydronium_dist_param%n_oxygens
         colvar_out%hydronium_dist_param%nh = colvar_in%hydronium_dist_param%nh
         colvar_out%hydronium_dist_param%nn = colvar_in%hydronium_dist_param%nn
         colvar_out%hydronium_dist_param%poh = colvar_in%hydronium_dist_param%poh
         colvar_out%hydronium_dist_param%qoh = colvar_in%hydronium_dist_param%qoh
         colvar_out%hydronium_dist_param%pf = colvar_in%hydronium_dist_param%pf
         colvar_out%hydronium_dist_param%qf = colvar_in%hydronium_dist_param%qf
         colvar_out%hydronium_dist_param%pm = colvar_in%hydronium_dist_param%pm
         colvar_out%hydronium_dist_param%qm = colvar_in%hydronium_dist_param%qm
         colvar_out%hydronium_dist_param%roh = colvar_in%hydronium_dist_param%roh
         colvar_out%hydronium_dist_param%lambda = colvar_in%hydronium_dist_param%lambda
         ndim = SIZE(colvar_in%hydronium_dist_param%i_oxygens)
         ALLOCATE (colvar_out%hydronium_dist_param%i_oxygens(ndim))
         ndim = SIZE(colvar_in%hydronium_dist_param%i_hydrogens)
         ALLOCATE (colvar_out%hydronium_dist_param%i_hydrogens(ndim))
         colvar_out%hydronium_dist_param%i_oxygens = colvar_in%hydronium_dist_param%i_oxygens+my_offset
         colvar_out%hydronium_dist_param%i_hydrogens = colvar_in%hydronium_dist_param%i_hydrogens+my_offset
      CASE (acid_hyd_dist_colvar_id)
         colvar_out%acid_hyd_dist_param%n_hydrogens = colvar_in%acid_hyd_dist_param%n_hydrogens
         colvar_out%acid_hyd_dist_param%n_oxygens_water = colvar_in%acid_hyd_dist_param%n_oxygens_water
         colvar_out%acid_hyd_dist_param%n_oxygens_acid = colvar_in%acid_hyd_dist_param%n_oxygens_acid
         colvar_out%acid_hyd_dist_param%nc = colvar_in%acid_hyd_dist_param%nc
         colvar_out%acid_hyd_dist_param%pwoh = colvar_in%acid_hyd_dist_param%pwoh
         colvar_out%acid_hyd_dist_param%qwoh = colvar_in%acid_hyd_dist_param%qwoh
         colvar_out%acid_hyd_dist_param%paoh = colvar_in%acid_hyd_dist_param%paoh
         colvar_out%acid_hyd_dist_param%qaoh = colvar_in%acid_hyd_dist_param%qaoh
         colvar_out%acid_hyd_dist_param%pcut = colvar_in%acid_hyd_dist_param%pcut
         colvar_out%acid_hyd_dist_param%qcut = colvar_in%acid_hyd_dist_param%qcut
         colvar_out%acid_hyd_dist_param%rwoh = colvar_in%acid_hyd_dist_param%rwoh
         colvar_out%acid_hyd_dist_param%raoh = colvar_in%acid_hyd_dist_param%raoh
         colvar_out%acid_hyd_dist_param%lambda = colvar_in%acid_hyd_dist_param%lambda
         ndim = SIZE(colvar_in%acid_hyd_dist_param%i_oxygens_water)
         ALLOCATE (colvar_out%acid_hyd_dist_param%i_oxygens_water(ndim))
         ndim = SIZE(colvar_in%acid_hyd_dist_param%i_oxygens_acid)
         ALLOCATE (colvar_out%acid_hyd_dist_param%i_oxygens_acid(ndim))
         ndim = SIZE(colvar_in%acid_hyd_dist_param%i_hydrogens)
         ALLOCATE (colvar_out%acid_hyd_dist_param%i_hydrogens(ndim))
         colvar_out%acid_hyd_dist_param%i_oxygens_water = colvar_in%acid_hyd_dist_param%i_oxygens_water+my_offset
         colvar_out%acid_hyd_dist_param%i_oxygens_acid = colvar_in%acid_hyd_dist_param%i_oxygens_acid+my_offset
         colvar_out%acid_hyd_dist_param%i_hydrogens = colvar_in%acid_hyd_dist_param%i_hydrogens+my_offset
      CASE (acid_hyd_shell_colvar_id)
         colvar_out%acid_hyd_shell_param%n_hydrogens = colvar_in%acid_hyd_shell_param%n_hydrogens
         colvar_out%acid_hyd_shell_param%n_oxygens_water = colvar_in%acid_hyd_shell_param%n_oxygens_water
         colvar_out%acid_hyd_shell_param%n_oxygens_acid = colvar_in%acid_hyd_shell_param%n_oxygens_acid
         colvar_out%acid_hyd_shell_param%nc = colvar_in%acid_hyd_shell_param%nc
         colvar_out%acid_hyd_shell_param%nh = colvar_in%acid_hyd_shell_param%nh
         colvar_out%acid_hyd_shell_param%pwoh = colvar_in%acid_hyd_shell_param%pwoh
         colvar_out%acid_hyd_shell_param%qwoh = colvar_in%acid_hyd_shell_param%qwoh
         colvar_out%acid_hyd_shell_param%paoh = colvar_in%acid_hyd_shell_param%paoh
         colvar_out%acid_hyd_shell_param%qaoh = colvar_in%acid_hyd_shell_param%qaoh
         colvar_out%acid_hyd_shell_param%poo = colvar_in%acid_hyd_shell_param%poo
         colvar_out%acid_hyd_shell_param%qoo = colvar_in%acid_hyd_shell_param%qoo
         colvar_out%acid_hyd_shell_param%pm = colvar_in%acid_hyd_shell_param%pm
         colvar_out%acid_hyd_shell_param%qm = colvar_in%acid_hyd_shell_param%qm
         colvar_out%acid_hyd_shell_param%pcut = colvar_in%acid_hyd_shell_param%pcut
         colvar_out%acid_hyd_shell_param%qcut = colvar_in%acid_hyd_shell_param%qcut
         colvar_out%acid_hyd_shell_param%rwoh = colvar_in%acid_hyd_shell_param%rwoh
         colvar_out%acid_hyd_shell_param%raoh = colvar_in%acid_hyd_shell_param%raoh
         colvar_out%acid_hyd_shell_param%roo = colvar_in%acid_hyd_shell_param%roo
         colvar_out%acid_hyd_shell_param%lambda = colvar_in%acid_hyd_shell_param%lambda
         ndim = SIZE(colvar_in%acid_hyd_shell_param%i_oxygens_water)
         ALLOCATE (colvar_out%acid_hyd_shell_param%i_oxygens_water(ndim))
         ndim = SIZE(colvar_in%acid_hyd_shell_param%i_oxygens_acid)
         ALLOCATE (colvar_out%acid_hyd_shell_param%i_oxygens_acid(ndim))
         ndim = SIZE(colvar_in%acid_hyd_shell_param%i_hydrogens)
         ALLOCATE (colvar_out%acid_hyd_shell_param%i_hydrogens(ndim))
         colvar_out%acid_hyd_shell_param%i_oxygens_water = colvar_in%acid_hyd_shell_param%i_oxygens_water+my_offset
         colvar_out%acid_hyd_shell_param%i_oxygens_acid = colvar_in%acid_hyd_shell_param%i_oxygens_acid+my_offset
         colvar_out%acid_hyd_shell_param%i_hydrogens = colvar_in%acid_hyd_shell_param%i_hydrogens+my_offset
      CASE (reaction_path_colvar_id, distance_from_path_colvar_id)
         colvar_out%reaction_path_param%dist_rmsd = colvar_in%reaction_path_param%dist_rmsd
         colvar_out%reaction_path_param%rmsd = colvar_in%reaction_path_param%rmsd
         colvar_out%reaction_path_param%nr_frames = colvar_in%reaction_path_param%nr_frames
         IF (colvar_in%reaction_path_param%dist_rmsd .OR. colvar_in%reaction_path_param%rmsd) THEN
            colvar_out%reaction_path_param%align_frames = colvar_in%reaction_path_param%align_frames
            colvar_out%reaction_path_param%subset = colvar_in%reaction_path_param%subset
            NULLIFY (colvar_out%reaction_path_param%i_rmsd)
            NULLIFY (colvar_out%reaction_path_param%r_ref)
            ndim = SIZE(colvar_in%reaction_path_param%i_rmsd)
            ALLOCATE (colvar_out%reaction_path_param%i_rmsd(ndim), stat=stat)
            colvar_out%reaction_path_param%i_rmsd = colvar_in%reaction_path_param%i_rmsd
            ndim = SIZE(colvar_in%reaction_path_param%r_ref, 1)
            ndim2 = SIZE(colvar_in%reaction_path_param%r_ref, 2)
            ALLOCATE (colvar_out%reaction_path_param%r_ref(ndim, ndim2), stat=stat)
            colvar_out%reaction_path_param%r_ref = colvar_in%reaction_path_param%r_ref
         ELSE
            ndim = SIZE(colvar_in%reaction_path_param%colvar_p)
            ALLOCATE (colvar_out%reaction_path_param%colvar_p(ndim))
            DO i = 1, ndim
               NULLIFY (colvar_out%reaction_path_param%colvar_p(i)%colvar)
               CALL colvar_clone(colvar_out%reaction_path_param%colvar_p(i)%colvar, &
                                 colvar_in%reaction_path_param%colvar_p(i)%colvar, &
                                 my_offset)
            END DO
            colvar_out%reaction_path_param%function_bounds = colvar_in%reaction_path_param%function_bounds
            NULLIFY (colvar_out%reaction_path_param%f_vals)
            ndim = SIZE(colvar_in%reaction_path_param%f_vals, 1)
            ndim2 = SIZE(colvar_in%reaction_path_param%f_vals, 2)
            ALLOCATE (colvar_out%reaction_path_param%f_vals(ndim, ndim2))
            colvar_out%reaction_path_param%f_vals = colvar_in%reaction_path_param%f_vals
         END IF
         colvar_out%reaction_path_param%step_size = colvar_in%reaction_path_param%step_size
         colvar_out%reaction_path_param%n_components = colvar_in%reaction_path_param%n_components
         colvar_out%reaction_path_param%lambda = colvar_in%reaction_path_param%lambda
      CASE (combine_colvar_id)
         ndim = SIZE(colvar_in%combine_cvs_param%colvar_p)
         ALLOCATE (colvar_out%combine_cvs_param%colvar_p(ndim))
         DO i = 1, ndim
            NULLIFY (colvar_out%combine_cvs_param%colvar_p(i)%colvar)
            CALL colvar_clone(colvar_out%combine_cvs_param%colvar_p(i)%colvar, &
                              colvar_in%combine_cvs_param%colvar_p(i)%colvar, &
                              my_offset)
         END DO
         colvar_out%combine_cvs_param%lerr = colvar_in%combine_cvs_param%lerr
         colvar_out%combine_cvs_param%dx = colvar_in%combine_cvs_param%dx
         colvar_out%combine_cvs_param%function = colvar_in%combine_cvs_param%function
         !
         ndim = SIZE(colvar_in%combine_cvs_param%c_parameters)
         ALLOCATE (colvar_out%combine_cvs_param%c_parameters(ndim))
         colvar_out%combine_cvs_param%c_parameters = colvar_in%combine_cvs_param%c_parameters
         !
         ndim = SIZE(colvar_in%combine_cvs_param%v_parameters)
         ALLOCATE (colvar_out%combine_cvs_param%v_parameters(ndim))
         colvar_out%combine_cvs_param%v_parameters = colvar_in%combine_cvs_param%v_parameters
         !
         ndim = SIZE(colvar_in%combine_cvs_param%variables)
         ALLOCATE (colvar_out%combine_cvs_param%variables(ndim))
         colvar_out%combine_cvs_param%variables = colvar_in%combine_cvs_param%variables
      CASE (rmsd_colvar_id)
         colvar_out%rmsd_param%n_atoms = colvar_in%rmsd_param%n_atoms
         colvar_out%rmsd_param%align_frames = colvar_in%rmsd_param%align_frames
         colvar_out%rmsd_param%nr_frames = colvar_in%rmsd_param%nr_frames
         colvar_out%rmsd_param%subset = colvar_in%rmsd_param%subset
         NULLIFY (colvar_out%rmsd_param%i_rmsd)
         NULLIFY (colvar_out%rmsd_param%weights)
         NULLIFY (colvar_out%rmsd_param%r_ref)
         ! INDEX
         ndim = SIZE(colvar_in%rmsd_param%i_rmsd)
         ALLOCATE (colvar_out%rmsd_param%i_rmsd(ndim))
         colvar_out%rmsd_param%i_rmsd = colvar_in%rmsd_param%i_rmsd+my_offset
         ! A and Bconfigurations and weights
         ndim = SIZE(colvar_in%rmsd_param%weights)
         ALLOCATE (colvar_out%rmsd_param%weights(ndim))
         colvar_out%rmsd_param%weights = colvar_in%rmsd_param%weights
         ndim = SIZE(colvar_in%rmsd_param%r_ref, 1)
         ndim2 = SIZE(colvar_in%rmsd_param%r_ref, 2)
         ALLOCATE (colvar_out%rmsd_param%r_ref(ndim, ndim2))
         colvar_out%rmsd_param%r_ref = colvar_in%rmsd_param%r_ref
      CASE (Wc_colvar_id)
         colvar_out%Wc%ids = colvar_in%Wc%ids+my_offset
         colvar_out%Wc%rcut = colvar_in%Wc%rcut
      CASE (HBP_colvar_id)
         ndim = colvar_out%HBP%nPoints
         ALLOCATE (colvar_out%HBP%ids(ndim, 3))
         ALLOCATE (colvar_out%HBP%ewc(ndim))
         colvar_out%HBP%ids = colvar_in%HBP%ids+my_offset
         colvar_out%HBP%ewc = colvar_in%HBP%ewc+my_offset
         colvar_out%HBP%nPoints = colvar_in%HBP%nPoints
         colvar_out%HBP%rcut = colvar_in%HBP%rcut
         colvar_out%HBP%shift = colvar_in%HBP%shift
      CASE (ring_puckering_colvar_id)
         ndim = colvar_in%ring_puckering_param%nring
         colvar_out%ring_puckering_param%nring = colvar_in%ring_puckering_param%nring
         colvar_out%ring_puckering_param%iq = colvar_in%ring_puckering_param%iq
         ALLOCATE (colvar_out%ring_puckering_param%atoms(ndim))
         colvar_out%ring_puckering_param%atoms = colvar_in%ring_puckering_param%atoms+my_offset
      CASE (mindist_colvar_id)
         colvar_out%mindist_param%n_dist_from = colvar_in%mindist_param%n_dist_from
         colvar_out%mindist_param%n_coord_to = colvar_in%mindist_param%n_coord_to
         colvar_out%mindist_param%n_coord_from = colvar_in%mindist_param%n_coord_from
         colvar_out%mindist_param%p_exp = colvar_in%mindist_param%p_exp
         colvar_out%mindist_param%q_exp = colvar_in%mindist_param%q_exp
         colvar_out%mindist_param%r_cut = colvar_in%mindist_param%r_cut
         colvar_out%mindist_param%lambda = colvar_in%mindist_param%lambda
         colvar_out%mindist_param%use_kinds_from = colvar_in%mindist_param%use_kinds_from
         colvar_out%mindist_param%use_kinds_to = colvar_in%mindist_param%use_kinds_to
         NULLIFY (colvar_out%mindist_param%k_coord_from, colvar_out%mindist_param%i_coord_from)
         NULLIFY (colvar_out%mindist_param%k_coord_to, colvar_out%mindist_param%i_coord_to)
         NULLIFY (colvar_out%mindist_param%i_dist_from)
         ! INDEX
         ndim = SIZE(colvar_in%mindist_param%i_dist_from)
         ALLOCATE (colvar_out%mindist_param%i_dist_from(ndim))
         colvar_out%mindist_param%i_dist_from = colvar_in%mindist_param%i_dist_from+my_offset
         IF (colvar_in%mindist_param%use_kinds_from) THEN
            ! KINDS
            ndim = SIZE(colvar_in%mindist_param%k_coord_from)
            ALLOCATE (colvar_out%mindist_param%k_coord_from(ndim))
            colvar_out%mindist_param%k_coord_from = colvar_in%mindist_param%k_coord_from
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%mindist_param%i_coord_from)
            ALLOCATE (colvar_out%mindist_param%i_coord_from(ndim))
            colvar_out%mindist_param%i_coord_from = colvar_in%mindist_param%i_coord_from+my_offset
         END IF
         IF (colvar_in%mindist_param%use_kinds_to) THEN
            ! KINDS
            ndim = SIZE(colvar_in%mindist_param%k_coord_to)
            ALLOCATE (colvar_out%mindist_param%k_coord_to(ndim))
            colvar_out%mindist_param%k_coord_to = colvar_in%mindist_param%k_coord_to
         ELSE
            ! INDEX
            ndim = SIZE(colvar_in%mindist_param%i_coord_to)
            ALLOCATE (colvar_out%mindist_param%i_coord_to(ndim))
            colvar_out%mindist_param%i_coord_to = colvar_in%mindist_param%i_coord_to+my_offset
         END IF

      END SELECT
      CALL colvar_setup(colvar_out)
   END SUBROUTINE colvar_clone

! **************************************************************************************************
!> \brief Clone points type of a colvar type
!> \param colvar_out ...
!> \param colvar_in the colvar to deallocate
!> \param offset ...
!> \author Teodoro Laino [tlaino] 03.2007
! **************************************************************************************************
   SUBROUTINE colvar_clone_points(colvar_out, colvar_in, offset)
      TYPE(colvar_type), POINTER                         :: colvar_out, colvar_in
      INTEGER, INTENT(IN)                                :: offset

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_clone_points', &
         routineP = moduleN//':'//routineN

      INTEGER                                            :: i, natoms, npoints

      colvar_out%use_points = colvar_in%use_points
      IF (colvar_in%use_points) THEN
         CPASSERT(ASSOCIATED(colvar_in%points))
         npoints = SIZE(colvar_in%points)
         ALLOCATE (colvar_out%points(npoints))
         DO i = 1, npoints
            IF (ASSOCIATED(colvar_in%points(i)%atoms)) THEN
               natoms = SIZE(colvar_in%points(i)%atoms)
               ALLOCATE (colvar_out%points(i)%atoms(natoms))
               colvar_out%points(i)%atoms = colvar_in%points(i)%atoms+offset
            ELSE
               NULLIFY (colvar_out%points(i)%atoms)
            END IF
            IF (ASSOCIATED(colvar_in%points(i)%weights)) THEN
               natoms = SIZE(colvar_in%points(i)%weights)
               ALLOCATE (colvar_out%points(i)%weights(natoms))
               colvar_out%points(i)%weights = colvar_in%points(i)%weights
            ELSE
               NULLIFY (colvar_out%points(i)%weights)
            END IF
            colvar_out%points(i)%type_id = colvar_in%points(i)%type_id
            colvar_out%points(i)%r = colvar_in%points(i)%r
         END DO
      ELSE
         NULLIFY (colvar_out%points)
      END IF

   END SUBROUTINE colvar_clone_points

! **************************************************************************************************
!> \brief Change the dimension of a colvar_p_type
!> \param colvar_set ...
!> \param lb1_new ...
!> \param ub1_new ...
!> \author Teodoro Laino [tlaino] 04.2006
! **************************************************************************************************
   SUBROUTINE colvar_p_reallocate(colvar_set, lb1_new, ub1_new)
      TYPE(colvar_p_type), DIMENSION(:), POINTER         :: colvar_set
      INTEGER, INTENT(IN)                                :: lb1_new, ub1_new

      CHARACTER(len=*), PARAMETER :: routineN = 'colvar_p_reallocate', &
         routineP = moduleN//':'//routineN

      INTEGER                                            :: j, lb1, lb1_old, ub1, ub1_old
      TYPE(colvar_p_type), DIMENSION(:), POINTER         :: work

      NULLIFY (work)
      IF (ASSOCIATED(colvar_set)) THEN
         lb1_old = LBOUND(colvar_set, 1)
         ub1_old = UBOUND(colvar_set, 1)
         lb1 = MAX(lb1_new, lb1_old)
         ub1 = MIN(ub1_new, ub1_old)
         ALLOCATE (work(lb1:ub1))
         DO j = lb1, ub1
            NULLIFY (work(j)%colvar)
            CALL colvar_clone(work(j)%colvar, colvar_set(j)%colvar)
         END DO
         DO j = lb1, ub1
            CALL colvar_release(colvar_set(j)%colvar)
            NULLIFY (colvar_set(j)%colvar)
         END DO
         DEALLOCATE (colvar_set)
      END IF

      ALLOCATE (colvar_set(lb1_new:ub1_new))

      DO j = lb1_new, ub1_new
         NULLIFY (colvar_set(j)%colvar)
      END DO
      IF (ASSOCIATED(work)) THEN
         lb1 = MAX(lb1_new, lb1_old)
         ub1 = MIN(ub1_new, ub1_old)
         DO j = lb1, ub1
            CALL colvar_clone(colvar_set(j)%colvar, work(j)%colvar)
         END DO
         DO j = lb1, ub1
            CALL colvar_release(work(j)%colvar)
            NULLIFY (work(j)%colvar)
         END DO
         DEALLOCATE (work)
      END IF
   END SUBROUTINE colvar_p_reallocate

! **************************************************************************************************
!> \brief Deallocate a set of colvar_p_type
!> \param colvar_p ...
!> \par History
!>      07.2003 created [fawzi]
!>      01.2014 moved from cp_subsys_release() into separate routine.
!> \author Ole Schuett
! **************************************************************************************************
   SUBROUTINE colvar_p_release(colvar_p)
      TYPE(colvar_p_type), DIMENSION(:), POINTER         :: colvar_p

      INTEGER                                            :: i

! Colvar info

      IF (ASSOCIATED(colvar_p)) THEN
         DO i = 1, SIZE(colvar_p)
            IF (ASSOCIATED(colvar_p(i)%colvar)) &
               CALL colvar_release(colvar_p(i)%colvar)
         ENDDO
         DEALLOCATE (colvar_p)
      END IF
   END SUBROUTINE colvar_p_release

! **************************************************************************************************
!> \brief Evaluate the position of the geometrical point
!> \param point ...
!> \param particles ...
!> \param r ...
!> \author Teodoro Laino - 03.2007
! **************************************************************************************************
   SUBROUTINE eval_point_pos(point, particles, r)
      TYPE(point_type)                                   :: point
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles
      REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: r

      INTEGER                                            :: i

      SELECT CASE (point%type_id)
      CASE (do_clv_geo_center)
         r = 0.0_dp
         DO i = 1, SIZE(point%atoms)
            r = r+particles(point%atoms(i))%r*point%weights(i)
         END DO
      CASE (do_clv_fix_point)
         r = point%r
      END SELECT

   END SUBROUTINE eval_point_pos

! **************************************************************************************************
!> \brief ...
!> \param point ...
!> \param particles ...
!> \param m ...
! **************************************************************************************************
   SUBROUTINE eval_point_mass(point, particles, m)
      TYPE(point_type)                                   :: point
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles
      REAL(KIND=dp), INTENT(OUT)                         :: m

      INTEGER                                            :: i

      SELECT CASE (point%type_id)
      CASE (do_clv_geo_center)
         m = 0.0_dp
         DO i = 1, SIZE(point%atoms)
            m = m+particles(point%atoms(i))%atomic_kind%mass*point%weights(i)
         END DO
      CASE (do_clv_fix_point)
         m = 0.0_dp
      END SELECT

   END SUBROUTINE eval_point_mass

! **************************************************************************************************
!> \brief Evaluate the position of the geometrical point
!> \param points ...
!> \param i ...
!> \param dsdr ...
!> \param f ...
!> \author Teodoro Laino - 03.2007
! **************************************************************************************************
   SUBROUTINE eval_point_der(points, i, dsdr, f)
      TYPE(point_type), DIMENSION(:), POINTER            :: points
      INTEGER, INTENT(IN)                                :: i
      REAL(KIND=dp), DIMENSION(:, :), POINTER            :: dsdr
      REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: f

      INTEGER                                            :: ind, j
      REAL(KIND=dp)                                      :: fac

      SELECT CASE (points (i)%type_id)
      CASE (do_clv_geo_center)
         ind = 0
         DO j = 1, i-1
            IF (ASSOCIATED(points(j)%atoms)) THEN
               ind = ind+SIZE(points(j)%atoms)
            END IF
         END DO
         DO j = 1, SIZE(points(i)%atoms)
            fac = points(i)%weights(j)
            dsdr(:, ind+j) = dsdr(:, ind+j)+f*fac
         END DO
      CASE (do_clv_fix_point)
         ! Do nothing if it's a fixed point in space
      END SELECT

   END SUBROUTINE eval_point_der

! **************************************************************************************************
!> \brief subtract b from the ss value of a colvar: general function for handling
!>        periodic/non-periodic colvar
!> \param colvar ...
!> \param b ...
!> \return ...
!> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
! **************************************************************************************************
   FUNCTION diff_colvar(colvar, b) RESULT(diff)
      TYPE(colvar_type), POINTER                         :: colvar
      REAL(KIND=dp), INTENT(IN)                          :: b
      REAL(KIND=dp)                                      :: diff

      CHARACTER(len=*), PARAMETER :: routineN = 'diff_colvar', routineP = moduleN//':'//routineN

      diff = colvar%ss-b
      IF (colvar%type_id == torsion_colvar_id) THEN
         ! The difference of a periodic COLVAR is always within [-pi,pi]
         diff = SIGN(1.0_dp, ASIN(SIN(diff)))*ACOS(COS(diff))
      END IF
   END FUNCTION diff_colvar

END MODULE colvar_types
