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

! **************************************************************************************************
!> \par History
!>      11.2002 created [fawzi]
!>      10.2014 Moved many components from qs_env to here [Ole Schuett]
!>      11.2014 unified k-point and gamma-point code [Ole Schuett]
!> \author Fawzi Mohamed
! **************************************************************************************************
MODULE qs_ks_types
   USE atomic_kind_types,               ONLY: atomic_kind_type
   USE atprop_types,                    ONLY: atprop_type
   USE cell_types,                      ONLY: cell_type
   USE cp_blacs_env,                    ONLY: cp_blacs_env_release,&
                                              cp_blacs_env_type
   USE cp_control_types,                ONLY: dft_control_release,&
                                              dft_control_type
   USE cp_dbcsr_api,                    ONLY: dbcsr_distribution_release,&
                                              dbcsr_distribution_type,&
                                              dbcsr_p_type
   USE cp_dbcsr_operations,             ONLY: dbcsr_deallocate_matrix_set
   USE cp_result_types,                 ONLY: cp_result_type
   USE cp_subsys_types,                 ONLY: cp_subsys_type
   USE distribution_1d_types,           ONLY: distribution_1d_type
   USE distribution_2d_types,           ONLY: distribution_2d_release,&
                                              distribution_2d_retain,&
                                              distribution_2d_type
   USE kpoint_transitional,             ONLY: get_1d_pointer,&
                                              get_2d_pointer,&
                                              kpoint_transitional_release,&
                                              kpoint_transitional_type,&
                                              set_1d_pointer,&
                                              set_2d_pointer
   USE kpoint_types,                    ONLY: kpoint_release,&
                                              kpoint_type
   USE message_passing,                 ONLY: mp_para_env_release,&
                                              mp_para_env_type
   USE molecule_kind_types,             ONLY: molecule_kind_type
   USE molecule_types,                  ONLY: molecule_type
   USE particle_types,                  ONLY: particle_type
   USE pw_env_types,                    ONLY: pw_env_release,&
                                              pw_env_retain,&
                                              pw_env_type
   USE pw_types,                        ONLY: pw_c1d_gs_type,&
                                              pw_r3d_rs_type
   USE qs_energy_types,                 ONLY: qs_energy_type
   USE qs_force_types,                  ONLY: qs_force_type
   USE qs_kind_types,                   ONLY: qs_kind_type
   USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type,&
                                              release_neighbor_list_sets
   USE qs_rho_types,                    ONLY: qs_rho_create,&
                                              qs_rho_release,&
                                              qs_rho_type
   USE qs_subsys_types,                 ONLY: qs_subsys_get,&
                                              qs_subsys_release,&
                                              qs_subsys_type
   USE task_list_types,                 ONLY: deallocate_task_list,&
                                              task_list_type
   USE virial_types,                    ONLY: virial_type
#include "./base/base_uses.f90"

   IMPLICIT NONE
   PRIVATE

   LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ks_types'

   PUBLIC :: qs_ks_env_type, qs_ks_env_create, qs_ks_did_change
   PUBLIC :: qs_ks_release, qs_ks_part_release, get_ks_env, set_ks_env

