!--------------------------------------------------------------------------------------------------!
!   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 Calculate the interaction radii for the operator matrix calculation.
!> \par History
!>      Joost VandeVondele : added exp_radius_very_extended
!>      24.09.2002 overloaded init_interaction_radii for KG use (gt)
!>      27.02.2004 integrated KG into QS version of init_interaction_radii (jgh)
!>      07.03.2006 new routine to extend kind interaction radius for semi-empiric (jgh)
!> \author MK (12.07.2000)
! **************************************************************************************************
MODULE qs_interactions

   USE ao_util,                         ONLY: exp_radius
   USE atomic_kind_types,               ONLY: atomic_kind_type,&
                                              get_atomic_kind
   USE basis_set_types,                 ONLY: get_gto_basis_set,&
                                              gto_basis_set_type,&
                                              set_gto_basis_set
   USE cp_control_types,                ONLY: qs_control_type,&
                                              semi_empirical_control_type
   USE cp_log_handling,                 ONLY: cp_get_default_logger,&
                                              cp_logger_type
   USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
                                              cp_print_key_unit_nr
   USE cp_units,                        ONLY: cp_unit_from_cp2k
   USE external_potential_types,        ONLY: all_potential_type,&
                                              get_potential,&
                                              gth_potential_type,&
                                              set_potential,&
                                              sgp_potential_type
   USE input_section_types,             ONLY: section_vals_type,&
                                              section_vals_val_get
   USE kinds,                           ONLY: default_string_length,&
                                              dp
   USE paw_proj_set_types,              ONLY: get_paw_proj_set,&
                                              paw_proj_set_type,&
                                              set_paw_proj_set
   USE qs_kind_types,                   ONLY: get_qs_kind,&
                                              qs_kind_type
   USE string_utilities,                ONLY: uppercase
#include "./base/base_uses.f90"

   IMPLICIT NONE

   PRIVATE

! *** Global parameters (only in this module)

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

! *** Public subroutines ***

   PUBLIC :: init_interaction_radii, init_se_nlradius, init_interaction_radii_orb_basis

   PUBLIC :: write_paw_radii, write_ppnl_radii, write_ppl_radii, write_core_charge_radii, &
             write_pgf_orb_radii

CONTAINS

