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

! **************************************************************************************************
!> \brief defines collective variables s({R}) and the derivative of this variable wrt R
!>      these can then be used in constraints, restraints and metadynamics ...
!> \par History
!>      04.2004 created
!>      01.2006 Refactored [Joost VandeVondele]
!> \author Alessandro Laio,Fawzi Mohamed
! **************************************************************************************************
MODULE colvar_methods

   USE cell_types,                      ONLY: cell_type,&
                                              pbc
   USE colvar_types,                    ONLY: &
        HBP_colvar_id, Wc_colvar_id, acid_hyd_dist_colvar_id, acid_hyd_shell_colvar_id, &
        angle_colvar_id, colvar_create, colvar_setup, colvar_type, combine_colvar_id, &
        coord_colvar_id, dfunct_colvar_id, dist_colvar_id, distance_from_path_colvar_id, &
        do_clv_fix_point, do_clv_geo_center, do_clv_x, do_clv_xy, do_clv_xz, do_clv_y, do_clv_yz, &
        do_clv_z, eval_point_der, eval_point_mass, eval_point_pos, gyration_colvar_id, &
        hydronium_dist_colvar_id, hydronium_shell_colvar_id, mindist_colvar_id, plane_def_atoms, &
        plane_def_vec, plane_distance_colvar_id, plane_plane_angle_colvar_id, &
        population_colvar_id, qparm_colvar_id, reaction_path_colvar_id, ring_puckering_colvar_id, &
        rmsd_colvar_id, rotation_colvar_id, torsion_colvar_id, u_colvar_id, xyz_diag_colvar_id, &
        xyz_outerdiag_colvar_id
   USE constraint_fxd,                  ONLY: check_fixed_atom_cns_colv
   USE cp_log_handling,                 ONLY: cp_get_default_logger,&
                                              cp_logger_get_default_io_unit,&
                                              cp_logger_type,&
                                              cp_to_string
   USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
                                              cp_print_key_unit_nr
   USE cp_para_types,                   ONLY: cp_para_env_type
   USE cp_parser_methods,               ONLY: parser_get_next_line,&
                                              parser_get_object
   USE cp_parser_types,                 ONLY: cp_parser_type,&
                                              parser_create,&
                                              parser_release
   USE cp_subsys_types,                 ONLY: cp_subsys_get,&
                                              cp_subsys_p_type,&
                                              cp_subsys_type
   USE cp_units,                        ONLY: cp_unit_to_cp2k
   USE force_env_types,                 ONLY: force_env_get,&
                                              force_env_type,&
                                              use_mixed_force
   USE force_fields_util,               ONLY: get_generic_info
   USE fparser,                         ONLY: EvalErrType,&
                                              evalf,&
                                              evalfd,&
                                              finalizef,&
                                              initf,&
                                              parsef
   USE input_constants,                 ONLY: rmsd_all,&
                                              rmsd_list,&
                                              rmsd_weightlist
   USE input_cp2k_colvar,               ONLY: create_colvar_xyz_d_section,&
                                              create_colvar_xyz_od_section
   USE input_enumeration_types,         ONLY: enum_i2c,&
                                              enumeration_type
   USE input_keyword_types,             ONLY: keyword_get,&
                                              keyword_type
   USE input_section_types,             ONLY: section_get_keyword,&
                                              section_release,&
                                              section_type,&
                                              section_vals_get,&
                                              section_vals_get_subs_vals,&
                                              section_vals_type,&
                                              section_vals_val_get
   USE kahan_sum,                       ONLY: accurate_sum
   USE kinds,                           ONLY: default_path_length,&
                                              default_string_length,&
                                              dp
   USE mathconstants,                   ONLY: fac,&
                                              maxfac,&
                                              pi,&
                                              twopi
   USE mathlib,                         ONLY: vector_product
   USE memory_utilities,                ONLY: reallocate
   USE message_passing,                 ONLY: mp_sum,&
                                              mp_sync
   USE mixed_energy_types,              ONLY: mixed_force_type
   USE mixed_environment_utils,         ONLY: get_subsys_map_index
   USE molecule_kind_types,             ONLY: fixd_constraint_type
   USE particle_list_types,             ONLY: particle_list_p_type,&
                                              particle_list_type
   USE particle_types,                  ONLY: particle_type
   USE qs_environment_types,            ONLY: get_qs_env,&
                                              qs_environment_type
   USE rmsd,                            ONLY: rmsd3
   USE spherical_harmonics,             ONLY: dlegendre,&
                                              legendre
   USE string_utilities,                ONLY: compress,&
                                              uppercase
   USE wannier_states_types,            ONLY: wannier_centres_type
#include "./base/base_uses.f90"

   IMPLICIT NONE
   PRIVATE

   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'colvar_methods'
   REAL(KIND=dp), PRIVATE, PARAMETER    :: tolerance_acos = 1.0E-5_dp

   PUBLIC :: colvar_read, &
             colvar_eval_glob_f, &
             colvar_eval_mol_f

CONTAINS