! **************************************************************************************************
!> \brief calculation environment to calculate the ks matrix,
!>      holds all the needed vars.
!>      assumes that the core hamiltonian and energy are up to date.
!> \param s_mstruct_changed if the sparsity structure of s in qs_env where this
!>        ks_env lives has changed
!> \param rho_changed if the rho stored in the qs_env has changed
!> \param forces_up_to_date if the forces are up to date
!> \param potential_changed if some external potential changed (such as due to the constraint)
!>
!> \param matrix_h core hamiltonian (matrix_h(1)), if needed by the calculation also
!>        its derivatives wrt. x,y, and z (matrix_h(2:4))
!> \param matrix_ks Khon-Sham matrix (filtered by the structure of S).
!>        with LSD an array with the different orbitals
!> \param matrix_s the overlap matrix (matrix_s(1)), if needed by the calculation also
!>        its derivatives wrt. x,y, and z (matrix_s(2:4))
!> \param kinetic kinetic part of h
!>
!> \param rho the (old) density, in various representations (ao+grid)
!> \param rho_xc the (old) soft density, used for the GAPW_XC method only
!> \param rho_core a grid with the charges of the cores of the atoms in the
!>        reciprocal (g) space
!> \param vppl a realspace grid with the local pseudopotential
!> \param vee a realspace grid with the external electrostatic potential
!>
!> \param neighbor_list_id the current version of the neighbor_list
!> \param sab_orb ,sac_ae, sac_ppl, sac_lri, sap_ppnl:
!>        neighbor lists for the calculation of the core Hamiltonian matrix
!> \param sap_oce: neighbor lists for the calculation of the expansion
!>        coefficients of the local atomic densities rho1_hard and rho1_soft
!> \param sab_se: neighbor lists for the calculation of the 2 centers
!>        hartree term in semi-empirical methods
!> \param sac_tbe: neighbor lists for the calculation of the tight binding
!>        Ewald terms (DFTB)
!> \param sab_core neighbor lists for the calculation of the core interactions
!> \param sab_xb neighbor lists for the calculation of the XB interactions in xTB
!> \param sab_xtb_pp neighbor lists for the calculation of the repulsive interactions in xTB
!> \param sab_xtb_nonbond neighbor lists for the calculation of the nonbonded interactions in xTB
!> \param sab_all neighbor lists for the calculation of the  matrix element of
!>        non-symmetric operators
!> \param sab_vdw: neighbor lists for the calculation of dispersion interactions
!> \param sab_scp: neighbor lists for the calculation of self-consistent polarization
!> \param sab_almo: neighbor lists to create ALMO delocalization template
!> \param sab_kp: neighbor lists to create kp image cell lists
!> \param sab_kp_nosym: neighbor lists to create kp image cell lists, non-symmetric
!>
!> \param kpoints information on the kpoints used
!> \param subsys the particles, molecules,... of this environment
!> \param dft_control object that contains the values of various parameters
!>        relevant to a dft calculation
!> \param distribution_2d: distribution of the atom pairs between the processors
!>
!> \par History
!>      04.2002 created [fawzi]
!>      10.2002 introduced pools, uses updated rho as input,
!>              removed most temporary variables, renamed may vars,
!>              began conversion to LSD [fawzi]
!>      10.2014 Moved many components from qs_env here [Ole Schuett]
!> \author Fawzi Mohamed
! **************************************************************************************************
   TYPE qs_ks_env_type
      PRIVATE
      LOGICAL                                               :: s_mstruct_changed = .TRUE., &
                                                               rho_changed = .TRUE., &
                                                               potential_changed = .TRUE., &
                                                               forces_up_to_date = .FALSE., &
                                                               complex_ks = .FALSE.
      INTEGER                                               :: n_evals = 0

      ! hartree is supposed to contain the hartree potential (for cube output)
      ! ugly to keep it always around only for a cube output...
      TYPE(pw_r3d_rs_type), POINTER                         :: v_hartree_rspace => Null()

      TYPE(kpoint_transitional_type)                        :: matrix_ks, &
                                                               matrix_s, &
                                                               kinetic, &
                                                               matrix_h, &
                                                               matrix_w, &
                                                               matrix_vxc, &
                                                               matrix_s_RI_aux, &
                                                               matrix_ks_im, &
                                                               matrix_h_im

      TYPE(dbcsr_p_type), DIMENSION(:), POINTER             :: matrix_p_mp2 => Null(), &
                                                               matrix_p_mp2_admm => Null()

      TYPE(qs_rho_type), POINTER                            :: rho => Null(), &
                                                               rho_xc => Null()

      TYPE(pw_r3d_rs_type), POINTER                         :: vppl => Null(), &
                                                               rho_nlcc => Null()
      TYPE(pw_c1d_gs_type), POINTER                         :: rho_nlcc_g => Null()

      TYPE(pw_c1d_gs_type), POINTER                         :: rho_core => NULL()
      TYPE(pw_r3d_rs_type), POINTER                         :: vee => NULL()

      INTEGER                                               :: neighbor_list_id = -1
      TYPE(neighbor_list_set_p_type), DIMENSION(:), POINTER :: sab_orb => Null(), &
                                                               sac_ae => Null(), &
                                                               sac_ppl => Null(), &
                                                               sac_lri => Null(), &
                                                               sap_ppnl => Null(), &
                                                               sap_oce => Null(), &
                                                               sab_se => Null(), &
                                                               sab_vdw => Null(), &
                                                               sab_scp => Null(), &
                                                               sab_tbe => Null(), &
                                                               sab_xtbe => Null(), &
                                                               sab_core => Null(), &
                                                               sab_xb => Null(), &
                                                               sab_xtb_pp => Null(), &
                                                               sab_xtb_nonbond => Null(), &
                                                               sab_all => Null(), &
                                                               sab_lrc => Null(), &
                                                               sab_almo => Null(), &
                                                               sab_kp => Null(), &
                                                               sab_kp_nosym => Null()

      TYPE(task_list_type), POINTER                         :: task_list => Null()
      TYPE(task_list_type), POINTER                         :: task_list_soft => Null()

      TYPE(kpoint_type), POINTER                            :: kpoints => Null()
      TYPE(qs_subsys_type), POINTER                         :: subsys => Null()
      TYPE(dft_control_type), POINTER                       :: dft_control => Null()
      TYPE(dbcsr_distribution_type), POINTER                :: dbcsr_dist => Null()
      TYPE(distribution_2d_type), POINTER                   :: distribution_2d => Null()
      TYPE(pw_env_type), POINTER                            :: pw_env => Null()
      TYPE(mp_para_env_type), POINTER                       :: para_env => Null()
      TYPE(cp_blacs_env_type), POINTER                      :: blacs_env => Null()
   END TYPE qs_ks_env_type

CONTAINS

! **************************************************************************************************
!> \brief Allocates a new instance of ks_env.
!> \param ks_env ...
!> \author Ole Schuett
! **************************************************************************************************
   SUBROUTINE qs_ks_env_create(ks_env)
      TYPE(qs_ks_env_type), INTENT(OUT)                  :: ks_env

      ALLOCATE (ks_env%rho)
      CALL qs_rho_create(ks_env%rho)
      ALLOCATE (ks_env%rho_xc)
      CALL qs_rho_create(ks_env%rho_xc)
   END SUBROUTINE qs_ks_env_create