! **************************************************************************************************
!> \brief   Initialize all the atomic kind radii for a given threshold value.
!> \param qs_control ...
!> \param qs_kind_set ...
!> \date    24.09.2002
!> \author  GT
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE init_interaction_radii(qs_control, qs_kind_set)

      TYPE(qs_control_type), INTENT(IN)                  :: qs_control
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set

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

      INTEGER :: handle, i, iexp_ppl, ikind, ip, iprj_ppnl, j, l, lppl, lppnl, lppsl, lprj, &
         lprj_ppnl, maxl, n_local, nexp_lpot, nexp_lsd, nexp_ppl, nkind, nloc
      INTEGER, DIMENSION(0:10)                           :: npot
      INTEGER, DIMENSION(1:10)                           :: nrloc
      INTEGER, DIMENSION(1:15, 0:10)                     :: nrpot
      INTEGER, DIMENSION(:), POINTER                     :: nct_lpot, nct_lsd, nprj, nprj_ppnl
      LOGICAL                                            :: ecp_local, ecp_semi_local, llsd, lpot, &
                                                            paw_atom
      LOGICAL, DIMENSION(0:5)                            :: is_nonlocal
      REAL(KIND=dp) :: alpha_core_charge, alpha_ppl, ccore_charge, cerf_ppl, core_charge_radius, &
         cval, ppl_radius, ppnl_radius, rcprj, zeta
      REAL(KIND=dp), DIMENSION(1:10)                     :: aloc, bloc
      REAL(KIND=dp), DIMENSION(1:15, 0:10)               :: apot, bpot
      REAL(KIND=dp), DIMENSION(:), POINTER               :: a_local, a_nonlocal, alpha_lpot, &
                                                            alpha_lsd, alpha_ppnl, c_local, &
                                                            cexp_ppl
      REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cprj_ppnl, cval_lpot, cval_lsd, rzetprj, &
                                                            zet
      REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: c_nonlocal
      TYPE(all_potential_type), POINTER                  :: all_potential
      TYPE(gth_potential_type), POINTER                  :: gth_potential
      TYPE(gto_basis_set_type), POINTER :: aux_basis_set, aux_fit_basis_set, aux_gw_basis, &
         aux_opt_basis_set, gapw_1c_basis, harris_basis, lri_basis, mao_basis, min_basis_set, &
         orb_basis_set, p_lri_basis, rhoin_basis, ri_aux_basis_set, ri_basis, ri_xas_basis, &
         soft_basis, tda_k_basis
      TYPE(paw_proj_set_type), POINTER                   :: paw_proj_set
      TYPE(sgp_potential_type), POINTER                  :: sgp_potential

      CALL timeset(routineN, handle)

      NULLIFY (all_potential, gth_potential, sgp_potential)
      NULLIFY (aux_basis_set, aux_fit_basis_set, aux_gw_basis, tda_k_basis, &
               harris_basis, lri_basis, mao_basis, orb_basis_set, p_lri_basis, ri_aux_basis_set, &
               ri_basis, ri_xas_basis, soft_basis, gapw_1c_basis, aux_opt_basis_set, min_basis_set)
      NULLIFY (nprj_ppnl, nprj)
      NULLIFY (alpha_ppnl, cexp_ppl, cprj_ppnl, zet)

      nkind = SIZE(qs_kind_set)
      nexp_ppl = 0

      DO ikind = 1, nkind

         CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set, basis_type="ORB")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_basis_set, basis_type="AUX")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=min_basis_set, basis_type="MIN")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_fit_basis_set, basis_type="AUX_FIT")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_opt_basis_set, basis_type="AUX_OPT")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=lri_basis, basis_type="LRI_AUX")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=p_lri_basis, basis_type="P_LRI_AUX")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_basis, basis_type="RI_HXC")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_aux_basis_set, basis_type="RI_AUX")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=mao_basis, basis_type="MAO")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=harris_basis, basis_type="HARRIS")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_gw_basis, basis_type="AUX_GW")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=ri_xas_basis, basis_type="RI_XAS")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=soft_basis, basis_type="ORB_SOFT")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=gapw_1c_basis, basis_type="GAPW_1C")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=tda_k_basis, basis_type="TDA_HFX")
         CALL get_qs_kind(qs_kind_set(ikind), basis_set=rhoin_basis, basis_type="RHOIN")
         CALL get_qs_kind(qs_kind_set(ikind), &
                          paw_proj_set=paw_proj_set, &
                          paw_atom=paw_atom, &
                          all_potential=all_potential, &
                          gth_potential=gth_potential, &
                          sgp_potential=sgp_potential)

         ! Calculate the orbital basis function radii ***
         ! For ALL electron this has to come before the calculation of the
         ! radii used to calculate the 3c lists.
         ! Indeed, there the radii of the GTO primitives are needed
         IF (ASSOCIATED(orb_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(orb_basis_set, qs_control%eps_pgf_orb, &
                                                  qs_control%eps_kg_orb)
         END IF

         IF (ASSOCIATED(all_potential)) THEN

            CALL get_potential(potential=all_potential, &
                               alpha_core_charge=alpha_core_charge, &
                               ccore_charge=ccore_charge)

            ! Calculate the radius of the core charge distribution

            core_charge_radius = exp_radius(0, alpha_core_charge, &
                                            qs_control%eps_core_charge, &
                                            ccore_charge)

            CALL set_potential(potential=all_potential, &
                               core_charge_radius=core_charge_radius)

         ELSE IF (ASSOCIATED(gth_potential)) THEN

            CALL get_potential(potential=gth_potential, &
                               alpha_core_charge=alpha_core_charge, &
                               ccore_charge=ccore_charge, &
                               alpha_ppl=alpha_ppl, &
                               cerf_ppl=cerf_ppl, &
                               nexp_ppl=nexp_ppl, &
                               cexp_ppl=cexp_ppl, &
                               lpot_present=lpot, &
                               lsd_present=llsd, &
                               lppnl=lppnl, &
                               alpha_ppnl=alpha_ppnl, &
                               nprj_ppnl=nprj_ppnl, &
                               cprj_ppnl=cprj_ppnl)

            ! Calculate the radius of the core charge distribution
            core_charge_radius = exp_radius(0, alpha_core_charge, &
                                            qs_control%eps_core_charge, &
                                            ccore_charge)

            ! Calculate the radii of the local part
            ! of the Goedecker pseudopotential (GTH)
            ppl_radius = exp_radius(0, alpha_ppl, qs_control%eps_ppl, cerf_ppl)

            DO iexp_ppl = 1, nexp_ppl
               lppl = 2*(iexp_ppl - 1)
               ppl_radius = MAX(ppl_radius, &
                                exp_radius(lppl, alpha_ppl, &
                                           qs_control%eps_ppl, &
                                           cexp_ppl(iexp_ppl), &
                                           rlow=ppl_radius))
            END DO
            IF (lpot) THEN
               ! extended local potential
               CALL get_potential(potential=gth_potential, &
                                  nexp_lpot=nexp_lpot, &
                                  alpha_lpot=alpha_lpot, &
                                  nct_lpot=nct_lpot, &
                                  cval_lpot=cval_lpot)
               DO j = 1, nexp_lpot
                  DO i = 1, nct_lpot(j)
                     lppl = 2*(i - 1)
                     ppl_radius = MAX(ppl_radius, &
                                      exp_radius(lppl, alpha_lpot(j), qs_control%eps_ppl, &
                                                 cval_lpot(i, j), rlow=ppl_radius))
                  END DO
               END DO
            END IF
            IF (llsd) THEN
               ! lsd local potential
               CALL get_potential(potential=gth_potential, &
                                  nexp_lsd=nexp_lsd, &
                                  alpha_lsd=alpha_lsd, &
                                  nct_lsd=nct_lsd, &
                                  cval_lsd=cval_lsd)
               DO j = 1, nexp_lsd
                  DO i = 1, nct_lsd(j)
                     lppl = 2*(i - 1)
                     ppl_radius = MAX(ppl_radius, &
                                      exp_radius(lppl, alpha_lsd(j), qs_control%eps_ppl, &
                                                 cval_lsd(i, j), rlow=ppl_radius))
                  END DO
               END DO
            END IF

            ! Calculate the radii of the non-local part
            ! of the Goedecker pseudopotential (GTH)
            ppnl_radius = 0.0_dp
            DO l = 0, lppnl
               DO iprj_ppnl = 1, nprj_ppnl(l)
                  lprj_ppnl = l + 2*(iprj_ppnl - 1)
                  ppnl_radius = MAX(ppnl_radius, &
                                    exp_radius(lprj_ppnl, alpha_ppnl(l), &
                                               qs_control%eps_pgf_orb, &
                                               cprj_ppnl(iprj_ppnl, l), &
                                               rlow=ppnl_radius))
               END DO
            END DO
            CALL set_potential(potential=gth_potential, &
                               core_charge_radius=core_charge_radius, &
                               ppl_radius=ppl_radius, &
                               ppnl_radius=ppnl_radius)

         ELSE IF (ASSOCIATED(sgp_potential)) THEN

            ! Calculate the radius of the core charge distribution
            CALL get_potential(potential=sgp_potential, &
                               alpha_core_charge=alpha_core_charge, &
                               ccore_charge=ccore_charge)
            core_charge_radius = exp_radius(0, alpha_core_charge, &
                                            qs_control%eps_core_charge, &
                                            ccore_charge)
            ! Calculate the radii of the local part
            ppl_radius = core_charge_radius
            CALL get_potential(potential=sgp_potential, ecp_local=ecp_local)
            IF (ecp_local) THEN
               CALL get_potential(potential=sgp_potential, nloc=nloc, nrloc=nrloc, aloc=aloc, bloc=bloc)
               DO i = 1, nloc
                  lppl = MAX(0, nrloc(i) - 2)
                  ppl_radius = MAX(ppl_radius, &
                                   exp_radius(lppl, bloc(i), qs_control%eps_ppl, aloc(i), rlow=ppl_radius))
               END DO
            ELSE
               CALL get_potential(potential=sgp_potential, n_local=n_local, a_local=a_local, c_local=c_local)
               DO i = 1, n_local
                  ppl_radius = MAX(ppl_radius, &
                                   exp_radius(0, a_local(i), qs_control%eps_ppl, c_local(i), rlow=ppl_radius))
               END DO
            END IF
            ! Calculate the radii of the semi-local part
            CALL get_potential(potential=sgp_potential, ecp_semi_local=ecp_semi_local)
            IF (ecp_semi_local) THEN
               CALL get_potential(potential=sgp_potential, sl_lmax=lppsl, npot=npot, nrpot=nrpot, &
                                  apot=apot, bpot=bpot)
               DO l = 0, lppsl
                  DO i = 1, npot(l)
                     lppl = MAX(0, nrpot(i, l) - 2)
                     ppl_radius = MAX(ppl_radius, &
                                      exp_radius(lppl, bpot(i, l), qs_control%eps_ppl, apot(i, l), &
                                                 rlow=ppl_radius))
                  END DO
               END DO
            END IF
            ! Calculate the radii of the non-local part
            ppnl_radius = 0.0_dp
            CALL get_potential(potential=sgp_potential, lmax=lppnl, n_nonlocal=nloc)
            CALL get_potential(potential=sgp_potential, is_nonlocal=is_nonlocal, &
                               a_nonlocal=a_nonlocal, c_nonlocal=c_nonlocal)
            DO l = 0, lppnl
               IF (is_nonlocal(l)) THEN
                  DO i = 1, nloc
                     cval = MAXVAL(ABS(c_nonlocal(i, :, l)))
                     ppnl_radius = MAX(ppnl_radius, &
                                       exp_radius(l, a_nonlocal(i), qs_control%eps_pgf_orb, cval, rlow=ppnl_radius))
                  END DO
               END IF
            END DO
            CALL set_potential(potential=sgp_potential, &
                               core_charge_radius=core_charge_radius, &
                               ppl_radius=ppl_radius, &
                               ppnl_radius=ppnl_radius)
         END IF

         ! Calculate the aux fit orbital basis function radii
         IF (ASSOCIATED(aux_fit_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(aux_fit_basis_set, qs_control%eps_pgf_orb, &
                                                  qs_control%eps_kg_orb)
         END IF

         ! Calculate the aux opt orbital basis function radii
         IF (ASSOCIATED(aux_opt_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(aux_opt_basis_set, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the minimal basis function radii
         IF (ASSOCIATED(min_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(min_basis_set, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the aux orbital basis function radii
         IF (ASSOCIATED(aux_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(aux_basis_set, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the RI aux orbital basis function radii
         IF (ASSOCIATED(RI_aux_basis_set)) THEN
            CALL init_interaction_radii_orb_basis(RI_aux_basis_set, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the MAO orbital basis function radii
         IF (ASSOCIATED(mao_basis)) THEN
            CALL init_interaction_radii_orb_basis(mao_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the HARRIS orbital basis function radii
         IF (ASSOCIATED(harris_basis)) THEN
            CALL init_interaction_radii_orb_basis(harris_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the AUX_GW orbital basis function radii
         IF (ASSOCIATED(aux_gw_basis)) THEN
            CALL init_interaction_radii_orb_basis(aux_gw_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the soft orbital basis function radii
         IF (ASSOCIATED(soft_basis)) THEN
            CALL init_interaction_radii_orb_basis(soft_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the GAPW 1 center basis function radii
         IF (ASSOCIATED(gapw_1c_basis)) THEN
            CALL init_interaction_radii_orb_basis(gapw_1c_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the HFX SR basis for TDA
         IF (ASSOCIATED(tda_k_basis)) THEN
            CALL init_interaction_radii_orb_basis(tda_k_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the lri basis function radii
         IF (ASSOCIATED(lri_basis)) THEN
            CALL init_interaction_radii_orb_basis(lri_basis, qs_control%eps_pgf_orb)
         END IF
         IF (ASSOCIATED(ri_basis)) THEN
            CALL init_interaction_radii_orb_basis(ri_basis, qs_control%eps_pgf_orb)
         END IF
         IF (ASSOCIATED(ri_xas_basis)) THEN
            CALL init_interaction_radii_orb_basis(ri_xas_basis, qs_control%eps_pgf_orb)
         END IF
         IF (ASSOCIATED(p_lri_basis)) THEN
            CALL init_interaction_radii_orb_basis(p_lri_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the density input basis function radii
         IF (ASSOCIATED(rhoin_basis)) THEN
            CALL init_interaction_radii_orb_basis(rhoin_basis, qs_control%eps_pgf_orb)
         END IF

         ! Calculate the paw projector basis function radii
         IF (ASSOCIATED(paw_proj_set)) THEN
            CALL get_paw_proj_set(paw_proj_set=paw_proj_set, &
                                  nprj=nprj, &
                                  maxl=maxl, &
                                  zetprj=zet, &
                                  rzetprj=rzetprj)
            rcprj = 0.0_dp
            rzetprj = 0.0_dp
            DO lprj = 0, maxl
               DO ip = 1, nprj(lprj)
                  zeta = zet(ip, lprj)
                  rzetprj(ip, lprj) = MAX(rzetprj(ip, lprj), &
                                          exp_radius(lprj, zeta, qs_control%eps_pgf_orb, &
                                                     1.0_dp, rlow=rzetprj(ip, lprj)))
                  rcprj = MAX(rcprj, rzetprj(ip, lprj))
               END DO
            END DO
            CALL set_paw_proj_set(paw_proj_set=paw_proj_set, &
                                  rzetprj=rzetprj, &
                                  rcprj=rcprj)

         END IF
      END DO ! ikind

      CALL timestop(handle)

   END SUBROUTINE init_interaction_radii

! **************************************************************************************************
!> \brief ...
!> \param orb_basis_set ...
!> \param eps_pgf_orb ...
!> \param eps_pgf_short ...
! **************************************************************************************************
   SUBROUTINE init_interaction_radii_orb_basis(orb_basis_set, eps_pgf_orb, eps_pgf_short)

      TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set
      REAL(KIND=dp), INTENT(IN)                          :: eps_pgf_orb
      REAL(KIND=dp), INTENT(IN), OPTIONAL                :: eps_pgf_short

      INTEGER                                            :: ipgf, iset, ishell, l, nset
      INTEGER, DIMENSION(:), POINTER                     :: npgf, nshell
      INTEGER, DIMENSION(:, :), POINTER                  :: lshell
      REAL(KIND=dp)                                      :: eps_short, gcca, kind_radius, &
                                                            short_radius, zeta
      REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius
      REAL(KIND=dp), DIMENSION(:, :), POINTER            :: pgf_radius, zet
      REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: gcc

      IF (ASSOCIATED(orb_basis_set)) THEN

         IF (PRESENT(eps_pgf_short)) THEN
            eps_short = eps_pgf_short
         ELSE
            eps_short = eps_pgf_orb
         END IF

         CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                nset=nset, &
                                nshell=nshell, &
                                npgf=npgf, &
                                l=lshell, &
                                zet=zet, &
                                gcc=gcc, &
                                pgf_radius=pgf_radius, &
                                set_radius=set_radius)

         kind_radius = 0.0_dp
         short_radius = 0.0_dp

         DO iset = 1, nset
            set_radius(iset) = 0.0_dp
            DO ipgf = 1, npgf(iset)
               pgf_radius(ipgf, iset) = 0.0_dp
               DO ishell = 1, nshell(iset)
                  l = lshell(ishell, iset)
                  gcca = gcc(ipgf, ishell, iset)
                  zeta = zet(ipgf, iset)
                  pgf_radius(ipgf, iset) = MAX(pgf_radius(ipgf, iset), &
                                               exp_radius(l, zeta, eps_pgf_orb, gcca, &
                                                          rlow=pgf_radius(ipgf, iset)))
                  short_radius = MAX(short_radius, &
                                     exp_radius(l, zeta, eps_short, gcca, &
                                                rlow=short_radius))
               END DO
               set_radius(iset) = MAX(set_radius(iset), pgf_radius(ipgf, iset))
            END DO
            kind_radius = MAX(kind_radius, set_radius(iset))
         END DO

         CALL set_gto_basis_set(gto_basis_set=orb_basis_set, &
                                pgf_radius=pgf_radius, &
                                set_radius=set_radius, &
                                kind_radius=kind_radius, &
                                short_kind_radius=short_radius)

      END IF

   END SUBROUTINE init_interaction_radii_orb_basis

! **************************************************************************************************
!> \brief ...
!> \param se_control ...
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
! **************************************************************************************************
   SUBROUTINE init_se_nlradius(se_control, atomic_kind_set, qs_kind_set, &
                               subsys_section)

      TYPE(semi_empirical_control_type), POINTER         :: se_control
      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      INTEGER                                            :: ikind, nkind
      REAL(KIND=dp)                                      :: kind_radius
      TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set
      TYPE(qs_kind_type), POINTER                        :: qs_kind

      NULLIFY (orb_basis_set, qs_kind)

      nkind = SIZE(qs_kind_set)

      DO ikind = 1, nkind

         qs_kind => qs_kind_set(ikind)

         CALL get_qs_kind(qs_kind=qs_kind, basis_set=orb_basis_set)

         IF (ASSOCIATED(orb_basis_set)) THEN

            CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                   kind_radius=kind_radius)

            kind_radius = MAX(kind_radius, se_control%cutoff_exc)

            CALL set_gto_basis_set(gto_basis_set=orb_basis_set, &
                                   kind_radius=kind_radius)

         END IF

      END DO

      CALL write_kind_radii(atomic_kind_set, qs_kind_set, subsys_section)

   END SUBROUTINE init_se_nlradius

! **************************************************************************************************
!> \brief ...
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
! **************************************************************************************************
   SUBROUTINE write_kind_radii(atomic_kind_set, qs_kind_set, subsys_section)

      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=10)                                  :: bas
      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, nkind, output_unit
      REAL(KIND=dp)                                      :: conv, kind_radius
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set

      NULLIFY (logger)
      logger => cp_get_default_logger()
      NULLIFY (orb_basis_set)
      bas = "ORBITAL   "

      nkind = SIZE(atomic_kind_set)
!   *** Print the kind radii ***
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/KIND_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T56,A,T63,A,T75,A)") &
            "RADII: "//TRIM(bas)//" BASIS in "//TRIM(unit_str), &
            "Kind", "Label", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
            IF (ASSOCIATED(orb_basis_set)) THEN
               CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                      kind_radius=kind_radius)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, kind_radius*conv
            ELSE
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T72,A9)") &
                  ikind, name, "no basis"
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/KIND_RADII")

   END SUBROUTINE write_kind_radii

! **************************************************************************************************
!> \brief  Write the radii of the core charge distributions to the output
!>         unit.
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
!> \date    15.09.2000
!> \author  MK
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE write_core_charge_radii(atomic_kind_set, qs_kind_set, subsys_section)
      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, nkind, output_unit
      REAL(KIND=dp)                                      :: conv, core_charge_radius
      TYPE(all_potential_type), POINTER                  :: all_potential
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(gth_potential_type), POINTER                  :: gth_potential

      NULLIFY (logger)
      logger => cp_get_default_logger()
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/CORE_CHARGE_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         nkind = SIZE(atomic_kind_set)
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T56,A,T63,A,T75,A)") &
            "RADII: CORE CHARGE DISTRIBUTIONS in "// &
            TRIM(unit_str), "Kind", "Label", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            CALL get_qs_kind(qs_kind_set(ikind), &
                             all_potential=all_potential, gth_potential=gth_potential)

            IF (ASSOCIATED(all_potential)) THEN
               CALL get_potential(potential=all_potential, &
                                  core_charge_radius=core_charge_radius)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, core_charge_radius*conv
            ELSE IF (ASSOCIATED(gth_potential)) THEN
               CALL get_potential(potential=gth_potential, &
                                  core_charge_radius=core_charge_radius)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, core_charge_radius*conv
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/CORE_CHARGE_RADII")
   END SUBROUTINE write_core_charge_radii

! **************************************************************************************************
!> \brief   Write the orbital basis function radii to the output unit.
!> \param basis ...
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
!> \date    05.06.2000
!> \author  MK
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE write_pgf_orb_radii(basis, atomic_kind_set, qs_kind_set, subsys_section)

      CHARACTER(len=*)                                   :: basis
      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=10)                                  :: bas
      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, ipgf, iset, nkind, nset, &
                                                            output_unit
      INTEGER, DIMENSION(:), POINTER                     :: npgf
      REAL(KIND=dp)                                      :: conv, kind_radius, short_kind_radius
      REAL(KIND=dp), DIMENSION(:), POINTER               :: set_radius
      REAL(KIND=dp), DIMENSION(:, :), POINTER            :: pgf_radius
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(gto_basis_set_type), POINTER                  :: aux_basis_set, lri_basis_set, &
                                                            orb_basis_set

      NULLIFY (logger)
      logger => cp_get_default_logger()
      NULLIFY (aux_basis_set, orb_basis_set, lri_basis_set)
      bas = " "
      bas(1:3) = basis(1:3)
      CALL uppercase(bas)
      IF (bas(1:3) == "ORB") THEN
         bas = "ORBITAL   "
      ELSE IF (bas(1:3) == "AUX") THEN
         bas = "AUXILLIARY"
      ELSE IF (bas(1:3) == "LRI") THEN
         bas = "LOCAL RI"
      ELSE
         CPABORT("Undefined basis set type")
      END IF

      nkind = SIZE(qs_kind_set)

!   *** Print the kind radii ***
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/KIND_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T46,A,T53,A,T63,A,T71,A)") &
            "RADII: "//TRIM(bas)//" BASIS in "//TRIM(unit_str), &
            "Kind", "Label", "Radius", "OCE Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            IF (bas(1:3) == "ORB") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
               IF (ASSOCIATED(orb_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                         kind_radius=kind_radius, &
                                         short_kind_radius=short_kind_radius)
               END IF
            ELSE IF (bas(1:3) == "AUX") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_basis_set, basis_type="AUX")
               IF (ASSOCIATED(aux_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=aux_basis_set, &
                                         kind_radius=kind_radius)
               END IF
            ELSE IF (bas(1:3) == "LOC") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=lri_basis_set, basis_type="LRI_AUX")
               IF (ASSOCIATED(lri_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=lri_basis_set, &
                                         kind_radius=kind_radius)
               END IF
            ELSE
               CPABORT("Undefined basis set type")
            END IF
            IF (ASSOCIATED(aux_basis_set) .OR. ASSOCIATED(orb_basis_set)) THEN
               WRITE (UNIT=output_unit, FMT="(T45,I5,T53,A5,T57,F12.6,T69,F12.6)") &
                  ikind, name, kind_radius*conv, short_kind_radius*conv
            ELSE
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T72,A9)") &
                  ikind, name, "no basis"
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/KIND_RADII")

!   *** Print the shell set radii ***
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/SET_RADII", extension=".Log")
      IF (output_unit > 0) THEN
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T51,A,T57,A,T65,A,T75,A)") &
            "RADII: SHELL SETS OF "//TRIM(bas)//" BASIS in "// &
            TRIM(unit_str), "Kind", "Label", "Set", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            IF (bas(1:3) == "ORB") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
               IF (ASSOCIATED(orb_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                         nset=nset, &
                                         set_radius=set_radius)
               END IF
            ELSE IF (bas(1:3) == "AUX") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_basis_set, basis_type="AUX")
               IF (ASSOCIATED(aux_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=aux_basis_set, &
                                         nset=nset, &
                                         set_radius=set_radius)
               END IF
            ELSE IF (bas(1:3) == "LOC") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=lri_basis_set, basis_type="LRI_AUX")
               IF (ASSOCIATED(lri_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=lri_basis_set, &
                                         nset=nset, &
                                         set_radius=set_radius)
               END IF
            ELSE
               CPABORT("Undefined basis set type")
            END IF
            IF (ASSOCIATED(aux_basis_set) .OR. ASSOCIATED(orb_basis_set)) THEN
               WRITE (UNIT=output_unit, FMT="(T50,I5,T57,A5,(T63,I5,T69,F12.6))") &
                  ikind, name, (iset, set_radius(iset)*conv, iset=1, nset)
            ELSE
               WRITE (UNIT=output_unit, FMT="(T50,I5,T58,A5,T73,A8)") &
                  ikind, name, "no basis"
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/SET_RADII")
!   *** Print the primitive Gaussian function radii ***
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/PGF_RADII", extension=".Log")
      IF (output_unit > 0) THEN
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T51,A,T57,A,T65,A,T75,A)") &
            "RADII: PRIMITIVE GAUSSIANS OF "//TRIM(bas)//" BASIS in "// &
            TRIM(unit_str), "Kind", "Label", "Set", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            IF (bas(1:3) == "ORB") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
               IF (ASSOCIATED(orb_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=orb_basis_set, &
                                         nset=nset, &
                                         npgf=npgf, &
                                         pgf_radius=pgf_radius)
               END IF
            ELSE IF (bas(1:3) == "AUX") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=aux_basis_set, basis_type="AUX")
               IF (ASSOCIATED(aux_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=aux_basis_set, &
                                         nset=nset, &
                                         npgf=npgf, &
                                         pgf_radius=pgf_radius)
               END IF
            ELSE IF (bas(1:3) == "LOC") THEN
               CALL get_qs_kind(qs_kind_set(ikind), basis_set=lri_basis_set, basis_type="LRI_AUX")
               IF (ASSOCIATED(lri_basis_set)) THEN
                  CALL get_gto_basis_set(gto_basis_set=lri_basis_set, &
                                         nset=nset, &
                                         npgf=npgf, &
                                         pgf_radius=pgf_radius)
               END IF
            ELSE
               CPABORT("Undefined basis type")
            END IF
            IF (ASSOCIATED(aux_basis_set) .OR. ASSOCIATED(orb_basis_set) .OR. &
                ASSOCIATED(lri_basis_set)) THEN
               DO iset = 1, nset
                  WRITE (UNIT=output_unit, FMT="(T50,I5,T57,A5,T63,I5,(T69,F12.6))") &
                     ikind, name, iset, &
                     (pgf_radius(ipgf, iset)*conv, ipgf=1, npgf(iset))
               END DO
            ELSE
               WRITE (UNIT=output_unit, FMT="(T50,I5,T58,A5,T73,A8)") &
                  ikind, name, "no basis"
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/PGF_RADII")
   END SUBROUTINE write_pgf_orb_radii

! **************************************************************************************************
!> \brief   Write the radii of the exponential functions of the Goedecker
!>           pseudopotential (GTH, local part) to the logical unit number
!>          "output_unit".
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
!> \date    06.10.2000
!> \author  MK
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE write_ppl_radii(atomic_kind_set, qs_kind_set, subsys_section)

      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, nkind, output_unit
      REAL(KIND=dp)                                      :: conv, ppl_radius
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(gth_potential_type), POINTER                  :: gth_potential

      NULLIFY (logger)
      logger => cp_get_default_logger()
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/PPL_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         nkind = SIZE(atomic_kind_set)
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T56,A,T63,A,T75,A)") &
            "RADII: LOCAL PART OF GTH/ELP PP in "// &
            TRIM(unit_str), "Kind", "Label", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            CALL get_qs_kind(qs_kind_set(ikind), gth_potential=gth_potential)
            IF (ASSOCIATED(gth_potential)) THEN
               CALL get_potential(potential=gth_potential, &
                                  ppl_radius=ppl_radius)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, ppl_radius*conv
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/PPL_RADII")
   END SUBROUTINE write_ppl_radii

! **************************************************************************************************
!> \brief  Write the radii of the projector functions of the Goedecker
!>          pseudopotential (GTH, non-local part) to the logical unit number
!>          "output_unit".
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
!> \date    06.10.2000
!> \author  MK
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE write_ppnl_radii(atomic_kind_set, qs_kind_set, subsys_section)

      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, nkind, output_unit
      REAL(KIND=dp)                                      :: conv, ppnl_radius
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(gth_potential_type), POINTER                  :: gth_potential

      NULLIFY (logger)
      logger => cp_get_default_logger()
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/PPNL_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         nkind = SIZE(atomic_kind_set)
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T56,A,T63,A,T75,A)") &
            "RADII: NON-LOCAL PART OF GTH PP in "// &
            TRIM(unit_str), "Kind", "Label", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            CALL get_qs_kind(qs_kind_set(ikind), gth_potential=gth_potential)
            IF (ASSOCIATED(gth_potential)) THEN
               CALL get_potential(potential=gth_potential, &
                                  ppnl_radius=ppnl_radius)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, ppnl_radius*conv
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/PPNL_RADII")
   END SUBROUTINE write_ppnl_radii

! **************************************************************************************************
!> \brief   Write the radii of the one center projector
!> \param atomic_kind_set ...
!> \param qs_kind_set ...
!> \param subsys_section ...
!> \version 1.0
! **************************************************************************************************
   SUBROUTINE write_paw_radii(atomic_kind_set, qs_kind_set, subsys_section)
      TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      TYPE(section_vals_type), POINTER                   :: subsys_section

      CHARACTER(LEN=default_string_length)               :: name, unit_str
      INTEGER                                            :: ikind, nkind, output_unit
      LOGICAL                                            :: paw_atom
      REAL(KIND=dp)                                      :: conv, rcprj
      TYPE(cp_logger_type), POINTER                      :: logger
      TYPE(paw_proj_set_type), POINTER                   :: paw_proj_set

      NULLIFY (logger)
      logger => cp_get_default_logger()
      output_unit = cp_print_key_unit_nr(logger, subsys_section, &
                                         "PRINT%RADII/GAPW_PRJ_RADII", extension=".Log")
      CALL section_vals_val_get(subsys_section, "PRINT%RADII%UNIT", c_val=unit_str)
      conv = cp_unit_from_cp2k(1.0_dp, TRIM(unit_str))
      IF (output_unit > 0) THEN
         nkind = SIZE(qs_kind_set)
         WRITE (UNIT=output_unit, FMT="(/,T2,A,T56,A,T63,A,T75,A)") &
            "RADII: ONE CENTER PROJECTORS in "// &
            TRIM(unit_str), "Kind", "Label", "Radius"
         DO ikind = 1, nkind
            CALL get_atomic_kind(atomic_kind_set(ikind), name=name)
            CALL get_qs_kind(qs_kind_set(ikind), &
                             paw_atom=paw_atom, paw_proj_set=paw_proj_set)
            IF (paw_atom .AND. ASSOCIATED(paw_proj_set)) THEN
               CALL get_paw_proj_set(paw_proj_set=paw_proj_set, &
                                     rcprj=rcprj)
               WRITE (UNIT=output_unit, FMT="(T55,I5,T63,A5,T69,F12.6)") &
                  ikind, name, rcprj*conv
            END IF
         END DO
      END IF
      CALL cp_print_key_finished_output(output_unit, logger, subsys_section, &
                                        "PRINT%RADII/GAPW_PRJ_RADII")
   END SUBROUTINE write_paw_radii

END MODULE qs_interactions
