!--------------------------------------------------------------------------------------------------!
!   CP2K: A general program to perform molecular dynamics simulations                              !
!   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
!                                                                                                  !
!   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
!--------------------------------------------------------------------------------------------------!

! **************************************************************************************************
!> \brief Define all structures types related to force_fields
!> \par History
!>      10.2008 Teodoro Laino [tlaino] - University of Zurich
!>      added native support for AMBER forcefield
!>      10.2014 Moved kind types into force_field_kind_types.F [Ole Schuett]
!> \author MK (29.08.2003)
! **************************************************************************************************
MODULE force_field_types

   USE damping_dipole_types,            ONLY: damping_info_type
   USE force_field_kind_types,          ONLY: legendre_data_type
   USE kinds,                           ONLY: default_path_length,&
                                              default_string_length,&
                                              dp
   USE pair_potential_types,            ONLY: pair_potential_p_release,&
                                              pair_potential_p_type
   USE shell_potential_types,           ONLY: shell_p_release,&
                                              shell_p_type
#include "./base/base_uses.f90"

   IMPLICIT NONE

   PRIVATE

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

! *** Define the derived structure types ***

! **************************************************************************************************
   TYPE input_info_type
      CHARACTER(LEN=default_string_length), POINTER :: charge_atm(:) => NULL()
      REAL(KIND=dp), POINTER                         :: charge(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: apol_atm(:) => NULL()
      REAL(KIND=dp), POINTER                         :: apol(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: cpol_atm(:) => NULL()
      REAL(KIND=dp), POINTER                         :: cpol(:) => NULL()
      INTEGER, POINTER                               :: bond_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bond_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bond_b(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_k(:, :) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_r0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_cs(:) => NULL()
      INTEGER, POINTER                               :: bend_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_c(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_theta0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_cb(:) => NULL()
      REAL(KIND=dp), POINTER, DIMENSION(:)           :: bend_r012 => NULL(), &
                                                        bend_r032 => NULL(), &
                                                        bend_kbs12 => NULL(), &
                                                        bend_kbs32 => NULL(), &
                                                        bend_kss => NULL()
      TYPE(legendre_data_type), POINTER, DIMENSION(:):: bend_legendre => NULL()
      INTEGER, POINTER                               :: ub_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_c(:) => NULL()
      REAL(KIND=dp), POINTER                         :: ub_k(:, :) => NULL()
      REAL(KIND=dp), POINTER                         :: ub_r0(:) => NULL()
      INTEGER, POINTER                               :: torsion_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_k(:) => NULL()
      INTEGER, POINTER                               :: torsion_m(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_phi0(:) => NULL()
      INTEGER, POINTER                               :: impr_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_phi0(:) => NULL()
      INTEGER, POINTER                               :: opbend_kind(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: opbend_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: opbend_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: opbend_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: opbend_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: opbend_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: opbend_phi0(:) => NULL()
      TYPE(pair_potential_p_type), POINTER          :: nonbonded => NULL()
      TYPE(pair_potential_p_type), POINTER          :: nonbonded14 => NULL()
      TYPE(shell_p_type), DIMENSION(:), POINTER     :: shell_list => NULL()
      TYPE(damping_info_type), DIMENSION(:), POINTER :: damping_list => NULL()
   END TYPE input_info_type

! **************************************************************************************************
   TYPE charmm_info_type
      CHARACTER(LEN=default_string_length), POINTER :: bond_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bond_b(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_r0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_c(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_theta0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: ub_c(:) => NULL()
      REAL(KIND=dp), POINTER                         :: ub_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: ub_r0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_k(:) => NULL()
      INTEGER, POINTER                               :: torsion_m(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_phi0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: impr_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_phi0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: nonbond_a(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_eps(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_rmin2(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: nonbond_a_14(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_eps_14(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_rmin2_14(:) => NULL()
   END TYPE charmm_info_type

! **************************************************************************************************
   TYPE amber_info_type
      CHARACTER(LEN=default_string_length), POINTER :: bond_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bond_b(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_r0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: bend_c(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_theta0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_a(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_b(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_c(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: torsion_d(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_k(:) => NULL()
      INTEGER, POINTER                               :: torsion_m(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_phi0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: nonbond_a(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_eps(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_rmin2(:) => NULL()
      INTEGER, POINTER                               :: raw_torsion_id(:, :) => NULL()
      REAL(KIND=dp), POINTER                         :: raw_torsion_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: raw_torsion_m(:) => NULL()
      REAL(KIND=dp), POINTER                         :: raw_torsion_phi0(:) => NULL()
   END TYPE amber_info_type

! **************************************************************************************************
   TYPE gromos_info_type
      INTEGER                                        :: ff_gromos_type = -1
      REAL(KIND=dp), POINTER                         :: solvent_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: solvent_r0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bond_r0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: bend_theta0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_k(:) => NULL()
      INTEGER, POINTER                               :: torsion_m(:) => NULL()
      REAL(KIND=dp), POINTER                         :: torsion_phi0(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_k(:) => NULL()
      REAL(KIND=dp), POINTER                         :: impr_phi0(:) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: nonbond_a(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_c6(:, :) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_c12(:, :) => NULL()
      CHARACTER(LEN=default_string_length), POINTER :: nonbond_a_14(:) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_c6_14(:, :) => NULL()
      REAL(KIND=dp), POINTER                        :: nonbond_c12_14(:, :) => NULL()
   END TYPE gromos_info_type

! **************************************************************************************************
   TYPE force_field_type
      LOGICAL                                   :: shift_cutoff = .FALSE., &
                                                   do_nonbonded = .FALSE., &
                                                   do_electrostatics = .FALSE., &
                                                   electrostatics = .FALSE., &
                                                   multiple_potential = .FALSE., &
                                                   ignore_missing_critical = .FALSE.
      INTEGER                                   :: ff_type = -1
      REAL(KIND=dp)                             :: rcut_nb = 0.0_dp
      REAL(KIND=dp)                             :: ei_scale14 = 0.0_dp
      REAL(KIND=dp)                             :: vdw_scale14 = 0.0_dp
      REAL(KIND=dp)                             :: eps_spline = 0.0_dp, &
                                                   max_energy = 0.0_dp, &
                                                   emax_spline = 0.0_dp, &
                                                   rlow_nb = 0.0_dp
      INTEGER                                   :: npoints = -1
      CHARACTER(LEN=default_path_length)       :: ff_file_name = ""
      TYPE(input_info_type), POINTER            :: inp_info => NULL()
      TYPE(charmm_info_type), POINTER           :: chm_info => NULL()
      TYPE(gromos_info_type), POINTER           :: gro_info => NULL()
      TYPE(amber_info_type), POINTER           :: amb_info => NULL()
   END TYPE force_field_type

! *** Public subroutines ***

   PUBLIC :: init_ff_type, &
             deallocate_ff_type, &
             init_inp_info, &
             deallocate_inp_info

! *** Public data types ***

   PUBLIC :: charmm_info_type, &
             amber_info_type, &
             gromos_info_type, &
             input_info_type, &
             force_field_type

CONTAINS

! **************************************************************************************************
!> \brief 1. Just NULLIFY and zero all the stuff
!> \param ff_type ...
!> \author ikuo
! **************************************************************************************************
   SUBROUTINE init_ff_type(ff_type)
      TYPE(force_field_type), INTENT(INOUT)              :: ff_type

!-----------------------------------------------------------------------------
! 1. Initialize
!-----------------------------------------------------------------------------

      NULLIFY (ff_type%inp_info, ff_type%chm_info, ff_type%amb_info, ff_type%gro_info)
      ALLOCATE (ff_type%inp_info)
      ALLOCATE (ff_type%chm_info)
      ALLOCATE (ff_type%gro_info)
      ALLOCATE (ff_type%amb_info)

      !-----------------------------------------------------------------------------
      ! 2. Initialize and Nullify things in ff_type%inp_info
      !-----------------------------------------------------------------------------
      CALL init_inp_info(ff_type%inp_info)

      !-----------------------------------------------------------------------------
      ! 3. Initialize and Nullify things in ff_type%chm_info
      !-----------------------------------------------------------------------------
      CALL init_chm_info(ff_type%chm_info)

      !-----------------------------------------------------------------------------
      ! 4. Initialize and Nullify things in ff_type%gro_info
      !-----------------------------------------------------------------------------
      CALL init_gromos_info(ff_type%gro_info)

      !-----------------------------------------------------------------------------
      ! 5. Initialize and Nullify things in ff_type%amb_info
      !-----------------------------------------------------------------------------
      CALL init_amber_info(ff_type%amb_info)

   END SUBROUTINE init_ff_type

! **************************************************************************************************
!> \brief Specific function to initialize the gro_info
!> \param gro_info ...
!> \author ikuo
! **************************************************************************************************
   SUBROUTINE init_gromos_info(gro_info)
      TYPE(gromos_info_type), POINTER                    :: gro_info

      NULLIFY (gro_info%solvent_k)
      NULLIFY (gro_info%solvent_r0)
      NULLIFY (gro_info%bond_k)
      NULLIFY (gro_info%bond_r0)
      NULLIFY (gro_info%bend_k)
      NULLIFY (gro_info%bend_theta0)
      NULLIFY (gro_info%torsion_k)
      NULLIFY (gro_info%torsion_m)
      NULLIFY (gro_info%torsion_phi0)
      NULLIFY (gro_info%impr_k)
      NULLIFY (gro_info%impr_phi0)
      NULLIFY (gro_info%nonbond_a)
      NULLIFY (gro_info%nonbond_c6)
      NULLIFY (gro_info%nonbond_c12)
      NULLIFY (gro_info%nonbond_a_14)
      NULLIFY (gro_info%nonbond_c6_14)
      NULLIFY (gro_info%nonbond_c12_14)

   END SUBROUTINE init_gromos_info

! **************************************************************************************************
!> \brief Specific function to initialize the chm_info
!> \param chm_info ...
!> \par History
!>      none
!> \author teo
! **************************************************************************************************
   SUBROUTINE init_chm_info(chm_info)
      TYPE(charmm_info_type), POINTER                    :: chm_info

      NULLIFY (chm_info%bond_a)
      NULLIFY (chm_info%bond_b)
      NULLIFY (chm_info%bond_k)
      NULLIFY (chm_info%bond_r0)
      NULLIFY (chm_info%bend_a)
      NULLIFY (chm_info%bend_b)
      NULLIFY (chm_info%bend_c)
      NULLIFY (chm_info%bend_k)
      NULLIFY (chm_info%bend_theta0)
      NULLIFY (chm_info%ub_a)
      NULLIFY (chm_info%ub_b)
      NULLIFY (chm_info%ub_c)
      NULLIFY (chm_info%ub_k)
      NULLIFY (chm_info%ub_r0)
      NULLIFY (chm_info%torsion_a)
      NULLIFY (chm_info%torsion_b)
      NULLIFY (chm_info%torsion_c)
      NULLIFY (chm_info%torsion_d)
      NULLIFY (chm_info%torsion_k)
      NULLIFY (chm_info%torsion_m)
      NULLIFY (chm_info%torsion_phi0)
      NULLIFY (chm_info%impr_a)
      NULLIFY (chm_info%impr_b)
      NULLIFY (chm_info%impr_c)
      NULLIFY (chm_info%impr_d)
      NULLIFY (chm_info%impr_k)
      NULLIFY (chm_info%impr_phi0)
      NULLIFY (chm_info%nonbond_a)
      NULLIFY (chm_info%nonbond_eps)
      NULLIFY (chm_info%nonbond_rmin2)
      NULLIFY (chm_info%nonbond_a_14)
      NULLIFY (chm_info%nonbond_eps_14)
      NULLIFY (chm_info%nonbond_rmin2_14)

   END SUBROUTINE init_chm_info

! **************************************************************************************************
!> \brief Specific function to initialize the chm_info
!> \param amb_info ...
!> \par History
!>      none
!> \author teo
! **************************************************************************************************
   SUBROUTINE init_amber_info(amb_info)
      TYPE(amber_info_type), POINTER                     :: amb_info

      NULLIFY (amb_info%bond_a)
      NULLIFY (amb_info%bond_b)
      NULLIFY (amb_info%bond_k)
      NULLIFY (amb_info%bond_r0)
      NULLIFY (amb_info%bend_a)
      NULLIFY (amb_info%bend_b)
      NULLIFY (amb_info%bend_c)
      NULLIFY (amb_info%bend_k)
      NULLIFY (amb_info%bend_theta0)
      NULLIFY (amb_info%torsion_a)
      NULLIFY (amb_info%torsion_b)
      NULLIFY (amb_info%torsion_c)
      NULLIFY (amb_info%torsion_d)
      NULLIFY (amb_info%torsion_k)
      NULLIFY (amb_info%torsion_m)
      NULLIFY (amb_info%torsion_phi0)
      NULLIFY (amb_info%nonbond_a)
      NULLIFY (amb_info%nonbond_eps)
      NULLIFY (amb_info%nonbond_rmin2)
      NULLIFY (amb_info%raw_torsion_id)
      NULLIFY (amb_info%raw_torsion_k)
      NULLIFY (amb_info%raw_torsion_m)
      NULLIFY (amb_info%raw_torsion_phi0)

   END SUBROUTINE init_amber_info

! **************************************************************************************************
!> \brief Specific function to initialize the inp_info
!> \param inp_info ...
!> \par History
!>      none
!> \author teo
! **************************************************************************************************
   SUBROUTINE init_inp_info(inp_info)
      TYPE(input_info_type), POINTER                     :: inp_info

      NULLIFY (inp_info%charge_atm)
      NULLIFY (inp_info%charge)
      NULLIFY (inp_info%apol_atm)
      NULLIFY (inp_info%apol)
      NULLIFY (inp_info%cpol_atm)
      NULLIFY (inp_info%cpol)
      NULLIFY (inp_info%bond_kind)
      NULLIFY (inp_info%bond_a)
      NULLIFY (inp_info%bond_b)
      NULLIFY (inp_info%bond_k)
      NULLIFY (inp_info%bond_r0)
      NULLIFY (inp_info%bond_cs)
      NULLIFY (inp_info%bend_kind)
      NULLIFY (inp_info%bend_a)
      NULLIFY (inp_info%bend_b)
      NULLIFY (inp_info%bend_c)
      NULLIFY (inp_info%bend_k)
      NULLIFY (inp_info%bend_theta0)
      NULLIFY (inp_info%bend_cb)
      NULLIFY (inp_info%bend_r012)
      NULLIFY (inp_info%bend_r032)
      NULLIFY (inp_info%bend_kbs12)
      NULLIFY (inp_info%bend_kbs32)
      NULLIFY (inp_info%bend_kss)
      NULLIFY (inp_info%bend_legendre)
      NULLIFY (inp_info%ub_kind)
      NULLIFY (inp_info%ub_a)
      NULLIFY (inp_info%ub_b)
      NULLIFY (inp_info%ub_c)
      NULLIFY (inp_info%ub_k)
      NULLIFY (inp_info%ub_r0)
      NULLIFY (inp_info%torsion_kind)
      NULLIFY (inp_info%torsion_a)
      NULLIFY (inp_info%torsion_b)
      NULLIFY (inp_info%torsion_c)
      NULLIFY (inp_info%torsion_d)
      NULLIFY (inp_info%torsion_k)
      NULLIFY (inp_info%torsion_m)
      NULLIFY (inp_info%torsion_phi0)
      NULLIFY (inp_info%impr_kind)
      NULLIFY (inp_info%impr_a)
      NULLIFY (inp_info%impr_b)
      NULLIFY (inp_info%impr_c)
      NULLIFY (inp_info%impr_d)
      NULLIFY (inp_info%impr_k)
      NULLIFY (inp_info%impr_phi0)
      NULLIFY (inp_info%opbend_kind)
      NULLIFY (inp_info%opbend_a)
      NULLIFY (inp_info%opbend_b)
      NULLIFY (inp_info%opbend_c)
      NULLIFY (inp_info%opbend_d)
      NULLIFY (inp_info%opbend_k)
      NULLIFY (inp_info%opbend_phi0)
      NULLIFY (inp_info%nonbonded)
      NULLIFY (inp_info%nonbonded14)
      NULLIFY (inp_info%shell_list)
      NULLIFY (inp_info%damping_list)

   END SUBROUTINE init_inp_info

! **************************************************************************************************
!> \brief 1. Just DEALLOCATE all the stuff
!> \param ff_type ...
! **************************************************************************************************
   SUBROUTINE deallocate_ff_type(ff_type)
      TYPE(force_field_type), INTENT(INOUT)              :: ff_type

!-----------------------------------------------------------------------------
! 1. DEALLOCATE things in ff_type%inp_info
!-----------------------------------------------------------------------------

      CALL deallocate_inp_info(ff_type%inp_info)

      !-----------------------------------------------------------------------------
      ! 2. DEALLOCATE things in ff_type%chm_info
      !-----------------------------------------------------------------------------
      CALL deallocate_chm_info(ff_type%chm_info)

      !-----------------------------------------------------------------------------
      ! 3. DEALLOCATE things in ff_type%gro_info
      !-----------------------------------------------------------------------------
      CALL deallocate_gromos_info(ff_type%gro_info)

      !-----------------------------------------------------------------------------
      ! 4. DEALLOCATE things in ff_type%amb_info
      !-----------------------------------------------------------------------------
      CALL deallocate_amb_info(ff_type%amb_info)

      !-----------------------------------------------------------------------------
      ! 5. DEALLOCATE things in ff_type
      !-----------------------------------------------------------------------------
      IF (ASSOCIATED(ff_type%inp_info)) THEN
         DEALLOCATE (ff_type%inp_info)
      END IF
      IF (ASSOCIATED(ff_type%chm_info)) THEN
         DEALLOCATE (ff_type%chm_info)
      END IF
      IF (ASSOCIATED(ff_type%gro_info)) THEN
         DEALLOCATE (ff_type%gro_info)
      END IF
      IF (ASSOCIATED(ff_type%amb_info)) THEN
         DEALLOCATE (ff_type%amb_info)
      END IF

   END SUBROUTINE deallocate_ff_type

! **************************************************************************************************
!> \brief Specific function to deallocate the gro_info
!> \param gro_info ...
!> \author ikuo
! **************************************************************************************************
   SUBROUTINE deallocate_gromos_info(gro_info)
      TYPE(gromos_info_type), POINTER                    :: gro_info

      IF (ASSOCIATED(gro_info%solvent_k)) THEN
         DEALLOCATE (gro_info%solvent_k)
      END IF
      IF (ASSOCIATED(gro_info%solvent_r0)) THEN
         DEALLOCATE (gro_info%solvent_r0)
      END IF
      IF (ASSOCIATED(gro_info%bond_k)) THEN
         DEALLOCATE (gro_info%bond_k)
      END IF
      IF (ASSOCIATED(gro_info%bond_r0)) THEN
         DEALLOCATE (gro_info%bond_r0)
      END IF
      IF (ASSOCIATED(gro_info%bend_k)) THEN
         DEALLOCATE (gro_info%bend_k)
      END IF
      IF (ASSOCIATED(gro_info%bend_theta0)) THEN
         DEALLOCATE (gro_info%bend_theta0)
      END IF
      IF (ASSOCIATED(gro_info%torsion_k)) THEN
         DEALLOCATE (gro_info%torsion_k)
      END IF
      IF (ASSOCIATED(gro_info%torsion_m)) THEN
         DEALLOCATE (gro_info%torsion_m)
      END IF
      IF (ASSOCIATED(gro_info%torsion_phi0)) THEN
         DEALLOCATE (gro_info%torsion_phi0)
      END IF
      IF (ASSOCIATED(gro_info%impr_k)) THEN
         DEALLOCATE (gro_info%impr_k)
      END IF
      IF (ASSOCIATED(gro_info%impr_phi0)) THEN
         DEALLOCATE (gro_info%impr_phi0)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_a)) THEN
         DEALLOCATE (gro_info%nonbond_a)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_c6)) THEN
         DEALLOCATE (gro_info%nonbond_c6)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_c12)) THEN
         DEALLOCATE (gro_info%nonbond_c12)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_a_14)) THEN
         DEALLOCATE (gro_info%nonbond_a_14)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_c6_14)) THEN
         DEALLOCATE (gro_info%nonbond_c6_14)
      END IF
      IF (ASSOCIATED(gro_info%nonbond_c12_14)) THEN
         DEALLOCATE (gro_info%nonbond_c12_14)
      END IF

   END SUBROUTINE deallocate_gromos_info

! **************************************************************************************************
!> \brief Specific function to deallocate the chm_info
!> \param chm_info ...
!> \par History
!>      none
!> \author teo
! **************************************************************************************************
   SUBROUTINE deallocate_chm_info(chm_info)
      TYPE(charmm_info_type), POINTER                    :: chm_info

      IF (ASSOCIATED(chm_info%bond_a)) THEN
         DEALLOCATE (chm_info%bond_a)
      END IF
      IF (ASSOCIATED(chm_info%bond_b)) THEN
         DEALLOCATE (chm_info%bond_b)
      END IF
      IF (ASSOCIATED(chm_info%bond_k)) THEN
         DEALLOCATE (chm_info%bond_k)
      END IF
      IF (ASSOCIATED(chm_info%bond_r0)) THEN
         DEALLOCATE (chm_info%bond_r0)
      END IF
      IF (ASSOCIATED(chm_info%bend_a)) THEN
         DEALLOCATE (chm_info%bend_a)
      END IF
      IF (ASSOCIATED(chm_info%bend_b)) THEN
         DEALLOCATE (chm_info%bend_b)
      END IF
      IF (ASSOCIATED(chm_info%bend_c)) THEN
         DEALLOCATE (chm_info%bend_c)
      END IF
      IF (ASSOCIATED(chm_info%bend_k)) THEN
         DEALLOCATE (chm_info%bend_k)
      END IF
      IF (ASSOCIATED(chm_info%bend_theta0)) THEN
         DEALLOCATE (chm_info%bend_theta0)
      END IF
      IF (ASSOCIATED(chm_info%ub_a)) THEN
         DEALLOCATE (chm_info%ub_a)
      END IF
      IF (ASSOCIATED(chm_info%ub_b)) THEN
         DEALLOCATE (chm_info%ub_b)
      END IF
      IF (ASSOCIATED(chm_info%ub_c)) THEN
         DEALLOCATE (chm_info%ub_c)
      END IF
      IF (ASSOCIATED(chm_info%ub_k)) THEN
         DEALLOCATE (chm_info%ub_k)
      END IF
      IF (ASSOCIATED(chm_info%ub_r0)) THEN
         DEALLOCATE (chm_info%ub_r0)
      END IF
      IF (ASSOCIATED(chm_info%torsion_a)) THEN
         DEALLOCATE (chm_info%torsion_a)
      END IF
      IF (ASSOCIATED(chm_info%torsion_b)) THEN
         DEALLOCATE (chm_info%torsion_b)
      END IF
      IF (ASSOCIATED(chm_info%torsion_c)) THEN
         DEALLOCATE (chm_info%torsion_c)
      END IF
      IF (ASSOCIATED(chm_info%torsion_d)) THEN
         DEALLOCATE (chm_info%torsion_d)
      END IF
      IF (ASSOCIATED(chm_info%torsion_k)) THEN
         DEALLOCATE (chm_info%torsion_k)
      END IF
      IF (ASSOCIATED(chm_info%torsion_m)) THEN
         DEALLOCATE (chm_info%torsion_m)
      END IF
      IF (ASSOCIATED(chm_info%torsion_phi0)) THEN
         DEALLOCATE (chm_info%torsion_phi0)
      END IF
      IF (ASSOCIATED(chm_info%impr_a)) THEN
         DEALLOCATE (chm_info%impr_a)
      END IF
      IF (ASSOCIATED(chm_info%impr_b)) THEN
         DEALLOCATE (chm_info%impr_b)
      END IF
      IF (ASSOCIATED(chm_info%impr_c)) THEN
         DEALLOCATE (chm_info%impr_c)
      END IF
      IF (ASSOCIATED(chm_info%impr_d)) THEN
         DEALLOCATE (chm_info%impr_d)
      END IF
      IF (ASSOCIATED(chm_info%impr_k)) THEN
         DEALLOCATE (chm_info%impr_k)
      END IF
      IF (ASSOCIATED(chm_info%impr_phi0)) THEN
         DEALLOCATE (chm_info%impr_phi0)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_a)) THEN
         DEALLOCATE (chm_info%nonbond_a)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_eps)) THEN
         DEALLOCATE (chm_info%nonbond_eps)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_rmin2)) THEN
         DEALLOCATE (chm_info%nonbond_rmin2)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_a_14)) THEN
         DEALLOCATE (chm_info%nonbond_a_14)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_eps_14)) THEN
         DEALLOCATE (chm_info%nonbond_eps_14)
      END IF
      IF (ASSOCIATED(chm_info%nonbond_rmin2_14)) THEN
         DEALLOCATE (chm_info%nonbond_rmin2_14)
      END IF

   END SUBROUTINE deallocate_chm_info

! **************************************************************************************************
!> \brief Specific function to deallocate the chm_info
!> \param amb_info ...
!> \par History
!>      none
!> \author Teodoro Laino [tlaino] - University of Zurich 10.2008
! **************************************************************************************************
   SUBROUTINE deallocate_amb_info(amb_info)
      TYPE(amber_info_type), POINTER                     :: amb_info

      IF (ASSOCIATED(amb_info%bond_a)) THEN
         DEALLOCATE (amb_info%bond_a)
      END IF
      IF (ASSOCIATED(amb_info%bond_b)) THEN
         DEALLOCATE (amb_info%bond_b)
      END IF
      IF (ASSOCIATED(amb_info%bond_k)) THEN
         DEALLOCATE (amb_info%bond_k)
      END IF
      IF (ASSOCIATED(amb_info%bond_r0)) THEN
         DEALLOCATE (amb_info%bond_r0)
      END IF
      IF (ASSOCIATED(amb_info%bend_a)) THEN
         DEALLOCATE (amb_info%bend_a)
      END IF
      IF (ASSOCIATED(amb_info%bend_b)) THEN
         DEALLOCATE (amb_info%bend_b)
      END IF
      IF (ASSOCIATED(amb_info%bend_c)) THEN
         DEALLOCATE (amb_info%bend_c)
      END IF
      IF (ASSOCIATED(amb_info%bend_k)) THEN
         DEALLOCATE (amb_info%bend_k)
      END IF
      IF (ASSOCIATED(amb_info%bend_theta0)) THEN
         DEALLOCATE (amb_info%bend_theta0)
      END IF
      IF (ASSOCIATED(amb_info%torsion_a)) THEN
         DEALLOCATE (amb_info%torsion_a)
      END IF
      IF (ASSOCIATED(amb_info%torsion_b)) THEN
         DEALLOCATE (amb_info%torsion_b)
      END IF
      IF (ASSOCIATED(amb_info%torsion_c)) THEN
         DEALLOCATE (amb_info%torsion_c)
      END IF
      IF (ASSOCIATED(amb_info%torsion_d)) THEN
         DEALLOCATE (amb_info%torsion_d)
      END IF
      IF (ASSOCIATED(amb_info%torsion_k)) THEN
         DEALLOCATE (amb_info%torsion_k)
      END IF
      IF (ASSOCIATED(amb_info%torsion_m)) THEN
         DEALLOCATE (amb_info%torsion_m)
      END IF
      IF (ASSOCIATED(amb_info%torsion_phi0)) THEN
         DEALLOCATE (amb_info%torsion_phi0)
      END IF
      IF (ASSOCIATED(amb_info%nonbond_a)) THEN
         DEALLOCATE (amb_info%nonbond_a)
      END IF
      IF (ASSOCIATED(amb_info%nonbond_eps)) THEN
         DEALLOCATE (amb_info%nonbond_eps)
      END IF
      IF (ASSOCIATED(amb_info%nonbond_rmin2)) THEN
         DEALLOCATE (amb_info%nonbond_rmin2)
      END IF
      IF (ASSOCIATED(amb_info%raw_torsion_id)) THEN
         DEALLOCATE (amb_info%raw_torsion_id)
      END IF
      IF (ASSOCIATED(amb_info%raw_torsion_k)) THEN
         DEALLOCATE (amb_info%raw_torsion_k)
      END IF
      IF (ASSOCIATED(amb_info%raw_torsion_m)) THEN
         DEALLOCATE (amb_info%raw_torsion_m)
      END IF
      IF (ASSOCIATED(amb_info%raw_torsion_phi0)) THEN
         DEALLOCATE (amb_info%raw_torsion_phi0)
      END IF

   END SUBROUTINE deallocate_amb_info

! **************************************************************************************************
!> \brief Specific function to deallocate the inp_info
!> \param inp_info ...
!> \par History
!>      none
!> \author teo
! **************************************************************************************************
   SUBROUTINE deallocate_inp_info(inp_info)
      TYPE(input_info_type), POINTER                     :: inp_info

      INTEGER                                            :: i

      IF (ASSOCIATED(inp_info%charge_atm)) THEN
         DEALLOCATE (inp_info%charge_atm)
      END IF
      IF (ASSOCIATED(inp_info%charge)) THEN
         DEALLOCATE (inp_info%charge)
      END IF
      IF (ASSOCIATED(inp_info%apol_atm)) THEN
         DEALLOCATE (inp_info%apol_atm)
      END IF
      IF (ASSOCIATED(inp_info%apol)) THEN
         DEALLOCATE (inp_info%apol)
      END IF
      IF (ASSOCIATED(inp_info%cpol_atm)) THEN
         DEALLOCATE (inp_info%cpol_atm)
      END IF
      IF (ASSOCIATED(inp_info%cpol)) THEN
         DEALLOCATE (inp_info%cpol)
      END IF
      IF (ASSOCIATED(inp_info%bond_kind)) THEN
         DEALLOCATE (inp_info%bond_kind)
      END IF
      IF (ASSOCIATED(inp_info%bond_a)) THEN
         DEALLOCATE (inp_info%bond_a)
      END IF
      IF (ASSOCIATED(inp_info%bond_b)) THEN
         DEALLOCATE (inp_info%bond_b)
      END IF
      IF (ASSOCIATED(inp_info%bond_k)) THEN
         DEALLOCATE (inp_info%bond_k)
      END IF
      IF (ASSOCIATED(inp_info%bond_r0)) THEN
         DEALLOCATE (inp_info%bond_r0)
      END IF
      IF (ASSOCIATED(inp_info%bond_cs)) THEN
         DEALLOCATE (inp_info%bond_cs)
      END IF
      IF (ASSOCIATED(inp_info%bend_kind)) THEN
         DEALLOCATE (inp_info%bend_kind)
      END IF
      IF (ASSOCIATED(inp_info%bend_a)) THEN
         DEALLOCATE (inp_info%bend_a)
      END IF
      IF (ASSOCIATED(inp_info%bend_b)) THEN
         DEALLOCATE (inp_info%bend_b)
      END IF
      IF (ASSOCIATED(inp_info%bend_c)) THEN
         DEALLOCATE (inp_info%bend_c)
      END IF
      IF (ASSOCIATED(inp_info%bend_k)) THEN
         DEALLOCATE (inp_info%bend_k)
      END IF
      IF (ASSOCIATED(inp_info%bend_theta0)) THEN
         DEALLOCATE (inp_info%bend_theta0)
      END IF
      IF (ASSOCIATED(inp_info%bend_legendre)) THEN
         DO i = 1, SIZE(inp_info%bend_legendre)
            IF (ASSOCIATED(inp_info%bend_legendre(i)%coeffs)) THEN
               DEALLOCATE (inp_info%bend_legendre(i)%coeffs)
               NULLIFY (inp_info%bend_legendre(i)%coeffs)
            END IF
         END DO
         DEALLOCATE (inp_info%bend_legendre)
         NULLIFY (inp_info%bend_legendre)
      END IF
      IF (ASSOCIATED(inp_info%bend_cb)) THEN
         DEALLOCATE (inp_info%bend_cb)
      END IF
      IF (ASSOCIATED(inp_info%bend_r012)) THEN
         DEALLOCATE (inp_info%bend_r012)
      END IF
      IF (ASSOCIATED(inp_info%bend_r032)) THEN
         DEALLOCATE (inp_info%bend_r032)
      END IF
      IF (ASSOCIATED(inp_info%bend_kbs12)) THEN
         DEALLOCATE (inp_info%bend_kbs12)
      END IF
      IF (ASSOCIATED(inp_info%bend_kbs32)) THEN
         DEALLOCATE (inp_info%bend_kbs32)
      END IF
      IF (ASSOCIATED(inp_info%bend_kss)) THEN
         DEALLOCATE (inp_info%bend_kss)
      END IF
      IF (ASSOCIATED(inp_info%ub_kind)) THEN
         DEALLOCATE (inp_info%ub_kind)
      END IF
      IF (ASSOCIATED(inp_info%ub_a)) THEN
         DEALLOCATE (inp_info%ub_a)
      END IF
      IF (ASSOCIATED(inp_info%ub_b)) THEN
         DEALLOCATE (inp_info%ub_b)
      END IF
      IF (ASSOCIATED(inp_info%ub_c)) THEN
         DEALLOCATE (inp_info%ub_c)
      END IF
      IF (ASSOCIATED(inp_info%ub_k)) THEN
         DEALLOCATE (inp_info%ub_k)
      END IF
      IF (ASSOCIATED(inp_info%ub_r0)) THEN
         DEALLOCATE (inp_info%ub_r0)
      END IF
      IF (ASSOCIATED(inp_info%torsion_kind)) THEN
         DEALLOCATE (inp_info%torsion_kind)
      END IF
      IF (ASSOCIATED(inp_info%torsion_a)) THEN
         DEALLOCATE (inp_info%torsion_a)
      END IF
      IF (ASSOCIATED(inp_info%torsion_b)) THEN
         DEALLOCATE (inp_info%torsion_b)
      END IF
      IF (ASSOCIATED(inp_info%torsion_c)) THEN
         DEALLOCATE (inp_info%torsion_c)
      END IF
      IF (ASSOCIATED(inp_info%torsion_d)) THEN
         DEALLOCATE (inp_info%torsion_d)
      END IF
      IF (ASSOCIATED(inp_info%torsion_k)) THEN
         DEALLOCATE (inp_info%torsion_k)
      END IF
      IF (ASSOCIATED(inp_info%torsion_m)) THEN
         DEALLOCATE (inp_info%torsion_m)
      END IF
      IF (ASSOCIATED(inp_info%torsion_phi0)) THEN
         DEALLOCATE (inp_info%torsion_phi0)
      END IF
      IF (ASSOCIATED(inp_info%impr_kind)) THEN
         DEALLOCATE (inp_info%impr_kind)
      END IF
      IF (ASSOCIATED(inp_info%impr_a)) THEN
         DEALLOCATE (inp_info%impr_a)
      END IF
      IF (ASSOCIATED(inp_info%impr_b)) THEN
         DEALLOCATE (inp_info%impr_b)
      END IF
      IF (ASSOCIATED(inp_info%impr_c)) THEN
         DEALLOCATE (inp_info%impr_c)
      END IF
      IF (ASSOCIATED(inp_info%impr_d)) THEN
         DEALLOCATE (inp_info%impr_d)
      END IF
      IF (ASSOCIATED(inp_info%impr_k)) THEN
         DEALLOCATE (inp_info%impr_k)
      END IF
      IF (ASSOCIATED(inp_info%impr_phi0)) THEN
         DEALLOCATE (inp_info%impr_phi0)
      END IF
      IF (ASSOCIATED(inp_info%opbend_kind)) THEN
         DEALLOCATE (inp_info%opbend_kind)
      END IF
      IF (ASSOCIATED(inp_info%opbend_a)) THEN
         DEALLOCATE (inp_info%opbend_a)
      END IF
      IF (ASSOCIATED(inp_info%opbend_b)) THEN
         DEALLOCATE (inp_info%opbend_b)
      END IF
      IF (ASSOCIATED(inp_info%opbend_c)) THEN
         DEALLOCATE (inp_info%opbend_c)
      END IF
      IF (ASSOCIATED(inp_info%opbend_d)) THEN
         DEALLOCATE (inp_info%opbend_d)
      END IF
      IF (ASSOCIATED(inp_info%opbend_k)) THEN
         DEALLOCATE (inp_info%opbend_k)
      END IF
      IF (ASSOCIATED(inp_info%opbend_phi0)) THEN
         DEALLOCATE (inp_info%opbend_phi0)
      END IF
      IF (ASSOCIATED(inp_info%nonbonded)) THEN
         CALL pair_potential_p_release(inp_info%nonbonded)
      END IF
      IF (ASSOCIATED(inp_info%nonbonded14)) THEN
         CALL pair_potential_p_release(inp_info%nonbonded14)
      END IF
      IF (ASSOCIATED(inp_info%shell_list)) THEN
         CALL shell_p_release(inp_info%shell_list)
      END IF
      IF (ASSOCIATED(inp_info%damping_list)) THEN
         DEALLOCATE (inp_info%damping_list)
      END IF

   END SUBROUTINE deallocate_inp_info

END MODULE force_field_types