! **************************************************************************************************
!> \brief reads a colvar from the input
!> \param colvar the place where to store what will be read
!> \param icol number of the current colvar (repetition in colvar_section)
!> \param colvar_section the colvar section
!> \param para_env ...
!> \par History
!>      04.2004 created [alessandro laio and fawzi mohamed]
!> \author teo
! **************************************************************************************************
   RECURSIVE SUBROUTINE colvar_read(colvar, icol, colvar_section, para_env)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: icol
      TYPE(section_vals_type), POINTER                   :: colvar_section
      TYPE(cp_para_env_type), POINTER                    :: para_env

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

      CHARACTER(LEN=3)                                   :: fmid
      CHARACTER(LEN=7)                                   :: tag, tag_comp, tag_comp1, tag_comp2
      CHARACTER(LEN=default_path_length)                 :: path_function
      CHARACTER(LEN=default_string_length)               :: tmpStr, tmpStr2
      CHARACTER(LEN=default_string_length), &
         DIMENSION(:), POINTER                           :: c_kinds, my_par
      INTEGER                                            :: handle, i, iatm, icomponent, iend, &
                                                            ifunc, ii, isize, istart, iw, iw1, j, &
                                                            k, kk, n_var, n_var_k, ncol, ndim, &
                                                            nr_frame, v_count
      INTEGER, DIMENSION(:), POINTER                     :: iatms
      INTEGER, DIMENSION(:, :), POINTER                  :: p_bounds
      LOGICAL                                            :: check, use_mixed_energy
      LOGICAL, DIMENSION(26)                             :: my_subsection
      REAL(dp), DIMENSION(:), POINTER                    :: s1, wei, weights
      REAL(dp), DIMENSION(:, :), POINTER                 :: p_range, s1v
      REAL(KIND=dp), DIMENSION(1)                        :: my_val
      REAL(KIND=dp), DIMENSION(:), POINTER               :: g_range, grid_point, grid_sp, my_vals, &
                                                            range
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(enumeration_type), POINTER                    :: enum
      TYPE(keyword_type), POINTER                        :: keyword
      TYPE(section_type), POINTER                        :: section
      TYPE(section_vals_type), POINTER :: acid_hyd_dist_section, acid_hyd_shell_section, &
         angle_section, colvar_subsection, combine_section, coordination_section, dfunct_section, &
         distance_from_path_section, distance_section, frame_section, gyration_section, &
         HBP_section, hydronium_dist_section, hydronium_shell_section, mindist_section, &
         path_section, plane_dist_section, plane_plane_angle_section, plane_sections, &
         point_section, population_section, qparm_section, reaction_path_section, &
         ring_puckering_section, rmsd_section, rotation_section, torsion_section, u_section, &
         Wc_section, wrk_section
      TYPE(section_vals_type), POINTER :: xyz_diag_section, xyz_outerdiag_section

      CALL timeset(routineN, handle)
      NULLIFY (logger, c_kinds, iatms)
      logger => cp_get_default_logger()
      my_subsection = .FALSE.
      distance_section => section_vals_get_subs_vals(colvar_section, "DISTANCE", i_rep_section=icol)
      dfunct_section => section_vals_get_subs_vals(colvar_section, "DISTANCE_FUNCTION", &
                                                   i_rep_section=icol)
      angle_section => section_vals_get_subs_vals(colvar_section, "ANGLE", i_rep_section=icol)
      torsion_section => section_vals_get_subs_vals(colvar_section, "TORSION", i_rep_section=icol)
      coordination_section => section_vals_get_subs_vals(colvar_section, "COORDINATION", i_rep_section=icol)
      plane_dist_section => section_vals_get_subs_vals(colvar_section, "DISTANCE_POINT_PLANE", i_rep_section=icol)
      plane_plane_angle_section &
         => section_vals_get_subs_vals(colvar_section, "ANGLE_PLANE_PLANE", i_rep_section=icol)
      rotation_section => section_vals_get_subs_vals(colvar_section, "BOND_ROTATION", i_rep_section=icol)
      qparm_section => section_vals_get_subs_vals(colvar_section, "QPARM", i_rep_section=icol)
      hydronium_shell_section => section_vals_get_subs_vals(colvar_section, "HYDRONIUM_SHELL", i_rep_section=icol)
      hydronium_dist_section => section_vals_get_subs_vals(colvar_section, "HYDRONIUM_DISTANCE", i_rep_section=icol)
      acid_hyd_dist_section => section_vals_get_subs_vals(colvar_section, "ACID_HYDRONIUM_DISTANCE", i_rep_section=icol)
      acid_hyd_shell_section &
         => section_vals_get_subs_vals(colvar_section, "ACID_HYDRONIUM_SHELL", i_rep_section=icol)
      reaction_path_section => section_vals_get_subs_vals(colvar_section, "REACTION_PATH", i_rep_section=icol, &
                                                          can_return_null=.TRUE.)
      distance_from_path_section &
         => section_vals_get_subs_vals(colvar_section, "DISTANCE_FROM_PATH", &
                                       i_rep_section=icol, can_return_null=.TRUE.)
      combine_section => section_vals_get_subs_vals(colvar_section, "COMBINE_COLVAR", i_rep_section=icol, &
                                                    can_return_null=.TRUE.)
      population_section => section_vals_get_subs_vals(colvar_section, "POPULATION", i_rep_section=icol)
      gyration_section => section_vals_get_subs_vals(colvar_section, "GYRATION_RADIUS", i_rep_section=icol)
      rmsd_section => section_vals_get_subs_vals(colvar_section, "RMSD", i_rep_section=icol)
      xyz_diag_section => section_vals_get_subs_vals(colvar_section, "XYZ_DIAG", i_rep_section=icol)
      xyz_outerdiag_section => section_vals_get_subs_vals(colvar_section, "XYZ_OUTERDIAG", i_rep_section=icol)
      u_section => section_vals_get_subs_vals(colvar_section, "U", i_rep_section=icol)
      Wc_section => section_vals_get_subs_vals(colvar_section, "WC", i_rep_section=icol)
      HBP_section => section_vals_get_subs_vals(colvar_section, "HBP", i_rep_section=icol)
      ring_puckering_section &
         => section_vals_get_subs_vals(colvar_section, "RING_PUCKERING", i_rep_section=icol)
      mindist_section => section_vals_get_subs_vals(colvar_section, "CONDITIONED_DISTANCE", i_rep_section=icol)

      CALL section_vals_get(distance_section, explicit=my_subsection(1))
      CALL section_vals_get(angle_section, explicit=my_subsection(2))
      CALL section_vals_get(torsion_section, explicit=my_subsection(3))
      CALL section_vals_get(coordination_section, explicit=my_subsection(4))
      CALL section_vals_get(plane_dist_section, explicit=my_subsection(5))
      CALL section_vals_get(rotation_section, explicit=my_subsection(6))
      CALL section_vals_get(dfunct_section, explicit=my_subsection(7))
      CALL section_vals_get(qparm_section, explicit=my_subsection(8))
      CALL section_vals_get(hydronium_shell_section, explicit=my_subsection(9))
      ! These are just special cases since they are not present in their own defition of COLVARS
      IF (ASSOCIATED(reaction_path_section)) THEN
         CALL section_vals_get(reaction_path_section, &
                               explicit=my_subsection(10))
      END IF
      IF (ASSOCIATED(distance_from_path_section)) THEN
         CALL section_vals_get(distance_from_path_section, &
                               explicit=my_subsection(16))
      END IF
      IF (ASSOCIATED(combine_section)) THEN
         CALL section_vals_get(combine_section, explicit=my_subsection(11))
      END IF
      CALL section_vals_get(population_section, explicit=my_subsection(12))
      CALL section_vals_get(plane_plane_angle_section, &
                            explicit=my_subsection(13))
      CALL section_vals_get(gyration_section, explicit=my_subsection(14))
      CALL section_vals_get(rmsd_section, explicit=my_subsection(15))
      CALL section_vals_get(xyz_diag_section, explicit=my_subsection(17))
      CALL section_vals_get(xyz_outerdiag_section, explicit=my_subsection(18))
      CALL section_vals_get(u_section, explicit=my_subsection(19))
      CALL section_vals_get(Wc_section, explicit=my_subsection(20))
      CALL section_vals_get(HBP_section, explicit=my_subsection(21))
      CALL section_vals_get(ring_puckering_section, &
                            explicit=my_subsection(22))
      CALL section_vals_get(mindist_section, explicit=my_subsection(23))
      CALL section_vals_get(acid_hyd_dist_section, explicit=my_subsection(24))
      CALL section_vals_get(acid_hyd_shell_section, explicit=my_subsection(25))
      CALL section_vals_get(hydronium_dist_section, explicit=my_subsection(26))

      ! Only one colvar can be present
      CPASSERT(COUNT(my_subsection) == 1)
      CPASSERT(.NOT. ASSOCIATED(colvar))

      IF (my_subsection(1)) THEN
         ! Distance
         wrk_section => distance_section
         CALL colvar_create(colvar, dist_colvar_id)
         CALL colvar_check_points(colvar, distance_section)
         CALL section_vals_val_get(distance_section, "ATOMS", i_vals=iatms)
         colvar%dist_param%i_at = iatms(1)
         colvar%dist_param%j_at = iatms(2)
         CALL section_vals_val_get(distance_section, "AXIS", i_val=colvar%dist_param%axis_id)
      ELSE IF (my_subsection(2)) THEN
         ! Angle
         wrk_section => angle_section
         CALL colvar_create(colvar, angle_colvar_id)
         CALL colvar_check_points(colvar, angle_section)
         CALL section_vals_val_get(angle_section, "ATOMS", i_vals=iatms)
         colvar%angle_param%i_at_angle = iatms
      ELSE IF (my_subsection(3)) THEN
         ! Torsion
         wrk_section => torsion_section
         CALL colvar_create(colvar, torsion_colvar_id)
         CALL colvar_check_points(colvar, torsion_section)
         CALL section_vals_val_get(torsion_section, "ATOMS", i_vals=iatms)
         colvar%torsion_param%i_at_tors = iatms
         colvar%torsion_param%o0 = 0.0_dp
      ELSE IF (my_subsection(4)) THEN
         ! Coordination
         wrk_section => coordination_section
         CALL colvar_create(colvar, coord_colvar_id)
         CALL colvar_check_points(colvar, coordination_section)
         NULLIFY (colvar%coord_param%i_at_from, colvar%coord_param%c_kinds_from)
         NULLIFY (colvar%coord_param%i_at_to, colvar%coord_param%c_kinds_to)
         NULLIFY (colvar%coord_param%i_at_to_b, colvar%coord_param%c_kinds_to_b)
         ! This section can be repeated
         CALL section_vals_val_get(coordination_section, "ATOMS_FROM", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(coordination_section, "ATOMS_FROM", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%coord_param%i_at_from, 1, ndim+SIZE(iatms))
               colvar%coord_param%i_at_from(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%coord_param%n_atoms_from = ndim
            colvar%coord_param%use_kinds_from = .FALSE.
         ELSE
            ! KINDS
            CALL section_vals_val_get(coordination_section, "KINDS_FROM", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(coordination_section, "KINDS_FROM", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%coord_param%c_kinds_from, 1, ndim+SIZE(c_kinds))
               colvar%coord_param%c_kinds_from(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%coord_param%n_atoms_from = 0
            colvar%coord_param%use_kinds_from = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%coord_param%c_kinds_from(k))
            END DO
         END IF
         ! This section can be repeated
         CALL section_vals_val_get(coordination_section, "ATOMS_TO", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(coordination_section, "ATOMS_TO", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%coord_param%i_at_to, 1, ndim+SIZE(iatms))
               colvar%coord_param%i_at_to(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%coord_param%n_atoms_to = ndim
            colvar%coord_param%use_kinds_to = .FALSE.
         ELSE
            ! KINDS
            CALL section_vals_val_get(coordination_section, "KINDS_TO", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(coordination_section, "KINDS_TO", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%coord_param%c_kinds_to, 1, ndim+SIZE(c_kinds))
               colvar%coord_param%c_kinds_to(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%coord_param%n_atoms_to = 0
            colvar%coord_param%use_kinds_to = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%coord_param%c_kinds_to(k))
            END DO
         END IF
         ! Let's finish reading the other parameters
         CALL section_vals_val_get(coordination_section, "R0", r_val=colvar%coord_param%r_0)
         CALL section_vals_val_get(coordination_section, "NN", i_val=colvar%coord_param%nncrd)
         CALL section_vals_val_get(coordination_section, "ND", i_val=colvar%coord_param%ndcrd)
         ! This section can be repeated
         CALL section_vals_val_get(coordination_section, "ATOMS_TO_B", n_rep_val=n_var)
         CALL section_vals_val_get(coordination_section, "KINDS_TO_B", n_rep_val=n_var_k)
         ndim = 0
         IF (n_var /= 0 .OR. n_var_k /= 0) THEN
            colvar%coord_param%do_chain = .TRUE.
            IF (n_var /= 0) THEN
               ! INDEX LIST
               DO k = 1, n_var
                  CALL section_vals_val_get(coordination_section, "ATOMS_TO_B", i_rep_val=k, i_vals=iatms)
                  CALL reallocate(colvar%coord_param%i_at_to_b, 1, ndim+SIZE(iatms))
                  colvar%coord_param%i_at_to_b(ndim+1:ndim+SIZE(iatms)) = iatms
                  ndim = ndim+SIZE(iatms)
               END DO
               colvar%coord_param%n_atoms_to_b = ndim
               colvar%coord_param%use_kinds_to_b = .FALSE.
            ELSE
               ! KINDS
               CALL section_vals_val_get(coordination_section, "KINDS_TO_B", n_rep_val=n_var_k)
               CPASSERT(n_var_k > 0)
               DO k = 1, n_var_k
                  CALL section_vals_val_get(coordination_section, "KINDS_TO_B", i_rep_val=k, c_vals=c_kinds)
                  CALL reallocate(colvar%coord_param%c_kinds_to_b, 1, ndim+SIZE(c_kinds))
                  colvar%coord_param%c_kinds_to_b(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
                  ndim = ndim+SIZE(c_kinds)
               END DO
               colvar%coord_param%n_atoms_to_b = 0
               colvar%coord_param%use_kinds_to_b = .TRUE.
               ! Uppercase the label
               DO k = 1, ndim
                  CALL uppercase(colvar%coord_param%c_kinds_to_b(k))
               END DO
            END IF
            ! Let's finish reading the other parameters
            CALL section_vals_val_get(coordination_section, "R0_B", r_val=colvar%coord_param%r_0_b)
            CALL section_vals_val_get(coordination_section, "NN_B", i_val=colvar%coord_param%nncrd_b)
            CALL section_vals_val_get(coordination_section, "ND_B", i_val=colvar%coord_param%ndcrd_b)
         ELSE
            colvar%coord_param%do_chain = .FALSE.
            colvar%coord_param%n_atoms_to_b = 0
            colvar%coord_param%use_kinds_to_b = .FALSE.
            NULLIFY (colvar%coord_param%i_at_to_b)
            NULLIFY (colvar%coord_param%c_kinds_to_b)
            colvar%coord_param%nncrd_b = 0
            colvar%coord_param%ndcrd_b = 0
            colvar%coord_param%r_0_b = 0._dp
         END IF

      ELSE IF (my_subsection(5)) THEN
         ! Distance point from plane
         wrk_section => plane_dist_section
         CALL colvar_create(colvar, plane_distance_colvar_id)
         CALL colvar_check_points(colvar, plane_dist_section)
         CALL section_vals_val_get(plane_dist_section, "ATOMS_PLANE", i_vals=iatms)
         CPASSERT(SIZE(iatms) == 3)
         colvar%plane_distance_param%plane = iatms
         CALL section_vals_val_get(plane_dist_section, "ATOM_POINT", i_val=iatm)
         colvar%plane_distance_param%point = iatm
         CALL section_vals_val_get(plane_dist_section, "PBC", l_val=colvar%plane_distance_param%use_pbc)
      ELSE IF (my_subsection(6)) THEN
         ! Rotation colvar of a segment w.r.t. another segment
         wrk_section => rotation_section
         CALL colvar_create(colvar, rotation_colvar_id)
         CALL colvar_check_points(colvar, rotation_section)
         CALL section_vals_val_get(rotation_section, "P1_BOND1", i_val=colvar%rotation_param%i_at1_bond1)
         CALL section_vals_val_get(rotation_section, "P2_BOND1", i_val=colvar%rotation_param%i_at2_bond1)
         CALL section_vals_val_get(rotation_section, "P1_BOND2", i_val=colvar%rotation_param%i_at1_bond2)
         CALL section_vals_val_get(rotation_section, "P2_BOND2", i_val=colvar%rotation_param%i_at2_bond2)
      ELSE IF (my_subsection(7)) THEN
         ! Difference of two distances
         wrk_section => dfunct_section
         CALL colvar_create(colvar, dfunct_colvar_id)
         CALL colvar_check_points(colvar, dfunct_section)
         CALL section_vals_val_get(dfunct_section, "ATOMS", i_vals=iatms)
         colvar%dfunct_param%i_at_dfunct = iatms
         CALL section_vals_val_get(dfunct_section, "COEFFICIENT", r_val=colvar%dfunct_param%coeff)
         CALL section_vals_val_get(dfunct_section, "PBC", l_val=colvar%dfunct_param%use_pbc)
      ELSE IF (my_subsection(8)) THEN
         ! Q Parameter
         wrk_section => qparm_section
         CALL colvar_create(colvar, qparm_colvar_id)
         CALL colvar_check_points(colvar, qparm_section)
         CALL section_vals_val_get(qparm_section, "RCUT", r_val=colvar%qparm_param%rcut)
         CALL section_vals_val_get(qparm_section, "RSTART", r_val=colvar%qparm_param%rstart)
         CALL section_vals_val_get(qparm_section, "INCLUDE_IMAGES", l_val=colvar%qparm_param%include_images)
         !CALL section_vals_val_get(qparm_section, "ALPHA", r_val=colvar%qparm_param%alpha)
         CALL section_vals_val_get(qparm_section, "L", i_val=colvar%qparm_param%l)
         NULLIFY (colvar%qparm_param%i_at_from)
         NULLIFY (colvar%qparm_param%i_at_to)
         CALL section_vals_val_get(qparm_section, "ATOMS_FROM", n_rep_val=n_var)
         ndim = 0
         DO k = 1, n_var
            CALL section_vals_val_get(qparm_section, "ATOMS_FROM", i_rep_val=k, i_vals=iatms)
            CALL reallocate(colvar%qparm_param%i_at_from, 1, ndim+SIZE(iatms))
            colvar%qparm_param%i_at_from(ndim+1:ndim+SIZE(iatms)) = iatms
            ndim = ndim+SIZE(iatms)
         END DO
         colvar%qparm_param%n_atoms_from = ndim
         ! This section can be repeated
         CALL section_vals_val_get(qparm_section, "ATOMS_TO", n_rep_val=n_var)
         ndim = 0
         DO k = 1, n_var
            CALL section_vals_val_get(qparm_section, "ATOMS_TO", i_rep_val=k, i_vals=iatms)
            CALL reallocate(colvar%qparm_param%i_at_to, 1, ndim+SIZE(iatms))
            colvar%qparm_param%i_at_to(ndim+1:ndim+SIZE(iatms)) = iatms
            ndim = ndim+SIZE(iatms)
         END DO
         colvar%qparm_param%n_atoms_to = ndim
      ELSE IF (my_subsection(9)) THEN
         ! Hydronium
         CALL colvar_create(colvar, hydronium_shell_colvar_id)
         NULLIFY (colvar%hydronium_shell_param%i_oxygens)
         NULLIFY (colvar%hydronium_shell_param%i_hydrogens)
         CALL read_hydronium_colvars(hydronium_shell_section, colvar, hydronium_shell_colvar_id, &
                                     colvar%hydronium_shell_param%n_oxygens, &
                                     colvar%hydronium_shell_param%n_hydrogens, &
                                     colvar%hydronium_shell_param%i_oxygens, &
                                     colvar%hydronium_shell_param%i_hydrogens)
      ELSE IF (my_subsection(10) .OR. my_subsection(16)) THEN
         !reaction path or distance from reaction path
         IF (my_subsection(10)) THEN
            path_section => reaction_path_section
            CALL colvar_create(colvar, reaction_path_colvar_id)
            fmid = "POS"
            ifunc = 1
         ELSE IF (my_subsection(16)) THEN
            path_section => distance_from_path_section
            CALL colvar_create(colvar, distance_from_path_colvar_id)
            fmid = "DIS"
            ifunc = 2
         END IF
         colvar%use_points = .FALSE.
         CALL section_vals_val_get(path_section, "LAMBDA", r_val=colvar%reaction_path_param%lambda)
         CALL section_vals_val_get(path_section, "DISTANCES_RMSD", l_val=colvar%reaction_path_param%dist_rmsd)
         CALL section_vals_val_get(path_section, "RMSD", l_val=colvar%reaction_path_param%rmsd)
         IF (colvar%reaction_path_param%dist_rmsd .AND. colvar%reaction_path_param%rmsd) THEN
            CPABORT("CV REACTION PATH: only one between DISTANCES_RMSD and RMSD can be used ")
         END IF
         IF (colvar%reaction_path_param%dist_rmsd .OR. colvar%reaction_path_param%rmsd) THEN
            NULLIFY (colvar%reaction_path_param%i_rmsd, colvar%reaction_path_param%r_ref)
            frame_section => section_vals_get_subs_vals(path_section, "FRAME")
            CALL section_vals_get(frame_section, n_repetition=nr_frame)

            colvar%reaction_path_param%nr_frames = nr_frame
            CALL read_frames(frame_section, para_env, nr_frame, colvar%reaction_path_param%r_ref, &
                             colvar%reaction_path_param%n_components)
            CALL section_vals_val_get(path_section, "SUBSET_TYPE", i_val=colvar%reaction_path_param%subset)
            IF (colvar%reaction_path_param%subset == rmsd_all) THEN
               ALLOCATE (colvar%reaction_path_param%i_rmsd(colvar%reaction_path_param%n_components))
               DO i = 1, colvar%reaction_path_param%n_components
                  colvar%reaction_path_param%i_rmsd(i) = i
               END DO
            ELSE IF (colvar%reaction_path_param%subset == rmsd_list) THEN
               ! This section can be repeated
               CALL section_vals_val_get(path_section, "ATOMS", n_rep_val=n_var)
               ndim = 0
               IF (n_var /= 0) THEN
                  ! INDEX LIST
                  DO k = 1, n_var
                     CALL section_vals_val_get(path_section, "ATOMS", i_rep_val=k, i_vals=iatms)
                     CALL reallocate(colvar%reaction_path_param%i_rmsd, 1, ndim+SIZE(iatms))
                     colvar%reaction_path_param%i_rmsd(ndim+1:ndim+SIZE(iatms)) = iatms
                     ndim = ndim+SIZE(iatms)
                  END DO
                  colvar%reaction_path_param%n_components = ndim
               ELSE
                  CPABORT("CV REACTION PATH: if SUBSET_TYPE=LIST a list of atoms needs to be provided ")
               END IF
            END IF

            CALL section_vals_val_get(path_section, "ALIGN_FRAMES", l_val=colvar%reaction_path_param%align_frames)
         ELSE
            colvar_subsection => section_vals_get_subs_vals(path_section, "COLVAR")
            CALL section_vals_get(colvar_subsection, n_repetition=ncol)
            ALLOCATE (colvar%reaction_path_param%colvar_p(ncol))
            IF (ncol > 0) THEN
               DO i = 1, ncol
                  NULLIFY (colvar%reaction_path_param%colvar_p(i)%colvar)
                  CALL colvar_read(colvar%reaction_path_param%colvar_p(i)%colvar, i, colvar_subsection, para_env)
               ENDDO
            ELSE
               CPABORT("CV REACTION PATH: the number of CV to define the path must be >0 ")
            ENDIF
            colvar%reaction_path_param%n_components = ncol
            NULLIFY (range)
            CALL section_vals_val_get(path_section, "RANGE", r_vals=range)
            CALL section_vals_val_get(path_section, "STEP_SIZE", r_val=colvar%reaction_path_param%step_size)
            iend = CEILING(MAX(RANGE(1), RANGE(2))/colvar%reaction_path_param%step_size)
            istart = FLOOR(MIN(RANGE(1), RANGE(2))/colvar%reaction_path_param%step_size)
            colvar%reaction_path_param%function_bounds(1) = istart
            colvar%reaction_path_param%function_bounds(2) = iend
            colvar%reaction_path_param%nr_frames = 2 !iend - istart + 1
            ALLOCATE (colvar%reaction_path_param%f_vals(ncol, istart:iend))
            CALL section_vals_val_get(path_section, "VARIABLE", c_vals=my_par, i_rep_val=1)
            CALL section_vals_val_get(path_section, "FUNCTION", n_rep_val=ncol)
            check = (ncol == SIZE(colvar%reaction_path_param%colvar_p))
            CPASSERT(check)
            CALL initf(ncol)
            DO i = 1, ncol
               CALL section_vals_val_get(path_section, "FUNCTION", c_val=path_function, i_rep_val=i)
               CALL compress(path_function, full=.TRUE.)
               CALL parsef(i, TRIM(path_function), my_par)
               DO j = istart, iend
                  my_val = REAL(j, kind=dp)*colvar%reaction_path_param%step_size
                  colvar%reaction_path_param%f_vals(i, j) = evalf(i, my_val)
               END DO
            END DO
            CALL finalizef()

            iw1 = cp_print_key_unit_nr(logger, path_section, &
                                       "MAP", middle_name=fmid, extension=".dat", file_status="REPLACE")
            IF (iw1 > 0) THEN
               CALL section_vals_val_get(path_section, "MAP%GRID_SPACING", n_rep_val=ncol)
               ALLOCATE (grid_sp(ncol))
               DO i = 1, ncol
                  CALL section_vals_val_get(path_section, "MAP%GRID_SPACING", r_val=grid_sp(i))
               END DO
               CALL section_vals_val_get(path_section, "MAP%RANGE", n_rep_val=ncol)
               CPASSERT(ncol == SIZE(grid_sp))
               ALLOCATE (p_range(2, ncol))
               ALLOCATE (p_bounds(2, ncol))
               DO i = 1, ncol
                  CALL section_vals_val_get(path_section, "MAP%RANGE", r_vals=g_range)
                  p_range(:, i) = g_range(:)
                  p_bounds(2, i) = CEILING(MAX(p_range(1, i), p_range(2, i))/grid_sp(i))
                  p_bounds(1, i) = FLOOR(MIN(p_range(1, i), p_range(2, i))/grid_sp(i))
               END DO
               ALLOCATE (s1v(2, istart:iend))
               ALLOCATE (s1(2))
               ALLOCATE (grid_point(ncol))
               v_count = 0
               kk = rec_eval_grid(iw1, ncol, colvar%reaction_path_param%f_vals, v_count, &
                                  grid_point, grid_sp, colvar%reaction_path_param%step_size, istart, &
                                  iend, s1v, s1, p_bounds, colvar%reaction_path_param%lambda, ifunc=ifunc, &
                                  nconf=colvar%reaction_path_param%nr_frames)
               DEALLOCATE (grid_sp)
               DEALLOCATE (p_range)
               DEALLOCATE (p_bounds)
               DEALLOCATE (s1v)
               DEALLOCATE (s1)
               DEALLOCATE (grid_point)
            END IF
            CALL cp_print_key_finished_output(iw1, logger, path_section, &
                                              "MAP")
         END IF

      ELSE IF (my_subsection(11)) THEN
         ! combine colvar
         CALL colvar_create(colvar, combine_colvar_id)
         colvar%use_points = .FALSE.
         colvar_subsection => section_vals_get_subs_vals(combine_section, "COLVAR")
         CALL section_vals_get(colvar_subsection, n_repetition=ncol)
         ALLOCATE (colvar%combine_cvs_param%colvar_p(ncol))
         ! In case we need to print some information..
         iw = cp_print_key_unit_nr(logger, colvar_section, &
                                   "PRINT%PROGRAM_RUN_INFO", extension=".colvarLog")
         IF (iw > 0) THEN
            WRITE (iw, '( A )') '          '// &
               '**********************************************************************'
            WRITE (iw, '( A,I8)') ' COLVARS| COLVAR INPUT INDEX: ', icol
            WRITE (iw, '( A,T49,4I8)') ' COLVARS| COMBINATION OF THE FOLOWING COLVARS:'
         END IF
         CALL cp_print_key_finished_output(iw, logger, colvar_section, &
                                           "PRINT%PROGRAM_RUN_INFO")
         ! Parsing the real COLVARs
         DO i = 1, ncol
            NULLIFY (colvar%combine_cvs_param%colvar_p(i)%colvar)
            CALL colvar_read(colvar%combine_cvs_param%colvar_p(i)%colvar, i, colvar_subsection, para_env)
         END DO
         ! Function definition
         CALL section_vals_val_get(combine_section, "FUNCTION", c_val=colvar%combine_cvs_param%function)
         CALL compress(colvar%combine_cvs_param%function, full=.TRUE.)
         ! Variables
         CALL section_vals_val_get(combine_section, "VARIABLES", c_vals=my_par)
         ALLOCATE (colvar%combine_cvs_param%variables(SIZE(my_par)))
         colvar%combine_cvs_param%variables = my_par
         ! Check that the number of COLVAR provided is equal to the number of variables..
         IF (SIZE(my_par) /= ncol) &
            CALL cp_abort(__LOCATION__, &
                          "Number of defined COLVAR for COMBINE_COLVAR is different from the "// &
                          "number of variables! It is not possible to define COLVARs in a COMBINE_COLVAR "// &
                          "and avoid their usage in the combininig function!")
         ! Parameters
         ALLOCATE (colvar%combine_cvs_param%c_parameters(0))
         CALL section_vals_val_get(combine_section, "PARAMETERS", n_rep_val=ncol)
         DO i = 1, ncol
            isize = SIZE(colvar%combine_cvs_param%c_parameters)
            CALL section_vals_val_get(combine_section, "PARAMETERS", c_vals=my_par, i_rep_val=i)
            CALL reallocate(colvar%combine_cvs_param%c_parameters, 1, isize+SIZE(my_par))
            colvar%combine_cvs_param%c_parameters(isize+1:isize+SIZE(my_par)) = my_par
         END DO
         ALLOCATE (colvar%combine_cvs_param%v_parameters(0))
         CALL section_vals_val_get(combine_section, "VALUES", n_rep_val=ncol)
         DO i = 1, ncol
            isize = SIZE(colvar%combine_cvs_param%v_parameters)
            CALL section_vals_val_get(combine_section, "VALUES", r_vals=my_vals, i_rep_val=i)
            CALL reallocate(colvar%combine_cvs_param%v_parameters, 1, isize+SIZE(my_vals))
            colvar%combine_cvs_param%v_parameters(isize+1:isize+SIZE(my_vals)) = my_vals
         END DO
         ! Info on derivative evaluation
         CALL section_vals_val_get(combine_section, "DX", r_val=colvar%combine_cvs_param%dx)
         CALL section_vals_val_get(combine_section, "ERROR_LIMIT", r_val=colvar%combine_cvs_param%lerr)
      ELSE IF (my_subsection(12)) THEN
         ! Population
         wrk_section => population_section
         CALL colvar_create(colvar, population_colvar_id)
         CALL colvar_check_points(colvar, population_section)

         NULLIFY (colvar%population_param%i_at_from, colvar%population_param%c_kinds_from)
         NULLIFY (colvar%population_param%i_at_to, colvar%population_param%c_kinds_to)
         ! This section can be repeated

         CALL section_vals_val_get(population_section, "ATOMS_FROM", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(population_section, "ATOMS_FROM", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%population_param%i_at_from, 1, ndim+SIZE(iatms))
               colvar%population_param%i_at_from(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%population_param%n_atoms_from = ndim
            colvar%population_param%use_kinds_from = .FALSE.
         ELSE
            ! KINDS
            CALL section_vals_val_get(population_section, "KINDS_FROM", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(population_section, "KINDS_FROM", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%population_param%c_kinds_from, 1, ndim+SIZE(c_kinds))
               colvar%population_param%c_kinds_from(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%population_param%n_atoms_from = 0
            colvar%population_param%use_kinds_from = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%population_param%c_kinds_from(k))
            END DO
         END IF
         ! This section can be repeated
         CALL section_vals_val_get(population_section, "ATOMS_TO", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(population_section, "ATOMS_TO", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%population_param%i_at_to, 1, ndim+SIZE(iatms))
               colvar%population_param%i_at_to(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%population_param%n_atoms_to = ndim
            colvar%population_param%use_kinds_to = .FALSE.
         ELSE
            ! KINDS
            CALL section_vals_val_get(population_section, "KINDS_TO", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(population_section, "KINDS_TO", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%population_param%c_kinds_to, 1, ndim+SIZE(c_kinds))
               colvar%population_param%c_kinds_to(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%population_param%n_atoms_to = 0
            colvar%population_param%use_kinds_to = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%population_param%c_kinds_to(k))
            END DO
         END IF
         ! Let's finish reading the other parameters
         CALL section_vals_val_get(population_section, "R0", r_val=colvar%population_param%r_0)
         CALL section_vals_val_get(population_section, "NN", i_val=colvar%population_param%nncrd)
         CALL section_vals_val_get(population_section, "ND", i_val=colvar%population_param%ndcrd)
         CALL section_vals_val_get(population_section, "N0", i_val=colvar%population_param%n0)
         CALL section_vals_val_get(population_section, "SIGMA", r_val=colvar%population_param%sigma)
      ELSE IF (my_subsection(13)) THEN
         ! Angle between two planes
         wrk_section => plane_plane_angle_section
         CALL colvar_create(colvar, plane_plane_angle_colvar_id)
         CALL colvar_check_points(colvar, plane_plane_angle_section)
         ! Read the specification of the two planes
         plane_sections => section_vals_get_subs_vals(plane_plane_angle_section, "PLANE")
         CALL section_vals_get(plane_sections, n_repetition=n_var)
         IF (n_var /= 2) &
            CPABORT("PLANE_PLANE_ANGLE Colvar section: Two PLANE sections must be provided!")
         ! Plane 1
         CALL section_vals_val_get(plane_sections, "DEF_TYPE", i_rep_section=1, &
                                   i_val=colvar%plane_plane_angle_param%plane1%type_of_def)
         IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_vec) THEN
            CALL section_vals_val_get(plane_sections, "NORMAL_VECTOR", i_rep_section=1, &
                                      r_vals=s1)
            colvar%plane_plane_angle_param%plane1%normal_vec = s1
         ELSE
            CALL section_vals_val_get(plane_sections, "ATOMS", i_rep_section=1, &
                                      i_vals=iatms)
            colvar%plane_plane_angle_param%plane1%points = iatms
         END IF

         ! Plane 2
         CALL section_vals_val_get(plane_sections, "DEF_TYPE", i_rep_section=2, &
                                   i_val=colvar%plane_plane_angle_param%plane2%type_of_def)
         IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_vec) THEN
            CALL section_vals_val_get(plane_sections, "NORMAL_VECTOR", i_rep_section=2, &
                                      r_vals=s1)
            colvar%plane_plane_angle_param%plane2%normal_vec = s1
         ELSE
            CALL section_vals_val_get(plane_sections, "ATOMS", i_rep_section=2, &
                                      i_vals=iatms)
            colvar%plane_plane_angle_param%plane2%points = iatms
         END IF
      ELSE IF (my_subsection(14)) THEN
         ! Gyration Radius
         wrk_section => gyration_section
         CALL colvar_create(colvar, gyration_colvar_id)
         CALL colvar_check_points(colvar, gyration_section)

         NULLIFY (colvar%gyration_param%i_at, colvar%gyration_param%c_kinds)

         ! This section can be repeated
         CALL section_vals_val_get(gyration_section, "ATOMS", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(gyration_section, "ATOMS", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%gyration_param%i_at, 1, ndim+SIZE(iatms))
               colvar%gyration_param%i_at(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%gyration_param%n_atoms = ndim
            colvar%gyration_param%use_kinds = .FALSE.
         ELSE
            ! KINDS
            CALL section_vals_val_get(gyration_section, "KINDS", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(gyration_section, "KINDS", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%gyration_param%c_kinds, 1, ndim+SIZE(c_kinds))
               colvar%gyration_param%c_kinds(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%gyration_param%n_atoms = 0
            colvar%gyration_param%use_kinds = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%gyration_param%c_kinds(k))
            END DO
         END IF
      ELSE IF (my_subsection(15)) THEN
         ! RMSD_AB
         wrk_section => rmsd_section
         CALL colvar_create(colvar, rmsd_colvar_id)

         NULLIFY (colvar%rmsd_param%i_rmsd, colvar%rmsd_param%r_ref, colvar%rmsd_param%weights)

         frame_section => section_vals_get_subs_vals(rmsd_section, "FRAME")
         CALL section_vals_get(frame_section, n_repetition=nr_frame)

         colvar%rmsd_param%nr_frames = nr_frame
         ! Calculation is aborted if reference frame are less than 2
         CPASSERT(nr_frame >= 1 .AND. nr_frame <= 2)
         CALL read_frames(frame_section, para_env, nr_frame, colvar%rmsd_param%r_ref, &
                          colvar%rmsd_param%n_atoms)

         ALLOCATE (colvar%rmsd_param%weights(colvar%rmsd_param%n_atoms))
         colvar%rmsd_param%weights = 0.0_dp

         CALL section_vals_val_get(rmsd_section, "SUBSET_TYPE", i_val=colvar%rmsd_param%subset)
         IF (colvar%rmsd_param%subset == rmsd_all) THEN
            ALLOCATE (colvar%rmsd_param%i_rmsd(colvar%rmsd_param%n_atoms))
            DO i = 1, colvar%rmsd_param%n_atoms
               colvar%rmsd_param%i_rmsd(i) = i
            END DO
         ELSE IF (colvar%rmsd_param%subset == rmsd_list) THEN
            ! This section can be repeated
            CALL section_vals_val_get(rmsd_section, "ATOMS", n_rep_val=n_var)
            ndim = 0
            IF (n_var /= 0) THEN
               ! INDEX LIST
               DO k = 1, n_var
                  CALL section_vals_val_get(rmsd_section, "ATOMS", i_rep_val=k, i_vals=iatms)
                  CALL reallocate(colvar%rmsd_param%i_rmsd, 1, ndim+SIZE(iatms))
                  colvar%rmsd_param%i_rmsd(ndim+1:ndim+SIZE(iatms)) = iatms
                  ndim = ndim+SIZE(iatms)
               END DO
               colvar%rmsd_param%n_atoms = ndim
            ELSE
               CPABORT("CV RMSD: if SUBSET_TYPE=LIST a list of atoms needs to be provided ")
            END IF
         ELSE IF (colvar%rmsd_param%subset == rmsd_weightlist) THEN
            CALL section_vals_val_get(rmsd_section, "ATOMS", n_rep_val=n_var)
            ndim = 0
            IF (n_var /= 0) THEN
               ! INDEX LIST
               DO k = 1, n_var
                  CALL section_vals_val_get(rmsd_section, "ATOMS", i_rep_val=k, i_vals=iatms)
                  CALL reallocate(colvar%rmsd_param%i_rmsd, 1, ndim+SIZE(iatms))
                  colvar%rmsd_param%i_rmsd(ndim+1:ndim+SIZE(iatms)) = iatms
                  ndim = ndim+SIZE(iatms)
               END DO
               colvar%rmsd_param%n_atoms = ndim
            ELSE
               CPABORT("CV RMSD: if SUBSET_TYPE=WEIGHT_LIST a list of atoms needs to be provided ")
            END IF
            CALL section_vals_val_get(rmsd_section, "WEIGHTS", n_rep_val=n_var)
            ndim = 0
            IF (n_var /= 0) THEN
               ! INDEX LIST
               DO k = 1, n_var
                  CALL section_vals_val_get(rmsd_section, "WEIGHTS", i_rep_val=k, r_vals=wei)
                  CALL reallocate(weights, 1, ndim+SIZE(wei))
                  weights(ndim+1:ndim+SIZE(wei)) = wei
                  ndim = ndim+SIZE(wei)
               END DO
               IF (ndim /= colvar%rmsd_param%n_atoms) &
                  CALL cp_abort(__LOCATION__, "CV RMSD: list of atoms and list of "// &
                                "weights need to contain same number of entries. ")
               DO i = 1, ndim
                  ii = colvar%rmsd_param%i_rmsd(i)
                  colvar%rmsd_param%weights(ii) = weights(i)
               END DO
               DEALLOCATE (weights)
            ELSE
               CPABORT("CV RMSD: if SUBSET_TYPE=WEIGHT_LIST a list of weights need to be provided. ")
            END IF

         ELSE
            CPABORT("CV RMSD: unknown SUBSET_TYPE.")
         END IF

         CALL section_vals_val_get(rmsd_section, "ALIGN_FRAMES", l_val=colvar%rmsd_param%align_frames)
      ELSE IF (my_subsection(17)) THEN
         ! Work on XYZ positions of atoms
         wrk_section => xyz_diag_section
         CALL colvar_create(colvar, xyz_diag_colvar_id)
         CALL colvar_check_points(colvar, wrk_section)
         CALL section_vals_val_get(wrk_section, "ATOM", i_val=iatm)
         CALL section_vals_val_get(wrk_section, "COMPONENT", i_val=icomponent)
         CALL section_vals_val_get(wrk_section, "PBC", l_val=colvar%xyz_diag_param%use_pbc)
         CALL section_vals_val_get(wrk_section, "ABSOLUTE_POSITION", l_val=colvar%xyz_diag_param%use_absolute_position)
         colvar%xyz_diag_param%i_atom = iatm
         colvar%xyz_diag_param%component = icomponent
      ELSE IF (my_subsection(18)) THEN
         ! Work on the outer diagonal (two atoms A,B) XYZ positions
         wrk_section => xyz_outerdiag_section
         CALL colvar_create(colvar, xyz_outerdiag_colvar_id)
         CALL colvar_check_points(colvar, wrk_section)
         CALL section_vals_val_get(wrk_section, "ATOMS", i_vals=iatms)
         colvar%xyz_outerdiag_param%i_atoms = iatms
         CALL section_vals_val_get(wrk_section, "COMPONENT_A", i_val=icomponent)
         colvar%xyz_outerdiag_param%components(1) = icomponent
         CALL section_vals_val_get(wrk_section, "COMPONENT_B", i_val=icomponent)
         colvar%xyz_outerdiag_param%components(2) = icomponent
         CALL section_vals_val_get(wrk_section, "PBC", l_val=colvar%xyz_outerdiag_param%use_pbc)
      ELSE IF (my_subsection(19)) THEN
         ! Energy
         wrk_section => u_section
         CALL colvar_create(colvar, u_colvar_id)
         colvar%u_param%mixed_energy_section => section_vals_get_subs_vals(wrk_section, "MIXED")
         CALL section_vals_get(colvar%u_param%mixed_energy_section, explicit=use_mixed_energy)
         IF (.NOT. use_mixed_energy) NULLIFY (colvar%u_param%mixed_energy_section)
      ELSE IF (my_subsection(20)) THEN
         ! Wc hydrogen bond
         wrk_section => Wc_section
         CALL colvar_create(colvar, Wc_colvar_id)
         CALL colvar_check_points(colvar, Wc_section)
         CALL section_vals_val_get(Wc_section, "ATOMS", i_vals=iatms)
         CALL section_vals_val_get(wrk_section, "RCUT", r_val=my_val(1))
         colvar%Wc%rcut = cp_unit_to_cp2k(my_val(1), "angstrom")
         colvar%Wc%ids = iatms
      ELSE IF (my_subsection(21)) THEN
         ! HBP colvar
         wrk_section => HBP_section
         CALL colvar_create(colvar, HBP_colvar_id)
         CALL colvar_check_points(colvar, HBP_section)
         CALL section_vals_val_get(wrk_section, "NPOINTS", i_val=colvar%HBP%nPoints)
         CALL section_vals_val_get(wrk_section, "RCUT", r_val=my_val(1))
         colvar%HBP%rcut = cp_unit_to_cp2k(my_val(1), "angstrom")
         CALL section_vals_val_get(wrk_section, "RCUT", r_val=colvar%HBP%shift)

         ALLOCATE (colvar%HBP%ids(colvar%HBP%nPoints, 3))
         ALLOCATE (colvar%HBP%ewc(colvar%HBP%nPoints))
         DO i = 1, colvar%HBP%nPoints
            CALL section_vals_val_get(wrk_section, "ATOMS", i_rep_val=i, i_vals=iatms)
            colvar%HBP%ids(i, :) = iatms
         ENDDO
      ELSE IF (my_subsection(22)) THEN
         ! Ring Puckering
         CALL colvar_create(colvar, ring_puckering_colvar_id)
         CALL section_vals_val_get(ring_puckering_section, "ATOMS", i_vals=iatms)
         colvar%ring_puckering_param%nring = SIZE(iatms)
         ALLOCATE (colvar%ring_puckering_param%atoms(SIZE(iatms)))
         colvar%ring_puckering_param%atoms = iatms
         CALL section_vals_val_get(ring_puckering_section, "COORDINATE", &
                                   i_val=colvar%ring_puckering_param%iq)
         ! test the validity of the parameters
         ndim = colvar%ring_puckering_param%nring
         IF (ndim <= 3) &
            CPABORT("CV Ring Puckering: Ring size has to be 4 or larger. ")
         ii = colvar%ring_puckering_param%iq
         IF (ABS(ii) == 1 .OR. ii < -(ndim-1)/2 .OR. ii > ndim/2) &
            CPABORT("CV Ring Puckering: Invalid coordinate number.")
      ELSE IF (my_subsection(23)) THEN
         ! Minimum Distance
         wrk_section => mindist_section
         CALL colvar_create(colvar, mindist_colvar_id)
         CALL colvar_check_points(colvar, mindist_section)
         NULLIFY (colvar%mindist_param%i_dist_from, colvar%mindist_param%i_coord_from, &
                  colvar%mindist_param%k_coord_from, colvar%mindist_param%i_coord_to, &
                  colvar%mindist_param%k_coord_to)
         CALL section_vals_val_get(mindist_section, "ATOMS_DISTANCE", i_vals=iatms)
         colvar%mindist_param%n_dist_from = SIZE(iatms)
         ALLOCATE (colvar%mindist_param%i_dist_from(SIZE(iatms)))
         colvar%mindist_param%i_dist_from = iatms
         CALL section_vals_val_get(mindist_section, "ATOMS_FROM", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(mindist_section, "ATOMS_FROM", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%mindist_param%i_coord_from, 1, ndim+SIZE(iatms))
               colvar%mindist_param%i_coord_from(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%mindist_param%n_coord_from = ndim
            colvar%mindist_param%use_kinds_from = .FALSE.
         ELSE
            !KINDS
            CALL section_vals_val_get(mindist_section, "KINDS_FROM", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(mindist_section, "KINDS_FROM", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%mindist_param%k_coord_from, 1, ndim+SIZE(c_kinds))
               colvar%mindist_param%k_coord_from(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%mindist_param%n_coord_from = 0
            colvar%mindist_param%use_kinds_from = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%mindist_param%k_coord_from(k))
            END DO
         END IF

         CALL section_vals_val_get(mindist_section, "ATOMS_TO", n_rep_val=n_var)
         ndim = 0
         IF (n_var /= 0) THEN
            ! INDEX LIST
            DO k = 1, n_var
               CALL section_vals_val_get(mindist_section, "ATOMS_TO", i_rep_val=k, i_vals=iatms)
               CALL reallocate(colvar%mindist_param%i_coord_to, 1, ndim+SIZE(iatms))
               colvar%mindist_param%i_coord_to(ndim+1:ndim+SIZE(iatms)) = iatms
               ndim = ndim+SIZE(iatms)
            END DO
            colvar%mindist_param%n_coord_to = ndim
            colvar%mindist_param%use_kinds_to = .FALSE.
         ELSE
            !KINDS
            CALL section_vals_val_get(mindist_section, "KINDS_TO", n_rep_val=n_var)
            CPASSERT(n_var > 0)
            DO k = 1, n_var
               CALL section_vals_val_get(mindist_section, "KINDS_TO", i_rep_val=k, c_vals=c_kinds)
               CALL reallocate(colvar%mindist_param%k_coord_to, 1, ndim+SIZE(c_kinds))
               colvar%mindist_param%k_coord_to(ndim+1:ndim+SIZE(c_kinds)) = c_kinds
               ndim = ndim+SIZE(c_kinds)
            END DO
            colvar%mindist_param%n_coord_to = 0
            colvar%mindist_param%use_kinds_to = .TRUE.
            ! Uppercase the label
            DO k = 1, ndim
               CALL uppercase(colvar%mindist_param%k_coord_to(k))
            END DO
         END IF

         CALL section_vals_val_get(mindist_section, "R0", r_val=colvar%mindist_param%r_cut)
         CALL section_vals_val_get(mindist_section, "NN", i_val=colvar%mindist_param%p_exp)
         CALL section_vals_val_get(mindist_section, "ND", i_val=colvar%mindist_param%q_exp)
!       CALL section_vals_val_get(mindist_section,"NC",r_val=colvar%mindist_param%n_cut)
         CALL section_vals_val_get(mindist_section, "LAMBDA", r_val=colvar%mindist_param%lambda)
      ELSE IF (my_subsection(24)) THEN
         ! Distance carboxylic acid and hydronium
         CALL colvar_create(colvar, acid_hyd_dist_colvar_id)
         NULLIFY (colvar%acid_hyd_dist_param%i_oxygens_water)
         NULLIFY (colvar%acid_hyd_dist_param%i_oxygens_acid)
         NULLIFY (colvar%acid_hyd_dist_param%i_hydrogens)
         CALL read_acid_hydronium_colvars(acid_hyd_dist_section, colvar, acid_hyd_dist_colvar_id, &
                                          colvar%acid_hyd_dist_param%n_oxygens_water, &
                                          colvar%acid_hyd_dist_param%n_oxygens_acid, &
                                          colvar%acid_hyd_dist_param%n_hydrogens, &
                                          colvar%acid_hyd_dist_param%i_oxygens_water, &
                                          colvar%acid_hyd_dist_param%i_oxygens_acid, &
                                          colvar%acid_hyd_dist_param%i_hydrogens)
      ELSE IF (my_subsection(25)) THEN
         ! Number of oxygens in 1st shell of hydronium for carboxylic acid / water system
         CALL colvar_create(colvar, acid_hyd_shell_colvar_id)
         NULLIFY (colvar%acid_hyd_shell_param%i_oxygens_water)
         NULLIFY (colvar%acid_hyd_shell_param%i_oxygens_acid)
         NULLIFY (colvar%acid_hyd_shell_param%i_hydrogens)
         CALL read_acid_hydronium_colvars(acid_hyd_shell_section, colvar, acid_hyd_shell_colvar_id, &
                                          colvar%acid_hyd_shell_param%n_oxygens_water, &
                                          colvar%acid_hyd_shell_param%n_oxygens_acid, &
                                          colvar%acid_hyd_shell_param%n_hydrogens, &
                                          colvar%acid_hyd_shell_param%i_oxygens_water, &
                                          colvar%acid_hyd_shell_param%i_oxygens_acid, &
                                          colvar%acid_hyd_shell_param%i_hydrogens)
      ELSE IF (my_subsection(26)) THEN
         ! Distance hydronium and hydroxide, autoionization of water
         CALL colvar_create(colvar, hydronium_dist_colvar_id)
         NULLIFY (colvar%hydronium_dist_param%i_oxygens)
         NULLIFY (colvar%hydronium_dist_param%i_hydrogens)
         CALL read_hydronium_colvars(hydronium_dist_section, colvar, hydronium_dist_colvar_id, &
                                     colvar%hydronium_dist_param%n_oxygens, &
                                     colvar%hydronium_dist_param%n_hydrogens, &
                                     colvar%hydronium_dist_param%i_oxygens, &
                                     colvar%hydronium_dist_param%i_hydrogens)
      END IF
      CALL colvar_setup(colvar)

      iw = cp_print_key_unit_nr(logger, colvar_section, &
                                "PRINT%PROGRAM_RUN_INFO", extension=".colvarLog")
      IF (iw > 0) THEN
         tag = "ATOMS: "
         IF (colvar%use_points) tag = "POINTS:"
         ! Description header
         IF (colvar%type_id /= combine_colvar_id) THEN
            WRITE (iw, '( A )') '          '// &
               '----------------------------------------------------------------------'
            WRITE (iw, '( A,I8)') ' COLVARS| COLVAR INPUT INDEX: ', icol
         END IF
         ! Colvar Description
         SELECT CASE (colvar%type_id)
         CASE (angle_colvar_id)
            WRITE (iw, '( A,T57,3I8)') ' COLVARS| ANGLE          >>> '//tag, &
               colvar%angle_param%i_at_angle
         CASE (dfunct_colvar_id)
            WRITE (iw, '( A,T49,4I8)') ' COLVARS| DISTANCE DIFFERENCE  >>> '//tag, &
               colvar%dfunct_param%i_at_dfunct
         CASE (plane_distance_colvar_id)
            WRITE (iw, '( A,T57,3I8)') ' COLVARS| PLANE DISTANCE - PLANE  >>> '//tag, &
               colvar%plane_distance_param%plane
            WRITE (iw, '( A,T73,1I8)') ' COLVARS| PLANE DISTANCE - POINT  >>> '//tag, &
               colvar%plane_distance_param%point
         CASE (plane_plane_angle_colvar_id)
            IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) THEN
               WRITE (iw, '( A,T57,3I8)') ' COLVARS| PLANE-PLANE ANGLE - PLANE 1  (ATOMS) >>> '//tag, &
                  colvar%plane_plane_angle_param%plane1%points
            ELSE
               WRITE (iw, '( A,T57,3F8.3)') ' COLVARS| PLANE-PLANE ANGLE - PLANE 1 (VECTOR) >>> '//tag, &
                  colvar%plane_plane_angle_param%plane1%normal_vec
            END IF

            IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) THEN
               WRITE (iw, '( A,T57,3I8)') ' COLVARS| PLANE-PLANE ANGLE - PLANE 1  (ATOMS) >>> '//tag, &
                  colvar%plane_plane_angle_param%plane2%points
            ELSE
               WRITE (iw, '( A,T57,3F8.3)') ' COLVARS| PLANE-PLANE ANGLE - PLANE 1 (VECTOR) >>> '//tag, &
                  colvar%plane_plane_angle_param%plane2%normal_vec
            END IF
         CASE (torsion_colvar_id)
            WRITE (iw, '( A,T49,4I8)') ' COLVARS| TORSION       >>> '//tag, &
               colvar%torsion_param%i_at_tors
         CASE (dist_colvar_id)
            WRITE (iw, '( A,T65,2I8)') ' COLVARS| BOND          >>> '//tag, &
               colvar%dist_param%i_at, colvar%dist_param%j_at
         CASE (coord_colvar_id)
            IF (colvar%coord_param%do_chain) THEN
               WRITE (iw, '( A)') ' COLVARS| COORDINATION CHAIN FC(from->to)*FC(to->to_B)>> '
            END IF
            IF (colvar%coord_param%use_kinds_from) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| COORDINATION  >>> FROM KINDS', &
                                           ADJUSTR(colvar%coord_param%c_kinds_from(kk) (1:10)), &
                                           kk=1, SIZE(colvar%coord_param%c_kinds_from))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| COORDINATION  >>> FROM '//tag, &
                                           colvar%coord_param%i_at_from(kk), &
                                           kk=1, SIZE(colvar%coord_param%i_at_from))
            END IF
            IF (colvar%coord_param%use_kinds_to) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| COORDINATION  >>>   TO KINDS', &
                                           ADJUSTR(colvar%coord_param%c_kinds_to(kk) (1:10)), &
                                           kk=1, SIZE(colvar%coord_param%c_kinds_to))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| COORDINATION  >>>   TO '//tag, &
                                           colvar%coord_param%i_at_to(kk), &
                                           kk=1, SIZE(colvar%coord_param%i_at_to))
            END IF
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| R0', colvar%coord_param%r_0
            WRITE (iw, '( A,T71,I10)') ' COLVARS| NN', colvar%coord_param%nncrd
            WRITE (iw, '( A,T71,I10)') ' COLVARS| ND', colvar%coord_param%ndcrd
            IF (colvar%coord_param%do_chain) THEN
               IF (colvar%coord_param%use_kinds_to_b) THEN
                  WRITE (iw, '( A,T71,A10)') (' COLVARS| COORDINATION  >>>   TO KINDS B', &
                                              ADJUSTR(colvar%coord_param%c_kinds_to_b(kk) (1:10)), &
                                              kk=1, SIZE(colvar%coord_param%c_kinds_to_b))
               ELSE
                  WRITE (iw, '( A,T71,I10)') (' COLVARS| COORDINATION  >>>   TO '//tag//' B', &
                                              colvar%coord_param%i_at_to_b(kk), &
                                              kk=1, SIZE(colvar%coord_param%i_at_to_b))
               END IF
               WRITE (iw, '( A,T71,F10.5)') ' COLVARS| R0 B', colvar%coord_param%r_0_b
               WRITE (iw, '( A,T71,I10)') ' COLVARS| NN B', colvar%coord_param%nncrd_b
               WRITE (iw, '( A,T71,I10)') ' COLVARS| ND B', colvar%coord_param%ndcrd_b
            END IF
         CASE (population_colvar_id)
            IF (colvar%population_param%use_kinds_from) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| POPULATION based on coordination >>> FROM KINDS', &
                                           ADJUSTR(colvar%population_param%c_kinds_from(kk) (1:10)), &
                                           kk=1, SIZE(colvar%population_param%c_kinds_from))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| POPULATION based on coordination >>> FROM '//tag, &
                                           colvar%population_param%i_at_from(kk), &
                                           kk=1, SIZE(colvar%population_param%i_at_from))
            END IF
            IF (colvar%population_param%use_kinds_to) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| POPULATION based on coordination >>>   TO KINDS', &
                                           ADJUSTR(colvar%population_param%c_kinds_to(kk) (1:10)), &
                                           kk=1, SIZE(colvar%population_param%c_kinds_to))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| POPULATION based on coordination   >>>   TO '//tag, &
                                           colvar%population_param%i_at_to(kk), &
                                           kk=1, SIZE(colvar%population_param%i_at_to))
            END IF
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| R0', colvar%population_param%r_0
            WRITE (iw, '( A,T71,I10)') ' COLVARS| NN', colvar%population_param%nncrd
            WRITE (iw, '( A,T71,I10)') ' COLVARS| ND', colvar%population_param%ndcrd
            WRITE (iw, '( A,T71,I10)') ' COLVARS| N0', colvar%population_param%n0
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| SIGMA', colvar%population_param%sigma
         CASE (gyration_colvar_id)
            IF (colvar%gyration_param%use_kinds) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| Gyration Radius >>> KINDS', &
                                           ADJUSTR(colvar%gyration_param%c_kinds(kk) (1:10)), &
                                           kk=1, SIZE(colvar%gyration_param%c_kinds))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| Gyration Radius >>> ATOMS '//tag, &
                                           colvar%gyration_param%i_at(kk), &
                                           kk=1, SIZE(colvar%gyration_param%i_at))
            END IF
         CASE (rotation_colvar_id)
            WRITE (iw, '( A,T71,I10)') ' COLVARS| BOND_ROTATION   - POINT 1 LINE 1  >>> '//tag, &
               colvar%rotation_param%i_at1_bond1
            WRITE (iw, '( A,T71,I10)') ' COLVARS| BOND_ROTATION   - POINT 2 LINE 1  >>> '//tag, &
               colvar%rotation_param%i_at2_bond1
            WRITE (iw, '( A,T71,I10)') ' COLVARS| BOND_ROTATION   - POINT 1 LINE 2  >>> '//tag, &
               colvar%rotation_param%i_at1_bond2
            WRITE (iw, '( A,T71,I10)') ' COLVARS| BOND_ROTATION   - POINT 2 LINE 2  >>> '//tag, &
               colvar%rotation_param%i_at2_bond2
         CASE (qparm_colvar_id)
            WRITE (iw, '( A,T71,I10)') (' COLVARS| Q-PARM  >>> FROM '//tag, &
                                        colvar%qparm_param%i_at_from(kk), &
                                        kk=1, SIZE(colvar%qparm_param%i_at_from))
            WRITE (iw, '( A,T71,I10)') (' COLVARS| Q-PARM  >>>   TO '//tag, &
                                        colvar%qparm_param%i_at_to(kk), &
                                        kk=1, SIZE(colvar%qparm_param%i_at_to))
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RCUT', colvar%qparm_param%rcut
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RSTART', colvar%qparm_param%rstart
            WRITE (iw, '( A,T71,L10)') ' COLVARS| INCLUDE IMAGES', colvar%qparm_param%include_images
            !WRITE (iw, '( A,T71,F10.5)') ' COLVARS| ALPHA', colvar%qparm_param%alpha
            WRITE (iw, '( A,T71,I10)') ' COLVARS| L', colvar%qparm_param%l
         CASE (combine_colvar_id)
            WRITE (iw, '( A)') ' COLVARS| COMBINING FUNCTION : '// &
               TRIM(colvar%combine_cvs_param%function)
            WRITE (iw, '( A)', ADVANCE="NO") ' COLVARS| VARIABLES : '
            DO i = 1, SIZE(colvar%combine_cvs_param%variables)
               WRITE (iw, '( A)', ADVANCE="NO") &
                  TRIM(colvar%combine_cvs_param%variables(i))//" "
            END DO
            WRITE (iw, '(/)')
            WRITE (iw, '( A)') ' COLVARS| DEFINED PARAMETERS [label]  [value]:'
            DO i = 1, SIZE(colvar%combine_cvs_param%c_parameters)
               WRITE (iw, '( A,A7,F9.3)') '                            ', &
                  TRIM(colvar%combine_cvs_param%c_parameters(i)), colvar%combine_cvs_param%v_parameters(i)
            END DO
            WRITE (iw, '( A,T71,G10.5)') ' COLVARS| ERROR ON DERIVATIVE EVALUATION', &
               colvar%combine_cvs_param%lerr
            WRITE (iw, '( A,T71,G10.5)') ' COLVARS| DX', &
               colvar%combine_cvs_param%dx
         CASE (reaction_path_colvar_id)
            CPWARN("Description header for REACTION_PATH COLVAR missing!!")
         CASE (distance_from_path_colvar_id)
            CPWARN("Description header for REACTION_PATH COLVAR missing!!")
         CASE (hydronium_shell_colvar_id)
            WRITE (iw, '( A,T71,I10)') ' COLVARS| POH', colvar%hydronium_shell_param%poh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QOH', colvar%hydronium_shell_param%qoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| POO', colvar%hydronium_shell_param%poo
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QOO', colvar%hydronium_shell_param%qoo
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| ROO', colvar%hydronium_shell_param%roo
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| ROH', colvar%hydronium_shell_param%roh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NH', colvar%hydronium_shell_param%nh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| LAMBDA', colvar%hydronium_shell_param%lambda
         CASE (hydronium_dist_colvar_id)
            WRITE (iw, '( A,T71,I10)') ' COLVARS| POH', colvar%hydronium_dist_param%poh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QOH', colvar%hydronium_dist_param%qoh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| ROH', colvar%hydronium_dist_param%roh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PM', colvar%hydronium_dist_param%pm
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QM', colvar%hydronium_dist_param%qm
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NH', colvar%hydronium_dist_param%nh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PF', colvar%hydronium_dist_param%pf
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QF', colvar%hydronium_dist_param%qf
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NN', colvar%hydronium_dist_param%nn
         CASE (acid_hyd_dist_colvar_id)
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PAOH', colvar%acid_hyd_dist_param%paoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QAOH', colvar%acid_hyd_dist_param%qaoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PWOH', colvar%acid_hyd_dist_param%pwoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QWOH', colvar%acid_hyd_dist_param%qwoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PCUT', colvar%acid_hyd_dist_param%pcut
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QCUT', colvar%acid_hyd_dist_param%qcut
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RAOH', colvar%acid_hyd_dist_param%raoh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RWOH', colvar%acid_hyd_dist_param%rwoh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NC', colvar%acid_hyd_dist_param%nc
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| LAMBDA', colvar%acid_hyd_dist_param%lambda
         CASE (acid_hyd_shell_colvar_id)
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PAOH', colvar%acid_hyd_shell_param%paoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QAOH', colvar%acid_hyd_shell_param%qaoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PWOH', colvar%acid_hyd_shell_param%pwoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QWOH', colvar%acid_hyd_shell_param%qwoh
            WRITE (iw, '( A,T71,I10)') ' COLVARS| POO', colvar%acid_hyd_shell_param%poo
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QOO', colvar%acid_hyd_shell_param%qoo
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PM', colvar%acid_hyd_shell_param%pm
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QM', colvar%acid_hyd_shell_param%qm
            WRITE (iw, '( A,T71,I10)') ' COLVARS| PCUT', colvar%acid_hyd_shell_param%pcut
            WRITE (iw, '( A,T71,I10)') ' COLVARS| QCUT', colvar%acid_hyd_shell_param%qcut
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RAOH', colvar%acid_hyd_shell_param%raoh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| RWOH', colvar%acid_hyd_shell_param%rwoh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| ROO', colvar%acid_hyd_shell_param%roo
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NH', colvar%acid_hyd_shell_param%nh
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| NC', colvar%acid_hyd_shell_param%nc
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| LAMBDA', colvar%acid_hyd_shell_param%lambda
         CASE (rmsd_colvar_id)
            CPWARN("Description header for RMSD COLVAR missing!!")
         CASE (xyz_diag_colvar_id)
            NULLIFY (section, keyword, enum)
            CALL create_colvar_xyz_d_section(section)
            keyword => section_get_keyword(section, "COMPONENT")
            CALL keyword_get(keyword, enum=enum)
            tag_comp = enum_i2c(enum, colvar%xyz_diag_param%component)
            CALL section_release(section)

            WRITE (iw, '( A,T57,3I8)') ' COLVARS| POSITION ('//TRIM(tag_comp) &
               //')  >>> '//tag, colvar%xyz_diag_param%i_atom
         CASE (xyz_outerdiag_colvar_id)
            NULLIFY (section, keyword, enum)
            CALL create_colvar_xyz_od_section(section)
            keyword => section_get_keyword(section, "COMPONENT_A")
            CALL keyword_get(keyword, enum=enum)
            tag_comp1 = enum_i2c(enum, colvar%xyz_outerdiag_param%components(1))
            keyword => section_get_keyword(section, "COMPONENT_B")
            CALL keyword_get(keyword, enum=enum)
            tag_comp2 = enum_i2c(enum, colvar%xyz_outerdiag_param%components(2))
            CALL section_release(section)

            WRITE (iw, '( A,T57,3I8)') ' COLVARS| CROSS TERM POSITION ('//TRIM(tag_comp1) &
               //" * "//TRIM(tag_comp2)//')  >>> '//tag, colvar%xyz_outerdiag_param%i_atoms
         CASE (u_colvar_id)
            WRITE (iw, '( A,T77,A4)') ' COLVARS| ENERGY          >>> '//tag, 'all!'
         CASE (Wc_colvar_id)
            WRITE (iw, '( A,T57,F16.8)') ' COLVARS| Wc          >>> RCUT: ', &
               colvar%Wc%rcut
            WRITE (iw, '( A,T57,3I8)') ' COLVARS| Wc          >>> '//tag, &
               colvar%Wc%ids
         CASE (HBP_colvar_id)
            WRITE (iw, '( A,T57,I8)') ' COLVARS| HBP          >>> NPOINTS', &
               colvar%HBP%nPoints
            WRITE (iw, '( A,T57,F16.8)') ' COLVARS| HBP          >>> RCUT', &
               colvar%HBP%rcut
            WRITE (iw, '( A,T57,F16.8)') ' COLVARS| HBP          >>> RCUT', &
               colvar%HBP%shift
            DO i = 1, colvar%HBP%nPoints
               WRITE (iw, '( A,T57,3I8)') ' COLVARS| HBP          >>> '//tag, &
                  colvar%HBP%ids(i, :)
            ENDDO
         CASE (ring_puckering_colvar_id)
            WRITE (iw, '( A,T57,I8)') ' COLVARS| Ring Puckering      >>> ring size', &
               colvar%ring_puckering_param%nring
            IF (colvar%ring_puckering_param%iq == 0) THEN
               WRITE (iw, '( A,T40,A)') ' COLVARS| Ring Puckering      >>> coordinate', &
                  ' Total Puckering Amplitude'
            ELSEIF (colvar%ring_puckering_param%iq > 0) THEN
               WRITE (iw, '( A,T35,A,T57,I8)') ' COLVARS| Ring Puckering      >>> coordinate', &
                  ' Puckering Amplitude', &
                  colvar%ring_puckering_param%iq
            ELSE
               WRITE (iw, '( A,T35,A,T57,I8)') ' COLVARS| Ring Puckering      >>> coordinate', &
                  ' Puckering Angle', &
                  colvar%ring_puckering_param%iq
            END IF
         CASE (mindist_colvar_id)
            WRITE (iw, '( A)') ' COLVARS| CONDITIONED DISTANCE>> '
            WRITE (iw, '( A,T71,I10)') (' COLVARS| COND.DISTANCE  >>> DISTANCE FROM '//tag, &
                                        colvar%mindist_param%i_dist_from(kk), &
                                        kk=1, SIZE(colvar%mindist_param%i_dist_from))
            IF (colvar%mindist_param%use_kinds_from) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| COND.DIST.  >>> COORDINATION FROM KINDS ', &
                                           ADJUSTR(colvar%mindist_param%k_coord_from(kk) (1:10)), &
                                           kk=1, SIZE(colvar%mindist_param%k_coord_from))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| COND.DIST.  >>> COORDINATION FROM '//tag, &
                                           colvar%mindist_param%i_coord_from(kk), &
                                           kk=1, SIZE(colvar%mindist_param%i_coord_from))
            END IF
            IF (colvar%mindist_param%use_kinds_to) THEN
               WRITE (iw, '( A,T71,A10)') (' COLVARS| COND.DIST.  >>> COORDINATION TO KINDS ', &
                                           ADJUSTR(colvar%mindist_param%k_coord_to(kk) (1:10)), &
                                           kk=1, SIZE(colvar%mindist_param%k_coord_to))
            ELSE
               WRITE (iw, '( A,T71,I10)') (' COLVARS| COND.DIST.  >>> COORDINATION TO '//tag, &
                                           colvar%mindist_param%i_coord_to(kk), &
                                           kk=1, SIZE(colvar%mindist_param%i_coord_to))
            END IF
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| R0', colvar%mindist_param%r_cut
            WRITE (iw, '( A,T71,I10)') ' COLVARS| NN', colvar%mindist_param%p_exp
            WRITE (iw, '( A,T71,I10)') ' COLVARS| ND', colvar%mindist_param%q_exp
            WRITE (iw, '( A,T71,F10.5)') ' COLVARS| LAMBDA', colvar%mindist_param%lambda

         END SELECT
         IF (colvar%use_points) THEN
            WRITE (iw, '( A)') ' COLVARS| INFORMATION ON DEFINED GEOMETRICAL POINTS'
            DO kk = 1, SIZE(colvar%points)
               point_section => section_vals_get_subs_vals(wrk_section, "POINT")
               CALL section_vals_val_get(point_section, "TYPE", i_rep_section=kk, c_val=tmpStr)
               tmpStr2 = cp_to_string(kk)
               WRITE (iw, '( A)') ' COLVARS|  POINT Nr.'//TRIM(tmpStr2)//' OF TYPE: '//TRIM(tmpStr)
               IF (ASSOCIATED(colvar%points(kk)%atoms)) THEN
                  WRITE (iw, '( A)') ' COLVARS|   ATOMS BUILDING THE GEOMETRICAL POINT'
                  WRITE (iw, '( A, I10)') (' COLVARS|   ATOM:', colvar%points(kk)%atoms(k), k=1, SIZE(colvar%points(kk)%atoms))
               ELSE
                  WRITE (iw, '( A,4X,3F12.6)') ' COLVARS|   XYZ POSITION OF FIXED POINT:', colvar%points(kk)%r
               END IF
            END DO
         END IF
         ! Close the description layer
         IF (colvar%type_id /= combine_colvar_id) THEN
            WRITE (iw, '( A )') '          '// &
               '----------------------------------------------------------------------'
         ELSE
            WRITE (iw, '( A )') '          '// &
               '**********************************************************************'
         END IF
      END IF
      CALL cp_print_key_finished_output(iw, logger, colvar_section, &
                                        "PRINT%PROGRAM_RUN_INFO")
      CALL timestop(handle)
   END SUBROUTINE colvar_read

! **************************************************************************************************
!> \brief read collective variables for the autoionization of water
!> \param section ...
!> \param colvar collective variable
!> \param colvar_id  ...
!> \param n_oxygens number of oxygens
!> \param n_hydrogens number of hydrogens
!> \param i_oxygens list of oxygens
!> \param i_hydrogens list of hydrogens
!> \author Dorothea Golze
! **************************************************************************************************
   SUBROUTINE read_hydronium_colvars(section, colvar, colvar_id, n_oxygens, n_hydrogens, &
                                     i_oxygens, i_hydrogens)
      TYPE(section_vals_type), POINTER                   :: section
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: colvar_id
      INTEGER, INTENT(OUT)                               :: n_oxygens, n_hydrogens
      INTEGER, DIMENSION(:), POINTER                     :: i_oxygens, i_hydrogens

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

      INTEGER                                            :: k, n_var, ndim
      INTEGER, DIMENSION(:), POINTER                     :: iatms

      NULLIFY (iatms)

      CALL section_vals_val_get(section, "OXYGENS", n_rep_val=n_var)
      ndim = 0
      DO k = 1, n_var
         CALL section_vals_val_get(section, "OXYGENS", i_vals=iatms)
         CALL reallocate(i_oxygens, 1, ndim+SIZE(iatms))
         i_oxygens(ndim+1:ndim+SIZE(iatms)) = iatms
         ndim = ndim+SIZE(iatms)
      END DO
      n_oxygens = ndim

      CALL section_vals_val_get(section, "HYDROGENS", n_rep_val=n_var)
      ndim = 0
      DO k = 1, n_var
         CALL section_vals_val_get(section, "HYDROGENS", i_vals=iatms)
         CALL reallocate(i_hydrogens, 1, ndim+SIZE(iatms))
         i_hydrogens(ndim+1:ndim+SIZE(iatms)) = iatms
         ndim = ndim+SIZE(iatms)
      END DO
      n_hydrogens = ndim

      SELECT CASE (colvar_id)
      CASE (hydronium_shell_colvar_id)
         CALL section_vals_val_get(section, "ROO", r_val=colvar%hydronium_shell_param%roo)
         CALL section_vals_val_get(section, "ROH", r_val=colvar%hydronium_shell_param%roh)
         CALL section_vals_val_get(section, "pOH", i_val=colvar%hydronium_shell_param%poh)
         CALL section_vals_val_get(section, "qOH", i_val=colvar%hydronium_shell_param%qoh)
         CALL section_vals_val_get(section, "pOO", i_val=colvar%hydronium_shell_param%poo)
         CALL section_vals_val_get(section, "qOO", i_val=colvar%hydronium_shell_param%qoo)
         CALL section_vals_val_get(section, "pM", i_val=colvar%hydronium_shell_param%pm)
         CALL section_vals_val_get(section, "qM", i_val=colvar%hydronium_shell_param%qm)
         CALL section_vals_val_get(section, "NH", r_val=colvar%hydronium_shell_param%nh)
         CALL section_vals_val_get(section, "LAMBDA", r_val=colvar%hydronium_shell_param%lambda)
      CASE (hydronium_dist_colvar_id)
         CALL section_vals_val_get(section, "ROH", r_val=colvar%hydronium_dist_param%roh)
         CALL section_vals_val_get(section, "pOH", i_val=colvar%hydronium_dist_param%poh)
         CALL section_vals_val_get(section, "qOH", i_val=colvar%hydronium_dist_param%qoh)
         CALL section_vals_val_get(section, "pF", i_val=colvar%hydronium_dist_param%pf)
         CALL section_vals_val_get(section, "qF", i_val=colvar%hydronium_dist_param%qf)
         CALL section_vals_val_get(section, "pM", i_val=colvar%hydronium_dist_param%pm)
         CALL section_vals_val_get(section, "qM", i_val=colvar%hydronium_dist_param%qm)
         CALL section_vals_val_get(section, "NH", r_val=colvar%hydronium_dist_param%nh)
         CALL section_vals_val_get(section, "NN", r_val=colvar%hydronium_dist_param%nn)
         CALL section_vals_val_get(section, "LAMBDA", r_val=colvar%hydronium_dist_param%lambda)
      END SELECT

   END SUBROUTINE read_hydronium_colvars

! **************************************************************************************************
!> \brief read collective variables for the dissociation of a carboxylic acid
!>        in water
!> \param section ...
!> \param colvar collective variable
!> \param colvar_id  ...
!> \param n_oxygens_water number of oxygens of water molecules
!> \param n_oxygens_acid number of oxgyens of carboxyl groups
!> \param n_hydrogens number of hydrogens (water and carboxyl group)
!> \param i_oxygens_water list of oxygens of water molecules
!> \param i_oxygens_acid list of oxygens of carboxyl group
!> \param i_hydrogens list of hydrogens (water and carboxyl group)
!> \author Dorothea Golze
! **************************************************************************************************
   SUBROUTINE read_acid_hydronium_colvars(section, colvar, colvar_id, n_oxygens_water, &
                                          n_oxygens_acid, n_hydrogens, i_oxygens_water, &
                                          i_oxygens_acid, i_hydrogens)
      TYPE(section_vals_type), POINTER                   :: section
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: colvar_id
      INTEGER, INTENT(OUT)                               :: n_oxygens_water, n_oxygens_acid, &
                                                            n_hydrogens
      INTEGER, DIMENSION(:), POINTER                     :: i_oxygens_water, i_oxygens_acid, &
                                                            i_hydrogens

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

      INTEGER                                            :: k, n_var, ndim
      INTEGER, DIMENSION(:), POINTER                     :: iatms

      NULLIFY (iatms)

      CALL section_vals_val_get(section, "OXYGENS_WATER", n_rep_val=n_var)
      ndim = 0
      DO k = 1, n_var
         CALL section_vals_val_get(section, "OXYGENS_WATER", i_vals=iatms)
         CALL reallocate(i_oxygens_water, 1, ndim+SIZE(iatms))
         i_oxygens_water(ndim+1:ndim+SIZE(iatms)) = iatms
         ndim = ndim+SIZE(iatms)
      END DO
      n_oxygens_water = ndim

      CALL section_vals_val_get(section, "OXYGENS_ACID", n_rep_val=n_var)
      ndim = 0
      DO k = 1, n_var
         CALL section_vals_val_get(section, "OXYGENS_ACID", i_vals=iatms)
         CALL reallocate(i_oxygens_acid, 1, ndim+SIZE(iatms))
         i_oxygens_acid(ndim+1:ndim+SIZE(iatms)) = iatms
         ndim = ndim+SIZE(iatms)
      END DO
      n_oxygens_acid = ndim

      CALL section_vals_val_get(section, "HYDROGENS", n_rep_val=n_var)
      ndim = 0
      DO k = 1, n_var
         CALL section_vals_val_get(section, "HYDROGENS", i_vals=iatms)
         CALL reallocate(i_hydrogens, 1, ndim+SIZE(iatms))
         i_hydrogens(ndim+1:ndim+SIZE(iatms)) = iatms
         ndim = ndim+SIZE(iatms)
      END DO
      n_hydrogens = ndim

      SELECT CASE (colvar_id)
      CASE (acid_hyd_dist_colvar_id)
         CALL section_vals_val_get(section, "pWOH", i_val=colvar%acid_hyd_dist_param%pwoh)
         CALL section_vals_val_get(section, "qWOH", i_val=colvar%acid_hyd_dist_param%qwoh)
         CALL section_vals_val_get(section, "pAOH", i_val=colvar%acid_hyd_dist_param%paoh)
         CALL section_vals_val_get(section, "qAOH", i_val=colvar%acid_hyd_dist_param%qaoh)
         CALL section_vals_val_get(section, "pCUT", i_val=colvar%acid_hyd_dist_param%pcut)
         CALL section_vals_val_get(section, "qCUT", i_val=colvar%acid_hyd_dist_param%qcut)
         CALL section_vals_val_get(section, "RWOH", r_val=colvar%acid_hyd_dist_param%rwoh)
         CALL section_vals_val_get(section, "RAOH", r_val=colvar%acid_hyd_dist_param%raoh)
         CALL section_vals_val_get(section, "NC", r_val=colvar%acid_hyd_dist_param%nc)
         CALL section_vals_val_get(section, "LAMBDA", r_val=colvar%acid_hyd_dist_param%lambda)
      CASE (acid_hyd_shell_colvar_id)
         CALL section_vals_val_get(section, "pWOH", i_val=colvar%acid_hyd_shell_param%pwoh)
         CALL section_vals_val_get(section, "qWOH", i_val=colvar%acid_hyd_shell_param%qwoh)
         CALL section_vals_val_get(section, "pAOH", i_val=colvar%acid_hyd_shell_param%paoh)
         CALL section_vals_val_get(section, "qAOH", i_val=colvar%acid_hyd_shell_param%qaoh)
         CALL section_vals_val_get(section, "pOO", i_val=colvar%acid_hyd_shell_param%poo)
         CALL section_vals_val_get(section, "qOO", i_val=colvar%acid_hyd_shell_param%qoo)
         CALL section_vals_val_get(section, "pM", i_val=colvar%acid_hyd_shell_param%pm)
         CALL section_vals_val_get(section, "qM", i_val=colvar%acid_hyd_shell_param%qm)
         CALL section_vals_val_get(section, "pCUT", i_val=colvar%acid_hyd_shell_param%pcut)
         CALL section_vals_val_get(section, "qCUT", i_val=colvar%acid_hyd_shell_param%qcut)
         CALL section_vals_val_get(section, "RWOH", r_val=colvar%acid_hyd_shell_param%rwoh)
         CALL section_vals_val_get(section, "RAOH", r_val=colvar%acid_hyd_shell_param%raoh)
         CALL section_vals_val_get(section, "ROO", r_val=colvar%acid_hyd_shell_param%roo)
         CALL section_vals_val_get(section, "NC", r_val=colvar%acid_hyd_shell_param%nc)
         CALL section_vals_val_get(section, "NH", r_val=colvar%acid_hyd_shell_param%nh)
         CALL section_vals_val_get(section, "LAMBDA", r_val=colvar%acid_hyd_shell_param%lambda)
      END SELECT

   END SUBROUTINE read_acid_hydronium_colvars

! **************************************************************************************************
!> \brief Check and setup about the use of geometrical points instead of atoms
!> \param colvar the colvat to initialize
!> \param section ...
!> \author Teodoro Laino, [teo] 03.2007
! **************************************************************************************************
   SUBROUTINE colvar_check_points(colvar, section)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(section_vals_type), POINTER                   :: section

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

      INTEGER                                            :: i, irep, natoms, npoints, nrep, nweights
      INTEGER, DIMENSION(:), POINTER                     :: atoms
      LOGICAL                                            :: explicit
      REAL(KIND=dp), DIMENSION(:), POINTER               :: r, weights
      TYPE(section_vals_type), POINTER                   :: point_sections

      NULLIFY (point_sections)
      NULLIFY (atoms)
      NULLIFY (weights)
      CPASSERT(ASSOCIATED(colvar))
      point_sections => section_vals_get_subs_vals(section, "POINT")
      CALL section_vals_get(point_sections, explicit=explicit)
      IF (explicit) THEN
         colvar%use_points = .TRUE.
         CALL section_vals_get(point_sections, n_repetition=npoints)
         ALLOCATE (colvar%points(npoints))
         ! Read points definition
         DO i = 1, npoints
            natoms = 0
            nweights = 0
            NULLIFY (colvar%points(i)%atoms)
            NULLIFY (colvar%points(i)%weights)
            CALL section_vals_val_get(point_sections, "TYPE", i_rep_section=i, i_val=colvar%points(i)%type_id)
            SELECT CASE (colvar%points (i)%type_id)
            CASE (do_clv_geo_center)
               ! Define a point through a list of atoms..
               CALL section_vals_val_get(point_sections, "ATOMS", i_rep_section=i, n_rep_val=nrep, i_vals=atoms)
               DO irep = 1, nrep
                  CALL section_vals_val_get(point_sections, "ATOMS", i_rep_section=i, i_rep_val=irep, i_vals=atoms)
                  natoms = natoms+SIZE(atoms)
               END DO
               ALLOCATE (colvar%points(i)%atoms(natoms))
               natoms = 0
               DO irep = 1, nrep
                  CALL section_vals_val_get(point_sections, "ATOMS", i_rep_section=i, i_rep_val=irep, i_vals=atoms)
                  colvar%points(i)%atoms(natoms+1:) = atoms(:)
                  natoms = natoms+SIZE(atoms)
               END DO
               ! Define weights of the list
               ALLOCATE (colvar%points(i)%weights(natoms))
               colvar%points(i)%weights = 1.0_dp/REAL(natoms, KIND=dp)
               CALL section_vals_val_get(point_sections, "WEIGHTS", i_rep_section=i, n_rep_val=nrep)
               IF (nrep /= 0) THEN
                  DO irep = 1, nrep
                     CALL section_vals_val_get(point_sections, "WEIGHTS", i_rep_section=i, i_rep_val=irep, &
                                               r_vals=weights)
                     colvar%points(i)%weights(nweights+1:) = weights(:)
                     nweights = nweights+SIZE(weights)
                  END DO
                  CPASSERT(natoms == nweights)
               END IF
            CASE (do_clv_fix_point)
               ! Define the point as a fixed point in space..
               CALL section_vals_val_get(point_sections, "XYZ", i_rep_section=i, r_vals=r)
               colvar%points(i)%r = r
            END SELECT
         END DO
      END IF
   END SUBROUTINE colvar_check_points

! **************************************************************************************************
!> \brief evaluates the derivatives (dsdr) given and due to the given colvar
!>      variables in a molecular environment
!> \param colvar the collective variable to evaluate
!> \param cell ...
!> \param particles ...
!> \param pos ...
!> \param fixd_list ...
!> \author Teodoro Laino
! **************************************************************************************************
   SUBROUTINE colvar_eval_mol_f(colvar, cell, particles, pos, fixd_list)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles
      REAL(kind=dp), DIMENSION(:, :), INTENT(IN), &
         OPTIONAL                                        :: pos
      TYPE(fixd_constraint_type), DIMENSION(:), &
         OPTIONAL, POINTER                               :: fixd_list

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

      INTEGER                                            :: i, j
      LOGICAL                                            :: colvar_ok

      colvar_ok = ASSOCIATED(colvar)
      CPASSERT(colvar_ok)

      IF (PRESENT(pos)) THEN
         DO i = 1, SIZE(colvar%i_atom)
            j = colvar%i_atom(i)
            particles(j)%r = pos(:, j)
         END DO
      END IF
      ! Initialize the content of the derivative
      colvar%dsdr = 0.0_dp
      SELECT CASE (colvar%type_id)
      CASE (dist_colvar_id)
         CALL dist_colvar(colvar, cell, particles=particles)
      CASE (coord_colvar_id)
         CALL coord_colvar(colvar, cell, particles=particles)
      CASE (population_colvar_id)
         CALL population_colvar(colvar, cell, particles=particles)
      CASE (gyration_colvar_id)
         CALL gyration_radius_colvar(colvar, cell, particles=particles)
      CASE (torsion_colvar_id)
         CALL torsion_colvar(colvar, cell, particles=particles)
      CASE (angle_colvar_id)
         CALL angle_colvar(colvar, cell, particles=particles)
      CASE (dfunct_colvar_id)
         CALL dfunct_colvar(colvar, cell, particles=particles)
      CASE (plane_distance_colvar_id)
         CALL plane_distance_colvar(colvar, cell, particles=particles)
      CASE (plane_plane_angle_colvar_id)
         CALL plane_plane_angle_colvar(colvar, cell, particles=particles)
      CASE (rotation_colvar_id)
         CALL rotation_colvar(colvar, cell, particles=particles)
      CASE (qparm_colvar_id)
         CALL qparm_colvar(colvar, cell, particles=particles)
      CASE (hydronium_shell_colvar_id)
         CALL hydronium_shell_colvar(colvar, cell, particles=particles)
      CASE (hydronium_dist_colvar_id)
         CALL hydronium_dist_colvar(colvar, cell, particles=particles)
      CASE (acid_hyd_dist_colvar_id)
         CALL acid_hyd_dist_colvar(colvar, cell, particles=particles)
      CASE (acid_hyd_shell_colvar_id)
         CALL acid_hyd_shell_colvar(colvar, cell, particles=particles)
      CASE (rmsd_colvar_id)
         CALL rmsd_colvar(colvar, particles=particles)
      CASE (reaction_path_colvar_id)
         CALL reaction_path_colvar(colvar, cell, particles=particles)
      CASE (distance_from_path_colvar_id)
         CALL distance_from_path_colvar(colvar, cell, particles=particles)
      CASE (combine_colvar_id)
         CALL combine_colvar(colvar, cell, particles=particles)
      CASE (xyz_diag_colvar_id)
         CALL xyz_diag_colvar(colvar, cell, particles=particles)
      CASE (xyz_outerdiag_colvar_id)
         CALL xyz_outerdiag_colvar(colvar, cell, particles=particles)
      CASE (ring_puckering_colvar_id)
         CALL ring_puckering_colvar(colvar, cell, particles=particles)
      CASE (mindist_colvar_id)
         CALL mindist_colvar(colvar, cell, particles=particles)
      CASE (u_colvar_id)
         CPABORT("need force_env!")
      CASE (Wc_colvar_id)
         !!! FIXME this is rubbish at the moment as we have no force to be computed on this
         CALL Wc_colvar(colvar, cell, particles=particles)
      CASE (HBP_colvar_id)
         !!! FIXME this is rubbish at the moment as we have no force to be computed on this
         CALL HBP_colvar(colvar, cell, particles=particles)
      CASE DEFAULT
         CPABORT("")
      END SELECT
      ! Check for fixed atom constraints
      IF (PRESENT(fixd_list)) CALL check_fixed_atom_cns_colv(fixd_list, colvar)

   END SUBROUTINE colvar_eval_mol_f

! **************************************************************************************************
!> \brief evaluates the derivatives (dsdr) given and due to the given colvar
!> \param icolvar the collective variable to evaluate
!> \param force_env ...
!> \author Alessandro Laio and fawzi
!> \note
!>      The torsion that generally is defined without the continuity problem
!>      here (for free energy calculations) is defined only for (-pi,pi]
! **************************************************************************************************
   SUBROUTINE colvar_eval_glob_f(icolvar, force_env)
      INTEGER                                            :: icolvar
      TYPE(force_env_type), POINTER                      :: force_env

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

      LOGICAL                                            :: colvar_ok
      TYPE(cell_type), POINTER                           :: cell
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cp_subsys_type), POINTER                      :: subsys
      TYPE(qs_environment_type), POINTER                 :: qs_env

      NULLIFY (subsys, cell, colvar, qs_env)
      CALL force_env_get(force_env, subsys=subsys, cell=cell, qs_env=qs_env)
      colvar_ok = ASSOCIATED(subsys%colvar_p)
      CPASSERT(colvar_ok)

      colvar => subsys%colvar_p(icolvar)%colvar
      ! Initialize the content of the derivative
      colvar%dsdr = 0.0_dp
      SELECT CASE (colvar%type_id)
      CASE (dist_colvar_id)
         CALL dist_colvar(colvar, cell, subsys=subsys)
      CASE (coord_colvar_id)
         CALL coord_colvar(colvar, cell, subsys=subsys)
      CASE (population_colvar_id)
         CALL population_colvar(colvar, cell, subsys=subsys)
      CASE (gyration_colvar_id)
         CALL gyration_radius_colvar(colvar, cell, subsys=subsys)
      CASE (torsion_colvar_id)
         CALL torsion_colvar(colvar, cell, subsys=subsys, no_riemann_sheet_op=.TRUE.)
      CASE (angle_colvar_id)
         CALL angle_colvar(colvar, cell, subsys=subsys)
      CASE (dfunct_colvar_id)
         CALL dfunct_colvar(colvar, cell, subsys=subsys)
      CASE (plane_distance_colvar_id)
         CALL plane_distance_colvar(colvar, cell, subsys=subsys)
      CASE (plane_plane_angle_colvar_id)
         CALL plane_plane_angle_colvar(colvar, cell, subsys=subsys)
      CASE (rotation_colvar_id)
         CALL rotation_colvar(colvar, cell, subsys=subsys)
      CASE (qparm_colvar_id)
         CALL qparm_colvar(colvar, cell, subsys=subsys)
      CASE (hydronium_shell_colvar_id)
         CALL hydronium_shell_colvar(colvar, cell, subsys=subsys)
      CASE (hydronium_dist_colvar_id)
         CALL hydronium_dist_colvar(colvar, cell, subsys=subsys)
      CASE (acid_hyd_dist_colvar_id)
         CALL acid_hyd_dist_colvar(colvar, cell, subsys=subsys)
      CASE (acid_hyd_shell_colvar_id)
         CALL acid_hyd_shell_colvar(colvar, cell, subsys=subsys)
      CASE (rmsd_colvar_id)
         CALL rmsd_colvar(colvar, subsys=subsys)
      CASE (reaction_path_colvar_id)
         CALL reaction_path_colvar(colvar, cell, subsys=subsys)
      CASE (distance_from_path_colvar_id)
         CALL distance_from_path_colvar(colvar, cell, subsys=subsys)
      CASE (combine_colvar_id)
         CALL combine_colvar(colvar, cell, subsys=subsys)
      CASE (xyz_diag_colvar_id)
         CALL xyz_diag_colvar(colvar, cell, subsys=subsys)
      CASE (xyz_outerdiag_colvar_id)
         CALL xyz_outerdiag_colvar(colvar, cell, subsys=subsys)
      CASE (u_colvar_id)
         CALL u_colvar(colvar, force_env=force_env)
      CASE (Wc_colvar_id)
         CALL Wc_colvar(colvar, cell, subsys=subsys, qs_env=qs_env)
      CASE (HBP_colvar_id)
         CALL HBP_colvar(colvar, cell, subsys=subsys, qs_env=qs_env)
      CASE (ring_puckering_colvar_id)
         CALL ring_puckering_colvar(colvar, cell, subsys=subsys)
      CASE (mindist_colvar_id)
         CALL mindist_colvar(colvar, cell, subsys=subsys)
      CASE DEFAULT
         CPABORT("")
      END SELECT
      ! Check for fixed atom constraints
      CALL check_fixed_atom_cns_colv(subsys%gci%fixd_list, colvar)
   END SUBROUTINE colvar_eval_glob_f

! **************************************************************************************************
!> \brief evaluates the derivatives (dsdr) given and due to the given colvar
!>        for the specification of a recursive colvar type
!> \param colvar the collective variable to evaluate
!> \param cell ...
!> \param particles ...
!> \author sfchiff
! **************************************************************************************************
   SUBROUTINE colvar_recursive_eval(colvar, cell, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

! Initialize the content of the derivative

      colvar%dsdr = 0.0_dp
      SELECT CASE (colvar%type_id)
      CASE (dist_colvar_id)
         CALL dist_colvar(colvar, cell, particles=particles)
      CASE (coord_colvar_id)
         CALL coord_colvar(colvar, cell, particles=particles)
      CASE (torsion_colvar_id)
         CALL torsion_colvar(colvar, cell, particles=particles)
      CASE (angle_colvar_id)
         CALL angle_colvar(colvar, cell, particles=particles)
      CASE (dfunct_colvar_id)
         CALL dfunct_colvar(colvar, cell, particles=particles)
      CASE (plane_distance_colvar_id)
         CALL plane_distance_colvar(colvar, cell, particles=particles)
      CASE (plane_plane_angle_colvar_id)
         CALL plane_plane_angle_colvar(colvar, cell, particles=particles)
      CASE (rotation_colvar_id)
         CALL rotation_colvar(colvar, cell, particles=particles)
      CASE (qparm_colvar_id)
         CALL qparm_colvar(colvar, cell, particles=particles)
      CASE (hydronium_shell_colvar_id)
         CALL hydronium_shell_colvar(colvar, cell, particles=particles)
      CASE (hydronium_dist_colvar_id)
         CALL hydronium_dist_colvar(colvar, cell, particles=particles)
      CASE (acid_hyd_dist_colvar_id)
         CALL acid_hyd_dist_colvar(colvar, cell, particles=particles)
      CASE (acid_hyd_shell_colvar_id)
         CALL acid_hyd_shell_colvar(colvar, cell, particles=particles)
      CASE (rmsd_colvar_id)
         CALL rmsd_colvar(colvar, particles=particles)
      CASE (reaction_path_colvar_id)
         CALL reaction_path_colvar(colvar, cell, particles=particles)
      CASE (distance_from_path_colvar_id)
         CALL distance_from_path_colvar(colvar, cell, particles=particles)
      CASE (combine_colvar_id)
         CALL combine_colvar(colvar, cell, particles=particles)
      CASE (xyz_diag_colvar_id)
         CALL xyz_diag_colvar(colvar, cell, particles=particles)
      CASE (xyz_outerdiag_colvar_id)
         CALL xyz_outerdiag_colvar(colvar, cell, particles=particles)
      CASE (ring_puckering_colvar_id)
         CALL ring_puckering_colvar(colvar, cell, particles=particles)
      CASE (mindist_colvar_id)
         CALL mindist_colvar(colvar, cell, particles=particles)
      CASE (u_colvar_id)
         CPABORT("need force_env!")
      CASE (Wc_colvar_id)
         CALL Wc_colvar(colvar, cell, particles=particles)
      CASE (HBP_colvar_id)
         CALL HBP_colvar(colvar, cell, particles=particles)
      CASE DEFAULT
         CPABORT("")
      END SELECT
   END SUBROUTINE colvar_recursive_eval

! **************************************************************************************************
!> \brief Get coordinates of atoms or of geometrical points
!> \param colvar ...
!> \param i ...
!> \param ri ...
!> \param my_particles ...
!> \author Teodoro Laino 03.2007 [created]
! **************************************************************************************************
   SUBROUTINE get_coordinates(colvar, i, ri, my_particles)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: i
      REAL(KIND=dp), DIMENSION(3), INTENT(OUT)           :: ri
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      IF (colvar%use_points) THEN
         CALL eval_point_pos(colvar%points(i), my_particles, ri)
      ELSE
         ri(:) = my_particles(i)%r(:)
      END IF

   END SUBROUTINE get_coordinates

! **************************************************************************************************
!> \brief Get masses of atoms or of geometrical points
!> \param colvar ...
!> \param i ...
!> \param mi ...
!> \param my_particles ...
!> \author Teodoro Laino 03.2007 [created]
! **************************************************************************************************
   SUBROUTINE get_mass(colvar, i, mi, my_particles)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: i
      REAL(KIND=dp), INTENT(OUT)                         :: mi
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      IF (colvar%use_points) THEN
         CALL eval_point_mass(colvar%points(i), my_particles, mi)
      ELSE
         mi = my_particles(i)%atomic_kind%mass
      END IF

   END SUBROUTINE get_mass

! **************************************************************************************************
!> \brief Transfer derivatives to ds/dr
!> \param colvar ...
!> \param i ...
!> \param fi ...
!> \author Teodoro Laino 03.2007 [created]
! **************************************************************************************************
   SUBROUTINE put_derivative(colvar, i, fi)
      TYPE(colvar_type), POINTER                         :: colvar
      INTEGER, INTENT(IN)                                :: i
      REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: fi

      IF (colvar%use_points) THEN
         CALL eval_point_der(colvar%points, i, colvar%dsdr, fi)
      ELSE
         colvar%dsdr(:, i) = colvar%dsdr(:, i)+fi
      END IF

   END SUBROUTINE put_derivative

! **************************************************************************************************
!> \brief  evaluates the force due to the position colvar
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2010 [created]
! **************************************************************************************************
   SUBROUTINE xyz_diag_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i
      REAL(dp)                                           :: fi(3), r, r0(3), ss(3), xi(3), xpi(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == xyz_diag_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%xyz_diag_param%i_atom
      ! Atom coordinates
      CALL get_coordinates(colvar, i, xpi, my_particles)
      ! Use the current coordinates as initial coordinates, if no initialization
      ! was performed yet
      IF (.NOT. colvar%xyz_diag_param%use_absolute_position) THEN
         IF (ALL(colvar%xyz_diag_param%r0 == HUGE(0.0_dp))) THEN
            colvar%xyz_diag_param%r0 = xpi
         END IF
         r0 = colvar%xyz_diag_param%r0
      ELSE
         r0 = 0.0_dp
      ENDIF

      IF (colvar%xyz_diag_param%use_pbc) THEN
         ss = MATMUL(cell%h_inv, xpi-r0)
         ss = ss-NINT(ss)
         xi = MATMUL(cell%hmat, ss)
      ELSE
         xi = xpi-r0
      END IF

      IF (.NOT. colvar%xyz_diag_param%use_absolute_position) THEN
         SELECT CASE (colvar%xyz_diag_param%component)
         CASE (do_clv_x)
            xi(2) = 0.0_dp
            xi(3) = 0.0_dp
         CASE (do_clv_y)
            xi(1) = 0.0_dp
            xi(3) = 0.0_dp
         CASE (do_clv_z)
            xi(1) = 0.0_dp
            xi(2) = 0.0_dp
         CASE (do_clv_xy)
            xi(3) = 0.0_dp
         CASE (do_clv_xz)
            xi(2) = 0.0_dp
         CASE (do_clv_yz)
            xi(1) = 0.0_dp
         CASE DEFAULT
            ! do_clv_xyz
         END SELECT

         r = xi(1)**2+xi(2)**2+xi(3)**2
         fi(:) = 2.0_dp*xi
      ELSE
         SELECT CASE (colvar%xyz_diag_param%component)
         CASE (do_clv_x)
            r = xi(1)
            xi(1) = 1.0_dp
            xi(2) = 0.0_dp
            xi(3) = 0.0_dp
         CASE (do_clv_y)
            r = xi(2)
            xi(1) = 0.0_dp
            xi(2) = 1.0_dp
            xi(3) = 0.0_dp
         CASE (do_clv_z)
            r = xi(3)
            xi(1) = 0.0_dp
            xi(2) = 0.0_dp
            xi(3) = 1.0_dp
         CASE DEFAULT
            !Not implemented for anything which is not a single component.
            CPABORT("")
         END SELECT
         fi(:) = xi
      ENDIF

      colvar%ss = r
      CALL put_derivative(colvar, 1, fi)

   END SUBROUTINE xyz_diag_colvar

! **************************************************************************************************
!> \brief  evaluates the force due to the position colvar
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2010 [created]
! **************************************************************************************************
   SUBROUTINE xyz_outerdiag_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, k, l
      REAL(dp)                                           :: fi(3, 2), r, r0(3), ss(3), xi(3, 2), &
                                                            xpi(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == xyz_outerdiag_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      DO k = 1, 2
         i = colvar%xyz_outerdiag_param%i_atoms(k)
         ! Atom coordinates
         CALL get_coordinates(colvar, i, xpi, my_particles)
         r0 = colvar%xyz_outerdiag_param%r0(:, k)
         IF (ALL(colvar%xyz_outerdiag_param%r0(:, k) == HUGE(0.0_dp))) r0 = xpi

         IF (colvar%xyz_outerdiag_param%use_pbc) THEN
            ss = MATMUL(cell%h_inv, xpi-r0)
            ss = ss-NINT(ss)
            xi(:, k) = MATMUL(cell%hmat, ss)
         ELSE
            xi(:, k) = xpi-r0
         END IF

         SELECT CASE (colvar%xyz_outerdiag_param%components (k))
         CASE (do_clv_x)
            xi(2, k) = 0.0_dp
            xi(3, k) = 0.0_dp
         CASE (do_clv_y)
            xi(1, k) = 0.0_dp
            xi(3, k) = 0.0_dp
         CASE (do_clv_z)
            xi(1, k) = 0.0_dp
            xi(2, k) = 0.0_dp
         CASE (do_clv_xy)
            xi(3, k) = 0.0_dp
         CASE (do_clv_xz)
            xi(2, k) = 0.0_dp
         CASE (do_clv_yz)
            xi(1, k) = 0.0_dp
         CASE DEFAULT
            ! do_clv_xyz
         END SELECT
      END DO

      r = 0.0_dp
      fi = 0.0_dp
      DO i = 1, 3
         DO l = 1, 3
            IF (xi(l, 1) /= 0.0_dp) fi(l, 1) = fi(l, 1)+xi(i, 2)
            r = r+xi(l, 1)*xi(i, 2)
         END DO
         IF (xi(i, 2) /= 0.0_dp) fi(i, 2) = SUM(xi(:, 1))
      END DO

      colvar%ss = r
      CALL put_derivative(colvar, 1, fi(:, 1))
      CALL put_derivative(colvar, 2, fi(:, 2))

   END SUBROUTINE xyz_outerdiag_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the energy as collective variable
!> \param colvar ...
!> \param force_env ...
!> \par History Modified to allow functions of energy in a mixed_env environment
!>              Teodoro Laino [tlaino] - 02.2011
!> \author Sebastiano Caravati
! **************************************************************************************************
   SUBROUTINE u_colvar(colvar, force_env)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(force_env_type), OPTIONAL, POINTER            :: force_env

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

      CHARACTER(LEN=default_path_length)                 :: coupling_function
      CHARACTER(LEN=default_string_length)               :: def_error, this_error
      CHARACTER(LEN=default_string_length), &
         DIMENSION(:), POINTER                           :: parameters
      INTEGER                                            :: iatom, iforce_eval, iparticle, &
                                                            jparticle, natom, natom_iforce, &
                                                            nforce_eval
      INTEGER, DIMENSION(:), POINTER                     :: glob_natoms, map_index
      REAL(dp)                                           :: dedf, dx, err, fi(3), lerr, &
                                                            potential_energy
      REAL(KIND=dp), DIMENSION(:), POINTER               :: values
      TYPE(cp_subsys_p_type), DIMENSION(:), POINTER      :: subsystems
      TYPE(cp_subsys_type), POINTER                      :: subsys_main
      TYPE(mixed_force_type), DIMENSION(:), POINTER      :: global_forces
      TYPE(particle_list_p_type), DIMENSION(:), POINTER  :: particles
      TYPE(particle_list_type), POINTER                  :: particles_main
      TYPE(section_vals_type), POINTER                   :: force_env_section, mapping_section, &
                                                            wrk_section

      IF (PRESENT(force_env)) THEN
         NULLIFY (particles_main, subsys_main)
         CALL force_env_get(force_env=force_env, subsys=subsys_main)
         CALL cp_subsys_get(subsys=subsys_main, particles=particles_main)
         natom = SIZE(particles_main%els)
         colvar%n_atom_s = natom
         colvar%u_param%natom = natom
         CALL reallocate(colvar%i_atom, 1, natom)
         CALL reallocate(colvar%dsdr, 1, 3, 1, natom)
         DO iatom = 1, natom
            colvar%i_atom(iatom) = iatom
         ENDDO

         IF (.NOT. ASSOCIATED(colvar%u_param%mixed_energy_section)) THEN
            CALL force_env_get(force_env, potential_energy=potential_energy)
            colvar%ss = potential_energy

            DO iatom = 1, natom
               ! store derivative
               fi(:) = -particles_main%els(iatom)%f
               CALL put_derivative(colvar, iatom, fi)
            ENDDO
         ELSE
            IF (force_env%in_use /= use_mixed_force) &
               CALL cp_abort(__LOCATION__, &
                             'ASSERTION (cond) failed at line '//cp_to_string(__LINE__)// &
                             ' A combination of mixed force_eval energies has been requested as '// &
                             ' collective variable, but the MIXED env is not in use! Aborting.')
            CALL force_env_get(force_env, force_env_section=force_env_section)
            mapping_section => section_vals_get_subs_vals(force_env_section, "MIXED%MAPPING")
            NULLIFY (values, parameters, subsystems, particles, global_forces, map_index, glob_natoms)
            nforce_eval = SIZE(force_env%sub_force_env)
            ALLOCATE (glob_natoms(nforce_eval))
            ALLOCATE (subsystems(nforce_eval))
            ALLOCATE (particles(nforce_eval))
            ! Local Info to sync
            ALLOCATE (global_forces(nforce_eval))

            glob_natoms = 0
            DO iforce_eval = 1, nforce_eval
               NULLIFY (subsystems(iforce_eval)%subsys, particles(iforce_eval)%list)
               IF (.NOT. ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) CYCLE
               ! Get all available subsys
               CALL force_env_get(force_env=force_env%sub_force_env(iforce_eval)%force_env, &
                                  subsys=subsystems(iforce_eval)%subsys)
               ! Get available particles
               CALL cp_subsys_get(subsys=subsystems(iforce_eval)%subsys, &
                                  particles=particles(iforce_eval)%list)

               ! Get Mapping index array
               natom_iforce = SIZE(particles(iforce_eval)%list%els)

               ! Only the rank 0 process collect info for each computation
               IF (force_env%sub_force_env(iforce_eval)%force_env%para_env%mepos == &
                   force_env%sub_force_env(iforce_eval)%force_env%para_env%source) THEN
                  glob_natoms(iforce_eval) = natom_iforce
               END IF
            END DO

            ! Handling Parallel execution
            CALL mp_sync(force_env%para_env%group)
            CALL mp_sum(glob_natoms, force_env%para_env%group)

            ! Transfer forces
            DO iforce_eval = 1, nforce_eval
               ALLOCATE (global_forces(iforce_eval)%forces(3, glob_natoms(iforce_eval)))
               global_forces(iforce_eval)%forces = 0.0_dp
               IF (ASSOCIATED(force_env%sub_force_env(iforce_eval)%force_env)) THEN
                  IF (force_env%sub_force_env(iforce_eval)%force_env%para_env%mepos == &
                      force_env%sub_force_env(iforce_eval)%force_env%para_env%source) THEN
                     ! Forces
                     DO iparticle = 1, glob_natoms(iforce_eval)
                        global_forces(iforce_eval)%forces(:, iparticle) = &
                           particles(iforce_eval)%list%els(iparticle)%f
                     END DO
                  END IF
               END IF
               CALL mp_sum(global_forces(iforce_eval)%forces, force_env%para_env%group)
            END DO

            wrk_section => colvar%u_param%mixed_energy_section
            ! Support any number of force_eval sections
            CALL get_generic_info(wrk_section, "ENERGY_FUNCTION", coupling_function, parameters, &
                                  values, force_env%mixed_env%energies)
            CALL initf(1)
            CALL parsef(1, TRIM(coupling_function), parameters)
            ! Store the value of the COLVAR
            colvar%ss = evalf(1, values)
            CPASSERT(EvalErrType <= 0)

            DO iforce_eval = 1, nforce_eval
               CALL section_vals_val_get(wrk_section, "DX", r_val=dx)
               CALL section_vals_val_get(wrk_section, "ERROR_LIMIT", r_val=lerr)
               dedf = evalfd(1, iforce_eval, values, dx, err)
               IF (ABS(err) > lerr) THEN
                  WRITE (this_error, "(A,G12.6,A)") "(", err, ")"
                  WRITE (def_error, "(A,G12.6,A)") "(", lerr, ")"
                  CALL compress(this_error, .TRUE.)
                  CALL compress(def_error, .TRUE.)
                  CALL cp_warn(__LOCATION__, &
                               'ASSERTION (cond) failed at line '//cp_to_string(__LINE__)// &
                               ' Error '//TRIM(this_error)//' in computing numerical derivatives larger then'// &
                               TRIM(def_error)//' .')
               END IF
               ! General Mapping of forces...
               ! First: Get Mapping index array
               CALL get_subsys_map_index(mapping_section, glob_natoms(iforce_eval), iforce_eval, &
                                         nforce_eval, map_index)

               ! Second: store derivatives
               DO iparticle = 1, glob_natoms(iforce_eval)
                  jparticle = map_index(iparticle)
                  fi = -dedf*global_forces(iforce_eval)%forces(:, iparticle)
                  CALL put_derivative(colvar, jparticle, fi)
               END DO
               ! Deallocate map_index array
               IF (ASSOCIATED(map_index)) THEN
                  DEALLOCATE (map_index)
               END IF
            END DO
            CALL finalizef()
            DO iforce_eval = 1, nforce_eval
               DEALLOCATE (global_forces(iforce_eval)%forces)
            END DO
            DEALLOCATE (glob_natoms)
            DEALLOCATE (values)
            DEALLOCATE (parameters)
            DEALLOCATE (global_forces)
            DEALLOCATE (subsystems)
            DEALLOCATE (particles)
         END IF
      ELSE
         CPABORT("need force_env!")
      ENDIF
   END SUBROUTINE u_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the distance from the plane collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2006 [created]
! **************************************************************************************************
   SUBROUTINE plane_distance_colvar(colvar, cell, subsys, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, j, k, l
      REAL(dp) :: a, b, dsdxpn(3), dxpndxi(3, 3), dxpndxj(3, 3), dxpndxk(3, 3), fi(3), fj(3), &
         fk(3), fl(3), r12, ri(3), rj(3), rk(3), rl(3), ss(3), xpij(3), xpkj(3), xpl(3), xpn(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == plane_distance_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%plane_distance_param%plane(1)
      j = colvar%plane_distance_param%plane(2)
      k = colvar%plane_distance_param%plane(3)
      l = colvar%plane_distance_param%point
      ! Get coordinates of atoms or points
      CALL get_coordinates(colvar, i, ri, my_particles)
      CALL get_coordinates(colvar, j, rj, my_particles)
      CALL get_coordinates(colvar, k, rk, my_particles)
      CALL get_coordinates(colvar, l, rl, my_particles)
      xpij = ri-rj
      xpkj = rk-rj
      xpl = rl-(ri+rj+rk)/3.0_dp
      IF (colvar%plane_distance_param%use_pbc) THEN
         ! xpij
         ss = MATMUL(cell%h_inv, ri-rj)
         ss = ss-NINT(ss)
         xpij = MATMUL(cell%hmat, ss)
         ! xpkj
         ss = MATMUL(cell%h_inv, rk-rj)
         ss = ss-NINT(ss)
         xpkj = MATMUL(cell%hmat, ss)
         ! xpl
         ss = MATMUL(cell%h_inv, rl-(ri+rj+rk)/3.0_dp)
         ss = ss-NINT(ss)
         xpl = MATMUL(cell%hmat, ss)
      END IF
      ! xpn
      xpn(1) = xpij(2)*xpkj(3)-xpij(3)*xpkj(2)
      xpn(2) = xpij(3)*xpkj(1)-xpij(1)*xpkj(3)
      xpn(3) = xpij(1)*xpkj(2)-xpij(2)*xpkj(1)
      a = DOT_PRODUCT(xpn, xpn)
      b = DOT_PRODUCT(xpl, xpn)
      r12 = SQRT(a)
      colvar%ss = b/r12
      dsdxpn(1) = xpl(1)/r12-b*xpn(1)/(r12*a)
      dsdxpn(2) = xpl(2)/r12-b*xpn(2)/(r12*a)
      dsdxpn(3) = xpl(3)/r12-b*xpn(3)/(r12*a)
      !
      dxpndxi(1, 1) = 0.0_dp
      dxpndxi(1, 2) = 1.0_dp*xpkj(3)
      dxpndxi(1, 3) = -1.0_dp*xpkj(2)
      dxpndxi(2, 1) = -1.0_dp*xpkj(3)
      dxpndxi(2, 2) = 0.0_dp
      dxpndxi(2, 3) = 1.0_dp*xpkj(1)
      dxpndxi(3, 1) = 1.0_dp*xpkj(2)
      dxpndxi(3, 2) = -1.0_dp*xpkj(1)
      dxpndxi(3, 3) = 0.0_dp
      !
      dxpndxj(1, 1) = 0.0_dp
      dxpndxj(1, 2) = -1.0_dp*xpkj(3)+xpij(3)
      dxpndxj(1, 3) = -1.0_dp*xpij(2)+xpkj(2)
      dxpndxj(2, 1) = -1.0_dp*xpij(3)+xpkj(3)
      dxpndxj(2, 2) = 0.0_dp
      dxpndxj(2, 3) = -1.0_dp*xpkj(1)+xpij(1)
      dxpndxj(3, 1) = -1.0_dp*xpkj(2)+xpij(2)
      dxpndxj(3, 2) = -1.0_dp*xpij(1)+xpkj(1)
      dxpndxj(3, 3) = 0.0_dp
      !
      dxpndxk(1, 1) = 0.0_dp
      dxpndxk(1, 2) = -1.0_dp*xpij(3)
      dxpndxk(1, 3) = 1.0_dp*xpij(2)
      dxpndxk(2, 1) = 1.0_dp*xpij(3)
      dxpndxk(2, 2) = 0.0_dp
      dxpndxk(2, 3) = -1.0_dp*xpij(1)
      dxpndxk(3, 1) = -1.0_dp*xpij(2)
      dxpndxk(3, 2) = 1.0_dp*xpij(1)
      dxpndxk(3, 3) = 0.0_dp
      !
      fi(:) = MATMUL(dsdxpn, dxpndxi)-xpn/(3.0_dp*r12)
      fj(:) = MATMUL(dsdxpn, dxpndxj)-xpn/(3.0_dp*r12)
      fk(:) = MATMUL(dsdxpn, dxpndxk)-xpn/(3.0_dp*r12)
      fl(:) = xpn/r12
      ! Transfer derivatives on atoms
      CALL put_derivative(colvar, 1, fi)
      CALL put_derivative(colvar, 2, fj)
      CALL put_derivative(colvar, 3, fk)
      CALL put_derivative(colvar, 4, fl)

   END SUBROUTINE plane_distance_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the angle between two planes.
!>        plane-plane angle collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2009 [created]
! **************************************************************************************************
   SUBROUTINE plane_plane_angle_colvar(colvar, cell, subsys, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i1, i2, j1, j2, k1, k2, np
      LOGICAL                                            :: check
      REAL(dp) :: a1, a2, d, dnorm_dxpn(3), dprod12_dxpn(3), dsdxpn(3), dt_dxpn(3), dxpndxi(3, 3), &
         dxpndxj(3, 3), dxpndxk(3, 3), fi(3), fj(3), fk(3), fmod, norm1, norm2, prod_12, ri1(3), &
         ri2(3), rj1(3), rj2(3), rk1(3), rk2(3), ss(3), t, xpij1(3), xpij2(3), xpkj1(3), xpkj2(3), &
         xpn1(3), xpn2(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      check = colvar%type_id == plane_plane_angle_colvar_id
      CPASSERT(check)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ! Plane 1
      IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) THEN
         i1 = colvar%plane_plane_angle_param%plane1%points(1)
         j1 = colvar%plane_plane_angle_param%plane1%points(2)
         k1 = colvar%plane_plane_angle_param%plane1%points(3)

         ! Get coordinates of atoms or points
         CALL get_coordinates(colvar, i1, ri1, my_particles)
         CALL get_coordinates(colvar, j1, rj1, my_particles)
         CALL get_coordinates(colvar, k1, rk1, my_particles)

         ! xpij
         ss = MATMUL(cell%h_inv, ri1-rj1)
         ss = ss-NINT(ss)
         xpij1 = MATMUL(cell%hmat, ss)

         ! xpkj
         ss = MATMUL(cell%h_inv, rk1-rj1)
         ss = ss-NINT(ss)
         xpkj1 = MATMUL(cell%hmat, ss)

         ! xpn
         xpn1(1) = xpij1(2)*xpkj1(3)-xpij1(3)*xpkj1(2)
         xpn1(2) = xpij1(3)*xpkj1(1)-xpij1(1)*xpkj1(3)
         xpn1(3) = xpij1(1)*xpkj1(2)-xpij1(2)*xpkj1(1)
      ELSE
         xpn1 = colvar%plane_plane_angle_param%plane1%normal_vec
      END IF
      a1 = DOT_PRODUCT(xpn1, xpn1)
      norm1 = SQRT(a1)
      CPASSERT(norm1 /= 0.0_dp)

      ! Plane 2
      IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) THEN
         i2 = colvar%plane_plane_angle_param%plane2%points(1)
         j2 = colvar%plane_plane_angle_param%plane2%points(2)
         k2 = colvar%plane_plane_angle_param%plane2%points(3)

         ! Get coordinates of atoms or points
         CALL get_coordinates(colvar, i2, ri2, my_particles)
         CALL get_coordinates(colvar, j2, rj2, my_particles)
         CALL get_coordinates(colvar, k2, rk2, my_particles)

         ! xpij
         ss = MATMUL(cell%h_inv, ri2-rj2)
         ss = ss-NINT(ss)
         xpij2 = MATMUL(cell%hmat, ss)

         ! xpkj
         ss = MATMUL(cell%h_inv, rk2-rj2)
         ss = ss-NINT(ss)
         xpkj2 = MATMUL(cell%hmat, ss)

         ! xpn
         xpn2(1) = xpij2(2)*xpkj2(3)-xpij2(3)*xpkj2(2)
         xpn2(2) = xpij2(3)*xpkj2(1)-xpij2(1)*xpkj2(3)
         xpn2(3) = xpij2(1)*xpkj2(2)-xpij2(2)*xpkj2(1)
      ELSE
         xpn2 = colvar%plane_plane_angle_param%plane2%normal_vec
      END IF
      a2 = DOT_PRODUCT(xpn2, xpn2)
      norm2 = SQRT(a2)
      CPASSERT(norm2 /= 0.0_dp)

      ! The value of the angle is defined only between 0 and Pi
      prod_12 = DOT_PRODUCT(xpn1, xpn2)

      d = norm1*norm2
      t = prod_12/d
      t = MIN(1.0_dp, ABS(t))*SIGN(1.0_dp, t)
      colvar%ss = ACOS(t)

      IF ((ABS(colvar%ss) .LT. tolerance_acos) .OR. (ABS(colvar%ss-pi) .LT. tolerance_acos)) THEN
         fmod = 0.0_dp
      ELSE
         fmod = -1.0_dp/SIN(colvar%ss)
      ENDIF
      ! Compute derivatives
      np = 0
      ! Plane 1
      IF (colvar%plane_plane_angle_param%plane1%type_of_def == plane_def_atoms) THEN
         dprod12_dxpn = xpn2
         dnorm_dxpn = 1.0_dp/norm1*xpn1
         dt_dxpn = (dprod12_dxpn*d-prod_12*dnorm_dxpn*norm2)/d**2

         dsdxpn(1) = fmod*dt_dxpn(1)
         dsdxpn(2) = fmod*dt_dxpn(2)
         dsdxpn(3) = fmod*dt_dxpn(3)
         !
         dxpndxi(1, 1) = 0.0_dp
         dxpndxi(1, 2) = 1.0_dp*xpkj1(3)
         dxpndxi(1, 3) = -1.0_dp*xpkj1(2)
         dxpndxi(2, 1) = -1.0_dp*xpkj1(3)
         dxpndxi(2, 2) = 0.0_dp
         dxpndxi(2, 3) = 1.0_dp*xpkj1(1)
         dxpndxi(3, 1) = 1.0_dp*xpkj1(2)
         dxpndxi(3, 2) = -1.0_dp*xpkj1(1)
         dxpndxi(3, 3) = 0.0_dp
         !
         dxpndxj(1, 1) = 0.0_dp
         dxpndxj(1, 2) = -1.0_dp*xpkj1(3)+xpij1(3)
         dxpndxj(1, 3) = -1.0_dp*xpij1(2)+xpkj1(2)
         dxpndxj(2, 1) = -1.0_dp*xpij1(3)+xpkj1(3)
         dxpndxj(2, 2) = 0.0_dp
         dxpndxj(2, 3) = -1.0_dp*xpkj1(1)+xpij1(1)
         dxpndxj(3, 1) = -1.0_dp*xpkj1(2)+xpij1(2)
         dxpndxj(3, 2) = -1.0_dp*xpij1(1)+xpkj1(1)
         dxpndxj(3, 3) = 0.0_dp
         !
         dxpndxk(1, 1) = 0.0_dp
         dxpndxk(1, 2) = -1.0_dp*xpij1(3)
         dxpndxk(1, 3) = 1.0_dp*xpij1(2)
         dxpndxk(2, 1) = 1.0_dp*xpij1(3)
         dxpndxk(2, 2) = 0.0_dp
         dxpndxk(2, 3) = -1.0_dp*xpij1(1)
         dxpndxk(3, 1) = -1.0_dp*xpij1(2)
         dxpndxk(3, 2) = 1.0_dp*xpij1(1)
         dxpndxk(3, 3) = 0.0_dp
         !
         fi = MATMUL(dsdxpn, dxpndxi)
         fj = MATMUL(dsdxpn, dxpndxj)
         fk = MATMUL(dsdxpn, dxpndxk)

         ! Transfer derivatives on atoms
         CALL put_derivative(colvar, np+1, fi)
         CALL put_derivative(colvar, np+2, fj)
         CALL put_derivative(colvar, np+3, fk)
         np = 3
      END IF

      ! Plane 2
      IF (colvar%plane_plane_angle_param%plane2%type_of_def == plane_def_atoms) THEN
         dprod12_dxpn = xpn1
         dnorm_dxpn = 1.0_dp/norm2*xpn2
         dt_dxpn = (dprod12_dxpn*d-prod_12*dnorm_dxpn*norm1)/d**2

         dsdxpn(1) = fmod*dt_dxpn(1)
         dsdxpn(2) = fmod*dt_dxpn(2)
         dsdxpn(3) = fmod*dt_dxpn(3)
         !
         dxpndxi(1, 1) = 0.0_dp
         dxpndxi(1, 2) = 1.0_dp*xpkj1(3)
         dxpndxi(1, 3) = -1.0_dp*xpkj1(2)
         dxpndxi(2, 1) = -1.0_dp*xpkj1(3)
         dxpndxi(2, 2) = 0.0_dp
         dxpndxi(2, 3) = 1.0_dp*xpkj1(1)
         dxpndxi(3, 1) = 1.0_dp*xpkj1(2)
         dxpndxi(3, 2) = -1.0_dp*xpkj1(1)
         dxpndxi(3, 3) = 0.0_dp
         !
         dxpndxj(1, 1) = 0.0_dp
         dxpndxj(1, 2) = -1.0_dp*xpkj1(3)+xpij1(3)
         dxpndxj(1, 3) = -1.0_dp*xpij1(2)+xpkj1(2)
         dxpndxj(2, 1) = -1.0_dp*xpij1(3)+xpkj1(3)
         dxpndxj(2, 2) = 0.0_dp
         dxpndxj(2, 3) = -1.0_dp*xpkj1(1)+xpij1(1)
         dxpndxj(3, 1) = -1.0_dp*xpkj1(2)+xpij1(2)
         dxpndxj(3, 2) = -1.0_dp*xpij1(1)+xpkj1(1)
         dxpndxj(3, 3) = 0.0_dp
         !
         dxpndxk(1, 1) = 0.0_dp
         dxpndxk(1, 2) = -1.0_dp*xpij1(3)
         dxpndxk(1, 3) = 1.0_dp*xpij1(2)
         dxpndxk(2, 1) = 1.0_dp*xpij1(3)
         dxpndxk(2, 2) = 0.0_dp
         dxpndxk(2, 3) = -1.0_dp*xpij1(1)
         dxpndxk(3, 1) = -1.0_dp*xpij1(2)
         dxpndxk(3, 2) = 1.0_dp*xpij1(1)
         dxpndxk(3, 3) = 0.0_dp
         !
         fi = MATMUL(dsdxpn, dxpndxi)
         fj = MATMUL(dsdxpn, dxpndxj)
         fk = MATMUL(dsdxpn, dxpndxk)

         ! Transfer derivatives on atoms
         CALL put_derivative(colvar, np+1, fi)
         CALL put_derivative(colvar, np+2, fj)
         CALL put_derivative(colvar, np+3, fk)
      END IF

   END SUBROUTINE plane_plane_angle_colvar

! **************************************************************************************************
!> \brief Evaluates the value of the rotation angle between two bonds
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2006 [created]
! **************************************************************************************************
   SUBROUTINE rotation_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, idum
      REAL(dp)                                           :: a, b, fmod, t0, t1, t2, t3, xdum(3), &
                                                            xij(3), xkj(3)
      REAL(KIND=dp)                                      :: dp1b1(3), dp1b2(3), dp2b1(3), dp2b2(3), &
                                                            ss(3), xp1b1(3), xp1b2(3), xp2b1(3), &
                                                            xp2b2(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == rotation_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%rotation_param%i_at1_bond1
      CALL get_coordinates(colvar, i, xp1b1, my_particles)
      i = colvar%rotation_param%i_at2_bond1
      CALL get_coordinates(colvar, i, xp2b1, my_particles)
      i = colvar%rotation_param%i_at1_bond2
      CALL get_coordinates(colvar, i, xp1b2, my_particles)
      i = colvar%rotation_param%i_at2_bond2
      CALL get_coordinates(colvar, i, xp2b2, my_particles)
      ! xij
      ss = MATMUL(cell%h_inv, xp1b1-xp2b1)
      ss = ss-NINT(ss)
      xij = MATMUL(cell%hmat, ss)
      ! xkj
      ss = MATMUL(cell%h_inv, xp1b2-xp2b2)
      ss = ss-NINT(ss)
      xkj = MATMUL(cell%hmat, ss)
      ! evaluation of the angle..
      a = SQRT(DOT_PRODUCT(xij, xij))
      b = SQRT(DOT_PRODUCT(xkj, xkj))
      t0 = 1.0_dp/(a*b)
      t1 = 1.0_dp/(a**3.0_dp*b)
      t2 = 1.0_dp/(a*b**3.0_dp)
      t3 = DOT_PRODUCT(xij, xkj)
      colvar%ss = ACOS(t3*t0)
      IF ((ABS(colvar%ss) .LT. tolerance_acos) .OR. (ABS(colvar%ss-pi) .LT. tolerance_acos)) THEN
         fmod = 0.0_dp
      ELSE
         fmod = -1.0_dp/SIN(colvar%ss)
      ENDIF
      dp1b1 = xkj(:)*t0-xij(:)*t1*t3
      dp2b1 = -xkj(:)*t0+xij(:)*t1*t3
      dp1b2 = xij(:)*t0-xkj(:)*t2*t3
      dp2b2 = -xij(:)*t0+xkj(:)*t2*t3

      xdum = dp1b1*fmod
      idum = colvar%rotation_param%i_at1_bond1
      CALL put_derivative(colvar, idum, xdum)
      xdum = dp2b1*fmod
      idum = colvar%rotation_param%i_at2_bond1
      CALL put_derivative(colvar, idum, xdum)
      xdum = dp1b2*fmod
      idum = colvar%rotation_param%i_at1_bond2
      CALL put_derivative(colvar, idum, xdum)
      xdum = dp2b2*fmod
      idum = colvar%rotation_param%i_at2_bond2
      CALL put_derivative(colvar, idum, xdum)

   END SUBROUTINE rotation_colvar

! **************************************************************************************************
!> \brief evaluates the force due to the function of two distances
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2006 [created]
!> \note modified Florian Schiffmann 08.2008
! **************************************************************************************************
   SUBROUTINE dfunct_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, j, k, l
      REAL(dp)                                           :: fi(3), fj(3), fk(3), fl(3), r12, r34, &
                                                            ss(3), xij(3), xkl(3), xpi(3), xpj(3), &
                                                            xpk(3), xpl(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == dfunct_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%dfunct_param%i_at_dfunct(1)
      j = colvar%dfunct_param%i_at_dfunct(2)
      ! First bond
      CALL get_coordinates(colvar, i, xpi, my_particles)
      CALL get_coordinates(colvar, j, xpj, my_particles)
      IF (colvar%dfunct_param%use_pbc) THEN
         ss = MATMUL(cell%h_inv, xpi-xpj)
         ss = ss-NINT(ss)
         xij = MATMUL(cell%hmat, ss)
      ELSE
         xij = xpi-xpj
      END IF
      r12 = SQRT(xij(1)**2+xij(2)**2+xij(3)**2)
      ! Second bond
      k = colvar%dfunct_param%i_at_dfunct(3)
      l = colvar%dfunct_param%i_at_dfunct(4)
      CALL get_coordinates(colvar, k, xpk, my_particles)
      CALL get_coordinates(colvar, l, xpl, my_particles)
      IF (colvar%dfunct_param%use_pbc) THEN
         ss = MATMUL(cell%h_inv, xpk-xpl)
         ss = ss-NINT(ss)
         xkl = MATMUL(cell%hmat, ss)
      ELSE
         xkl = xpk-xpl
      END IF
      r34 = SQRT(xkl(1)**2+xkl(2)**2+xkl(3)**2)
      !
      colvar%ss = r12+colvar%dfunct_param%coeff*r34
      fi(:) = xij/r12
      fj(:) = -xij/r12
      fk(:) = colvar%dfunct_param%coeff*xkl/r34
      fl(:) = -colvar%dfunct_param%coeff*xkl/r34
      CALL put_derivative(colvar, 1, fi)
      CALL put_derivative(colvar, 2, fj)
      CALL put_derivative(colvar, 3, fk)
      CALL put_derivative(colvar, 4, fl)

   END SUBROUTINE dfunct_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the distance from the plane collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino 02.2006 [created]
! **************************************************************************************************
   SUBROUTINE angle_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, j, k
      REAL(dp)                                           :: a, b, fi(3), fj(3), fk(3), fmod, ri(3), &
                                                            rj(3), rk(3), ss(3), t0, t1, t2, t3, &
                                                            xij(3), xkj(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == angle_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%angle_param%i_at_angle(1)
      j = colvar%angle_param%i_at_angle(2)
      k = colvar%angle_param%i_at_angle(3)
      CALL get_coordinates(colvar, i, ri, my_particles)
      CALL get_coordinates(colvar, j, rj, my_particles)
      CALL get_coordinates(colvar, k, rk, my_particles)
      ! xij
      ss = MATMUL(cell%h_inv, ri-rj)
      ss = ss-NINT(ss)
      xij = MATMUL(cell%hmat, ss)
      ! xkj
      ss = MATMUL(cell%h_inv, rk-rj)
      ss = ss-NINT(ss)
      xkj = MATMUL(cell%hmat, ss)
      ! Evaluation of the angle..
      a = SQRT(DOT_PRODUCT(xij, xij))
      b = SQRT(DOT_PRODUCT(xkj, xkj))
      t0 = 1.0_dp/(a*b)
      t1 = 1.0_dp/(a**3.0_dp*b)
      t2 = 1.0_dp/(a*b**3.0_dp)
      t3 = DOT_PRODUCT(xij, xkj)
      colvar%ss = ACOS(t3*t0)
      IF ((ABS(colvar%ss) .LT. tolerance_acos) .OR. (ABS(colvar%ss-pi) .LT. tolerance_acos)) THEN
         fmod = 0.0_dp
      ELSE
         fmod = -1.0_dp/SIN(colvar%ss)
      ENDIF
      fi(:) = xkj(:)*t0-xij(:)*t1*t3
      fj(:) = -xkj(:)*t0+xij(:)*t1*t3-xij(:)*t0+xkj(:)*t2*t3
      fk(:) = xij(:)*t0-xkj(:)*t2*t3
      fi = fi*fmod
      fj = fj*fmod
      fk = fk*fmod
      CALL put_derivative(colvar, 1, fi)
      CALL put_derivative(colvar, 2, fj)
      CALL put_derivative(colvar, 3, fk)

   END SUBROUTINE angle_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the distance collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Alessandro Laio, Fawzi Mohamed
! **************************************************************************************************
   SUBROUTINE dist_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, j
      REAL(dp)                                           :: fi(3), fj(3), r12, ss(3), xij(3), &
                                                            xpi(3), xpj(3)
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)

      CPASSERT(colvar%type_id == dist_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      i = colvar%dist_param%i_at
      j = colvar%dist_param%j_at
      CALL get_coordinates(colvar, i, xpi, my_particles)
      CALL get_coordinates(colvar, j, xpj, my_particles)
      ss = MATMUL(cell%h_inv, xpi-xpj)
      ss = ss-NINT(ss)
      xij = MATMUL(cell%hmat, ss)
      SELECT CASE (colvar%dist_param%axis_id)
      CASE (do_clv_x)
         xij(2) = 0.0_dp
         xij(3) = 0.0_dp
      CASE (do_clv_y)
         xij(1) = 0.0_dp
         xij(3) = 0.0_dp
      CASE (do_clv_z)
         xij(1) = 0.0_dp
         xij(2) = 0.0_dp
      CASE (do_clv_xy)
         xij(3) = 0.0_dp
      CASE (do_clv_xz)
         xij(2) = 0.0_dp
      CASE (do_clv_yz)
         xij(1) = 0.0_dp
      CASE DEFAULT
         !do_clv_xyz
      END SELECT
      r12 = SQRT(xij(1)**2+xij(2)**2+xij(3)**2)

      colvar%ss = r12
      fi(:) = xij/r12
      fj(:) = -xij/r12

      CALL put_derivative(colvar, 1, fi)
      CALL put_derivative(colvar, 2, fj)

   END SUBROUTINE dist_colvar

! **************************************************************************************************
!> \brief evaluates the force due to the torsion collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \param no_riemann_sheet_op ...
!> \author Alessandro Laio, Fawzi Mohamed
! **************************************************************************************************
   SUBROUTINE torsion_colvar(colvar, cell, subsys, particles, no_riemann_sheet_op)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles
      LOGICAL, INTENT(IN), OPTIONAL                      :: no_riemann_sheet_op

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

      INTEGER                                            :: i, ii
      LOGICAL                                            :: no_riemann_sheet
      REAL(dp) :: angle, cosine, dedphi, dedxia, dedxib, dedxic, dedxid, dedxt, dedxu, dedyia, &
         dedyib, dedyic, dedyid, dedyt, dedyu, dedzia, dedzib, dedzic, dedzid, dedzt, dedzu, dt, &
         e, ftmp(3), o0, rcb, rt2, rtmp(3), rtru, ru2, sine, ss(3), xba, xca, xcb, xdb, xdc, xt, &
         xtu, xu, yba, yca, ycb, ydb, ydc, yt, ytu, yu, zba, zca, zcb, zdb, zdc, zt, ztu, zu
      REAL(dp), DIMENSION(3, 4)                          :: rr
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == torsion_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      no_riemann_sheet = .FALSE.
      IF (PRESENT(no_riemann_sheet_op)) no_riemann_sheet = no_riemann_sheet_op
      DO ii = 1, 4
         i = colvar%torsion_param%i_at_tors(ii)
         CALL get_coordinates(colvar, i, rtmp, my_particles)
         rr(:, ii) = rtmp(1:3)
      ENDDO
      o0 = colvar%torsion_param%o0
      ! ba
      ss = MATMUL(cell%h_inv, rr(:, 2)-rr(:, 1))
      ss = ss-NINT(ss)
      ss = MATMUL(cell%hmat, ss)
      xba = ss(1)
      yba = ss(2)
      zba = ss(3)
      ! cb
      ss = MATMUL(cell%h_inv, rr(:, 3)-rr(:, 2))
      ss = ss-NINT(ss)
      ss = MATMUL(cell%hmat, ss)
      xcb = ss(1)
      ycb = ss(2)
      zcb = ss(3)
      ! dc
      ss = MATMUL(cell%h_inv, rr(:, 4)-rr(:, 3))
      ss = ss-NINT(ss)
      ss = MATMUL(cell%hmat, ss)
      xdc = ss(1)
      ydc = ss(2)
      zdc = ss(3)
      !
      xt = yba*zcb-ycb*zba
      yt = zba*xcb-zcb*xba
      zt = xba*ycb-xcb*yba
      xu = ycb*zdc-ydc*zcb
      yu = zcb*xdc-zdc*xcb
      zu = xcb*ydc-xdc*ycb
      xtu = yt*zu-yu*zt
      ytu = zt*xu-zu*xt
      ztu = xt*yu-xu*yt
      rt2 = xt*xt+yt*yt+zt*zt
      ru2 = xu*xu+yu*yu+zu*zu
      rtru = SQRT(rt2*ru2)
      IF (rtru .NE. 0.0_dp) THEN
         rcb = SQRT(xcb*xcb+ycb*ycb+zcb*zcb)
         cosine = (xt*xu+yt*yu+zt*zu)/rtru
         sine = (xcb*xtu+ycb*ytu+zcb*ztu)/(rcb*rtru)
         cosine = MIN(1.0_dp, MAX(-1.0_dp, cosine))
         angle = ACOS(cosine)
         IF (sine .LT. 0.0_dp) angle = -angle
         !
         dt = angle ! [rad]
         dt = MOD(2.0E4_dp*pi+dt-o0, 2.0_dp*pi)
         IF (dt .GT. pi) dt = dt-2.0_dp*pi
         dt = o0+dt
         colvar%torsion_param%o0 = dt
         !
         !     calculate improper energy and master chain rule term
         !
         e = dt
         dedphi = 1.0_dp
         !
         !     chain rule terms for first derivative components
         !
         ! ca
         ss = MATMUL(cell%h_inv, rr(:, 3)-rr(:, 1))
         ss = ss-NINT(ss)
         ss = MATMUL(cell%hmat, ss)
         xca = ss(1)
         yca = ss(2)
         zca = ss(3)
         ! db
         ss = MATMUL(cell%h_inv, rr(:, 4)-rr(:, 2))
         ss = ss-NINT(ss)
         ss = MATMUL(cell%hmat, ss)
         xdb = ss(1)
         ydb = ss(2)
         zdb = ss(3)
         !
         dedxt = dedphi*(yt*zcb-ycb*zt)/(rt2*rcb)
         dedyt = dedphi*(zt*xcb-zcb*xt)/(rt2*rcb)
         dedzt = dedphi*(xt*ycb-xcb*yt)/(rt2*rcb)
         dedxu = -dedphi*(yu*zcb-ycb*zu)/(ru2*rcb)
         dedyu = -dedphi*(zu*xcb-zcb*xu)/(ru2*rcb)
         dedzu = -dedphi*(xu*ycb-xcb*yu)/(ru2*rcb)
         !
         !     compute first derivative components for this angle
         !
         dedxia = zcb*dedyt-ycb*dedzt
         dedyia = xcb*dedzt-zcb*dedxt
         dedzia = ycb*dedxt-xcb*dedyt
         dedzia = ycb*dedxt-xcb*dedyt
         dedxib = yca*dedzt-zca*dedyt+zdc*dedyu-ydc*dedzu
         dedyib = zca*dedxt-xca*dedzt+xdc*dedzu-zdc*dedxu
         dedzib = xca*dedyt-yca*dedxt+ydc*dedxu-xdc*dedyu
         dedxic = zba*dedyt-yba*dedzt+ydb*dedzu-zdb*dedyu
         dedyic = xba*dedzt-zba*dedxt+zdb*dedxu-xdb*dedzu
         dedzic = yba*dedxt-xba*dedyt+xdb*dedyu-ydb*dedxu
         dedxid = zcb*dedyu-ycb*dedzu
         dedyid = xcb*dedzu-zcb*dedxu
         dedzid = ycb*dedxu-xcb*dedyu
      ENDIF
      !
      colvar%ss = e
      IF (no_riemann_sheet) colvar%ss = ATAN2(SIN(e), COS(e))
      ftmp(1) = dedxia
      ftmp(2) = dedyia
      ftmp(3) = dedzia
      CALL put_derivative(colvar, 1, ftmp)
      ftmp(1) = dedxib
      ftmp(2) = dedyib
      ftmp(3) = dedzib
      CALL put_derivative(colvar, 2, ftmp)
      ftmp(1) = dedxic
      ftmp(2) = dedyic
      ftmp(3) = dedzic
      CALL put_derivative(colvar, 3, ftmp)
      ftmp(1) = dedxid
      ftmp(2) = dedyid
      ftmp(3) = dedzid
      CALL put_derivative(colvar, 4, ftmp)
   END SUBROUTINE torsion_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the Q PARM collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
! **************************************************************************************************
   SUBROUTINE qparm_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: aa, bb, cc, i, idim, ii, j, jj, l, mm, &
                                                            n_atoms_from, n_atoms_to, ncells(3)
      LOGICAL                                            :: include_images
      REAL(KIND=dp) :: denominator_tolerance, fact, ftmp(3), im_qlm, inv_n_atoms_from, nbond, &
         pre_fac, ql, qparm, r1cut, rcut, re_qlm, rij, rij_shift, shift(3), ss(3), ss0(3), xij(3), &
         xij_shift(3)
      REAL(KIND=dp), DIMENSION(3)                        :: d_im_qlm_dxi, d_nbond_dxi, d_ql_dxi, &
                                                            d_re_qlm_dxi, xpi, xpj
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      ! settings for numerical derivatives
      !REAL(KIND=dp) :: ri_step, dx_bond_j, dy_bond_j, dz_bond_j
      !INTEGER :: idel

      n_atoms_to = colvar%qparm_param%n_atoms_to
      n_atoms_from = colvar%qparm_param%n_atoms_from
      rcut = colvar%qparm_param%rcut
      l = colvar%qparm_param%l
      r1cut = colvar%qparm_param%rstart
      include_images = colvar%qparm_param%include_images
      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == qparm_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      CPASSERT(r1cut .LT. rcut)
      denominator_tolerance = 1.0E-8_dp

      !ri_step=0.1
      !DO idel=-50, 50
      !ftmp(:) = 0.0_dp

      qparm = 0.0_dp
      inv_n_atoms_from = 1.0_dp/REAL(n_atoms_from, KIND=dp)
      DO ii = 1, n_atoms_from
         i = colvar%qparm_param%i_at_from(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         !xpi(1)=xpi(1)+idel*ri_step
         ql = 0.0_dp
         d_ql_dxi(:) = 0.0_dp

         DO mm = -l, l
            nbond = 0.0_dp
            re_qlm = 0.0_dp
            im_qlm = 0.0_dp
            d_re_qlm_dxi(:) = 0.0_dp
            d_im_qlm_dxi(:) = 0.0_dp
            d_nbond_dxi(:) = 0.0_dp

            jloop: DO jj = 1, n_atoms_to

               j = colvar%qparm_param%i_at_to(jj)
               CALL get_coordinates(colvar, j, xpj, my_particles)

               IF (include_images) THEN

                  CPASSERT(cell%orthorhombic)

                  ! determine how many cells must be included in each direction
                  ! based on rcut
                  xij(:) = xpj(:)-xpi(:)
                  ss = MATMUL(cell%h_inv, xij)
                  ! these are fractional coordinates of the closest periodic image
                  ! lie in the [-0.5,0.5] interval
                  ss0 = ss-NINT(ss)
                  DO idim = 1, 3
                     shift(:) = 0.0_dp
                     shift(idim) = 1.0_dp
                     xij_shift = MATMUL(cell%hmat, shift)
                     rij_shift = SQRT(DOT_PRODUCT(xij_shift, xij_shift))
                     ncells(idim) = FLOOR(rcut/rij_shift-0.5)
                  ENDDO !idim

                  !IF (mm.eq.0) WRITE(*,'(A8,3I3,A3,I10)') "Ncells:", ncells, "J:", j
                  shift(1:3) = 0.0_dp
                  DO aa = -ncells(1), ncells(1)
                     DO bb = -ncells(2), ncells(2)
                        DO cc = -ncells(3), ncells(3)
                           ! do not include the central atom
                           IF (i == j .AND. aa .EQ. 0 .AND. bb .EQ. 0 .AND. cc .EQ. 0) CYCLE
                           shift(1) = REAL(aa, KIND=dp)
                           shift(2) = REAL(bb, KIND=dp)
                           shift(3) = REAL(cc, KIND=dp)
                           xij = MATMUL(cell%hmat, ss0(:)+shift(:))
                           rij = SQRT(DOT_PRODUCT(xij, xij))
                           !IF (rij > rcut) THEN
                           !   IF (mm.EQ.0) WRITE(*,'(A8,4F10.5)') " --", shift, rij
                           !ELSE
                           !   IF (mm.EQ.0) WRITE(*,'(A8,4F10.5)') " ++", shift, rij
                           !ENDIF
                           IF (rij > rcut) CYCLE

                           ! update qlm
                           CALL accumulate_qlm_over_neigbors(xij, rij, rcut, r1cut, &
                                                             denominator_tolerance, l, mm, nbond, re_qlm, im_qlm, &
                                                             d_re_qlm_dxi, d_im_qlm_dxi, d_nbond_dxi)

                        ENDDO
                     ENDDO
                  ENDDO

               ELSE

                  IF (i == j) CYCLE jloop
                  xij(:) = xpj(:)-xpi(:)
                  rij = SQRT(DOT_PRODUCT(xij, xij))
                  IF (rij > rcut) CYCLE

                  ! update qlm
                  CALL accumulate_qlm_over_neigbors(xij, rij, rcut, r1cut, &
                                                    denominator_tolerance, l, mm, nbond, re_qlm, im_qlm, &
                                                    d_re_qlm_dxi, d_im_qlm_dxi, d_nbond_dxi)

               ENDIF ! include images

            ENDDO jloop

            ! this factor is necessary if one whishes to sum over m=0,L
            ! instead of m=-L,+L. This is off now because it is cheap and safe
            fact = 1.0_dp
            !IF (ABS(mm) .GT. 0) THEN
            !   fact = 2.0_dp
            !ELSE
            !   fact = 1.0_dp
            !ENDIF

            IF (nbond .LT. denominator_tolerance) THEN
               CPWARN("QPARM: number of neighbors is very close to zero!")
            END IF

            d_nbond_dxi(:) = d_nbond_dxi(:)/nbond
            re_qlm = re_qlm/nbond
            d_re_qlm_dxi(:) = d_re_qlm_dxi(:)/nbond-d_nbond_dxi(:)*re_qlm
            im_qlm = im_qlm/nbond
            d_im_qlm_dxi(:) = d_im_qlm_dxi(:)/nbond-d_nbond_dxi(:)*im_qlm

            ql = ql+fact*(re_qlm*re_qlm+im_qlm*im_qlm)
            d_ql_dxi(:) = d_ql_dxi(:) &
                          +fact*2.0_dp*(re_qlm*d_re_qlm_dxi(:)+im_qlm*d_im_qlm_dxi(:))

         ENDDO ! loop over m

         pre_fac = (4.0_dp*pi)/(2.0_dp*l+1)
         !WRITE(*,'(A8,2F10.5)') "  si = ", SQRT(pre_fac*ql)
         qparm = qparm+SQRT(pre_fac*ql)
         ftmp(:) = 0.5_dp*SQRT(pre_fac/ql)*d_ql_dxi(:)
         ! multiply by -1 because aparently we have to save the force, not the gradient
         ftmp(:) = -1.0_dp*ftmp(:)

         CALL put_derivative(colvar, ii, ftmp)

      ENDDO ! loop over i

      colvar%ss = qparm*inv_n_atoms_from
      colvar%dsdr(:, :) = colvar%dsdr(:, :)*inv_n_atoms_from

      !WRITE(*,'(A15,3E20.10)') "COLVAR+DER = ", ri_step*idel, colvar%ss, -ftmp(1)

      !ENDDO ! numercal derivative

   END SUBROUTINE qparm_colvar

! **************************************************************************************************
!> \brief ...
!> \param xij ...
!> \param rij ...
!> \param rcut ...
!> \param r1cut ...
!> \param denominator_tolerance ...
!> \param ll ...
!> \param mm ...
!> \param nbond ...
!> \param re_qlm ...
!> \param im_qlm ...
!> \param d_re_qlm_dxi ...
!> \param d_im_qlm_dxi ...
!> \param d_nbond_dxi ...
! **************************************************************************************************
   SUBROUTINE accumulate_qlm_over_neigbors(xij, rij, rcut, r1cut, &
                                           denominator_tolerance, ll, mm, nbond, re_qlm, im_qlm, &
                                           d_re_qlm_dxi, d_im_qlm_dxi, d_nbond_dxi)

      REAL(KIND=dp), INTENT(IN)                          :: xij(3), rij, rcut, r1cut, &
                                                            denominator_tolerance
      INTEGER, INTENT(IN)                                :: ll, mm
      REAL(KIND=dp), INTENT(INOUT)                       :: nbond, re_qlm, im_qlm, d_re_qlm_dxi(3), &
                                                            d_im_qlm_dxi(3), d_nbond_dxi(3)

      REAL(KIND=dp)                                      :: bond, costheta, dplm, dylm, exp0, &
                                                            exp_fac, fi, plm, pre_fac, sqrt_c1
      REAL(KIND=dp), DIMENSION(3)                        :: dcosTheta, dfi

      !bond = 1.0_dp/(1.0_dp+EXP(alpha*(rij-rcut)))
      ! RZK: infinitely differentiable smooth cutoff function
      ! that is precisely 1.0 below r1cut and precisely 0.0 above rcut
      IF (rij .GT. rcut) THEN
         !bond = 0.0_dp
         !exp_fac = 0.0_dp
         RETURN
      ELSE
         IF (rij .LT. r1cut) THEN
            bond = 1.0_dp
            exp_fac = 0.0_dp
         ELSE
            exp0 = EXP((r1cut-rcut)/(rij-rcut)-(r1cut-rcut)/(r1cut-rij))
            bond = 1.0_dp/(1.0_dp+exp0)
            exp_fac = ((rcut-r1cut)/(rij-rcut)**2+(rcut-r1cut)/(r1cut-rij)**2)*exp0/(1.0_dp+exp0)**2
         ENDIF
      ENDIF
      IF (bond > 1.0_dp) THEN
         CPABORT("bond > 1.0_dp")
      END IF
      ! compute continuous bond order
      nbond = nbond+bond
      IF (ABS(xij(1)) .LT. denominator_tolerance &
          .AND. ABS(xij(2)) .LT. denominator_tolerance) THEN
         fi = 0.0_dp
      ELSE
         fi = ATAN2(xij(2), xij(1))
      ENDIF

      costheta = xij(3)/rij
      IF (costheta > 1.0_dp) costheta = 1.0_dp
      IF (costheta < -1.0_dp) costheta = -1.0_dp

      ! legendre works correctly only for positive m
      plm = legendre(costheta, ll, mm)
      dplm = dlegendre(costheta, ll, mm)
      IF ((ll+ABS(mm)) > maxfac) THEN
         CPABORT("(l+m) > maxfac")
      END IF
      ! use absolute m to compenstate for the defficiency of legendre
      sqrt_c1 = SQRT(((2*ll+1)*fac(ll-ABS(mm)))/(4*pi*fac(ll+ABS(mm))))
      pre_fac = bond*sqrt_c1
      dylm = pre_fac*dplm
      !WHY? IF (plm < 0.0_dp) THEN
      !WHY?    dylm = -pre_fac*dplm
      !WHY? ELSE
      !WHY?    dylm = pre_fac*dplm
      !WHY? ENDIF

      re_qlm = re_qlm+pre_fac*plm*COS(mm*fi)
      im_qlm = im_qlm+pre_fac*plm*SIN(mm*fi)

      !WRITE(*,'(A8,2I4,F10.5)') "  Qlm = ", mm, j, bond
      !WRITE(*,'(A8,2I4,2F10.5)') "  Qlm = ", mm, j, re_qlm, im_qlm

      dcosTheta(:) = xij(:)*xij(3)/(rij**3)
      dcosTheta(3) = dcosTheta(3)-1.0_dp/rij
      ! use tangent half-angle formula to compute d_fi/d_xi
      ! http://math.stackexchange.com/questions/989877/continuous-differentiability-of-atan2
      ! +/- sign changed because xij = xj - xi
      dfi(1) = xij(2)/(xij(1)**2+xij(2)**2)
      dfi(2) = -xij(1)/(xij(1)**2+xij(2)**2)
      dfi(3) = 0.0_dp
      d_re_qlm_dxi(:) = d_re_qlm_dxi(:) &
                        +exp_fac*sqrt_c1*plm*COS(mm*fi)*xij(:)/rij &
                        +dylm*dcosTheta(:)*COS(mm*fi) &
                        +pre_fac*plm*mm*(-1.0_dp)*SIN(mm*fi)*dfi(:)
      d_im_qlm_dxi(:) = d_im_qlm_dxi(:) &
                        +exp_fac*sqrt_c1*plm*SIN(mm*fi)*xij(:)/rij &
                        +dylm*dcosTheta(:)*SIN(mm*fi) &
                        +pre_fac*plm*mm*(+1.0_dp)*COS(mm*fi)*dfi(:)
      d_nbond_dxi(:) = d_nbond_dxi(:)+exp_fac*xij(:)/rij

   END SUBROUTINE accumulate_qlm_over_neigbors

! **************************************************************************************************
!> \brief evaluates the force due (and on) the hydronium_shell collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Marcel Baer
!> \note This function needs to be extended to the POINT structure!!
!>       non-standard conform.. it's a breach in the colvar module.
! **************************************************************************************************
   SUBROUTINE hydronium_shell_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, n_hydrogens, n_oxygens, &
                                                            pm, poh, poo, qm, qoh, qoo
      REAL(dp)                                           :: drji, fscalar, invden, lambda, nh, num, &
                                                            qtot, rji(3), roh, roo, rrel
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: M, noh, noo, qloc
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: dM, dnoh, dnoo
      REAL(dp), DIMENSION(3)                             :: rpi, rpj
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      n_oxygens = colvar%hydronium_shell_param%n_oxygens
      n_hydrogens = colvar%hydronium_shell_param%n_hydrogens
      nh = colvar%hydronium_shell_param%nh
      poh = colvar%hydronium_shell_param%poh
      qoh = colvar%hydronium_shell_param%qoh
      poo = colvar%hydronium_shell_param%poo
      qoo = colvar%hydronium_shell_param%qoo
      roo = colvar%hydronium_shell_param%roo
      roh = colvar%hydronium_shell_param%roh
      lambda = colvar%hydronium_shell_param%lambda
      pm = colvar%hydronium_shell_param%pm
      qm = colvar%hydronium_shell_param%qm

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == hydronium_shell_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ALLOCATE (dnoh(3, n_hydrogens, n_oxygens))
      ALLOCATE (noh(n_oxygens))
      ALLOCATE (M(n_oxygens))
      ALLOCATE (dM(3, n_hydrogens, n_oxygens))

      ALLOCATE (dnoo(3, n_oxygens, n_oxygens))
      ALLOCATE (noo(n_oxygens))

      ALLOCATE (qloc(n_oxygens))

      ! Zero Arrays:
      dnoh = 0._dp
      dnoo = 0._dp
      M = 0._dp
      dM = 0._dp
      noo = 0._dp
      qloc = 0._dp
      noh = 0._dp
      DO ii = 1, n_oxygens
         i = colvar%hydronium_shell_param%i_oxygens(ii)
         rpi(:) = my_particles(i)%r(1:3)
         ! Computing M( n ( ii ) )
         DO jj = 1, n_hydrogens
            j = colvar%hydronium_shell_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rji = pbc(rpj, rpi, cell)
            drji = SQRT(SUM(rji**2))
            rrel = drji/roh
            num = (1.0_dp-rrel**poh)
            invden = 1.0_dp/(1.0_dp-rrel**qoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               noh(ii) = noh(ii)+num*invden
               fscalar = ((-poh*(rrel**(poh-1))*invden) &
                          +num*(invden)**2*qoh*(rrel**(qoh-1)))/(drji*roh)
               dnoh(1:3, jj, ii) = rji(1:3)*fscalar
            ELSE
               !correct limit if rji --> roh
               noh(ii) = noh(ii)+REAL(poh, dp)/REAL(qoh, dp)
               fscalar = REAL(poh*(poh-qoh), dp)/(REAL(2*qoh, dp)*roh*drji)
               dnoh(1:3, jj, ii) = rji(1:3)*fscalar
            ENDIF
         END DO
         M(ii) = 1.0_dp-(1.0_dp-(noh(ii)/nh)**pm)/ &
                 (1.0_dp-(noh(ii)/nh)**qm)

         ! Computing no ( ii )
         DO jj = 1, n_oxygens
            IF (ii == jj) CYCLE
            j = colvar%hydronium_shell_param%i_oxygens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rji = pbc(rpj, rpi, cell)
            drji = SQRT(SUM(rji**2))
            rrel = drji/roo
            num = (1.0_dp-rrel**poo)
            invden = 1.0_dp/(1.0_dp-rrel**qoo)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               noo(ii) = noo(ii)+num*invden
               fscalar = ((-poo*(rrel**(poo-1))*invden) &
                          +num*(invden)**2*qoo*(rrel**(qoo-1)))/(drji*roo)
               dnoo(1:3, jj, ii) = rji(1:3)*fscalar
            ELSE
               !correct limit if rji --> roo
               noo(ii) = noo(ii)+REAL(poo, dp)/REAL(qoo, dp)
               fscalar = REAL(poo*(poo-qoo), dp)/(REAL(2*qoo, dp)*roo*drji)
               dnoo(1:3, jj, ii) = rji(1:3)*fscalar
            ENDIF
         END DO
      END DO

      ! computing qloc and Q
      qtot = 0._dp
      DO ii = 1, n_oxygens
         qloc(ii) = EXP(lambda*M(ii)*noo(ii))
         qtot = qtot+qloc(ii)
      END DO
      ! compute forces
      DO ii = 1, n_oxygens
         ! Computing f_OH
         DO jj = 1, n_hydrogens
            dM(1:3, jj, ii) = (pm*((noh(ii)/nh)**(pm-1))*dnoh(1:3, jj, ii))/nh/ &
                              (1.0_dp-(noh(ii)/nh)**qm)- &
                              (1.0_dp-(noh(ii)/nh)**pm)/ &
                              ((1.0_dp-(noh(ii)/nh)**qm)**2)* &
                              qm*dnoh(1:3, jj, ii)*(noh(ii)/nh)**(qm-1)/nh

            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii)+qloc(ii)*dM(1:3, jj, ii)*noo(ii)/qtot
            colvar%dsdr(1:3, n_oxygens+jj) = colvar%dsdr(1:3, n_oxygens+jj) &
                                             -qloc(ii)*dM(1:3, jj, ii)*noo(ii)/qtot
         END DO
         ! Computing f_OO
         DO jj = 1, n_oxygens
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii)+qloc(ii)*M(ii)*dnoo(1:3, jj, ii)/qtot
            colvar%dsdr(1:3, jj) = colvar%dsdr(1:3, jj) &
                                   -qloc(ii)*M(ii)*dnoo(1:3, jj, ii)/qtot
         END DO
      END DO

      colvar%ss = LOG(qtot)/lambda
      DEALLOCATE (dnoh)
      DEALLOCATE (noh)
      DEALLOCATE (M)
      DEALLOCATE (dM)
      DEALLOCATE (dnoo)
      DEALLOCATE (noo)
      DEALLOCATE (qloc)

   END SUBROUTINE hydronium_shell_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the hydronium_dist collective variable;
!>        distance between hydronium and hydroxide ion
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Dorothea Golze
! **************************************************************************************************
   SUBROUTINE hydronium_dist_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, k, kk, n_hydrogens, &
                                                            n_oxygens, offsetH, pf, pm, poh, qf, &
                                                            qm, qoh
      REAL(dp) :: drji, drki, fscalar, invden, lambda, nh, nn, num, rion, rion_den, rion_num, &
         rji(3), rki(3), roh, rrel, sum_expfac_F, sum_expfac_noh
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: dexpfac_F, dexpfac_noh, dF, dM, &
                                                            expfac_F, expfac_F_rki, expfac_noh, F, &
                                                            M, noh
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dexpfac_F_rki
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ddist_rki, dnoh
      REAL(dp), DIMENSION(3)                             :: rpi, rpj, rpk
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      n_oxygens = colvar%hydronium_dist_param%n_oxygens
      n_hydrogens = colvar%hydronium_dist_param%n_hydrogens
      poh = colvar%hydronium_dist_param%poh
      qoh = colvar%hydronium_dist_param%qoh
      roh = colvar%hydronium_dist_param%roh
      pm = colvar%hydronium_dist_param%pm
      qm = colvar%hydronium_dist_param%qm
      nh = colvar%hydronium_dist_param%nh
      pf = colvar%hydronium_dist_param%pf
      qf = colvar%hydronium_dist_param%qf
      nn = colvar%hydronium_dist_param%nn
      lambda = colvar%hydronium_dist_param%lambda

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == hydronium_dist_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ALLOCATE (dnoh(3, n_hydrogens, n_oxygens))
      ALLOCATE (noh(n_oxygens))
      ALLOCATE (M(n_oxygens), dM(n_oxygens))
      ALLOCATE (F(n_oxygens), dF(n_oxygens))
      ALLOCATE (expfac_noh(n_oxygens), dexpfac_noh(n_oxygens))
      ALLOCATE (expfac_F(n_oxygens), dexpfac_F(n_oxygens))
      ALLOCATE (ddist_rki(3, n_oxygens, n_oxygens))
      ALLOCATE (expfac_F_rki(n_oxygens))
      ALLOCATE (dexpfac_F_rki(n_oxygens, n_oxygens))

      ! Zero Arrays:
      noh = 0._dp
      dnoh = 0._dp
      rion_num = 0._dp
      F = 0._dp
      M = 0._dp
      dF = 0._dp
      dM = 0._dp
      expfac_noh = 0._dp
      expfac_F = 0._dp
      sum_expfac_noh = 0._dp
      sum_expfac_F = 0._dp
      ddist_rki = 0._dp
      expfac_F_rki = 0._dp
      dexpfac_F_rki = 0._dp

      !*** Calculate coordination function noh(ii) and its derivative
      DO ii = 1, n_oxygens
         i = colvar%hydronium_dist_param%i_oxygens(ii)
         rpi(:) = my_particles(i)%r(1:3)
         DO jj = 1, n_hydrogens
            j = colvar%hydronium_dist_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rji = pbc(rpj, rpi, cell)
            drji = SQRT(SUM(rji**2))
            rrel = drji/roh
            num = (1.0_dp-rrel**poh)
            invden = 1.0_dp/(1.0_dp-rrel**qoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               noh(ii) = noh(ii)+num*invden
               fscalar = ((-poh*(rrel**(poh-1))*invden) &
                          +num*(invden)**2*qoh*(rrel**(qoh-1)))/(drji*roh)
               dnoh(1:3, jj, ii) = rji(1:3)*fscalar
            ELSE
               !correct limit if rji --> roh
               noh(ii) = noh(ii)+REAL(poh, dp)/REAL(qoh, dp)
               fscalar = REAL(poh*(poh-qoh), dp)/(REAL(2*qoh, dp)*roh*drji)
               dnoh(1:3, jj, ii) = rji(1:3)*fscalar
            ENDIF
         END DO
      END DO

      !*** Calculate M, dM, exp(lambda*M) and sum_[exp(lambda*M)]
      DO ii = 1, n_oxygens
         num = 1.0_dp-(noh(ii)/nh)**pm
         invden = 1.0_dp/(1.0_dp-(noh(ii)/nh)**qm)
         M(ii) = 1.0_dp-num*invden
         dM(ii) = (pm*(noh(ii)/nh)**(pm-1)*invden-qm*num*(invden**2)* &
                   (noh(ii)/nh)**(qm-1))/nh
         expfac_noh(ii) = EXP(lambda*noh(ii))
         dexpfac_noh(ii) = lambda*expfac_noh(ii)
         sum_expfac_noh = sum_expfac_noh+expfac_noh(ii)
      END DO

      !*** Calculate F, dF, exp(lambda*F) and sum_[exp(lambda*F)]
      DO ii = 1, n_oxygens
         i = colvar%hydronium_dist_param%i_oxygens(ii)
         num = 1.0_dp-(noh(ii)/nn)**pf
         invden = 1.0_dp/(1.0_dp-(noh(ii)/nn)**qf)
         F(ii) = num*invden
         dF(ii) = (-pf*(noh(ii)/nn)**(pf-1)*invden+qf*num*(invden**2)* &
                   (noh(ii)/nn)**(qf-1))/nn
         expfac_F(ii) = EXP(lambda*F(ii))
         dexpfac_F(ii) = lambda*expfac_F(ii)
         sum_expfac_F = sum_expfac_F+expfac_F(ii)
      END DO

      !*** Calculation numerator of rion
      DO ii = 1, n_oxygens
         i = colvar%hydronium_dist_param%i_oxygens(ii)
         rpi(:) = my_particles(i)%r(1:3)
         DO kk = 1, n_oxygens
            IF (ii == kk) CYCLE
            k = colvar%hydronium_dist_param%i_oxygens(kk)
            rpk(:) = my_particles(k)%r(1:3)
            rki = pbc(rpk, rpi, cell)
            drki = SQRT(SUM(rki**2))
            expfac_F_rki(ii) = expfac_F_rki(ii)+drki*expfac_F(kk)
            ddist_rki(1:3, kk, ii) = rki(1:3)/drki
            dexpfac_F_rki(kk, ii) = drki*dexpfac_F(kk)
         ENDDO
         rion_num = rion_num+M(ii)*expfac_noh(ii)*expfac_F_rki(ii)
      ENDDO

      !*** Final H3O+/OH- distance
      rion_den = sum_expfac_noh*sum_expfac_F
      rion = rion_num/rion_den
      colvar%ss = rion

      offsetH = n_oxygens
      !*** Derivatives numerator
      DO ii = 1, n_oxygens
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   +dM(ii)*dnoh(1:3, jj, ii)*expfac_noh(ii) &
                                   *expfac_F_rki(ii)/rion_den
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           -dM(ii)*dnoh(1:3, jj, ii)*expfac_noh(ii) &
                                           *expfac_F_rki(ii)/rion_den
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   +M(ii)*dexpfac_noh(ii)*dnoh(1:3, jj, ii) &
                                   *expfac_F_rki(ii)/rion_den
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           -M(ii)*dexpfac_noh(ii)*dnoh(1:3, jj, ii) &
                                           *expfac_F_rki(ii)/rion_den
         ENDDO
         DO kk = 1, n_oxygens
            IF (ii == kk) CYCLE
            colvar%dsdr(1:3, kk) = colvar%dsdr(1:3, kk) &
                                   -M(ii)*expfac_noh(ii)*ddist_rki(1:3, kk, ii) &
                                   *expfac_F(kk)/rion_den
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   +M(ii)*expfac_noh(ii)*ddist_rki(1:3, kk, ii) &
                                   *expfac_F(kk)/rion_den
            DO jj = 1, n_hydrogens
               colvar%dsdr(1:3, kk) = colvar%dsdr(1:3, kk) &
                                      +M(ii)*expfac_noh(ii)*dexpfac_F_rki(kk, ii) &
                                      *dF(kk)*dnoh(1:3, jj, kk)/rion_den
               colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                              -M(ii)*expfac_noh(ii)*dexpfac_F_rki(kk, ii) &
                                              *dF(kk)*dnoh(1:3, jj, kk)/rion_den
            ENDDO
         ENDDO
      ENDDO
      !*** Derivatives denominator
      DO ii = 1, n_oxygens
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   -rion_num*sum_expfac_F*dexpfac_noh(ii) &
                                   *dnoh(1:3, jj, ii)/(rion_den**2)
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           +rion_num*sum_expfac_F*dexpfac_noh(ii) &
                                           *dnoh(1:3, jj, ii)/(rion_den**2)
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   -rion_num*sum_expfac_noh*dexpfac_F(ii)*dF(ii) &
                                   *dnoh(1:3, jj, ii)/(rion_den**2)
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           +rion_num*sum_expfac_noh*dexpfac_F(ii)*dF(ii) &
                                           *dnoh(1:3, jj, ii)/(rion_den**2)
         ENDDO
      ENDDO

      DEALLOCATE (noh, M, F, expfac_noh, expfac_F)
      DEALLOCATE (dnoh, dM, dF, dexpfac_noh, dexpfac_F)
      DEALLOCATE (ddist_rki, expfac_F_rki, dexpfac_F_rki)

   END SUBROUTINE hydronium_dist_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the acid-hydronium-distance
!>        collective variable. Colvar: distance between carboxy group and
!>        hydronium ion.
!> \param colvar collective variable
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Dorothea Golze
!> \note this function does not use POINTS, not reasonable for this colvar
! **************************************************************************************************
   SUBROUTINE acid_hyd_dist_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, k, kk, n_hydrogens, &
                                                            n_oxygens_acid, n_oxygens_water, &
                                                            offsetH, offsetO, paoh, pcut, pwoh, &
                                                            qaoh, qcut, qwoh
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: dexpfac, expfac, nwoh
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dexpfac_rik
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ddist_rik, dnaoh, dnwoh
      REAL(KIND=dp) :: dfcut, drik, drji, drjk, fbrace, fcut, fscalar, invden, invden_cut, lambda, &
         naoh, nc, num, num_cut, raoh, rik(3), rion, rion_den, rion_num, rji(3), rjk(3), rpi(3), &
         rpj(3), rpk(3), rrel, rwoh
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (my_particles, particles_i)

      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
      pwoh = colvar%acid_hyd_dist_param%pwoh
      qwoh = colvar%acid_hyd_dist_param%qwoh
      paoh = colvar%acid_hyd_dist_param%paoh
      qaoh = colvar%acid_hyd_dist_param%qaoh
      pcut = colvar%acid_hyd_dist_param%pcut
      qcut = colvar%acid_hyd_dist_param%qcut
      rwoh = colvar%acid_hyd_dist_param%rwoh
      raoh = colvar%acid_hyd_dist_param%raoh
      nc = colvar%acid_hyd_dist_param%nc
      lambda = colvar%acid_hyd_dist_param%lambda
      ALLOCATE (expfac(n_oxygens_water))
      ALLOCATE (nwoh(n_oxygens_water))
      ALLOCATE (dnwoh(3, n_hydrogens, n_oxygens_water))
      ALLOCATE (dnaoh(3, n_hydrogens, n_oxygens_acid))
      ALLOCATE (dexpfac(n_oxygens_water))
      ALLOCATE (ddist_rik(3, n_oxygens_water, n_oxygens_acid))
      ALLOCATE (dexpfac_rik(n_oxygens_water, n_oxygens_acid))
      rion_den = 0._dp
      rion_num = 0._dp
      nwoh(:) = 0._dp
      naoh = 0._dp
      dnaoh(:, :, :) = 0._dp
      dnwoh(:, :, :) = 0._dp
      ddist_rik(:, :, :) = 0._dp
      dexpfac(:) = 0._dp
      dexpfac_rik(:, :) = 0._dp

      CPASSERT(colvar%type_id == acid_hyd_dist_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ! Calculate coordination functions nwoh(ii) and denominator of rion
      DO ii = 1, n_oxygens_water
         i = colvar%acid_hyd_dist_param%i_oxygens_water(ii)
         rpi(:) = my_particles(i)%r(1:3)
         DO jj = 1, n_hydrogens
            j = colvar%acid_hyd_dist_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rji = pbc(rpj, rpi, cell)
            drji = SQRT(SUM(rji**2))
            rrel = drji/rwoh
            num = 1.0_dp-rrel**pwoh
            invden = 1.0_dp/(1.0_dp-rrel**qwoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               nwoh(ii) = nwoh(ii)+num*invden
               fscalar = (-pwoh*(rrel**(pwoh-1))*invden &
                          +num*(invden**2)*qwoh*(rrel**(qwoh-1)))/(drji*rwoh)
               dnwoh(1:3, jj, ii) = rji(1:3)*fscalar
            ELSE
               !correct limit if rji --> rwoh
               nwoh(ii) = nwoh(ii)+REAL(pwoh, dp)/REAL(qwoh, dp)
               fscalar = REAL(pwoh*(pwoh-qwoh), dp)/(REAL(2*qwoh, dp)*rwoh*drji)
               dnwoh(1:3, jj, ii) = rji(1:3)*fscalar
            ENDIF
         ENDDO
         expfac(ii) = EXP(lambda*nwoh(ii))
         dexpfac(ii) = lambda*expfac(ii)
         rion_den = rion_den+expfac(ii)
      ENDDO

      ! Calculate nominator of rion
      DO kk = 1, n_oxygens_acid
         k = colvar%acid_hyd_dist_param%i_oxygens_acid(kk)
         rpk(:) = my_particles(k)%r(1:3)
         DO ii = 1, n_oxygens_water
            i = colvar%acid_hyd_dist_param%i_oxygens_water(ii)
            rpi(:) = my_particles(i)%r(1:3)
            rik = pbc(rpi, rpk, cell)
            drik = SQRT(SUM(rik**2))
            rion_num = rion_num+drik*expfac(ii)
            ddist_rik(1:3, ii, kk) = rik(1:3)/drik
            dexpfac_rik(ii, kk) = drik*dexpfac(ii)
         ENDDO
      ENDDO

      !Calculate cutoff function
      DO kk = 1, n_oxygens_acid
         k = colvar%acid_hyd_dist_param%i_oxygens_acid(kk)
         rpk(:) = my_particles(k)%r(1:3)
         DO jj = 1, n_hydrogens
            j = colvar%acid_hyd_dist_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rjk = pbc(rpj, rpk, cell)
            drjk = SQRT(SUM(rjk**2))
            rrel = drjk/raoh
            num = 1.0_dp-rrel**paoh
            invden = 1.0_dp/(1.0_dp-rrel**qaoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               naoh = naoh+num*invden
               fscalar = (-paoh*(rrel**(paoh-1))*invden &
                          +num*(invden**2)*qaoh*(rrel**(qaoh-1)))/(drjk*raoh)
               dnaoh(1:3, jj, kk) = rjk(1:3)*fscalar
            ELSE
               !correct limit if rjk --> raoh
               naoh = naoh+REAL(paoh, dp)/REAL(qaoh, dp)
               fscalar = REAL(paoh*(paoh-qaoh), dp)/(REAL(2*qaoh, dp)*raoh*drjk)
               dnaoh(1:3, jj, kk) = rjk(1:3)*fscalar
            ENDIF
         ENDDO
      ENDDO
      num_cut = 1.0_dp-(naoh/nc)**pcut
      invden_cut = 1.0_dp/(1.0_dp-(naoh/nc)**qcut)
      fcut = num_cut*invden_cut

      !Final distance acid - hydronium
      fbrace = rion_num/rion_den/2.0_dp
      rion = fcut*fbrace
      colvar%ss = rion

      !Derivatives of fcut
      dfcut = ((-pcut*(naoh/nc)**(pcut-1)*invden_cut) &
               +num_cut*(invden_cut**2)*qcut*(naoh/nc)**(qcut-1))/nc
      offsetO = n_oxygens_water
      offsetH = n_oxygens_water+n_oxygens_acid
      DO kk = 1, n_oxygens_acid
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, offsetO+kk) = colvar%dsdr(1:3, offsetO+kk) &
                                           +dfcut*dnaoh(1:3, jj, kk)*fbrace
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           -dfcut*dnaoh(1:3, jj, kk)*fbrace
         ENDDO
      ENDDO

      !Derivatives of fbrace
      !***nominator
      DO kk = 1, n_oxygens_acid
         DO ii = 1, n_oxygens_water
            colvar%dsdr(1:3, offsetO+kk) = colvar%dsdr(1:3, offsetO+kk) &
                                           +fcut*ddist_rik(1:3, ii, kk)*expfac(ii)/rion_den/2.0_dp
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   -fcut*ddist_rik(1:3, ii, kk)*expfac(ii)/rion_den/2.0_dp
            DO jj = 1, n_hydrogens
               colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                      +fcut*dexpfac_rik(ii, kk)*dnwoh(1:3, jj, ii)/rion_den/2.0_dp
               colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                              -fcut*dexpfac_rik(ii, kk)*dnwoh(1:3, jj, ii)/rion_den/2.0_dp
            ENDDO
         ENDDO
      ENDDO
      !***denominator
      DO ii = 1, n_oxygens_water
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   -fcut*rion_num*dexpfac(ii)*dnwoh(1:3, jj, ii)/2.0_dp/(rion_den**2)
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           +fcut*rion_num*dexpfac(ii)*dnwoh(1:3, jj, ii)/2.0_dp/(rion_den**2)
         ENDDO
      ENDDO

   END SUBROUTINE acid_hyd_dist_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the acid-hydronium-shell
!>        collective variable. Colvar: number of oxygens in 1st shell of the
!>        hydronium.
!> \param colvar collective variable
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Dorothea Golze
!> \note this function does not use POINTS, not reasonable for this colvar
! **************************************************************************************************
   SUBROUTINE acid_hyd_shell_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER :: i, ii, j, jj, k, kk, n_hydrogens, n_oxygens_acid, n_oxygens_water, offsetH, &
         offsetO, paoh, pcut, pm, poo, pwoh, qaoh, qcut, qm, qoo, qwoh, tt
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: dM, M, noo, nwoh, qloc
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: dnaoh, dnoo, dnwoh
      REAL(KIND=dp) :: dfcut, drji, drjk, drki, fcut, fscalar, invden, invden_cut, lambda, naoh, &
         nc, nh, num, num_cut, qsol, qtot, raoh, rji(3), rjk(3), rki(3), roo, rpi(3), rpj(3), &
         rpk(3), rrel, rwoh
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (my_particles, particles_i)

      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
      pwoh = colvar%acid_hyd_shell_param%pwoh
      qwoh = colvar%acid_hyd_shell_param%qwoh
      paoh = colvar%acid_hyd_shell_param%paoh
      qaoh = colvar%acid_hyd_shell_param%qaoh
      poo = colvar%acid_hyd_shell_param%poo
      qoo = colvar%acid_hyd_shell_param%qoo
      pm = colvar%acid_hyd_shell_param%pm
      qm = colvar%acid_hyd_shell_param%qm
      pcut = colvar%acid_hyd_shell_param%pcut
      qcut = colvar%acid_hyd_shell_param%qcut
      rwoh = colvar%acid_hyd_shell_param%rwoh
      raoh = colvar%acid_hyd_shell_param%raoh
      roo = colvar%acid_hyd_shell_param%roo
      nc = colvar%acid_hyd_shell_param%nc
      nh = colvar%acid_hyd_shell_param%nh
      lambda = colvar%acid_hyd_shell_param%lambda
      ALLOCATE (nwoh(n_oxygens_water))
      ALLOCATE (dnwoh(3, n_hydrogens, n_oxygens_water))
      ALLOCATE (dnaoh(3, n_hydrogens, n_oxygens_acid))
      ALLOCATE (M(n_oxygens_water))
      ALLOCATE (dM(n_oxygens_water))
      ALLOCATE (noo(n_oxygens_water))
      ALLOCATE (dnoo(3, n_oxygens_water+n_oxygens_acid, n_oxygens_water))
      ALLOCATE (qloc(n_oxygens_water))
      nwoh(:) = 0._dp
      naoh = 0._dp
      noo = 0._dp
      dnaoh(:, :, :) = 0._dp
      dnwoh(:, :, :) = 0._dp
      dnoo(:, :, :) = 0._dp
      M = 0._dp
      dM = 0._dp
      qtot = 0._dp

      CPASSERT(colvar%type_id == acid_hyd_shell_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ! Calculate coordination functions nwoh(ii) and the M function
      DO ii = 1, n_oxygens_water
         i = colvar%acid_hyd_shell_param%i_oxygens_water(ii)
         rpi(:) = my_particles(i)%r(1:3)
         DO jj = 1, n_hydrogens
            j = colvar%acid_hyd_shell_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rji = pbc(rpj, rpi, cell)
            drji = SQRT(SUM(rji**2))
            rrel = drji/rwoh
            num = 1.0_dp-rrel**pwoh
            invden = 1.0_dp/(1.0_dp-rrel**qwoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               nwoh(ii) = nwoh(ii)+num*invden
               fscalar = (-pwoh*(rrel**(pwoh-1))*invden &
                          +num*(invden**2)*qwoh*(rrel**(qwoh-1)))/(drji*rwoh)
               dnwoh(1:3, jj, ii) = rji(1:3)*fscalar
            ELSE
               !correct limit if rji --> rwoh
               nwoh(ii) = nwoh(ii)+REAL(pwoh, dp)/REAL(qwoh, dp)
               fscalar = REAL(pwoh*(pwoh-qwoh), dp)/(REAL(2*qwoh, dp)*rwoh*drji)
               dnwoh(1:3, jj, ii) = rji(1:3)*fscalar
            ENDIF
         ENDDO
      ENDDO

      ! calculate M function
      DO ii = 1, n_oxygens_water
         num = 1.0_dp-(nwoh(ii)/nh)**pm
         invden = 1.0_dp/(1.0_dp-(nwoh(ii)/nh)**qm)
         M(ii) = 1.0_dp-num*invden
         dM(ii) = (pm*(nwoh(ii)/nh)**(pm-1)*invden-qm*num*(invden**2)* &
                   (nwoh(ii)/nh)**(qm-1))/nh
      ENDDO

      ! Computing noo(i)
      DO ii = 1, n_oxygens_water
         i = colvar%acid_hyd_shell_param%i_oxygens_water(ii)
         rpi(:) = my_particles(i)%r(1:3)
         DO kk = 1, n_oxygens_water+n_oxygens_acid
            IF (ii == kk) CYCLE
            IF (kk <= n_oxygens_water) THEN
               k = colvar%acid_hyd_shell_param%i_oxygens_water(kk)
               rpk(:) = my_particles(k)%r(1:3)
            ELSE
               tt = kk-n_oxygens_water
               k = colvar%acid_hyd_shell_param%i_oxygens_acid(tt)
               rpk(:) = my_particles(k)%r(1:3)
            ENDIF
            rki = pbc(rpk, rpi, cell)
            drki = SQRT(SUM(rki**2))
            rrel = drki/roo
            num = 1.0_dp-rrel**poo
            invden = 1.0_dp/(1.0_dp-rrel**qoo)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               noo(ii) = noo(ii)+num*invden
               fscalar = (-poo*(rrel**(poo-1))*invden &
                          +num*(invden**2)*qoo*(rrel**(qoo-1)))/(drki*roo)
               dnoo(1:3, kk, ii) = rki(1:3)*fscalar
            ELSE
               !correct limit if rki --> roo
               noo(ii) = noo(ii)+REAL(poo, dp)/REAL(qoo, dp)
               fscalar = REAL(poo*(poo-qoo), dp)/(REAL(2*qoo, dp)*roo*drki)
               dnoo(1:3, kk, ii) = rki(1:3)*fscalar
            ENDIF
         ENDDO
      ENDDO

      !Calculate cutoff function
      DO kk = 1, n_oxygens_acid
         k = colvar%acid_hyd_shell_param%i_oxygens_acid(kk)
         rpk(:) = my_particles(k)%r(1:3)
         DO jj = 1, n_hydrogens
            j = colvar%acid_hyd_shell_param%i_hydrogens(jj)
            rpj(:) = my_particles(j)%r(1:3)
            rjk = pbc(rpj, rpk, cell)
            drjk = SQRT(SUM(rjk**2))
            rrel = drjk/raoh
            num = 1.0_dp-rrel**paoh
            invden = 1.0_dp/(1.0_dp-rrel**qaoh)
            IF (ABS(1.0_dp-rrel) > 1.0E-6_dp) THEN
               naoh = naoh+num*invden
               fscalar = (-paoh*(rrel**(paoh-1))*invden &
                          +num*(invden**2)*qaoh*(rrel**(qaoh-1)))/(drjk*raoh)
               dnaoh(1:3, jj, kk) = rjk(1:3)*fscalar
            ELSE
               !correct limit if rjk --> raoh
               naoh = naoh+REAL(paoh, dp)/REAL(qaoh, dp)
               fscalar = REAL(paoh*(paoh-qaoh), dp)/(REAL(2*qaoh, dp)*raoh*drjk)
               dnaoh(1:3, jj, kk) = rjk(1:3)*fscalar
            ENDIF
         ENDDO
      ENDDO
      num_cut = 1.0_dp-(naoh/nc)**pcut
      invden_cut = 1.0_dp/(1.0_dp-(naoh/nc)**qcut)
      fcut = num_cut*invden_cut

      ! Final value: number of oxygens in 1st shell of hydronium
      DO ii = 1, n_oxygens_water
         qloc(ii) = EXP(lambda*M(ii)*noo(ii))
         qtot = qtot+qloc(ii)
      ENDDO
      qsol = LOG(qtot)/lambda
      colvar%ss = fcut*qsol

      ! Derivatives of fcut
      dfcut = ((-pcut*(naoh/nc)**(pcut-1)*invden_cut) &
               +num_cut*(invden_cut**2)*qcut*(naoh/nc)**(qcut-1))/nc
      offsetO = n_oxygens_water
      offsetH = n_oxygens_water+n_oxygens_acid
      DO kk = 1, n_oxygens_acid
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, offsetO+kk) = colvar%dsdr(1:3, offsetO+kk) &
                                           +dfcut*dnaoh(1:3, jj, kk)*qsol
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           -dfcut*dnaoh(1:3, jj, kk)*qsol
         ENDDO
      ENDDO

      ! Derivatives of qsol
      !*** M derivatives
      DO ii = 1, n_oxygens_water
         fscalar = fcut*qloc(ii)*dM(ii)*noo(ii)/qtot
         DO jj = 1, n_hydrogens
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii) &
                                   +fscalar*dnwoh(1:3, jj, ii)
            colvar%dsdr(1:3, offsetH+jj) = colvar%dsdr(1:3, offsetH+jj) &
                                           -fscalar*dnwoh(1:3, jj, ii)
         ENDDO
      ENDDO
      !*** noo derivatives
      DO ii = 1, n_oxygens_water
         fscalar = fcut*qloc(ii)*M(ii)/qtot
         DO kk = 1, n_oxygens_water+n_oxygens_acid
            IF (ii == kk) CYCLE
            colvar%dsdr(1:3, ii) = colvar%dsdr(1:3, ii)+fscalar*dnoo(1:3, kk, ii)
            colvar%dsdr(1:3, kk) = colvar%dsdr(1:3, kk)-fscalar*dnoo(1:3, kk, ii)
         ENDDO
      ENDDO

   END SUBROUTINE acid_hyd_shell_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) the coordination-chain collective variable
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author MI
!> \note When the third set of atoms is not defined, this variable is equivalent
!>       to the simple coordination number.
! **************************************************************************************************
   SUBROUTINE coord_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, k, kk, n_atoms_from, &
                                                            n_atoms_to_a, n_atoms_to_b, p_a, p_b, &
                                                            q_a, q_b
      REAL(dp) :: dfunc_ij, dfunc_jk, func_ij, func_jk, func_k, inv_n_atoms_from, invden_ij, &
         invden_jk, ncoord, num_ij, num_jk, r_0_a, r_0_b, rdist_ij, rdist_jk, rij, rjk
      REAL(dp), DIMENSION(3)                             :: ftmp_i, ftmp_j, ftmp_k, ss, xij, xjk, &
                                                            xpi, xpj, xpk
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

! If we defined the coordination number with KINDS then we have still
! to fill few missing informations...

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == coord_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      n_atoms_to_a = colvar%coord_param%n_atoms_to
      n_atoms_to_b = colvar%coord_param%n_atoms_to_b
      n_atoms_from = colvar%coord_param%n_atoms_from
      p_a = colvar%coord_param%nncrd
      q_a = colvar%coord_param%ndcrd
      r_0_a = colvar%coord_param%r_0
      p_b = colvar%coord_param%nncrd_b
      q_b = colvar%coord_param%ndcrd_b
      r_0_b = colvar%coord_param%r_0_b

      ncoord = 0.0_dp
      inv_n_atoms_from = 1.0_dp/REAL(n_atoms_from, KIND=dp)
      DO ii = 1, n_atoms_from
         i = colvar%coord_param%i_at_from(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         DO jj = 1, n_atoms_to_a
            j = colvar%coord_param%i_at_to(jj)
            CALL get_coordinates(colvar, j, xpj, my_particles)
            ! define coordination of atom A with itself to be 0. also fixes rij==0 for the force calculation
            IF (i .EQ. j) CYCLE
            ss = MATMUL(cell%h_inv, xpi(:)-xpj(:))
            ss = ss-NINT(ss)
            xij = MATMUL(cell%hmat, ss)
            rij = SQRT(xij(1)**2+xij(2)**2+xij(3)**2)
            IF (rij < 1.0e-8_dp) CYCLE
            rdist_ij = rij/r_0_a
            IF (ABS(1.0_dp-rdist_ij) > EPSILON(0.0_dp)*1.0E+4_dp) THEN
               num_ij = (1.0_dp-rdist_ij**p_a)
               invden_ij = 1.0_dp/(1.0_dp-rdist_ij**q_a)
               func_ij = num_ij*invden_ij
               IF (rij < 1.0E-8_dp) THEN
                  ! provide the correct limit of the derivative
                  dfunc_ij = 0.0_dp
               ELSE
                  dfunc_ij = (-p_a*rdist_ij**(p_a-1)*invden_ij &
                              +num_ij*(invden_ij)**2*q_a*rdist_ij**(q_a-1))/(rij*r_0_a)
               END IF
            ELSE
               ! Provide the correct limit for function value and derivative
               func_ij = REAL(p_a, KIND=dp)/REAL(q_a, KIND=dp)
               dfunc_ij = REAL(p_a, KIND=dp)*REAL((-q_a+p_a), KIND=dp)/(REAL(2*q_a, KIND=dp)*r_0_a)
            END IF
            IF (n_atoms_to_b /= 0) THEN
               func_k = 0.0_dp
               DO kk = 1, n_atoms_to_b
                  k = colvar%coord_param%i_at_to_b(kk)
                  IF (k .EQ. j) CYCLE
                  CALL get_coordinates(colvar, k, xpk, my_particles)
                  ss = MATMUL(cell%h_inv, xpj(:)-xpk(:))
                  ss = ss-NINT(ss)
                  xjk = MATMUL(cell%hmat, ss)
                  rjk = SQRT(xjk(1)**2+xjk(2)**2+xjk(3)**2)
                  IF (rjk < 1.0e-8_dp) CYCLE
                  rdist_jk = rjk/r_0_b
                  IF (ABS(1.0_dp-rdist_jk) > EPSILON(0.0_dp)*1.0E+4_dp) THEN
                     num_jk = (1.0_dp-rdist_jk**p_b)
                     invden_jk = 1.0_dp/(1.0_dp-rdist_jk**q_b)
                     func_jk = num_jk*invden_jk
                     IF (rjk < 1.0E-8_dp) THEN
                        ! provide the correct limit of the derivative
                        dfunc_jk = 0.0_dp
                     ELSE
                        dfunc_jk = (-p_b*rdist_jk**(p_b-1)*invden_jk &
                                    +num_jk*(invden_jk)**2*q_b*rdist_jk**(q_b-1))/(rjk*r_0_b)
                     END IF
                  ELSE
                     ! Provide the correct limit for function value and derivative
                     func_jk = REAL(p_b, KIND=dp)/REAL(q_b, KIND=dp)
                     dfunc_jk = REAL(p_b, KIND=dp)*REAL((-q_b+p_b), KIND=dp)/(REAL(2*q_b, KIND=dp)*r_0_b)
                  ENDIF
                  func_k = func_k+func_jk
                  ftmp_k = -func_ij*dfunc_jk*xjk
                  CALL put_derivative(colvar, n_atoms_from+n_atoms_to_a+kk, ftmp_k)

                  ftmp_j = -dfunc_ij*xij*func_jk+func_ij*dfunc_jk*xjk
                  CALL put_derivative(colvar, n_atoms_from+jj, ftmp_j)
               END DO
            ELSE
               func_k = 1.0_dp
               dfunc_jk = 0.0_dp
               ftmp_j = -dfunc_ij*xij
               CALL put_derivative(colvar, n_atoms_from+jj, ftmp_j)
            END IF
            ncoord = ncoord+func_ij*func_k
            ftmp_i = dfunc_ij*xij*func_k
            CALL put_derivative(colvar, ii, ftmp_i)
         ENDDO
      ENDDO
      colvar%ss = ncoord*inv_n_atoms_from
      colvar%dsdr(:, :) = colvar%dsdr(:, :)*inv_n_atoms_from
   END SUBROUTINE coord_colvar

! **************************************************************************************************
!> \brief ...
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
! **************************************************************************************************
   SUBROUTINE mindist_colvar(colvar, cell, subsys, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, n_coord_from, n_coord_to, &
                                                            n_dist_from, p, q
      REAL(dp) :: den_n, den_Q, fscalar, ftemp_i(3), inv_den_n, inv_den_Q, lambda, num_n, num_Q, &
         Qfunc, r12, r_cut, rfact, rij(3), rpi(3), rpj(3)
      REAL(dp), DIMENSION(:), POINTER                    :: dqfunc_dnL, expnL, nLcoord, sum_rij
      REAL(dp), DIMENSION(:, :, :), POINTER              :: dnLcoord, dqfunc_dr
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

! If we defined the coordination number with KINDS then we have still
! to fill few missing informations...

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == mindist_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      n_dist_from = colvar%mindist_param%n_dist_from
      n_coord_from = colvar%mindist_param%n_coord_from
      n_coord_to = colvar%mindist_param%n_coord_to
      p = colvar%mindist_param%p_exp
      q = colvar%mindist_param%q_exp
      r_cut = colvar%mindist_param%r_cut
      lambda = colvar%mindist_param%lambda

      NULLIFY (nLcoord, dnLcoord, dqfunc_dr, dqfunc_dnL, expnL, sum_rij)
      ALLOCATE (nLcoord(n_coord_from))
      ALLOCATE (dnLcoord(3, n_coord_from, n_coord_to))
      ALLOCATE (expnL(n_coord_from))
      ALLOCATE (sum_rij(n_coord_from))
      ALLOCATE (dqfunc_dr(3, n_dist_from, n_coord_from))
      ALLOCATE (dqfunc_dnL(n_coord_from))

      ! coordination numbers
      nLcoord = 0.0_dp
      dnLcoord = 0.0_dp
      expnL = 0.0_dp
      den_Q = 0.0_dp
      DO i = 1, n_coord_from
         ii = colvar%mindist_param%i_coord_from(i)
         rpi = my_particles(ii)%r(1:3)
         DO j = 1, n_coord_to
            jj = colvar%mindist_param%i_coord_to(j)
            rpj = my_particles(jj)%r(1:3)
            rij = pbc(rpj, rpi, cell)
            r12 = SQRT(rij(1)*rij(1)+rij(2)*rij(2)+rij(3)*rij(3))
            rfact = r12/r_cut
            num_n = 1.0_dp-rfact**p
            den_n = 1.0_dp-rfact**q
            inv_den_n = 1.0_dp/den_n
            IF (ABS(inv_den_n) < 1.e-10_dp) THEN
               inv_den_n = 1.e-10_dp
               num_n = ABS(num_n)
            END IF

            fscalar = (-p*rfact**(p-1)+num_n*q*rfact**(q-1)*inv_den_n)*inv_den_n/(r_cut*r12)

            dnLcoord(1, i, j) = rij(1)*fscalar
            dnLcoord(2, i, j) = rij(2)*fscalar
            dnLcoord(3, i, j) = rij(3)*fscalar

            nLcoord(i) = nLcoord(i)+num_n*inv_den_n
         END DO
         expnL(i) = EXP(lambda*nLcoord(i))
!dbg
! write(*,*) ii,nLcoord(i),expnL(i)
!dbg
         den_Q = den_Q+expnL(i)
      END DO
      inv_den_Q = 1.0_dp/den_Q

      qfunc = 0.0_dp
      dqfunc_dr = 0.0_dp
      dqfunc_dnL = 0.0_dp
      num_Q = 0.0_dp
      sum_rij = 0.0_dp
      DO i = 1, n_dist_from
         ii = colvar%mindist_param%i_dist_from(i)
         rpi = my_particles(ii)%r(1:3)
         DO j = 1, n_coord_from
            jj = colvar%mindist_param%i_coord_from(j)
            rpj = my_particles(jj)%r(1:3)
            rij = pbc(rpj, rpi, cell)
            r12 = SQRT(rij(1)*rij(1)+rij(2)*rij(2)+rij(3)*rij(3))

!dbg
! write(*,*) ii,jj,rpi(1:3),rpj(1:3),rij(1:3),r12
!dbg
            num_Q = num_Q+r12*expnL(j)

            sum_rij(j) = sum_rij(j)+r12
            dqfunc_dr(1, i, j) = expnL(j)*rij(1)/r12
            dqfunc_dr(2, i, j) = expnL(j)*rij(2)/r12
            dqfunc_dr(3, i, j) = expnL(j)*rij(3)/r12

         END DO

      END DO

      ! Function and derivatives
      qfunc = num_Q*inv_den_Q
      dqfunc_dr = dqfunc_dr*inv_den_Q
      colvar%ss = qfunc
!dbg
!      write(*,*) ' ss ',  colvar%ss
! stop
!dbg

      DO i = 1, n_coord_from
         dqfunc_dnL(i) = lambda*expnL(i)*inv_den_Q*(sum_rij(i)-num_Q*inv_den_Q)
      END DO

      !Compute Forces
      DO i = 1, n_dist_from
         DO j = 1, n_coord_from
            ftemp_i(1) = dqfunc_dr(1, i, j)
            ftemp_i(2) = dqfunc_dr(2, i, j)
            ftemp_i(3) = dqfunc_dr(3, i, j)

            CALL put_derivative(colvar, i, ftemp_i)
            CALL put_derivative(colvar, j+n_dist_from, -ftemp_i)

         END DO
      END DO
      DO i = 1, n_coord_from
         DO j = 1, n_coord_to
            ftemp_i(1) = dqfunc_dnL(i)*dnLcoord(1, i, j)
            ftemp_i(2) = dqfunc_dnL(i)*dnLcoord(2, i, j)
            ftemp_i(3) = dqfunc_dnL(i)*dnLcoord(3, i, j)

            CALL put_derivative(colvar, i+n_dist_from, ftemp_i)
            CALL put_derivative(colvar, j+n_dist_from+n_coord_from, -ftemp_i)

         END DO
      END DO

      DEALLOCATE (nLcoord)
      DEALLOCATE (dnLcoord)
      DEALLOCATE (expnL)
      DEALLOCATE (dqfunc_dr)
      DEALLOCATE (sum_rij)
      DEALLOCATE (dqfunc_dnL)

   END SUBROUTINE mindist_colvar

! **************************************************************************************************
!> \brief  evaluates function and forces due to a combination of COLVARs
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \author Teodoro Laino [tlaino] - 12.2008
! **************************************************************************************************
   SUBROUTINE combine_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      CHARACTER(LEN=default_string_length)               :: def_error, this_error
      CHARACTER(LEN=default_string_length), &
         ALLOCATABLE, DIMENSION(:)                       :: my_par
      INTEGER                                            :: i, ii, j, ncolv, ndim
      REAL(dp)                                           :: err
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: dss_vals, my_val, ss_vals
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: fi
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      CPASSERT(colvar%type_id == combine_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      ncolv = SIZE(colvar%combine_cvs_param%colvar_p)
      ALLOCATE (ss_vals(ncolv))
      ALLOCATE (dss_vals(ncolv))

      ! Evaluate the individual COLVARs
      DO i = 1, ncolv
         CALL colvar_recursive_eval(colvar%combine_cvs_param%colvar_p(i)%colvar, cell, my_particles)
         ss_vals(i) = colvar%combine_cvs_param%colvar_p(i)%colvar%ss
      ENDDO

      ! Evaluate the combination of the COLVARs
      CALL initf(1)
      ndim = SIZE(colvar%combine_cvs_param%c_parameters)+ &
             SIZE(colvar%combine_cvs_param%variables)
      ALLOCATE (my_par(ndim))
      my_par(1:SIZE(colvar%combine_cvs_param%variables)) = colvar%combine_cvs_param%variables
      my_par(SIZE(colvar%combine_cvs_param%variables)+1:) = colvar%combine_cvs_param%c_parameters
      ALLOCATE (my_val(ndim))
      my_val(1:SIZE(colvar%combine_cvs_param%variables)) = ss_vals
      my_val(SIZE(colvar%combine_cvs_param%variables)+1:) = colvar%combine_cvs_param%v_parameters
      CALL parsef(1, TRIM(colvar%combine_cvs_param%function), my_par)
      colvar%ss = evalf(1, my_val)
      DO i = 1, ncolv
         dss_vals(i) = evalfd(1, i, my_val, colvar%combine_cvs_param%dx, err)
         IF ((ABS(err) > colvar%combine_cvs_param%lerr)) THEN
            WRITE (this_error, "(A,G12.6,A)") "(", err, ")"
            WRITE (def_error, "(A,G12.6,A)") "(", colvar%combine_cvs_param%lerr, ")"
            CALL compress(this_error, .TRUE.)
            CALL compress(def_error, .TRUE.)
            CALL cp_warn(__LOCATION__, &
                         'ASSERTION (cond) failed at line '//cp_to_string(__LINE__)// &
                         ' Error '//TRIM(this_error)//' in computing numerical derivatives larger then'// &
                         TRIM(def_error)//' . ')
         END IF
      END DO
      DEALLOCATE (my_val)
      DEALLOCATE (my_par)
      CALL finalizef()

      ! Evaluate forces
      ALLOCATE (fi(3, colvar%n_atom_s))
      ii = 0
      DO i = 1, ncolv
         DO j = 1, colvar%combine_cvs_param%colvar_p(i)%colvar%n_atom_s
            ii = ii+1
            fi(:, ii) = colvar%combine_cvs_param%colvar_p(i)%colvar%dsdr(:, j)*dss_vals(i)
         END DO
      END DO

      DO i = 1, colvar%n_atom_s
         CALL put_derivative(colvar, i, fi(:, i))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (ss_vals)
      DEALLOCATE (dss_vals)
   END SUBROUTINE combine_colvar

! **************************************************************************************************
!> \brief evaluates the force due (and on) reaction path collective variable
!>             ss(R) = [\sum_i i*dt exp{-\lambda \sum_a(S_a(R)-f_a(i))^2}]/
!>                     [\sum_i exp{-\lambda \sum_a(S_a(R)-f_a(i))^2}]
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \par History
!>      extended MI 01.2010
!> \author fschiff
!> \note the system is still able to move in the space spanned by the CV
!>       perpendicular to the path
! **************************************************************************************************
   SUBROUTINE reaction_path_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      CPASSERT(colvar%type_id == reaction_path_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      IF (colvar%reaction_path_param%dist_rmsd) THEN
         CALL rpath_dist_rmsd(colvar, my_particles)
      ELSEIF (colvar%reaction_path_param%rmsd) THEN
         CALL rpath_rmsd(colvar, my_particles)
      ELSE
         CALL rpath_colvar(colvar, cell, my_particles)
      END IF

   END SUBROUTINE reaction_path_colvar

! **************************************************************************************************
!> \brief  position along the path calculated using selected colvars
!>         as compared to functions describing the variation of these same colvars
!>         along the path given as reference
!> \param colvar ...
!> \param cell ...
!> \param particles ...
!> \author fschiff
! **************************************************************************************************
   SUBROUTINE rpath_colvar(colvar, cell, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iend, ii, istart, j, k, ncolv, nconf
      REAL(dp)                                           :: lambda, step_size
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: s1, ss_vals
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: ds1, f_vals, fi, s1v
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ds1v

      istart = colvar%reaction_path_param%function_bounds(1)
      iend = colvar%reaction_path_param%function_bounds(2)

      nconf = colvar%reaction_path_param%nr_frames
      step_size = colvar%reaction_path_param%step_size
      ncolv = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      ALLOCATE (f_vals(ncolv, istart:iend))
      f_vals(:, :) = colvar%reaction_path_param%f_vals
      ALLOCATE (ss_vals(ncolv))

      DO i = 1, ncolv
         CALL colvar_recursive_eval(colvar%reaction_path_param%colvar_p(i)%colvar, cell, particles)
         ss_vals(i) = colvar%reaction_path_param%colvar_p(i)%colvar%ss
      ENDDO

      ALLOCATE (s1v(2, istart:iend))
      ALLOCATE (ds1v(ncolv, 2, istart:iend))

      ALLOCATE (s1(2))
      ALLOCATE (ds1(ncolv, 2))

      DO k = istart, iend
         s1v(1, k) = REAL(k, kind=dp)*step_size*EXP(-lambda*DOT_PRODUCT(ss_vals(:)-f_vals(:, k), ss_vals(:)-f_vals(:, k)))
         s1v(2, k) = EXP(-lambda*DOT_PRODUCT(ss_vals(:)-f_vals(:, k), ss_vals(:)-f_vals(:, k)))
         DO j = 1, ncolv
            ds1v(j, 1, k) = f_vals(j, k)*s1v(1, k)
            ds1v(j, 2, k) = f_vals(j, k)*s1v(2, k)
         END DO
      END DO
      DO i = 1, 2
         s1(i) = accurate_sum(s1v(i, :))
         DO j = 1, ncolv
            ds1(j, i) = accurate_sum(ds1v(j, i, :))
         END DO
      END DO

      colvar%ss = s1(1)/s1(2)/REAL(nconf-1, dp)

      ALLOCATE (fi(3, colvar%n_atom_s))

      ii = 0
      DO i = 1, ncolv
         DO j = 1, colvar%reaction_path_param%colvar_p(i)%colvar%n_atom_s
            ii = ii+1
            fi(:, ii) = colvar%reaction_path_param%colvar_p(i)%colvar%dsdr(:, j)*lambda* &
                        (ds1(i, 1)/s1(2)/REAL(nconf-1, dp)-colvar%ss*ds1(i, 2)/s1(2))*2.0_dp
         END DO
      END DO

      DO i = 1, colvar%n_atom_s
         CALL put_derivative(colvar, i, fi(:, i))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (f_vals)
      DEALLOCATE (ss_vals)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (s1)
      DEALLOCATE (ds1)

   END SUBROUTINE rpath_colvar

! **************************************************************************************************
!> \brief  position along the path calculated from the positions of a selected list of
!>         atoms as compared to the same positions in reference
!>         configurations belonging to the given path.
!> \param colvar ...
!> \param particles ...
!> \date  01.2010
!> \author MI
! **************************************************************************************************
   SUBROUTINE rpath_dist_rmsd(colvar, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iat, ii, ik, natom, nconf, rmsd_atom
      INTEGER, DIMENSION(:), POINTER                     :: iatom
      REAL(dp)                                           :: lambda, my_rmsd, s1(2), sum_exp
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: r, r0, vec_dif
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: dvec_dif, fi, riat, s1v
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ds1
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :, :)       :: ds1v
      REAL(dp), DIMENSION(:, :), POINTER                 :: path_conf

      nconf = colvar%reaction_path_param%nr_frames
      rmsd_atom = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      path_conf => colvar%reaction_path_param%r_ref
      iatom => colvar%reaction_path_param%i_rmsd

      natom = SIZE(particles)

      ALLOCATE (r0(3*natom))
      ALLOCATE (r(3*natom))
      ALLOCATE (riat(3, rmsd_atom))
      ALLOCATE (vec_dif(rmsd_atom))
      ALLOCATE (dvec_dif(3, rmsd_atom))
      ALLOCATE (s1v(2, nconf))
      ALLOCATE (ds1v(3, rmsd_atom, 2, nconf))
      ALLOCATE (ds1(3, rmsd_atom, 2))
      DO i = 1, natom
         ii = (i-1)*3
         r0(ii+1) = particles(i)%r(1)
         r0(ii+2) = particles(i)%r(2)
         r0(ii+3) = particles(i)%r(3)
      END DO

      DO iat = 1, rmsd_atom
         ii = iatom(iat)
         riat(:, iat) = particles(ii)%r
      END DO

      DO ik = 1, nconf
         DO i = 1, natom
            ii = (i-1)*3
            r(ii+1) = path_conf(ii+1, ik)
            r(ii+2) = path_conf(ii+2, ik)
            r(ii+3) = path_conf(ii+3, ik)
         END DO

         CALL rmsd3(particles, r, r0, output_unit=-1, my_val=my_rmsd, rotate=.TRUE.)

         sum_exp = 0.0_dp
         DO iat = 1, rmsd_atom
            i = iatom(iat)
            ii = (i-1)*3
            vec_dif(iat) = (riat(1, iat)-r(ii+1))**2+(riat(2, iat)-r(ii+2))**2 &
                           +(riat(3, iat)-r(ii+3))**2
            sum_exp = sum_exp+vec_dif(iat)
         END DO

         s1v(1, ik) = REAL(ik-1, dp)*EXP(-lambda*sum_exp)
         s1v(2, ik) = EXP(-lambda*sum_exp)
         DO iat = 1, rmsd_atom
            i = iatom(iat)
            ii = (i-1)*3
            ds1v(1, iat, 1, ik) = r(ii+1)*s1v(1, ik)
            ds1v(1, iat, 2, ik) = r(ii+1)*s1v(2, ik)
            ds1v(2, iat, 1, ik) = r(ii+2)*s1v(1, ik)
            ds1v(2, iat, 2, ik) = r(ii+2)*s1v(2, ik)
            ds1v(3, iat, 1, ik) = r(ii+3)*s1v(1, ik)
            ds1v(3, iat, 2, ik) = r(ii+3)*s1v(2, ik)
         END DO

      END DO
      s1(1) = accurate_sum(s1v(1, :))
      s1(2) = accurate_sum(s1v(2, :))
      DO i = 1, 2
         DO iat = 1, rmsd_atom
            ds1(1, iat, i) = accurate_sum(ds1v(1, iat, i, :))
            ds1(2, iat, i) = accurate_sum(ds1v(2, iat, i, :))
            ds1(3, iat, i) = accurate_sum(ds1v(3, iat, i, :))
         END DO
      END DO

      colvar%ss = s1(1)/s1(2)/REAL(nconf-1, dp)

      ALLOCATE (fi(3, rmsd_atom))

      DO iat = 1, rmsd_atom
         fi(1, iat) = 2.0_dp*lambda/s1(2)/REAL(nconf-1, dp)*(ds1(1, iat, 1)-ds1(1, iat, 2)*s1(1)/s1(2))
         fi(2, iat) = 2.0_dp*lambda/s1(2)/REAL(nconf-1, dp)*(ds1(2, iat, 1)-ds1(2, iat, 2)*s1(1)/s1(2))
         fi(3, iat) = 2.0_dp*lambda/s1(2)/REAL(nconf-1, dp)*(ds1(3, iat, 1)-ds1(3, iat, 2)*s1(1)/s1(2))
         CALL put_derivative(colvar, iat, fi(:, iat))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (r0)
      DEALLOCATE (r)
      DEALLOCATE (riat)
      DEALLOCATE (vec_dif)
      DEALLOCATE (dvec_dif)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (ds1)

   END SUBROUTINE rpath_dist_rmsd

! **************************************************************************************************
!> \brief ...
!> \param colvar ...
!> \param particles ...
! **************************************************************************************************
   SUBROUTINE rpath_rmsd(colvar, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iat, ii, ik, natom, nconf, rmsd_atom
      INTEGER, DIMENSION(:), POINTER                     :: iatom
      REAL(dp)                                           :: lambda, my_rmsd, s1(2)
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: r, r0
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: fi, riat, s1v
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ds1
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :, :)       :: ds1v
      REAL(dp), DIMENSION(:, :), POINTER                 :: path_conf
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: weight
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: drmsd

      nconf = colvar%reaction_path_param%nr_frames
      rmsd_atom = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      path_conf => colvar%reaction_path_param%r_ref
      iatom => colvar%reaction_path_param%i_rmsd

      natom = SIZE(particles)

      ALLOCATE (r0(3*natom))
      ALLOCATE (r(3*natom))
      ALLOCATE (riat(3, rmsd_atom))
      ALLOCATE (s1v(2, nconf))
      ALLOCATE (ds1v(3, rmsd_atom, 2, nconf))
      ALLOCATE (ds1(3, rmsd_atom, 2))
      ALLOCATE (drmsd(3, natom))
      drmsd = 0.0_dp
      ALLOCATE (weight(natom))

      DO i = 1, natom
         ii = (i-1)*3
         r0(ii+1) = particles(i)%r(1)
         r0(ii+2) = particles(i)%r(2)
         r0(ii+3) = particles(i)%r(3)
      END DO

      DO iat = 1, rmsd_atom
         ii = iatom(iat)
         riat(:, iat) = particles(ii)%r
      END DO

! set weights of atoms in the rmsd list
      weight = 0.0_dp
      DO iat = 1, rmsd_atom
         i = iatom(iat)
         weight(i) = 1.0_dp
      END DO

      DO ik = 1, nconf
         DO i = 1, natom
            ii = (i-1)*3
            r(ii+1) = path_conf(ii+1, ik)
            r(ii+2) = path_conf(ii+2, ik)
            r(ii+3) = path_conf(ii+3, ik)
         END DO

         CALL rmsd3(particles, r0, r, output_unit=-1, weights=weight, my_val=my_rmsd, &
                    rotate=.FALSE., drmsd3=drmsd)

         s1v(1, ik) = REAL(ik-1, dp)*EXP(-lambda*my_rmsd)
         s1v(2, ik) = EXP(-lambda*my_rmsd)
         DO iat = 1, rmsd_atom
            i = iatom(iat)
            ds1v(1, iat, 1, ik) = drmsd(1, i)*s1v(1, ik)
            ds1v(1, iat, 2, ik) = drmsd(1, i)*s1v(2, ik)
            ds1v(2, iat, 1, ik) = drmsd(2, i)*s1v(1, ik)
            ds1v(2, iat, 2, ik) = drmsd(2, i)*s1v(2, ik)
            ds1v(3, iat, 1, ik) = drmsd(3, i)*s1v(1, ik)
            ds1v(3, iat, 2, ik) = drmsd(3, i)*s1v(2, ik)
         END DO
      END DO ! ik

      s1(1) = accurate_sum(s1v(1, :))
      s1(2) = accurate_sum(s1v(2, :))
      DO i = 1, 2
         DO iat = 1, rmsd_atom
            ds1(1, iat, i) = accurate_sum(ds1v(1, iat, i, :))
            ds1(2, iat, i) = accurate_sum(ds1v(2, iat, i, :))
            ds1(3, iat, i) = accurate_sum(ds1v(3, iat, i, :))
         END DO
      END DO

      colvar%ss = s1(1)/s1(2)/REAL(nconf-1, dp)

      ALLOCATE (fi(3, rmsd_atom))

      DO iat = 1, rmsd_atom
         fi(1, iat) = -lambda/s1(2)/REAL(nconf-1, dp)*(ds1(1, iat, 1)-ds1(1, iat, 2)*s1(1)/s1(2))
         fi(2, iat) = -lambda/s1(2)/REAL(nconf-1, dp)*(ds1(2, iat, 1)-ds1(2, iat, 2)*s1(1)/s1(2))
         fi(3, iat) = -lambda/s1(2)/REAL(nconf-1, dp)*(ds1(3, iat, 1)-ds1(3, iat, 2)*s1(1)/s1(2))
         CALL put_derivative(colvar, iat, fi(:, iat))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (r0)
      DEALLOCATE (r)
      DEALLOCATE (riat)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (ds1)
      DEALLOCATE (drmsd)
      DEALLOCATE (weight)

   END SUBROUTINE rpath_rmsd

! **************************************************************************************************
!> \brief evaluates the force due (and on) distance from reaction path collective variable
!>             ss(R) = -1/\lambda \log[\sum_i exp{-\lambda \sum_a(S_a(R)-f_a(i))^2}]
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \date 01.2010
!> \author MI
! **************************************************************************************************
   SUBROUTINE distance_from_path_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      CPASSERT(colvar%type_id == distance_from_path_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      IF (colvar%reaction_path_param%dist_rmsd) THEN
         CALL dpath_dist_rmsd(colvar, my_particles)
      ELSEIF (colvar%reaction_path_param%rmsd) THEN
         CALL dpath_rmsd(colvar, my_particles)
      ELSE
         CALL dpath_colvar(colvar, cell, my_particles)
      END IF

   END SUBROUTINE distance_from_path_colvar

! **************************************************************************************************
!> \brief  distance from path calculated using selected colvars
!>         as compared to functions describing the variation of these same colvars
!>         along the path given as reference
!> \param colvar ...
!> \param cell ...
!> \param particles ...
!> \date  01.2010
!> \author MI
! **************************************************************************************************
   SUBROUTINE dpath_colvar(colvar, cell, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iend, ii, istart, j, k, ncolv
      REAL(dp)                                           :: lambda, s1
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: ds1, s1v, ss_vals
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: ds1v, f_vals, fi

      istart = colvar%reaction_path_param%function_bounds(1)
      iend = colvar%reaction_path_param%function_bounds(2)

      ncolv = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      ALLOCATE (f_vals(ncolv, istart:iend))
      f_vals(:, :) = colvar%reaction_path_param%f_vals
      ALLOCATE (ss_vals(ncolv))

      DO i = 1, ncolv
         CALL colvar_recursive_eval(colvar%reaction_path_param%colvar_p(i)%colvar, cell, particles)
         ss_vals(i) = colvar%reaction_path_param%colvar_p(i)%colvar%ss
      ENDDO

      ALLOCATE (s1v(istart:iend))
      ALLOCATE (ds1v(ncolv, istart:iend))
      ALLOCATE (ds1(ncolv))

      DO k = istart, iend
         s1v(k) = EXP(-lambda*DOT_PRODUCT(ss_vals(:)-f_vals(:, k), ss_vals(:)-f_vals(:, k)))
         DO j = 1, ncolv
            ds1v(j, k) = f_vals(j, k)*s1v(k)
         END DO
      END DO

      s1 = accurate_sum(s1v(:))
      DO j = 1, ncolv
         ds1(j) = accurate_sum(ds1v(j, :))
      END DO
      colvar%ss = -1.0_dp/lambda*LOG(s1)

      ALLOCATE (fi(3, colvar%n_atom_s))

      ii = 0
      DO i = 1, ncolv
         DO j = 1, colvar%reaction_path_param%colvar_p(i)%colvar%n_atom_s
            ii = ii+1
            fi(:, ii) = colvar%reaction_path_param%colvar_p(i)%colvar%dsdr(:, j)* &
                        2.0_dp*(ss_vals(i)-ds1(i)/s1)
         END DO
      END DO

      DO i = 1, colvar%n_atom_s
         CALL put_derivative(colvar, i, fi(:, i))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (f_vals)
      DEALLOCATE (ss_vals)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (ds1)

   END SUBROUTINE dpath_colvar

! **************************************************************************************************
!> \brief  distance from path calculated from the positions of a selected list of
!>         atoms as compared to the same positions in reference
!>         configurations belonging to the given path.
!> \param colvar ...
!> \param particles ...
!> \date  01.2010
!> \author MI
! **************************************************************************************************
   SUBROUTINE dpath_dist_rmsd(colvar, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iat, ii, ik, natom, nconf, rmsd_atom
      INTEGER, DIMENSION(:), POINTER                     :: iatom
      REAL(dp)                                           :: lambda, s1, sum_exp
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: r, r0, s1v, vec_dif
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: ds1, dvec_dif, fi, riat
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ds1v
      REAL(dp), DIMENSION(:, :), POINTER                 :: path_conf

      nconf = colvar%reaction_path_param%nr_frames
      rmsd_atom = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      path_conf => colvar%reaction_path_param%r_ref
      iatom => colvar%reaction_path_param%i_rmsd

      natom = SIZE(particles)

      ALLOCATE (r0(3*natom))
      ALLOCATE (r(3*natom))
      ALLOCATE (riat(3, rmsd_atom))
      ALLOCATE (vec_dif(rmsd_atom))
      ALLOCATE (dvec_dif(3, rmsd_atom))
      ALLOCATE (s1v(nconf))
      ALLOCATE (ds1v(3, rmsd_atom, nconf))
      ALLOCATE (ds1(3, rmsd_atom))
      DO i = 1, natom
         ii = (i-1)*3
         r0(ii+1) = particles(i)%r(1)
         r0(ii+2) = particles(i)%r(2)
         r0(ii+3) = particles(i)%r(3)
      END DO

      DO iat = 1, rmsd_atom
         ii = iatom(iat)
         riat(:, iat) = particles(ii)%r
      END DO

      DO ik = 1, nconf
         DO i = 1, natom
            ii = (i-1)*3
            r(ii+1) = path_conf(ii+1, ik)
            r(ii+2) = path_conf(ii+2, ik)
            r(ii+3) = path_conf(ii+3, ik)
         END DO

         CALL rmsd3(particles, r, r0, output_unit=-1, rotate=.TRUE.)

         sum_exp = 0.0_dp
         DO iat = 1, rmsd_atom
            i = iatom(iat)
            ii = (i-1)*3
            vec_dif(iat) = (riat(1, iat)-r(ii+1))**2+(riat(2, iat)-r(ii+2))**2+(riat(3, iat)-r(ii+3))**2
            sum_exp = sum_exp+vec_dif(iat)
            dvec_dif(1, iat) = r(ii+1)
            dvec_dif(2, iat) = r(ii+2)
            dvec_dif(3, iat) = r(ii+3)
         END DO
         s1v(ik) = EXP(-lambda*sum_exp)
         DO iat = 1, rmsd_atom
            ds1v(1, iat, ik) = dvec_dif(1, iat)*s1v(ik)
            ds1v(2, iat, ik) = dvec_dif(2, iat)*s1v(ik)
            ds1v(3, iat, ik) = dvec_dif(3, iat)*s1v(ik)
         END DO
      END DO

      s1 = accurate_sum(s1v(:))
      DO iat = 1, rmsd_atom
         ds1(1, iat) = accurate_sum(ds1v(1, iat, :))
         ds1(2, iat) = accurate_sum(ds1v(2, iat, :))
         ds1(3, iat) = accurate_sum(ds1v(3, iat, :))
      END DO
      colvar%ss = -1.0_dp/lambda*LOG(s1)

      ALLOCATE (fi(3, rmsd_atom))

      DO iat = 1, rmsd_atom
         fi(:, iat) = 2.0_dp*(riat(:, iat)-ds1(:, iat)/s1)
         CALL put_derivative(colvar, iat, fi(:, iat))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (r0)
      DEALLOCATE (r)
      DEALLOCATE (riat)
      DEALLOCATE (vec_dif)
      DEALLOCATE (dvec_dif)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (ds1)
   END SUBROUTINE dpath_dist_rmsd

! **************************************************************************************************
!> \brief ...
!> \param colvar ...
!> \param particles ...
! **************************************************************************************************
   SUBROUTINE dpath_rmsd(colvar, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(particle_type), DIMENSION(:), POINTER         :: particles

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

      INTEGER                                            :: i, iat, ii, ik, natom, nconf, rmsd_atom
      INTEGER, DIMENSION(:), POINTER                     :: iatom
      REAL(dp)                                           :: lambda, my_rmsd, s1
      REAL(dp), ALLOCATABLE, DIMENSION(:)                :: r, r0, s1v
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: ds1, fi, riat
      REAL(dp), ALLOCATABLE, DIMENSION(:, :, :)          :: ds1v
      REAL(dp), DIMENSION(:, :), POINTER                 :: path_conf
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: weight
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: drmsd

      nconf = colvar%reaction_path_param%nr_frames
      rmsd_atom = colvar%reaction_path_param%n_components
      lambda = colvar%reaction_path_param%lambda
      path_conf => colvar%reaction_path_param%r_ref
      iatom => colvar%reaction_path_param%i_rmsd

      natom = SIZE(particles)

      ALLOCATE (r0(3*natom))
      ALLOCATE (r(3*natom))
      ALLOCATE (riat(3, rmsd_atom))
      ALLOCATE (s1v(nconf))
      ALLOCATE (ds1v(3, rmsd_atom, nconf))
      ALLOCATE (ds1(3, rmsd_atom))
      ALLOCATE (drmsd(3, natom))
      drmsd = 0.0_dp
      ALLOCATE (weight(natom))

      DO i = 1, natom
         ii = (i-1)*3
         r0(ii+1) = particles(i)%r(1)
         r0(ii+2) = particles(i)%r(2)
         r0(ii+3) = particles(i)%r(3)
      END DO

      DO iat = 1, rmsd_atom
         ii = iatom(iat)
         riat(:, iat) = particles(ii)%r
      END DO

! set weights of atoms in the rmsd list
      weight = 0.0_dp
      DO iat = 1, rmsd_atom
         i = iatom(iat)
         weight(i) = 1.0_dp
      END DO

      DO ik = 1, nconf
         DO i = 1, natom
            ii = (i-1)*3
            r(ii+1) = path_conf(ii+1, ik)
            r(ii+2) = path_conf(ii+2, ik)
            r(ii+3) = path_conf(ii+3, ik)
         END DO

         CALL rmsd3(particles, r0, r, output_unit=-1, weights=weight, my_val=my_rmsd, &
                    rotate=.FALSE., drmsd3=drmsd)

         s1v(ik) = EXP(-lambda*my_rmsd)
         DO iat = 1, rmsd_atom
            i = iatom(iat)
            ds1v(1, iat, ik) = drmsd(1, i)*s1v(ik)
            ds1v(2, iat, ik) = drmsd(2, i)*s1v(ik)
            ds1v(3, iat, ik) = drmsd(3, i)*s1v(ik)
         END DO
      END DO

      s1 = accurate_sum(s1v(:))
      DO iat = 1, rmsd_atom
         ds1(1, iat) = accurate_sum(ds1v(1, iat, :))
         ds1(2, iat) = accurate_sum(ds1v(2, iat, :))
         ds1(3, iat) = accurate_sum(ds1v(3, iat, :))
      END DO
      colvar%ss = -1.0_dp/lambda*LOG(s1)

      ALLOCATE (fi(3, rmsd_atom))

      DO iat = 1, rmsd_atom
         fi(:, iat) = ds1(:, iat)/s1
         CALL put_derivative(colvar, iat, fi(:, iat))
      END DO

      DEALLOCATE (fi)
      DEALLOCATE (r0)
      DEALLOCATE (r)
      DEALLOCATE (riat)
      DEALLOCATE (s1v)
      DEALLOCATE (ds1v)
      DEALLOCATE (ds1)
      DEALLOCATE (drmsd)
      DEALLOCATE (weight)

   END SUBROUTINE dpath_rmsd

! **************************************************************************************************
!> \brief evaluates the force due to population colvar
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \date  01.2009
!> \author fsterpone
! **************************************************************************************************
   SUBROUTINE population_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, jj, n_atoms_from, n_atoms_to, &
                                                            ndcrd, nncrd
      REAL(dp) :: dfunc, dfunc_coord, ftmp(3), func, func_coord, inv_n_atoms_from, invden, n_0, &
         ncoord, norm, num, population, r12, r_0, rdist, sigma, ss(3), xij(3)
      REAL(dp), ALLOCATABLE, DIMENSION(:, :)             :: ftmp_coord
      REAL(dp), DIMENSION(3)                             :: xpi, xpj
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

! If we defined the coordination number with KINDS then we have still
! to fill few missing informations...

      NULLIFY (particles_i)
      CPASSERT(colvar%type_id == population_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      n_atoms_to = colvar%population_param%n_atoms_to
      n_atoms_from = colvar%population_param%n_atoms_from
      nncrd = colvar%population_param%nncrd
      ndcrd = colvar%population_param%ndcrd
      r_0 = colvar%population_param%r_0
      n_0 = colvar%population_param%n0
      sigma = colvar%population_param%sigma

      ALLOCATE (ftmp_coord(3, n_atoms_to))
      ftmp_coord = 0.0_dp

      ncoord = 0.0_dp
      population = 0.0_dp

      colvar%dsdr = 0.0_dp
      inv_n_atoms_from = 1.0_dp/REAL(n_atoms_from, KIND=dp)

      norm = SQRT(pi*2.0_dp)*sigma
      norm = 1/norm

      DO ii = 1, n_atoms_from
         i = colvar%population_param%i_at_from(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         DO jj = 1, n_atoms_to
            i = colvar%population_param%i_at_to(jj)
            CALL get_coordinates(colvar, i, xpj, my_particles)
            ss = MATMUL(cell%h_inv, xpi(:)-xpj(:))
            ss = ss-NINT(ss)
            xij = MATMUL(cell%hmat, ss)
            r12 = SQRT(xij(1)**2+xij(2)**2+xij(3)**2)
            IF (r12 < 1.0e-8_dp) CYCLE
            rdist = r12/r_0
            num = (1.0_dp-rdist**nncrd)
            invden = 1.0_dp/(1.0_dp-rdist**ndcrd)
            func_coord = num*invden
            dfunc_coord = (-nncrd*rdist**(nncrd-1)*invden &
                           +num*(invden)**2*ndcrd*rdist**(ndcrd-1))/(r12*r_0)

            ncoord = ncoord+func_coord
            ftmp_coord(1, jj) = dfunc_coord*xij(1)
            ftmp_coord(2, jj) = dfunc_coord*xij(2)
            ftmp_coord(3, jj) = dfunc_coord*xij(3)
         END DO

         func = EXP(-(ncoord-n_0)**2/(2.0_dp*sigma*sigma))
         dfunc = -func*(ncoord-n_0)/(sigma*sigma)

         population = population+norm*func
         DO jj = 1, n_atoms_to
            ftmp(1) = ftmp_coord(1, jj)*dfunc
            ftmp(2) = ftmp_coord(2, jj)*dfunc
            ftmp(3) = ftmp_coord(3, jj)*dfunc
            CALL put_derivative(colvar, ii, ftmp)
            ftmp(1) = -ftmp_coord(1, jj)*dfunc
            ftmp(2) = -ftmp_coord(2, jj)*dfunc
            ftmp(3) = -ftmp_coord(3, jj)*dfunc
            CALL put_derivative(colvar, n_atoms_from+jj, ftmp)
         ENDDO
         ncoord = 0.0_dp
      ENDDO
      colvar%ss = population
   END SUBROUTINE population_colvar

! **************************************************************************************************
!> \brief evaluates the force due to the gyration radius colvar
!>        sum_i (r_i-rcom)^2/N
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \date  03.2009
!> \author MI
! **************************************************************************************************
   SUBROUTINE gyration_radius_colvar(colvar, cell, subsys, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, n_atoms
      REAL(dp)                                           :: dri2, func, gyration, inv_n, mass_tot, mi
      REAL(dp), DIMENSION(3)                             :: dfunc, dxi, ftmp, ss, xpcom, xpi
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (particles_i, my_particles)
      CPASSERT(colvar%type_id == gyration_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      n_atoms = colvar%gyration_param%n_atoms
      inv_n = 1.0_dp/n_atoms

      !compute COM position
      xpcom = 0.0_dp
      mass_tot = 0.0_dp
      DO ii = 1, n_atoms
         i = colvar%gyration_param%i_at(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         CALL get_mass(colvar, i, mi, my_particles)
         xpcom(:) = xpcom(:)+xpi(:)*mi
         mass_tot = mass_tot+mi
      END DO
      xpcom(:) = xpcom(:)/mass_tot

      func = 0.0_dp
      ftmp = 0.0_dp
      dfunc = 0.0_dp
      DO ii = 1, n_atoms
         i = colvar%gyration_param%i_at(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         ss = MATMUL(cell%h_inv, xpi(:)-xpcom(:))
         ss = ss-NINT(ss)
         dxi = MATMUL(cell%hmat, ss)
         dri2 = (dxi(1)**2+dxi(2)**2+dxi(3)**2)
         func = func+dri2
         dfunc(:) = dfunc(:)+dxi(:)
      END DO
      gyration = SQRT(inv_n*func)

      DO ii = 1, n_atoms
         i = colvar%gyration_param%i_at(ii)
         CALL get_coordinates(colvar, i, xpi, my_particles)
         CALL get_mass(colvar, i, mi, my_particles)
         ss = MATMUL(cell%h_inv, xpi(:)-xpcom(:))
         ss = ss-NINT(ss)
         dxi = MATMUL(cell%hmat, ss)
         ftmp(1) = dxi(1)-dfunc(1)*mi/mass_tot
         ftmp(2) = dxi(2)-dfunc(2)*mi/mass_tot
         ftmp(3) = dxi(3)-dfunc(3)*mi/mass_tot
         ftmp(:) = ftmp(:)*inv_n/gyration
         CALL put_derivative(colvar, ii, ftmp)
      END DO
      colvar%ss = gyration

   END SUBROUTINE gyration_radius_colvar

! **************************************************************************************************
!> \brief evaluates the force due to the rmsd colvar
!> \param colvar ...
!> \param subsys ...
!> \param particles ...
!> \date  12.2009
!> \author MI
!> \note  could be extended to be used with more than 2 reference structures
! **************************************************************************************************
   SUBROUTINE rmsd_colvar(colvar, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      CALL rmsd_colvar_low(colvar, subsys, particles)
   END SUBROUTINE rmsd_colvar

! **************************************************************************************************
!> \brief  evaluates the force due to the rmsd colvar
!>        ss = (RMSDA-RMSDB)/(RMSDA+RMSDB)
!>        RMSD is calculated with respect to two reference structures, A and B,
!>        considering all the atoms of the system or only a subset of them,
!>        as selected by the input keyword LIST
!> \param colvar ...
!> \param subsys ...
!> \param particles ...
!> \date  12.2009
!> \par History TL 2012 (generalized to any number of frames)
!> \author MI
! **************************************************************************************************
   SUBROUTINE rmsd_colvar_low(colvar, subsys, particles)

      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, natom, nframes
      REAL(kind=dp)                                      :: cv_val, f1, ftmp(3)
      REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: der, r, rmsd
      REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :)        :: r0
      REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: drmsd
      REAL(kind=dp), DIMENSION(:), POINTER               :: weights
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      NULLIFY (my_particles, particles_i, weights)
      CPASSERT(colvar%type_id == rmsd_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      natom = SIZE(my_particles)
      nframes = colvar%rmsd_param%nr_frames
      ALLOCATE (drmsd(3, natom, nframes))
      drmsd = 0.0_dp

      ALLOCATE (r0(3*natom, nframes))
      ALLOCATE (rmsd(nframes))
      ALLOCATE (der(nframes))
      ALLOCATE (r(3*natom))

      weights => colvar%rmsd_param%weights
      DO i = 1, natom
         ii = (i-1)*3
         r(ii+1) = my_particles(i)%r(1)
         r(ii+2) = my_particles(i)%r(2)
         r(ii+3) = my_particles(i)%r(3)
      END DO
      r0(:, :) = colvar%rmsd_param%r_ref
      rmsd = 0.0_dp

      CALL rmsd3(my_particles, r, r0(:, 1), output_unit=-1, weights=weights, my_val=rmsd(1), rotate=.FALSE., drmsd3=drmsd(:, :, 1))

      IF (nframes == 2) THEN
         CALL rmsd3(my_particles, r, r0(:, 2), output_unit=-1, weights=weights, &
                    my_val=rmsd(2), rotate=.FALSE., drmsd3=drmsd(:, :, 2))

         f1 = 1.0_dp/(rmsd(1)+rmsd(2))
         ! (rmsdA-rmsdB)/(rmsdA+rmsdB)
         cv_val = (rmsd(1)-rmsd(2))*f1
         ! (rmsdA+rmsdB)^-1-(rmsdA-rmsdB)/(rmsdA+rmsdB)^2
         der(1) = f1-cv_val*f1
         ! -(rmsdA+rmsdB)^-1-(rmsdA-rmsdB)/(rmsdA+rmsdB)^2
         der(2) = -f1-cv_val*f1

         DO i = 1, colvar%rmsd_param%n_atoms
            ii = colvar%rmsd_param%i_rmsd(i)
            IF (weights(ii) > 0.0_dp) THEN
               ftmp(1) = der(1)*drmsd(1, ii, 1)+der(2)*drmsd(1, ii, 2)
               ftmp(2) = der(1)*drmsd(2, ii, 1)+der(2)*drmsd(2, ii, 2)
               ftmp(3) = der(1)*drmsd(3, ii, 1)+der(2)*drmsd(3, ii, 2)
               CALL put_derivative(colvar, i, ftmp)
            END IF
         END DO
      ELSE IF (nframes == 1) THEN
         ! Protect in case of numerical issues (for two identical frames!)
         rmsd(1) = ABS(rmsd(1))
         cv_val = SQRT(rmsd(1))
         f1 = 0.0_dp
         IF (cv_val /= 0.0_dp) f1 = 0.5_dp/cv_val
         DO i = 1, colvar%rmsd_param%n_atoms
            ii = colvar%rmsd_param%i_rmsd(i)
            IF (weights(ii) > 0.0_dp) THEN
               ftmp(1) = f1*drmsd(1, ii, 1)
               ftmp(2) = f1*drmsd(2, ii, 1)
               ftmp(3) = f1*drmsd(3, ii, 1)
               CALL put_derivative(colvar, i, ftmp)
            END IF
         END DO
      ELSE
         CPABORT("RMSD implemented only for 1 and 2 reference frames!")
      END IF
      colvar%ss = cv_val

      DEALLOCATE (der)
      DEALLOCATE (r0)
      DEALLOCATE (r)
      DEALLOCATE (drmsd)
      DEALLOCATE (rmsd)

   END SUBROUTINE rmsd_colvar_low

! **************************************************************************************************
!> \brief evaluates the force from ring puckering collective variables
!>   Cramer and Pople, JACS 97 1354 (1975)
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \date 08.2012
!> \author JGH
! **************************************************************************************************
   SUBROUTINE ring_puckering_colvar(colvar, cell, subsys, particles)
      TYPE(colvar_type), POINTER                         :: colvar
      TYPE(cell_type), POINTER                           :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particles

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

      INTEGER                                            :: i, ii, j, jj, m, nring
      REAL(KIND=dp)                                      :: a, at, b, da, db, ds, kr, rpxpp, svar
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cosj, sinj, z
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: r
      REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: nforce, zforce
      REAL(KIND=dp), DIMENSION(3)                        :: ftmp, nv, r0, rp, rpp, uv
      REAL(KIND=dp), DIMENSION(3, 3)                     :: dnvp, dnvpp
      TYPE(particle_list_type), POINTER                  :: particles_i
      TYPE(particle_type), DIMENSION(:), POINTER         :: my_particles

      CPASSERT(colvar%type_id == ring_puckering_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF

      nring = colvar%ring_puckering_param%nring
      ALLOCATE (r(3, nring), z(nring), cosj(nring), sinj(nring))
      ALLOCATE (nforce(3, 3, nring), zforce(nring, nring, 3))
      DO ii = 1, nring
         i = colvar%ring_puckering_param%atoms(ii)
         CALL get_coordinates(colvar, i, r(:, ii), my_particles)
      END DO
      ! get all atoms within PBC distance of atom 1
      r0(:) = r(:, 1)
      DO ii = 1, nring
         r(:, ii) = pbc(r(:, ii), r0, cell)
      END DO
      !compute origin position
      r0 = 0.0_dp
      DO ii = 1, nring
         r0(:) = r0(:)+r(:, ii)
      END DO
      kr = 1._dp/REAL(nring, KIND=dp)
      r0(:) = r0(:)*kr
      DO ii = 1, nring
         r(:, ii) = r(:, ii)-r0(:)
      END DO
      ! orientation vectors
      rp = 0._dp
      rpp = 0._dp
      DO ii = 1, nring
         cosj(ii) = COS(twopi*(ii-1)*kr)
         sinj(ii) = SIN(twopi*(ii-1)*kr)
         rp(:) = rp(:)+r(:, ii)*sinj(ii)
         rpp(:) = rpp(:)+r(:, ii)*cosj(ii)
      END DO
      nv = vector_product(rp, rpp)
      nv = nv/SQRT(SUM(nv**2))

      ! derivatives of normal
      uv = vector_product(rp, rpp)
      rpxpp = SQRT(SUM(uv**2))
      DO i = 1, 3
         uv = 0._dp
         uv(i) = 1._dp
         uv = vector_product(uv, rpp)/rpxpp
         dnvp(:, i) = uv-nv*SUM(uv*nv)
         uv = 0._dp
         uv(i) = 1._dp
         uv = vector_product(rp, uv)/rpxpp
         dnvpp(:, i) = uv-nv*SUM(uv*nv)
      END DO
      DO ii = 1, nring
         nforce(:, :, ii) = dnvp(:, :)*sinj(ii)+dnvpp(:, :)*cosj(ii)
      END DO

      ! molecular z-coordinate
      DO ii = 1, nring
         z(ii) = SUM(r(:, ii)*nv(:))
      END DO
      ! z-force
      DO ii = 1, nring
         DO jj = 1, nring
            IF (ii == jj) THEN
               zforce(ii, jj, :) = nv
            ELSE
               zforce(ii, jj, :) = 0._dp
            END IF
            DO i = 1, 3
               DO j = 1, 3
                  zforce(ii, jj, i) = zforce(ii, jj, i)+r(j, ii)*nforce(j, i, jj)
               END DO
            END DO
         END DO
      END DO

      IF (colvar%ring_puckering_param%iq == 0) THEN
         ! total puckering amplitude
         svar = SQRT(SUM(z**2))
         DO ii = 1, nring
            ftmp = 0._dp
            DO jj = 1, nring
               ftmp(:) = ftmp(:)+zforce(jj, ii, :)*z(jj)
            END DO
            ftmp = ftmp/svar
            CALL put_derivative(colvar, ii, ftmp)
         END DO
      ELSE
         m = ABS(colvar%ring_puckering_param%iq)
         CPASSERT(m /= 1)
         IF (MOD(nring, 2) == 0 .AND. colvar%ring_puckering_param%iq == nring/2) THEN
            ! single puckering amplitude
            svar = 0._dp
            DO ii = 1, nring
               IF (MOD(ii, 2) == 0) THEN
                  svar = svar-z(ii)
               ELSE
                  svar = svar+z(ii)
               END IF
            END DO
            svar = svar*SQRT(kr)
            DO ii = 1, nring
               ftmp = 0._dp
               DO jj = 1, nring
                  IF (MOD(jj, 2) == 0) THEN
                     ftmp(:) = ftmp(:)-zforce(jj, ii, :)*SQRT(kr)
                  ELSE
                     ftmp(:) = ftmp(:)+zforce(jj, ii, :)*SQRT(kr)
                  END IF
               END DO
               CALL put_derivative(colvar, ii, -ftmp)
            END DO
         ELSE
            CPASSERT(m <= (nring-1)/2)
            a = 0._dp
            b = 0._dp
            DO ii = 1, nring
               a = a+z(ii)*COS(twopi*m*(ii-1)*kr)
               b = b-z(ii)*SIN(twopi*m*(ii-1)*kr)
            END DO
            a = a*SQRT(2._dp*kr)
            b = b*SQRT(2._dp*kr)
            IF (colvar%ring_puckering_param%iq > 0) THEN
               ! puckering amplitude
               svar = SQRT(a*a+b*b)
               da = a/svar
               db = b/svar
            ELSE
               ! puckering phase angle
               at = ATAN2(a, b)
               IF (at > pi/2._dp) THEN
                  svar = 2.5_dp*pi-at
               ELSE
                  svar = 0.5_dp*pi-at
               END IF
               da = -b/(a*a+b*b)
               db = a/(a*a+b*b)
            END IF
            DO jj = 1, nring
               ftmp = 0._dp
               DO ii = 1, nring
                  ds = da*COS(twopi*m*(ii-1)*kr)
                  ds = ds-db*SIN(twopi*m*(ii-1)*kr)
                  ftmp(:) = ftmp(:)+ds*SQRT(2._dp*kr)*zforce(ii, jj, :)
               END DO
               CALL put_derivative(colvar, jj, ftmp)
            END DO
         END IF
      END IF

      colvar%ss = svar

      DEALLOCATE (r, z, cosj, sinj, nforce, zforce)

   END SUBROUTINE ring_puckering_colvar

! **************************************************************************************************
!> \brief used to print reaction_path function values on an arbitrary dimensional grid
!> \param iw1 ...
!> \param ncol ...
!> \param f_vals ...
!> \param v_count ...
!> \param gp ...
!> \param grid_sp ...
!> \param step_size ...
!> \param istart ...
!> \param iend ...
!> \param s1v ...
!> \param s1 ...
!> \param p_bounds ...
!> \param lambda ...
!> \param ifunc ...
!> \param nconf ...
!> \return ...
!> \author fschiff
! **************************************************************************************************
   RECURSIVE FUNCTION rec_eval_grid(iw1, ncol, f_vals, v_count, &
                                    gp, grid_sp, step_size, istart, iend, s1v, s1, p_bounds, lambda, ifunc, nconf) RESULT(k)
      INTEGER                                            :: iw1, ncol
      REAL(dp), DIMENSION(:, :), POINTER                 :: f_vals
      INTEGER                                            :: v_count
      REAL(dp), DIMENSION(:), POINTER                    :: gp, grid_sp
      REAL(dp)                                           :: step_size
      INTEGER                                            :: istart, iend
      REAL(dp), DIMENSION(:, :), POINTER                 :: s1v
      REAL(dp), DIMENSION(:), POINTER                    :: s1
      INTEGER, DIMENSION(:, :), POINTER                  :: p_bounds
      REAL(dp)                                           :: lambda
      INTEGER                                            :: ifunc, nconf, k

      INTEGER                                            :: count1, i

      k = 1
      IF (v_count .LT. ncol) THEN
         count1 = v_count+1
         DO i = p_bounds(1, count1), p_bounds(2, count1)
            gp(count1) = REAL(i, KIND=dp)*grid_sp(count1)
            k = rec_eval_grid(iw1, ncol, f_vals, count1, gp, grid_sp, step_size, &
                              istart, iend, s1v, s1, p_bounds, lambda, ifunc, nconf)
         END DO
      ELSE IF (v_count == ncol .AND. ifunc == 1) THEN
         DO i = istart, iend
            s1v(1, i) = REAL(i, kind=dp)*step_size*EXP(-lambda*DOT_PRODUCT(gp(:)-f_vals(:, i), &
                                                                           gp(:)-f_vals(:, i)))
            s1v(2, i) = EXP(-lambda*DOT_PRODUCT(gp(:)-f_vals(:, i), gp(:)-f_vals(:, i)))
         END DO
         DO i = 1, 2
            s1(i) = accurate_sum(s1v(i, :))
         END DO
         WRITE (iw1, '(5F10.5)') gp(:), s1(1)/s1(2)/REAL(nconf-1, dp)
      ELSE IF (v_count == ncol .AND. ifunc == 2) THEN
         DO i = istart, iend
            s1v(1, i) = EXP(-lambda*DOT_PRODUCT(gp(:)-f_vals(:, i), gp(:)-f_vals(:, i)))
         END DO
         s1(1) = accurate_sum(s1v(1, :))

         WRITE (iw1, '(5F10.5)') gp(:), -lambda*LOG(s1(1))
      END IF
   END FUNCTION rec_eval_grid

! **************************************************************************************************
!> \brief  Reads the coordinates of reference configurations given in input
!>         either as xyz files or in &COORD section
!> \param frame_section ...
!> \param para_env ...
!> \param nr_frames ...
!> \param r_ref ...
!> \param n_atoms ...
!> \date 01.2010
!> \author MI
! **************************************************************************************************
   SUBROUTINE read_frames(frame_section, para_env, nr_frames, r_ref, n_atoms)

      TYPE(section_vals_type), POINTER                   :: frame_section
      TYPE(cp_para_env_type), POINTER                    :: para_env
      INTEGER, INTENT(IN)                                :: nr_frames
      REAL(dp), DIMENSION(:, :), POINTER                 :: r_ref
      INTEGER, INTENT(OUT)                               :: n_atoms

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

      CHARACTER(LEN=default_path_length)                 :: filename
      CHARACTER(LEN=default_string_length)               :: dummy_char
      INTEGER                                            :: i, j, natom
      LOGICAL                                            :: explicit, my_end
      REAL(KIND=dp), DIMENSION(:), POINTER               :: rptr
      TYPE(cp_parser_type), POINTER                      :: parser
      TYPE(section_vals_type), POINTER                   :: coord_section

      NULLIFY (rptr)

      DO i = 1, nr_frames
         coord_section => section_vals_get_subs_vals(frame_section, "COORD", i_rep_section=i)
         CALL section_vals_get(coord_section, explicit=explicit)
         ! Cartesian Coordinates
         IF (explicit) THEN
            CALL section_vals_val_get(coord_section, "_DEFAULT_KEYWORD_", &
                                      n_rep_val=natom)
            IF (i == 1) THEN
               ALLOCATE (r_ref(3*natom, nr_frames))
               n_atoms = natom
            ELSE
               CPASSERT(3*natom == SIZE(r_ref, 1))
            END IF
            DO j = 1, natom
               CALL section_vals_val_get(coord_section, "_DEFAULT_KEYWORD_", &
                                         i_rep_val=j, r_vals=rptr)
               r_ref((j-1)*3+1:(j-1)*3+3, i) = rptr(1:3)
            END DO ! natom
         ELSE
            CALL section_vals_val_get(frame_section, "COORD_FILE_NAME", i_rep_section=i, c_val=filename)
            CPASSERT(TRIM(filename) /= "")
            NULLIFY (parser)
            ALLOCATE (rptr(3))
            CALL parser_create(parser, filename, para_env=para_env, parse_white_lines=.TRUE.)
            CALL parser_get_next_line(parser, 1)
            ! Start parser
            CALL parser_get_object(parser, natom)
            CALL parser_get_next_line(parser, 1)
            IF (i == 1) THEN
               ALLOCATE (r_ref(3*natom, nr_frames))
               n_atoms = natom
            ELSE
               CPASSERT(3*natom == SIZE(r_ref, 1))
            END IF
            DO j = 1, natom
               ! Atom coordinates
               CALL parser_get_next_line(parser, 1, at_end=my_end)
               IF (my_end) &
                  CALL cp_abort(__LOCATION__, &
                                "Number of lines in XYZ format not equal to the number of atoms."// &
                                " Error in XYZ format for COORD_A (CV rmsd). Very probably the"// &
                                " line with title is missing or is empty. Please check the XYZ file and rerun your job!")
               READ (parser%input_line, *) dummy_char, rptr(1:3)
               r_ref((j-1)*3+1, i) = cp_unit_to_cp2k(rptr(1), "angstrom")
               r_ref((j-1)*3+2, i) = cp_unit_to_cp2k(rptr(2), "angstrom")
               r_ref((j-1)*3+3, i) = cp_unit_to_cp2k(rptr(3), "angstrom")
            END DO ! natom
            CALL parser_release(parser)
            DEALLOCATE (rptr)
         END IF
      END DO ! nr_frames

   END SUBROUTINE read_frames

! **************************************************************************************************
!> \brief evaluates the collective variable associated with a hydrogen bond
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \param qs_env should be removed
!> \author alin m elena
! **************************************************************************************************
   SUBROUTINE Wc_colvar(colvar, cell, subsys, particles, qs_env)
      TYPE(colvar_type), POINTER               :: colvar
      TYPE(cell_type), POINTER                 :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER  :: subsys
      TYPE(particle_type), DIMENSION(:), &
         OPTIONAL, POINTER                      :: particles
      TYPE(qs_environment_type), POINTER, OPTIONAL       :: qs_env

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

      INTEGER                                  :: Od, H, Oa
      REAL(dp)                                 :: rOd(3), rOa(3), rH(3), &
                                                  x, y, s(3), xv(3), dmin, amin
      INTEGER                                  :: idmin, iamin, i, j
      TYPE(particle_list_type), POINTER        :: particles_i
      TYPE(particle_type), DIMENSION(:), &
         POINTER                                :: my_particles
      TYPE(wannier_centres_type), DIMENSION(:), POINTER :: wc
      INTEGER, ALLOCATABLE                     :: wcai(:), wcdi(:)
      INTEGER                                  :: nwca, nwcd
      REAL(dp)                                 :: rcut

      NULLIFY (particles_i, wc)

      CPASSERT(colvar%type_id == Wc_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      CALL get_qs_env(qs_env, WannierCentres=wc)
      rcut = colvar%Wc%rcut ! distances are in bohr as far as I remember
      Od = colvar%Wc%ids(1)
      H = colvar%Wc%ids(2)
      Oa = colvar%Wc%ids(3)
      CALL get_coordinates(colvar, Od, rOd, my_particles)
      CALL get_coordinates(colvar, H, rH, my_particles)
      CALL get_coordinates(colvar, Oa, rOa, my_particles)
      ALLOCATE (wcai(SIZE(wc(1)%WannierHamDiag)))
      ALLOCATE (wcdi(SIZE(wc(1)%WannierHamDiag)))
      nwca = 0
      nwcd = 0
      DO j = 1, SIZE(wc(1)%WannierHamDiag)
         x = distance(rOd-wc(1)%centres(:, j))
         y = distance(rOa-wc(1)%centres(:, j))
         IF (x < rcut) THEN
            nwcd = nwcd+1
            wcdi(nwcd) = j
            CYCLE
         ENDIF
         IF (y < rcut) THEN
            nwca = nwca+1
            wcai(nwca) = j
         ENDIF
      ENDDO

      dmin = distance(rH-wc(1)%centres(:, wcdi(1)))
      amin = distance(rH-wc(1)%centres(:, wcai(1)))
      idmin = wcdi(1)
      iamin = wcai(1)
      !dmin constains the smallest numer, amin the next smallest
      DO i = 2, nwcd
         x = distance(rH-wc(1)%centres(:, wcdi(i)))
         IF (x < dmin) THEN
            dmin = x
            idmin = wcdi(i)
         ENDIF
      ENDDO
      DO i = 2, nwca
         x = distance(rH-wc(1)%centres(:, wcai(i)))
         IF (x < amin) THEN
            amin = x
            iamin = wcai(i)
         ENDIF
      ENDDO
!     zero=0.0_dp
!     CALL put_derivative(colvar, 1, zero)
!     CALL put_derivative(colvar, 2,zero)
!     CALL put_derivative(colvar, 3, zero)

!     write(*,'(2(i0,1x),4(f16.8,1x))')idmin,iamin,wc(1)%WannierHamDiag(idmin),wc(1)%WannierHamDiag(iamin),dmin,amin
      colvar%ss = wc(1)%WannierHamDiag(idmin)-wc(1)%WannierHamDiag(iamin)
      DEALLOCATE (wcai)
      DEALLOCATE (wcdi)

   CONTAINS
! **************************************************************************************************
!> \brief ...
!> \param rij ...
!> \return ...
! **************************************************************************************************
      REAL(dp) FUNCTION distance(rij)
      REAL(dp), INTENT(in)                               :: rij(3)

         s = MATMUL(cell%h_inv, rij)
         s = s-NINT(s)
         xv = MATMUL(cell%hmat, s)
         distance = SQRT(DOT_PRODUCT(xv, xv))
      END FUNCTION distance

   END SUBROUTINE Wc_colvar

! **************************************************************************************************
!> \brief evaluates the collective variable associated with a hydrogen bond wire
!> \param colvar ...
!> \param cell ...
!> \param subsys ...
!> \param particles ...
!> \param qs_env ...
!> \author alin m elena
! **************************************************************************************************
   SUBROUTINE HBP_colvar(colvar, cell, subsys, particles, qs_env)
      TYPE(colvar_type), POINTER               :: colvar
      TYPE(cell_type), POINTER                 :: cell
      TYPE(cp_subsys_type), OPTIONAL, POINTER  :: subsys
      TYPE(particle_type), DIMENSION(:), &
         OPTIONAL, POINTER                      :: particles
      TYPE(qs_environment_type), POINTER, OPTIONAL       :: qs_env ! optional just because I am lazy... but I should get rid of it...

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

      INTEGER                                  :: Od, H, Oa
      REAL(dp)                                 :: rOd(3), rOa(3), rH(3), &
                                                  x, y, s(3), xv(3), dmin, amin
      INTEGER                                  :: idmin, iamin, i, j, il, output_unit
      TYPE(particle_list_type), POINTER        :: particles_i
      TYPE(particle_type), DIMENSION(:), &
         POINTER                                :: my_particles
      TYPE(wannier_centres_type), &
         DIMENSION(:), POINTER :: wc
      INTEGER, ALLOCATABLE                     :: wcai(:), wcdi(:)
      INTEGER                                  :: nwca, nwcd
      REAL(dp)                                 :: rcut

      NULLIFY (particles_i, wc)
      output_unit = cp_logger_get_default_io_unit()

      CPASSERT(colvar%type_id == HBP_colvar_id)
      IF (PRESENT(particles)) THEN
         my_particles => particles
      ELSE
         CPASSERT(PRESENT(subsys))
         CALL cp_subsys_get(subsys, particles=particles_i)
         my_particles => particles_i%els
      END IF
      CALL get_qs_env(qs_env, WannierCentres=wc)
      rcut = colvar%HBP%rcut ! distances are in bohr as far as I remember
      ALLOCATE (wcai(SIZE(wc(1)%WannierHamDiag)))
      ALLOCATE (wcdi(SIZE(wc(1)%WannierHamDiag)))
      colvar%ss = 0.0_dp
      DO il = 1, colvar%HBP%nPoints
         Od = colvar%HBP%ids(il, 1)
         H = colvar%HBP%ids(il, 2)
         Oa = colvar%HBP%ids(il, 3)
         CALL get_coordinates(colvar, Od, rOd, my_particles)
         CALL get_coordinates(colvar, H, rH, my_particles)
         CALL get_coordinates(colvar, Oa, rOa, my_particles)
         nwca = 0
         nwcd = 0
         DO j = 1, SIZE(wc(1)%WannierHamDiag)
            x = distance(rOd-wc(1)%centres(:, j))
            y = distance(rOa-wc(1)%centres(:, j))
            IF (x < rcut) THEN
               nwcd = nwcd+1
               wcdi(nwcd) = j
               CYCLE
            ENDIF
            IF (y < rcut) THEN
               nwca = nwca+1
               wcai(nwca) = j
            ENDIF
         ENDDO

         dmin = distance(rH-wc(1)%centres(:, wcdi(1)))
         amin = distance(rH-wc(1)%centres(:, wcai(1)))
         idmin = wcdi(1)
         iamin = wcai(1)
         !dmin constains the smallest numer, amin the next smallest
         DO i = 2, nwcd
            x = distance(rH-wc(1)%centres(:, wcdi(i)))
            IF (x < dmin) THEN
               dmin = x
               idmin = wcdi(i)
            ENDIF
         ENDDO
         DO i = 2, nwca
            x = distance(rH-wc(1)%centres(:, wcai(i)))
            IF (x < amin) THEN
               amin = x
               iamin = wcai(i)
            ENDIF
         ENDDO
         colvar%HBP%ewc(il) = colvar%HBP%shift+wc(1)%WannierHamDiag(idmin)-wc(1)%WannierHamDiag(iamin)
         colvar%ss = colvar%ss+colvar%HBP%shift+wc(1)%WannierHamDiag(idmin)-wc(1)%WannierHamDiag(iamin)
      ENDDO
      IF (output_unit > 0) THEN
         DO il = 1, colvar%HBP%nPoints
            WRITE (output_unit, '(a,1(f16.8,1x))') "HBP| = ", colvar%HBP%ewc(il)
         ENDDO
         WRITE (output_unit, '(a,1(f16.8,1x))') "HBP|\theta(x) = ", colvar%ss
      ENDIF
      DEALLOCATE (wcai)
      DEALLOCATE (wcdi)

   CONTAINS
! **************************************************************************************************
!> \brief ...
!> \param rij ...
!> \return ...
! **************************************************************************************************
      REAL(dp) FUNCTION distance(rij)
      REAL(dp), INTENT(in)                               :: rij(3)

         s = MATMUL(cell%h_inv, rij)
         s = s-NINT(s)
         xv = MATMUL(cell%hmat, s)
         distance = SQRT(DOT_PRODUCT(xv, xv))
      END FUNCTION distance

   END SUBROUTINE HBP_colvar

END MODULE colvar_methods