! **************************************************************************************************
!> \brief ...
!> \param ks_env ...
!> \param v_hartree_rspace ...
!> \param s_mstruct_changed ...
!> \param rho_changed ...
!> \param potential_changed ...
!> \param forces_up_to_date ...
!> \param complex_ks ...
!> \param matrix_h ...
!> \param matrix_h_im ...
!> \param matrix_ks ...
!> \param matrix_ks_im ...
!> \param matrix_vxc ...
!> \param kinetic ...
!> \param matrix_s ...
!> \param matrix_s_RI_aux ...
!> \param matrix_w ...
!> \param matrix_p_mp2 ...
!> \param matrix_p_mp2_admm ...
!> \param matrix_h_kp ...
!> \param matrix_h_im_kp ...
!> \param matrix_ks_kp ...
!> \param matrix_vxc_kp ...
!> \param kinetic_kp ...
!> \param matrix_s_kp ...
!> \param matrix_w_kp ...
!> \param matrix_s_RI_aux_kp ...
!> \param matrix_ks_im_kp ...
!> \param rho ...
!> \param rho_xc ...
!> \param vppl ...
!> \param rho_core ...
!> \param rho_nlcc ...
!> \param rho_nlcc_g ...
!> \param vee ...
!> \param neighbor_list_id ...
!> \param sab_orb ...
!> \param sab_all ...
!> \param sac_ae ...
!> \param sac_ppl ...
!> \param sac_lri ...
!> \param sap_ppnl ...
!> \param sap_oce ...
!> \param sab_lrc ...
!> \param sab_se ...
!> \param sab_xtbe ...
!> \param sab_tbe ...
!> \param sab_core ...
!> \param sab_xb ...
!> \param sab_xtb_pp ...
!> \param sab_xtb_nonbond ...
!> \param sab_vdw ...
!> \param sab_scp ...
!> \param sab_almo ...
!> \param sab_kp ...
!> \param sab_kp_nosym ...
!> \param task_list ...
!> \param task_list_soft ...
!> \param kpoints ...
!> \param do_kpoints ...
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param cell ...
!> \param cell_ref ...
!> \param use_ref_cell ...
!> \param particle_set ...
!> \param energy ...
!> \param force ...
!> \param local_particles ...
!> \param local_molecules ...
!> \param molecule_kind_set ...
!> \param molecule_set ...
!> \param subsys ...
!> \param cp_subsys ...
!> \param virial ...
!> \param results ...
!> \param atprop ...
!> \param nkind ...
!> \param natom ...
!> \param dft_control ...
!> \param dbcsr_dist ...
!> \param distribution_2d ...
!> \param pw_env ...
!> \param para_env ...
!> \param blacs_env ...
!> \param nelectron_total ...
!> \param nelectron_spin ...
! **************************************************************************************************
   SUBROUTINE get_ks_env(ks_env, v_hartree_rspace, &
                         s_mstruct_changed, rho_changed, &
                         potential_changed, forces_up_to_date, complex_ks, &
                         matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, &
                         kinetic, matrix_s, &
                         matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, &
                         matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, &
                         matrix_s_RI_aux_kp, matrix_ks_im_kp, &
                         rho, rho_xc, &
                         vppl, rho_core, rho_nlcc, rho_nlcc_g, vee, &
                         neighbor_list_id, &
                         sab_orb, sab_all, sac_ae, sac_ppl, sac_lri, sap_ppnl, sap_oce, sab_lrc, &
                         sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, &
                         sab_vdw, sab_scp, sab_almo, sab_kp, sab_kp_nosym, &
                         task_list, task_list_soft, &
                         kpoints, do_kpoints, &
                         atomic_kind_set, qs_kind_set, cell, cell_ref, use_ref_cell, &
                         particle_set, energy, force, local_particles, local_molecules, &
                         molecule_kind_set, molecule_set, subsys, cp_subsys, virial, results, atprop, &
                         nkind, natom, dft_control, dbcsr_dist, distribution_2d, pw_env, &
                         para_env, blacs_env, nelectron_total, nelectron_spin)

      TYPE(qs_ks_env_type), INTENT(IN)                   :: ks_env
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: v_hartree_rspace
      LOGICAL, OPTIONAL                                  :: s_mstruct_changed, rho_changed, &
                                                            potential_changed, forces_up_to_date, &
                                                            complex_ks
      TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, POINTER :: matrix_h, matrix_h_im, matrix_ks, &
         matrix_ks_im, matrix_vxc, kinetic, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, &
         matrix_p_mp2_admm
      TYPE(dbcsr_p_type), DIMENSION(:, :), OPTIONAL, POINTER :: matrix_h_kp, matrix_h_im_kp, &
         matrix_ks_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, &
         matrix_ks_im_kp
      TYPE(qs_rho_type), OPTIONAL, POINTER               :: rho, rho_xc
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: vppl
      TYPE(pw_c1d_gs_type), OPTIONAL, POINTER            :: rho_core
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: rho_nlcc
      TYPE(pw_c1d_gs_type), OPTIONAL, POINTER            :: rho_nlcc_g
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: vee
      INTEGER, OPTIONAL                                  :: neighbor_list_id
      TYPE(neighbor_list_set_p_type), DIMENSION(:), OPTIONAL, POINTER :: sab_orb, sab_all, sac_ae, &
         sac_ppl, sac_lri, sap_ppnl, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, &
         sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_vdw, sab_scp, sab_almo, sab_kp, sab_kp_nosym
      TYPE(task_list_type), OPTIONAL, POINTER            :: task_list, task_list_soft
      TYPE(kpoint_type), OPTIONAL, POINTER               :: kpoints
      LOGICAL, OPTIONAL                                  :: do_kpoints
      TYPE(atomic_kind_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: qs_kind_set
      TYPE(cell_type), OPTIONAL, POINTER                 :: cell, cell_ref
      LOGICAL, OPTIONAL                                  :: use_ref_cell
      TYPE(particle_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: particle_set
      TYPE(qs_energy_type), OPTIONAL, POINTER            :: energy
      TYPE(qs_force_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: force
      TYPE(distribution_1d_type), OPTIONAL, POINTER      :: local_particles, local_molecules
      TYPE(molecule_kind_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: molecule_kind_set
      TYPE(molecule_type), DIMENSION(:), OPTIONAL, &
         POINTER                                         :: molecule_set
      TYPE(qs_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(cp_subsys_type), OPTIONAL, POINTER            :: cp_subsys
      TYPE(virial_type), OPTIONAL, POINTER               :: virial
      TYPE(cp_result_type), OPTIONAL, POINTER            :: results
      TYPE(atprop_type), OPTIONAL, POINTER               :: atprop
      INTEGER, OPTIONAL                                  :: nkind, natom
      TYPE(dft_control_type), OPTIONAL, POINTER          :: dft_control
      TYPE(dbcsr_distribution_type), OPTIONAL, POINTER   :: dbcsr_dist
      TYPE(distribution_2d_type), OPTIONAL, POINTER      :: distribution_2d
      TYPE(pw_env_type), OPTIONAL, POINTER               :: pw_env
      TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
      TYPE(cp_blacs_env_type), OPTIONAL, POINTER         :: blacs_env
      INTEGER, OPTIONAL                                  :: nelectron_total
      INTEGER, DIMENSION(2), OPTIONAL                    :: nelectron_spin

      IF (.NOT. ASSOCIATED(ks_env%subsys)) CPABORT("get_ks_env: subsys not associated")

      IF (PRESENT(s_mstruct_changed)) s_mstruct_changed = ks_env%s_mstruct_changed
      IF (PRESENT(rho_changed)) rho_changed = ks_env%rho_changed
      IF (PRESENT(potential_changed)) potential_changed = ks_env%potential_changed
      IF (PRESENT(forces_up_to_date)) forces_up_to_date = ks_env%forces_up_to_date
      IF (PRESENT(complex_ks)) complex_ks = ks_env%complex_ks
      IF (PRESENT(v_hartree_rspace)) v_hartree_rspace => ks_env%v_hartree_rspace

      IF (PRESENT(matrix_ks)) matrix_ks => get_1d_pointer(ks_env%matrix_ks)
      IF (PRESENT(matrix_s)) matrix_s => get_1d_pointer(ks_env%matrix_s)
      IF (PRESENT(matrix_s_RI_aux)) matrix_s_RI_aux => get_1d_pointer(ks_env%matrix_s_RI_aux)
      IF (PRESENT(kinetic)) kinetic => get_1d_pointer(ks_env%kinetic)
      IF (PRESENT(matrix_h)) matrix_h => get_1d_pointer(ks_env%matrix_h)
      IF (PRESENT(matrix_h_im)) matrix_h_im => get_1d_pointer(ks_env%matrix_h_im)
      IF (PRESENT(matrix_w)) matrix_w => get_1d_pointer(ks_env%matrix_w)
      IF (PRESENT(matrix_vxc)) matrix_vxc => get_1d_pointer(ks_env%matrix_vxc)

      IF (PRESENT(matrix_ks_kp)) matrix_ks_kp => get_2d_pointer(ks_env%matrix_ks)
      IF (PRESENT(matrix_ks_im_kp)) matrix_ks_im_kp => get_2d_pointer(ks_env%matrix_ks_im)
      IF (PRESENT(matrix_s_kp)) matrix_s_kp => get_2d_pointer(ks_env%matrix_s)
      IF (PRESENT(matrix_s_RI_aux_kp)) matrix_s_RI_aux_kp => get_2d_pointer(ks_env%matrix_s_RI_aux)
      IF (PRESENT(matrix_w_kp)) matrix_w_kp => get_2d_pointer(ks_env%matrix_w)
      IF (PRESENT(kinetic_kp)) kinetic_kp => get_2d_pointer(ks_env%kinetic)
      IF (PRESENT(matrix_h_kp)) matrix_h_kp => get_2d_pointer(ks_env%matrix_h)
      IF (PRESENT(matrix_h_im_kp)) matrix_h_im_kp => get_2d_pointer(ks_env%matrix_h_im)
      IF (PRESENT(matrix_vxc_kp)) matrix_vxc_kp => get_2d_pointer(ks_env%matrix_vxc)
      IF (PRESENT(matrix_ks_im)) matrix_ks_im => get_1d_pointer(ks_env%matrix_ks_im)

      IF (PRESENT(matrix_p_mp2)) matrix_p_mp2 => ks_env%matrix_p_mp2
      IF (PRESENT(matrix_p_mp2_admm)) matrix_p_mp2_admm => ks_env%matrix_p_mp2_admm
      IF (PRESENT(rho)) rho => ks_env%rho
      IF (PRESENT(rho_xc)) rho_xc => ks_env%rho_xc
      IF (PRESENT(rho_core)) rho_core => ks_env%rho_core
      IF (PRESENT(rho_nlcc)) rho_nlcc => ks_env%rho_nlcc
      IF (PRESENT(rho_nlcc_g)) rho_nlcc_g => ks_env%rho_nlcc_g
      IF (PRESENT(vppl)) vppl => ks_env%vppl
      IF (PRESENT(vee)) vee => ks_env%vee

      IF (PRESENT(neighbor_list_id)) neighbor_list_id = ks_env%neighbor_list_id
      IF (PRESENT(sab_orb)) sab_orb => ks_env%sab_orb
      IF (PRESENT(sab_all)) sab_all => ks_env%sab_all
      IF (PRESENT(sab_vdw)) sab_vdw => ks_env%sab_vdw
      IF (PRESENT(sab_scp)) sab_scp => ks_env%sab_scp
      IF (PRESENT(sac_ae)) sac_ae => ks_env%sac_ae
      IF (PRESENT(sac_ppl)) sac_ppl => ks_env%sac_ppl
      IF (PRESENT(sac_lri)) sac_lri => ks_env%sac_lri
      IF (PRESENT(sap_ppnl)) sap_ppnl => ks_env%sap_ppnl
      IF (PRESENT(sap_oce)) sap_oce => ks_env%sap_oce
      IF (PRESENT(sab_se)) sab_se => ks_env%sab_se
      IF (PRESENT(sab_lrc)) sab_lrc => ks_env%sab_lrc
      IF (PRESENT(sab_tbe)) sab_tbe => ks_env%sab_tbe
      IF (PRESENT(sab_xtbe)) sab_xtbe => ks_env%sab_xtbe
      IF (PRESENT(sab_core)) sab_core => ks_env%sab_core
      IF (PRESENT(sab_xb)) sab_xb => ks_env%sab_xb
      IF (PRESENT(sab_xtb_pp)) sab_xtb_pp => ks_env%sab_xtb_pp
      IF (PRESENT(sab_xtb_nonbond)) sab_xtb_nonbond => ks_env%sab_xtb_nonbond
      IF (PRESENT(sab_almo)) sab_almo => ks_env%sab_almo
      IF (PRESENT(sab_kp)) sab_kp => ks_env%sab_kp
      IF (PRESENT(sab_kp_nosym)) sab_kp_nosym => ks_env%sab_kp_nosym
      IF (PRESENT(dft_control)) dft_control => ks_env%dft_control
      IF (PRESENT(dbcsr_dist)) dbcsr_dist => ks_env%dbcsr_dist
      IF (PRESENT(distribution_2d)) distribution_2d => ks_env%distribution_2d
      IF (PRESENT(pw_env)) pw_env => ks_env%pw_env
      IF (PRESENT(para_env)) para_env => ks_env%para_env
      IF (PRESENT(blacs_env)) blacs_env => ks_env%blacs_env

      IF (PRESENT(task_list)) task_list => ks_env%task_list
      IF (PRESENT(task_list_soft)) task_list_soft => ks_env%task_list_soft

      IF (PRESENT(kpoints)) kpoints => ks_env%kpoints
      IF (PRESENT(do_kpoints)) THEN
         do_kpoints = (ks_env%kpoints%nkp > 0)
      END IF

      IF (PRESENT(subsys)) subsys => ks_env%subsys
      CALL qs_subsys_get(ks_env%subsys, &
                         local_molecules=local_molecules, &
                         local_particles=local_particles, &
                         atprop=atprop, &
                         virial=virial, &
                         results=results, &
                         cell=cell, &
                         cell_ref=cell_ref, &
                         use_ref_cell=use_ref_cell, &
                         energy=energy, &
                         force=force, &
                         qs_kind_set=qs_kind_set, &
                         cp_subsys=cp_subsys, &
                         atomic_kind_set=atomic_kind_set, &
                         particle_set=particle_set, &
                         molecule_kind_set=molecule_kind_set, &
                         molecule_set=molecule_set, &
                         natom=natom, &
                         nkind=nkind, &
                         nelectron_total=nelectron_total, &
                         nelectron_spin=nelectron_spin)

   END SUBROUTINE get_ks_env

! **************************************************************************************************
!> \brief ...
!> \param ks_env ...
!> \param v_hartree_rspace ...
!> \param s_mstruct_changed ...
!> \param rho_changed ...
!> \param potential_changed ...
!> \param forces_up_to_date ...
!> \param complex_ks ...
!> \param matrix_h ...
!> \param matrix_h_im ...
!> \param matrix_ks ...
!> \param matrix_ks_im ...
!> \param matrix_vxc ...
!> \param kinetic ...
!> \param matrix_s ...
!> \param matrix_s_RI_aux ...
!> \param matrix_w ...
!> \param matrix_p_mp2 ...
!> \param matrix_p_mp2_admm ...
!> \param matrix_h_kp ...
!> \param matrix_h_im_kp ...
!> \param matrix_ks_kp ...
!> \param matrix_vxc_kp ...
!> \param kinetic_kp ...
!> \param matrix_s_kp ...
!> \param matrix_w_kp ...
!> \param matrix_s_RI_aux_kp ...
!> \param matrix_ks_im_kp ...
!> \param vppl ...
!> \param rho_core ...
!> \param rho_nlcc ...
!> \param rho_nlcc_g ...
!> \param vee ...
!> \param neighbor_list_id ...
!> \param kpoints ...
!> \param sab_orb ...
!> \param sab_all ...
!> \param sac_ae ...
!> \param sac_ppl ...
!> \param sac_lri ...
!> \param sap_ppnl ...
!> \param sap_oce ...
!> \param sab_lrc ...
!> \param sab_se ...
!> \param sab_xtbe ...
!> \param sab_tbe ...
!> \param sab_core ...
!> \param sab_xb ...
!> \param sab_xtb_pp ...
!> \param sab_xtb_nonbond ...
!> \param sab_vdw ...
!> \param sab_scp ...
!> \param sab_almo ...
!> \param sab_kp ...
!> \param sab_kp_nosym ...
!> \param task_list ...
!> \param task_list_soft ...
!> \param subsys ...
!> \param dft_control ...
!> \param dbcsr_dist ...
!> \param distribution_2d ...
!> \param pw_env ...
!> \param para_env ...
!> \param blacs_env ...
! **************************************************************************************************
   SUBROUTINE set_ks_env(ks_env, v_hartree_rspace, &
                         s_mstruct_changed, rho_changed, &
                         potential_changed, forces_up_to_date, complex_ks, &
                         matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, &
                         kinetic, matrix_s, &
                         matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, &
                         matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, &
                         matrix_s_RI_aux_kp, matrix_ks_im_kp, &
                         vppl, rho_core, rho_nlcc, rho_nlcc_g, vee, &
                         neighbor_list_id, &
                         kpoints, &
                         sab_orb, sab_all, sac_ae, sac_ppl, sac_lri, sap_ppnl, sap_oce, sab_lrc, &
                         sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, &
                         sab_vdw, sab_scp, sab_almo, sab_kp, sab_kp_nosym, &
                         task_list, task_list_soft, &
                         subsys, dft_control, dbcsr_dist, distribution_2d, pw_env, &
                         para_env, blacs_env)

      TYPE(qs_ks_env_type), INTENT(INOUT)                :: ks_env
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: v_hartree_rspace
      LOGICAL, OPTIONAL                                  :: s_mstruct_changed, rho_changed, &
                                                            potential_changed, forces_up_to_date, &
                                                            complex_ks
      TYPE(dbcsr_p_type), DIMENSION(:), OPTIONAL, POINTER :: matrix_h, matrix_h_im, matrix_ks, &
         matrix_ks_im, matrix_vxc, kinetic, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, &
         matrix_p_mp2_admm
      TYPE(dbcsr_p_type), DIMENSION(:, :), OPTIONAL, POINTER :: matrix_h_kp, matrix_h_im_kp, &
         matrix_ks_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, &
         matrix_ks_im_kp
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: vppl
      TYPE(pw_c1d_gs_type), OPTIONAL, POINTER            :: rho_core
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: rho_nlcc
      TYPE(pw_c1d_gs_type), OPTIONAL, POINTER            :: rho_nlcc_g
      TYPE(pw_r3d_rs_type), OPTIONAL, POINTER            :: vee
      INTEGER, OPTIONAL                                  :: neighbor_list_id
      TYPE(kpoint_type), OPTIONAL, POINTER               :: kpoints
      TYPE(neighbor_list_set_p_type), DIMENSION(:), OPTIONAL, POINTER :: sab_orb, sab_all, sac_ae, &
         sac_ppl, sac_lri, sap_ppnl, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, &
         sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_vdw, sab_scp, sab_almo, sab_kp, sab_kp_nosym
      TYPE(task_list_type), OPTIONAL, POINTER            :: task_list, task_list_soft
      TYPE(qs_subsys_type), OPTIONAL, POINTER            :: subsys
      TYPE(dft_control_type), OPTIONAL, POINTER          :: dft_control
      TYPE(dbcsr_distribution_type), OPTIONAL, POINTER   :: dbcsr_dist
      TYPE(distribution_2d_type), OPTIONAL, POINTER      :: distribution_2d
      TYPE(pw_env_type), OPTIONAL, POINTER               :: pw_env
      TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
      TYPE(cp_blacs_env_type), OPTIONAL, POINTER         :: blacs_env

      IF (PRESENT(s_mstruct_changed)) ks_env%s_mstruct_changed = s_mstruct_changed
      IF (PRESENT(rho_changed)) ks_env%rho_changed = rho_changed
      IF (PRESENT(potential_changed)) ks_env%potential_changed = potential_changed
      IF (PRESENT(forces_up_to_date)) ks_env%forces_up_to_date = forces_up_to_date
      IF (PRESENT(complex_ks)) ks_env%complex_ks = complex_ks
      IF (ks_env%s_mstruct_changed .OR. ks_env%potential_changed .OR. ks_env%rho_changed) &
         ks_env%forces_up_to_date = .FALSE.
      IF (PRESENT(v_hartree_rspace)) ks_env%v_hartree_rspace => v_hartree_rspace

      IF (PRESENT(matrix_h)) CALL set_1d_pointer(ks_env%matrix_h, matrix_h)
      IF (PRESENT(matrix_h_kp)) CALL set_2d_pointer(ks_env%matrix_h, matrix_h_kp)

      IF (PRESENT(matrix_h_im)) CALL set_1d_pointer(ks_env%matrix_h_im, matrix_h_im)
      IF (PRESENT(matrix_h_im_kp)) CALL set_2d_pointer(ks_env%matrix_h_im, matrix_h_im_kp)

      IF (PRESENT(matrix_ks)) CALL set_1d_pointer(ks_env%matrix_ks, matrix_ks)
      IF (PRESENT(matrix_ks_kp)) CALL set_2d_pointer(ks_env%matrix_ks, matrix_ks_kp)

      IF (PRESENT(matrix_vxc)) CALL set_1d_pointer(ks_env%matrix_vxc, matrix_vxc)
      IF (PRESENT(matrix_vxc_kp)) CALL set_2d_pointer(ks_env%matrix_vxc, matrix_vxc_kp)

      IF (PRESENT(matrix_s)) CALL set_1d_pointer(ks_env%matrix_s, matrix_s)
      IF (PRESENT(matrix_s_kp)) CALL set_2d_pointer(ks_env%matrix_s, matrix_s_kp)

      IF (PRESENT(kinetic)) CALL set_1d_pointer(ks_env%kinetic, kinetic)
      IF (PRESENT(kinetic_kp)) CALL set_2d_pointer(ks_env%kinetic, kinetic_kp)

      IF (PRESENT(matrix_w)) CALL set_1d_pointer(ks_env%matrix_w, matrix_w)
      IF (PRESENT(matrix_w_kp)) CALL set_2d_pointer(ks_env%matrix_w, matrix_w_kp)

      IF (PRESENT(matrix_s_RI_aux)) CALL set_1d_pointer(ks_env%matrix_s_RI_aux, matrix_s_RI_aux)
      IF (PRESENT(matrix_s_RI_aux_kp)) CALL set_2d_pointer(ks_env%matrix_s_RI_aux, matrix_s_RI_aux_kp)

      IF (PRESENT(matrix_ks_im)) CALL set_1d_pointer(ks_env%matrix_ks_im, matrix_ks_im)
      IF (PRESENT(matrix_ks_im_kp)) CALL set_2d_pointer(ks_env%matrix_ks_im, matrix_ks_im_kp)

      IF (PRESENT(matrix_p_mp2)) ks_env%matrix_p_mp2 => matrix_p_mp2
      IF (PRESENT(matrix_p_mp2_admm)) ks_env%matrix_p_mp2_admm => matrix_p_mp2_admm
      IF (PRESENT(rho_core)) ks_env%rho_core => rho_core
      IF (PRESENT(rho_nlcc)) ks_env%rho_nlcc => rho_nlcc
      IF (PRESENT(rho_nlcc_g)) ks_env%rho_nlcc_g => rho_nlcc_g
      IF (PRESENT(vppl)) ks_env%vppl => vppl
      IF (PRESENT(vee)) ks_env%vee => vee

      IF (PRESENT(neighbor_list_id)) ks_env%neighbor_list_id = neighbor_list_id
      IF (PRESENT(kpoints)) ks_env%kpoints => kpoints
      IF (PRESENT(sab_orb)) ks_env%sab_orb => sab_orb
      IF (PRESENT(sab_vdw)) ks_env%sab_vdw => sab_vdw
      IF (PRESENT(sab_scp)) ks_env%sab_scp => sab_scp
      IF (PRESENT(sab_all)) ks_env%sab_all => sab_all
      IF (PRESENT(sac_ae)) ks_env%sac_ae => sac_ae
      IF (PRESENT(sac_ppl)) ks_env%sac_ppl => sac_ppl
      IF (PRESENT(sac_lri)) ks_env%sac_lri => sac_lri
      IF (PRESENT(sap_ppnl)) ks_env%sap_ppnl => sap_ppnl
      IF (PRESENT(sap_oce)) ks_env%sap_oce => sap_oce
      IF (PRESENT(sab_se)) ks_env%sab_se => sab_se
      IF (PRESENT(sab_lrc)) ks_env%sab_lrc => sab_lrc
      IF (PRESENT(sab_tbe)) ks_env%sab_tbe => sab_tbe
      IF (PRESENT(sab_xtbe)) ks_env%sab_xtbe => sab_xtbe
      IF (PRESENT(sab_core)) ks_env%sab_core => sab_core
      IF (PRESENT(sab_xb)) ks_env%sab_xb => sab_xb
      IF (PRESENT(sab_xtb_pp)) ks_env%sab_xtb_pp => sab_xtb_pp
      IF (PRESENT(sab_xtb_nonbond)) ks_env%sab_xtb_nonbond => sab_xtb_nonbond
      IF (PRESENT(sab_almo)) ks_env%sab_almo => sab_almo
      IF (PRESENT(sab_kp)) ks_env%sab_kp => sab_kp
      IF (PRESENT(sab_kp_nosym)) ks_env%sab_kp_nosym => sab_kp_nosym

      IF (PRESENT(task_list)) ks_env%task_list => task_list
      IF (PRESENT(task_list_soft)) ks_env%task_list_soft => task_list_soft

      IF (PRESENT(subsys)) THEN
         IF (ASSOCIATED(ks_env%subsys)) THEN
         IF (ASSOCIATED(ks_env%subsys, subsys)) THEN
            CALL qs_subsys_release(ks_env%subsys)
            DEALLOCATE (ks_env%subsys)
         END IF
         END IF
         ks_env%subsys => subsys
      END IF
      IF (PRESENT(dft_control)) THEN
         IF (ASSOCIATED(ks_env%dft_control)) THEN
         IF (.NOT. ASSOCIATED(ks_env%dft_control, dft_control)) THEN
            CALL dft_control_release(ks_env%dft_control)
            DEALLOCATE (ks_env%dft_control)
         END IF
         END IF
         ks_env%dft_control => dft_control
      END IF
      IF (PRESENT(dbcsr_dist)) THEN
         IF (ASSOCIATED(ks_env%dbcsr_dist)) THEN
            IF (.NOT. ASSOCIATED(ks_env%dbcsr_dist, dbcsr_dist)) THEN
               CALL dbcsr_distribution_release(ks_env%dbcsr_dist)
               DEALLOCATE (ks_env%dbcsr_dist)
            END IF
         END IF
         ks_env%dbcsr_dist => dbcsr_dist
      END IF
      IF (PRESENT(distribution_2d)) THEN
         CALL distribution_2d_retain(distribution_2d)
         CALL distribution_2d_release(ks_env%distribution_2d)
         ks_env%distribution_2d => distribution_2d
      END IF
      IF (PRESENT(pw_env)) THEN
         CALL pw_env_retain(pw_env)
         CALL pw_env_release(ks_env%pw_env)
         ks_env%pw_env => pw_env
      END IF
      IF (PRESENT(para_env)) THEN
         CALL para_env%retain()
         CALL mp_para_env_release(ks_env%para_env)
         ks_env%para_env => para_env
      END IF
      IF (PRESENT(blacs_env)) THEN
         CALL blacs_env%retain()
         CALL cp_blacs_env_release(ks_env%blacs_env)
         ks_env%blacs_env => blacs_env
      END IF
   END SUBROUTINE set_ks_env

! **************************************************************************************************
!> \brief releases the ks_env (see doc/ReferenceCounting.html)
!> \param ks_env the ks_env to be released
!> \par History
!>      05.2002 created [fawzi]
!> \author Fawzi Mohamed
! **************************************************************************************************
   SUBROUTINE qs_ks_release(ks_env)
      TYPE(qs_ks_env_type), INTENT(INOUT)                :: ks_env

      IF (ASSOCIATED(ks_env%v_hartree_rspace)) THEN
         CALL ks_env%v_hartree_rspace%release()
         DEALLOCATE (ks_env%v_hartree_rspace)
      END IF

      CALL kpoint_transitional_release(ks_env%matrix_ks)
      CALL kpoint_transitional_release(ks_env%matrix_ks_im)
      CALL kpoint_transitional_release(ks_env%matrix_h)
      CALL kpoint_transitional_release(ks_env%matrix_h_im)
      CALL kpoint_transitional_release(ks_env%matrix_vxc)
      CALL kpoint_transitional_release(ks_env%matrix_s)
      CALL kpoint_transitional_release(ks_env%matrix_w)
      CALL kpoint_transitional_release(ks_env%kinetic)
      CALL kpoint_transitional_release(ks_env%matrix_s_RI_aux)

      IF (ASSOCIATED(ks_env%matrix_p_mp2)) &
         CALL dbcsr_deallocate_matrix_set(ks_env%matrix_p_mp2)
      IF (ASSOCIATED(ks_env%matrix_p_mp2_admm)) &
         CALL dbcsr_deallocate_matrix_set(ks_env%matrix_p_mp2_admm)
      IF (ASSOCIATED(ks_env%rho)) THEN
         CALL qs_rho_release(ks_env%rho)
         DEALLOCATE (ks_env%rho)
      END IF
      IF (ASSOCIATED(ks_env%rho_xc)) THEN
         CALL qs_rho_release(ks_env%rho_xc)
         DEALLOCATE (ks_env%rho_xc)
      END IF
      IF (ASSOCIATED(ks_env%distribution_2d)) &
         CALL distribution_2d_release(ks_env%distribution_2d)
      IF (ASSOCIATED(ks_env%task_list)) &
         CALL deallocate_task_list(ks_env%task_list)
      IF (ASSOCIATED(ks_env%task_list_soft)) &
         CALL deallocate_task_list(ks_env%task_list_soft)

      IF (ASSOCIATED(ks_env%rho_nlcc_g)) THEN
         CALL ks_env%rho_nlcc_g%release()
         DEALLOCATE (ks_env%rho_nlcc_g)
      END IF
      IF (ASSOCIATED(ks_env%rho_nlcc)) THEN
         CALL ks_env%rho_nlcc%release()
         DEALLOCATE (ks_env%rho_nlcc)
      END IF
      IF (ASSOCIATED(ks_env%rho_core)) THEN
         CALL ks_env%rho_core%release()
         DEALLOCATE (ks_env%rho_core)
      END IF
      IF (ASSOCIATED(ks_env%vppl)) THEN
         CALL ks_env%vppl%release()
         DEALLOCATE (ks_env%vppl)
      END IF
      IF (ASSOCIATED(ks_env%vee)) THEN
         CALL ks_env%vee%release()
         DEALLOCATE (ks_env%vee)
      END IF
      IF (ASSOCIATED(ks_env%dbcsr_dist)) THEN
         CALL dbcsr_distribution_release(ks_env%dbcsr_dist)
         DEALLOCATE (ks_env%dbcsr_dist)
      END IF

      CALL release_neighbor_list_sets(ks_env%sab_orb)
      CALL release_neighbor_list_sets(ks_env%sac_ae)
      CALL release_neighbor_list_sets(ks_env%sac_ppl)
      CALL release_neighbor_list_sets(ks_env%sac_lri)
      CALL release_neighbor_list_sets(ks_env%sap_ppnl)
      CALL release_neighbor_list_sets(ks_env%sap_oce)
      CALL release_neighbor_list_sets(ks_env%sab_se)
      CALL release_neighbor_list_sets(ks_env%sab_vdw)
      CALL release_neighbor_list_sets(ks_env%sab_scp)
      CALL release_neighbor_list_sets(ks_env%sab_tbe)
      CALL release_neighbor_list_sets(ks_env%sab_xtbe)
      CALL release_neighbor_list_sets(ks_env%sab_core)
      CALL release_neighbor_list_sets(ks_env%sab_xb)
      CALL release_neighbor_list_sets(ks_env%sab_xtb_pp)
      CALL release_neighbor_list_sets(ks_env%sab_xtb_nonbond)
      CALL release_neighbor_list_sets(ks_env%sab_all)
      CALL release_neighbor_list_sets(ks_env%sab_lrc)
      CALL release_neighbor_list_sets(ks_env%sab_almo)
      CALL release_neighbor_list_sets(ks_env%sab_kp)
      CALL release_neighbor_list_sets(ks_env%sab_kp_nosym)
      IF (ASSOCIATED(ks_env%dft_control)) THEN
         CALL dft_control_release(ks_env%dft_control)
         DEALLOCATE (ks_env%dft_control)
      END IF
      CALL kpoint_release(ks_env%kpoints)
      IF (ASSOCIATED(ks_env%subsys)) THEN
         CALL qs_subsys_release(ks_env%subsys)
         DEALLOCATE (ks_env%subsys)
      END IF
      CALL pw_env_release(ks_env%pw_env)
      CALL mp_para_env_release(ks_env%para_env)
      CALL cp_blacs_env_release(ks_env%blacs_env)

   END SUBROUTINE qs_ks_release

! **************************************************************************************************
!> \brief releases part of the ks_env
!> \param ks_env the ks_env to be released
!> \par History
!>      04.2022 created [JGH]
! **************************************************************************************************
   SUBROUTINE qs_ks_part_release(ks_env)
      TYPE(qs_ks_env_type), INTENT(INOUT)                :: ks_env

      IF (ASSOCIATED(ks_env%v_hartree_rspace)) THEN
         CALL ks_env%v_hartree_rspace%release()
         DEALLOCATE (ks_env%v_hartree_rspace)
      END IF

      CALL kpoint_transitional_release(ks_env%matrix_h)
      CALL kpoint_transitional_release(ks_env%matrix_h_im)
      CALL kpoint_transitional_release(ks_env%matrix_ks_im)
      CALL kpoint_transitional_release(ks_env%matrix_vxc)
      CALL kpoint_transitional_release(ks_env%matrix_w)
      CALL kpoint_transitional_release(ks_env%kinetic)
      CALL kpoint_transitional_release(ks_env%matrix_s_RI_aux)

      IF (ASSOCIATED(ks_env%matrix_p_mp2)) &
         CALL dbcsr_deallocate_matrix_set(ks_env%matrix_p_mp2)
      IF (ASSOCIATED(ks_env%matrix_p_mp2_admm)) &
         CALL dbcsr_deallocate_matrix_set(ks_env%matrix_p_mp2_admm)
      IF (ASSOCIATED(ks_env%rho)) THEN
         CALL qs_rho_release(ks_env%rho)
         DEALLOCATE (ks_env%rho)
      END IF
      IF (ASSOCIATED(ks_env%rho_xc)) THEN
         CALL qs_rho_release(ks_env%rho_xc)
         DEALLOCATE (ks_env%rho_xc)
      END IF
      IF (ASSOCIATED(ks_env%task_list)) &
         CALL deallocate_task_list(ks_env%task_list)
      IF (ASSOCIATED(ks_env%task_list_soft)) &
         CALL deallocate_task_list(ks_env%task_list_soft)

      IF (ASSOCIATED(ks_env%rho_nlcc_g)) THEN
         CALL ks_env%rho_nlcc_g%release()
         DEALLOCATE (ks_env%rho_nlcc_g)
      END IF
      IF (ASSOCIATED(ks_env%rho_nlcc)) THEN
         CALL ks_env%rho_nlcc%release()
         DEALLOCATE (ks_env%rho_nlcc)
      END IF
      IF (ASSOCIATED(ks_env%rho_core)) THEN
         CALL ks_env%rho_core%release()
         DEALLOCATE (ks_env%rho_core)
      END IF
      IF (ASSOCIATED(ks_env%vppl)) THEN
         CALL ks_env%vppl%release()
         DEALLOCATE (ks_env%vppl)
      END IF
      IF (ASSOCIATED(ks_env%vee)) THEN
         CALL ks_env%vee%release()
         DEALLOCATE (ks_env%vee)
      END IF

      CALL release_neighbor_list_sets(ks_env%sac_ae)
      CALL release_neighbor_list_sets(ks_env%sac_ppl)
      CALL release_neighbor_list_sets(ks_env%sac_lri)
      CALL release_neighbor_list_sets(ks_env%sap_ppnl)
      CALL release_neighbor_list_sets(ks_env%sap_oce)
      CALL release_neighbor_list_sets(ks_env%sab_se)
      CALL release_neighbor_list_sets(ks_env%sab_vdw)
      CALL release_neighbor_list_sets(ks_env%sab_scp)
      CALL release_neighbor_list_sets(ks_env%sab_tbe)
      CALL release_neighbor_list_sets(ks_env%sab_xtbe)
      CALL release_neighbor_list_sets(ks_env%sab_core)
      CALL release_neighbor_list_sets(ks_env%sab_xb)
      CALL release_neighbor_list_sets(ks_env%sab_xtb_pp)
      CALL release_neighbor_list_sets(ks_env%sab_xtb_nonbond)
      CALL release_neighbor_list_sets(ks_env%sab_all)
      CALL release_neighbor_list_sets(ks_env%sab_lrc)
      CALL release_neighbor_list_sets(ks_env%sab_almo)
      CALL release_neighbor_list_sets(ks_env%sab_kp)
      CALL release_neighbor_list_sets(ks_env%sab_kp_nosym)
      CALL kpoint_release(ks_env%kpoints)
      CALL pw_env_release(ks_env%pw_env, ks_env%para_env)
   END SUBROUTINE qs_ks_part_release

! **************************************************************************************************
!> \brief tells that some of the things relevant to the ks calculation
!>      did change. has to be called when changes happen otherwise
!>      the calculation will give wrong results.
!> \param ks_env the environment that is informed about the changes
!> \param s_mstruct_changed if true it means that the structure of the
!>        overlap matrix has changed
!>        (atoms have moved)
!> \param rho_changed if true it means that the density has changed
!> \param potential_changed ...
!> \param full_reset if true everything has changed
!> \par History
!>      4.2002 created [fawzi]
!>     12.2014 moved from qs_ks_methods, added deallocation of KS-matrices [Ole Schuett]
!> \author Fawzi Mohamed
! **************************************************************************************************
   SUBROUTINE qs_ks_did_change(ks_env, s_mstruct_changed, rho_changed, &
                               potential_changed, full_reset)
      TYPE(qs_ks_env_type), INTENT(INOUT)                :: ks_env
      LOGICAL, INTENT(in), OPTIONAL                      :: s_mstruct_changed, rho_changed, &
                                                            potential_changed, full_reset

      CHARACTER(len=*), PARAMETER                        :: routineN = 'qs_ks_did_change'

      INTEGER                                            :: handle
      LOGICAL                                            :: my_mstruct_chg

      CALL timeset(routineN, handle)
      my_mstruct_chg = .FALSE.

      IF (PRESENT(rho_changed)) THEN
         IF (rho_changed) ks_env%rho_changed = .TRUE.
      END IF

      IF (PRESENT(potential_changed)) THEN
         IF (potential_changed) ks_env%potential_changed = .TRUE.
      END IF

      IF (PRESENT(s_mstruct_changed)) THEN
         IF (s_mstruct_changed) my_mstruct_chg = .TRUE.
      END IF

      IF (PRESENT(full_reset)) THEN
         IF (full_reset) THEN
            ks_env%potential_changed = .TRUE.
            my_mstruct_chg = .TRUE.
         END IF
      END IF

      IF (my_mstruct_chg) THEN
         ks_env%s_mstruct_changed = .TRUE.
         ! *** deallocate matrices that will have the wrong structure ***
         CALL kpoint_transitional_release(ks_env%matrix_ks)
         !TODO: deallocate imaginary parts as well
         IF (ks_env%complex_ks) THEN
            CALL kpoint_transitional_release(ks_env%matrix_ks_im)
         END IF
         !CALL dbcsr_deallocate_matrix_set(ks_env%matrix_ks_im)
         !CALL dbcsr_deallocate_matrix_set(ks_env%matrix_ks_aux_fit_im)
      END IF

      CALL timestop(handle)

   END SUBROUTINE qs_ks_did_change

END MODULE qs_ks_types
