LCOV - code coverage report
Current view: top level - src - iao_analysis.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:dc8eeee) Lines: 859 875 98.2 %
Date: 2025-05-15 08:34:30 Functions: 14 14 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Calculate intrinsic atomic orbitals and analyze wavefunctions
      10             : !> \par History
      11             : !>      03.2023 created [JGH]
      12             : !> \author JGH
      13             : ! **************************************************************************************************
      14             : MODULE iao_analysis
      15             :    USE ai_contraction,                  ONLY: block_add,&
      16             :                                               contraction
      17             :    USE ai_overlap,                      ONLY: overlap_ab
      18             :    USE atomic_charges,                  ONLY: print_atomic_charges
      19             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      20             :                                               get_atomic_kind
      21             :    USE auto_basis,                      ONLY: create_oce_basis
      22             :    USE basis_set_types,                 ONLY: deallocate_gto_basis_set,&
      23             :                                               get_gto_basis_set,&
      24             :                                               gto_basis_set_p_type,&
      25             :                                               gto_basis_set_type,&
      26             :                                               init_orb_basis_set
      27             :    USE bibliography,                    ONLY: Knizia2013,&
      28             :                                               cite_reference
      29             :    USE cell_types,                      ONLY: cell_type,&
      30             :                                               pbc
      31             :    USE cp_array_utils,                  ONLY: cp_2d_r_p_type
      32             :    USE cp_control_types,                ONLY: dft_control_type
      33             :    USE cp_dbcsr_api,                    ONLY: &
      34             :         dbcsr_copy, dbcsr_create, dbcsr_distribution_type, dbcsr_get_block_p, dbcsr_get_info, &
      35             :         dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
      36             :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_p_type, dbcsr_release, &
      37             :         dbcsr_replicate_all, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      38             :    USE cp_dbcsr_contrib,                ONLY: dbcsr_reserve_diag_blocks,&
      39             :                                               dbcsr_trace
      40             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      41             :                                               copy_fm_to_dbcsr,&
      42             :                                               cp_dbcsr_plus_fm_fm_t,&
      43             :                                               cp_dbcsr_sm_fm_multiply,&
      44             :                                               dbcsr_deallocate_matrix_set
      45             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      46             :                                               cp_fm_geadd,&
      47             :                                               cp_fm_invert,&
      48             :                                               cp_fm_rot_cols,&
      49             :                                               cp_fm_rot_rows
      50             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      51             :                                               cp_fm_struct_release,&
      52             :                                               cp_fm_struct_type
      53             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      54             :                                               cp_fm_get_diag,&
      55             :                                               cp_fm_get_element,&
      56             :                                               cp_fm_get_info,&
      57             :                                               cp_fm_release,&
      58             :                                               cp_fm_set_all,&
      59             :                                               cp_fm_to_fm,&
      60             :                                               cp_fm_type
      61             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      62             :                                               cp_logger_type
      63             :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      64             :                                               cp_print_key_unit_nr
      65             :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      66             :    USE iao_types,                       ONLY: iao_env_type
      67             :    USE input_constants,                 ONLY: do_iaoloc_enone,&
      68             :                                               do_iaoloc_pm2
      69             :    USE input_section_types,             ONLY: section_get_ivals,&
      70             :                                               section_vals_get,&
      71             :                                               section_vals_type,&
      72             :                                               section_vals_val_get
      73             :    USE kinds,                           ONLY: default_path_length,&
      74             :                                               default_string_length,&
      75             :                                               dp
      76             :    USE machine,                         ONLY: m_walltime
      77             :    USE mathconstants,                   ONLY: twopi
      78             :    USE mathlib,                         ONLY: invmat_symm,&
      79             :                                               jacobi
      80             :    USE message_passing,                 ONLY: mp_comm_type
      81             :    USE min_basis_set,                   ONLY: create_minbas_set
      82             :    USE molden_utils,                    ONLY: write_mos_molden
      83             :    USE orbital_pointers,                ONLY: ncoset
      84             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      85             :    USE particle_list_types,             ONLY: particle_list_type
      86             :    USE particle_methods,                ONLY: get_particle_set
      87             :    USE particle_types,                  ONLY: particle_type
      88             :    USE pw_env_types,                    ONLY: pw_env_get,&
      89             :                                               pw_env_type
      90             :    USE pw_pool_types,                   ONLY: pw_pool_type
      91             :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      92             :                                               pw_r3d_rs_type
      93             :    USE qs_collocate_density,            ONLY: calculate_wavefunction
      94             :    USE qs_environment_types,            ONLY: get_qs_env,&
      95             :                                               qs_environment_type
      96             :    USE qs_interactions,                 ONLY: init_interaction_radii_orb_basis
      97             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      98             :                                               qs_kind_type
      99             :    USE qs_ks_types,                     ONLY: get_ks_env,&
     100             :                                               qs_ks_env_type
     101             :    USE qs_loc_utils,                    ONLY: compute_berry_operator
     102             :    USE qs_localization_methods,         ONLY: initialize_weights,&
     103             :                                               rotate_orbitals,&
     104             :                                               scdm_qrfact
     105             :    USE qs_mo_methods,                   ONLY: make_basis_lowdin
     106             :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
     107             :                                               deallocate_mo_set,&
     108             :                                               get_mo_set,&
     109             :                                               init_mo_set,&
     110             :                                               mo_set_type,&
     111             :                                               set_mo_set
     112             :    USE qs_moments,                      ONLY: build_local_moment_matrix
     113             :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type,&
     114             :                                               release_neighbor_list_sets
     115             :    USE qs_neighbor_lists,               ONLY: setup_neighbor_list
     116             :    USE qs_overlap,                      ONLY: build_overlap_matrix_simple
     117             :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
     118             :                                               qs_subsys_type
     119             : #include "./base/base_uses.f90"
     120             : 
     121             :    IMPLICIT NONE
     122             :    PRIVATE
     123             : 
     124             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'iao_analysis'
     125             : 
     126             :    PUBLIC ::  iao_wfn_analysis, iao_charges, iao_calculate_dmat, print_center_spread
     127             : 
     128             :    INTERFACE iao_calculate_dmat
     129             :       MODULE PROCEDURE iao_calculate_dmat_diag, & ! diagonal occupation matrix
     130             :          iao_calculate_dmat_full    ! full occupation matrix
     131             :    END INTERFACE
     132             : 
     133             : ! **************************************************************************************************
     134             : 
     135             : CONTAINS
     136             : 
     137             : ! **************************************************************************************************
     138             : !> \brief ...
     139             : !> \param qs_env ...
     140             : !> \param iao_env ...
     141             : !> \param unit_nr ...
     142             : !> \param c_iao_coef ...
     143             : !> \param mos ...
     144             : !> \param bond_centers ...
     145             : ! **************************************************************************************************
     146          34 :    SUBROUTINE iao_wfn_analysis(qs_env, iao_env, unit_nr, c_iao_coef, mos, bond_centers)
     147             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     148             :       TYPE(iao_env_type), INTENT(IN)                     :: iao_env
     149             :       INTEGER, INTENT(IN)                                :: unit_nr
     150             :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:), &
     151             :          OPTIONAL                                        :: c_iao_coef
     152             :       TYPE(mo_set_type), DIMENSION(:), OPTIONAL, POINTER :: mos
     153             :       REAL(KIND=dp), DIMENSION(:, :, :), OPTIONAL        :: bond_centers
     154             : 
     155             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'iao_wfn_analysis'
     156             : 
     157             :       CHARACTER(LEN=2)                                   :: element_symbol
     158             :       CHARACTER(LEN=default_string_length)               :: bname
     159             :       INTEGER                                            :: handle, i, iatom, ikind, isgf, ispin, &
     160             :                                                             nao, natom, nimages, nkind, no, norb, &
     161             :                                                             nref, ns, nsgf, nspin, nvec, nx, order
     162          34 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: first_sgf, last_sgf, nsgfat
     163             :       INTEGER, DIMENSION(2)                              :: nocc
     164             :       LOGICAL                                            :: cubes_iao, cubes_ibo, molden_iao, &
     165             :                                                             molden_ibo, uniform_occupation
     166             :       REAL(KIND=dp)                                      :: fin, fout, t1, t2, trace, zval
     167          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: fdiag
     168          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: mcharge
     169          34 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: moments
     170          34 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: occupation_numbers
     171          34 :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: smat_kind
     172          34 :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:, :) :: oce_atom
     173             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     174             :       TYPE(cp_fm_type)                                   :: p_orb_ref, p_ref_orb, smo
     175          34 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: c_loc_orb, ciao, cloc, cvec, iao_coef
     176          34 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: zij_atom
     177             :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     178          34 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: sref, sro, sxo
     179          34 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s
     180             :       TYPE(dbcsr_type)                                   :: dmat
     181             :       TYPE(dbcsr_type), POINTER                          :: smat
     182             :       TYPE(dft_control_type), POINTER                    :: dft_control
     183          34 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: oce_basis_set_list, orb_basis_set_list, &
     184          34 :                                                             ref_basis_set_list
     185             :       TYPE(gto_basis_set_type), POINTER                  :: ocebasis, orbbasis, refbasis
     186          34 :       TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:)       :: mo_iao, mo_loc
     187          34 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: my_mos
     188             :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     189          34 :          POINTER                                         :: sro_list, srr_list, sxo_list
     190          34 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     191          34 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     192             :       TYPE(qs_kind_type), POINTER                        :: qs_kind
     193             :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     194             :       TYPE(section_vals_type), POINTER                   :: iao_cubes_section, iao_molden_section, &
     195             :                                                             ibo_cc_section, ibo_cubes_section, &
     196             :                                                             ibo_molden_section
     197             : 
     198             :       ! only do IAO analysis if explicitly requested
     199           0 :       CPASSERT(iao_env%do_iao)
     200             : 
     201             :       ! k-points?
     202          34 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     203          34 :       nspin = dft_control%nspins
     204          34 :       nimages = dft_control%nimages
     205          34 :       IF (nimages > 1) THEN
     206           0 :          IF (unit_nr > 0) THEN
     207             :             WRITE (UNIT=unit_nr, FMT="(T2,A)") &
     208           0 :                "K-Points: Intrinsic Atomic Orbitals Analysis not available."
     209             :          END IF
     210             :       END IF
     211           0 :       IF (nimages > 1) RETURN
     212             : 
     213          34 :       CALL timeset(routineN, handle)
     214             : 
     215          34 :       IF (unit_nr > 0) THEN
     216          17 :          WRITE (unit_nr, '(/,T2,A)') '!-----------------------------------------------------------------------------!'
     217          17 :          WRITE (UNIT=unit_nr, FMT="(T24,A)") "INTRINSIC ATOMIC ORBITALS ANALYSIS"
     218          17 :          WRITE (UNIT=unit_nr, FMT="(T13,A)") "G. Knizia, J. Chem. Theory Comput. 9, 4834-4843 (2013)"
     219          17 :          WRITE (unit_nr, '(T2,A)') '!-----------------------------------------------------------------------------!'
     220             :       END IF
     221          34 :       CALL cite_reference(Knizia2013)
     222             : 
     223             :       ! input sections
     224          34 :       iao_molden_section => iao_env%iao_molden_section
     225          34 :       iao_cubes_section => iao_env%iao_cubes_section
     226          34 :       ibo_molden_section => iao_env%ibo_molden_section
     227          34 :       ibo_cubes_section => iao_env%ibo_cubes_section
     228          34 :       ibo_cc_section => iao_env%ibo_cc_section
     229             : 
     230             :       !
     231          34 :       molden_iao = .FALSE.
     232          34 :       IF (ASSOCIATED(iao_molden_section)) THEN
     233           4 :          CALL section_vals_get(iao_molden_section, explicit=molden_iao)
     234             :       END IF
     235          34 :       cubes_iao = .FALSE.
     236          34 :       IF (ASSOCIATED(iao_cubes_section)) THEN
     237           4 :          CALL section_vals_get(iao_cubes_section, explicit=cubes_iao)
     238             :       END IF
     239          34 :       molden_ibo = .FALSE.
     240          34 :       IF (ASSOCIATED(ibo_molden_section)) THEN
     241           4 :          CALL section_vals_get(ibo_molden_section, explicit=molden_ibo)
     242             :       END IF
     243          34 :       cubes_ibo = .FALSE.
     244          34 :       IF (ASSOCIATED(ibo_cubes_section)) THEN
     245           4 :          CALL section_vals_get(ibo_cubes_section, explicit=cubes_ibo)
     246             :       END IF
     247             : 
     248             :       ! check for or generate reference basis
     249          34 :       CALL create_minbas_set(qs_env, unit_nr)
     250             : 
     251             :       ! overlap matrices
     252          34 :       CALL get_qs_env(qs_env, matrix_s_kp=matrix_s)
     253          34 :       smat => matrix_s(1, 1)%matrix
     254             :       !
     255          34 :       CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
     256          34 :       nkind = SIZE(qs_kind_set)
     257         276 :       ALLOCATE (ref_basis_set_list(nkind), orb_basis_set_list(nkind))
     258         104 :       DO ikind = 1, nkind
     259          70 :          qs_kind => qs_kind_set(ikind)
     260          70 :          NULLIFY (ref_basis_set_list(ikind)%gto_basis_set)
     261          70 :          NULLIFY (orb_basis_set_list(ikind)%gto_basis_set)
     262          70 :          NULLIFY (refbasis, orbbasis)
     263          70 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=orbbasis, basis_type="ORB")
     264          70 :          IF (ASSOCIATED(orbbasis)) orb_basis_set_list(ikind)%gto_basis_set => orbbasis
     265          70 :          CALL get_qs_kind(qs_kind=qs_kind, basis_set=refbasis, basis_type="MIN")
     266         104 :          IF (ASSOCIATED(refbasis)) ref_basis_set_list(ikind)%gto_basis_set => refbasis
     267             :       END DO
     268             : 
     269             :       ! neighbor lists
     270          34 :       NULLIFY (srr_list, sro_list)
     271          34 :       CALL setup_neighbor_list(srr_list, ref_basis_set_list, qs_env=qs_env)
     272          34 :       CALL setup_neighbor_list(sro_list, ref_basis_set_list, orb_basis_set_list, qs_env=qs_env)
     273             : 
     274             :       ! Srr and Sro overlap matrices
     275          34 :       NULLIFY (sref, sro)
     276          34 :       CALL get_qs_env(qs_env, ks_env=ks_env)
     277             :       CALL build_overlap_matrix_simple(ks_env, sref, &
     278          34 :                                        ref_basis_set_list, ref_basis_set_list, srr_list)
     279             :       CALL build_overlap_matrix_simple(ks_env, sro, &
     280          34 :                                        ref_basis_set_list, orb_basis_set_list, sro_list)
     281             :       !
     282          34 :       IF (PRESENT(mos)) THEN
     283          30 :          my_mos => mos
     284             :       ELSE
     285           4 :          CALL get_qs_env(qs_env, mos=my_mos)
     286             :       END IF
     287          34 :       CALL get_mo_set(my_mos(1), mo_coeff=mo_coeff)
     288          34 :       CALL dbcsr_get_info(sro(1)%matrix, nfullrows_total=nref, nfullcols_total=nao)
     289             : 
     290             :       ! Projectors
     291          34 :       NULLIFY (fm_struct)
     292             :       CALL cp_fm_struct_create(fm_struct, context=mo_coeff%matrix_struct%context, nrow_global=nref, &
     293          34 :                                ncol_global=nao, para_env=mo_coeff%matrix_struct%para_env)
     294          34 :       CALL cp_fm_create(p_ref_orb, fm_struct)
     295          34 :       CALL cp_fm_struct_release(fm_struct)
     296          34 :       NULLIFY (fm_struct)
     297             :       CALL cp_fm_struct_create(fm_struct, context=mo_coeff%matrix_struct%context, nrow_global=nao, &
     298          34 :                                ncol_global=nref, para_env=mo_coeff%matrix_struct%para_env)
     299          34 :       CALL cp_fm_create(p_orb_ref, fm_struct)
     300          34 :       CALL cp_fm_struct_release(fm_struct)
     301             :       !
     302          34 :       CALL iao_projectors(smat, sref(1)%matrix, sro(1)%matrix, p_orb_ref, p_ref_orb, iao_env%eps_svd)
     303             : 
     304             :       ! occupied orbitals, orbitals considered for IAO generation
     305          34 :       nocc(1:2) = 0
     306          70 :       DO ispin = 1, nspin
     307             :          CALL get_mo_set(my_mos(ispin), mo_coeff=mo_coeff, nmo=norb, uniform_occupation=uniform_occupation, &
     308          36 :                          occupation_numbers=occupation_numbers)
     309          36 :          IF (uniform_occupation) THEN
     310          34 :             nvec = norb
     311             :          ELSE
     312           2 :             nvec = 0
     313          46 :             DO i = 1, norb
     314          46 :                IF (occupation_numbers(i) > iao_env%eps_occ) THEN
     315          44 :                   nvec = i
     316             :                ELSE
     317             :                   EXIT
     318             :                END IF
     319             :             END DO
     320             :          END IF
     321         106 :          nocc(ispin) = nvec
     322             :       END DO
     323             :       ! generate IAOs
     324         208 :       ALLOCATE (iao_coef(nspin), cvec(nspin))
     325          70 :       DO ispin = 1, nspin
     326          36 :          CALL get_mo_set(my_mos(ispin), mo_coeff=mo_coeff)
     327          36 :          nvec = nocc(ispin)
     328          70 :          IF (nvec > 0) THEN
     329          36 :             NULLIFY (fm_struct)
     330          36 :             CALL cp_fm_struct_create(fm_struct, ncol_global=nvec, template_fmstruct=mo_coeff%matrix_struct)
     331          36 :             CALL cp_fm_create(cvec(ispin), fm_struct)
     332          36 :             CALL cp_fm_struct_release(fm_struct)
     333          36 :             CALL cp_fm_to_fm(mo_coeff, cvec(ispin), nvec)
     334             :             !
     335          36 :             NULLIFY (fm_struct)
     336          36 :             CALL cp_fm_struct_create(fm_struct, ncol_global=nref, template_fmstruct=mo_coeff%matrix_struct)
     337          36 :             CALL cp_fm_create(iao_coef(ispin), fm_struct)
     338          36 :             CALL cp_fm_struct_release(fm_struct)
     339             :             !
     340          36 :             CALL intrinsic_ao_calc(smat, p_orb_ref, p_ref_orb, cvec(ispin), iao_coef(ispin))
     341             :          END IF
     342             :       END DO
     343             :       !
     344          34 :       IF (iao_env%do_charges) THEN
     345             :          ! MOs in IAO basis
     346         104 :          ALLOCATE (ciao(nspin))
     347          70 :          DO ispin = 1, nspin
     348          36 :             CALL get_mo_set(my_mos(ispin), mo_coeff=mo_coeff, nao=nao, nmo=norb)
     349          36 :             CALL cp_fm_create(smo, mo_coeff%matrix_struct)
     350          36 :             NULLIFY (fm_struct)
     351          36 :             CALL cp_fm_struct_create(fm_struct, nrow_global=nref, template_fmstruct=mo_coeff%matrix_struct)
     352          36 :             CALL cp_fm_create(ciao(ispin), fm_struct)
     353          36 :             CALL cp_fm_struct_release(fm_struct)
     354             :             ! CIAO = A(T)*S*C
     355          36 :             CALL cp_dbcsr_sm_fm_multiply(smat, mo_coeff, smo, ncol=norb)
     356          36 :             CALL parallel_gemm('T', 'N', nref, norb, nao, 1.0_dp, iao_coef(ispin), smo, 0.0_dp, ciao(ispin))
     357         106 :             CALL cp_fm_release(smo)
     358             :          END DO
     359             :          !
     360             :          ! population analysis
     361          34 :          IF (unit_nr > 0) THEN
     362          17 :             WRITE (unit_nr, '(/,T2,A)') 'Intrinsic AO Population Analysis '
     363             :          END IF
     364          34 :          CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, natom=natom)
     365          34 :          CALL get_ks_env(ks_env=ks_env, particle_set=particle_set)
     366         136 :          ALLOCATE (mcharge(natom, nspin))
     367          34 :          CALL dbcsr_get_info(sref(1)%matrix, nfullrows_total=nref)
     368          70 :          DO ispin = 1, nspin
     369             :             CALL get_mo_set(my_mos(ispin), &
     370             :                             uniform_occupation=uniform_occupation, &
     371          36 :                             occupation_numbers=occupation_numbers)
     372             :             ! diagonal block matrix
     373          36 :             CALL dbcsr_create(dmat, template=sref(1)%matrix)
     374          36 :             CALL dbcsr_reserve_diag_blocks(dmat)
     375             :             !
     376          36 :             CALL iao_calculate_dmat(ciao(ispin), dmat, occupation_numbers, uniform_occupation)
     377          36 :             CALL dbcsr_trace(dmat, trace)
     378          36 :             IF (unit_nr > 0) THEN
     379          18 :                WRITE (unit_nr, '(T2,A,I2,T66,F15.4)') 'Number of Electrons: Trace(Piao) Spin ', ispin, trace
     380             :             END IF
     381          36 :             CALL iao_charges(dmat, mcharge(:, ispin))
     382         142 :             CALL dbcsr_release(dmat)
     383             :          END DO
     384             :          CALL print_atomic_charges(particle_set, qs_kind_set, unit_nr, "Intrinsic Atomic Orbital Charges", &
     385          34 :                                    electronic_charges=mcharge)
     386          34 :          DEALLOCATE (mcharge)
     387          68 :          CALL cp_fm_release(ciao)
     388             :       END IF
     389             :       !
     390             :       ! Deallocate the neighbor list structure
     391          34 :       CALL release_neighbor_list_sets(srr_list)
     392          34 :       CALL release_neighbor_list_sets(sro_list)
     393          34 :       IF (ASSOCIATED(sref)) CALL dbcsr_deallocate_matrix_set(sref)
     394          34 :       IF (ASSOCIATED(sro)) CALL dbcsr_deallocate_matrix_set(sro)
     395          34 :       CALL cp_fm_release(p_ref_orb)
     396          34 :       CALL cp_fm_release(p_orb_ref)
     397          34 :       CALL cp_fm_release(cvec)
     398          34 :       DEALLOCATE (orb_basis_set_list)
     399             :       !
     400          34 :       IF (iao_env%do_oce) THEN
     401             :          ! generate OCE basis
     402           4 :          IF (unit_nr > 0) THEN
     403           2 :             WRITE (unit_nr, '(T2,A)') "IAO One-Center Expansion: OCE Basis Set"
     404             :          END IF
     405           4 :          CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
     406           4 :          nkind = SIZE(qs_kind_set)
     407          40 :          ALLOCATE (oce_basis_set_list(nkind), orb_basis_set_list(nkind))
     408          16 :          DO ikind = 1, nkind
     409          12 :             qs_kind => qs_kind_set(ikind)
     410          12 :             NULLIFY (orb_basis_set_list(ikind)%gto_basis_set)
     411          12 :             NULLIFY (orbbasis)
     412          12 :             CALL get_qs_kind(qs_kind=qs_kind, basis_set=orbbasis, basis_type="ORB")
     413          16 :             IF (ASSOCIATED(orbbasis)) orb_basis_set_list(ikind)%gto_basis_set => orbbasis
     414             :          END DO
     415          16 :          DO ikind = 1, nkind
     416          12 :             orbbasis => orb_basis_set_list(ikind)%gto_basis_set
     417          12 :             CPASSERT(ASSOCIATED(orbbasis))
     418          12 :             NULLIFY (ocebasis)
     419          12 :             CALL create_oce_basis(ocebasis, orbbasis, iao_env%lmax_oce, iao_env%nbas_oce)
     420          12 :             CALL init_orb_basis_set(ocebasis)
     421          12 :             CALL init_interaction_radii_orb_basis(ocebasis, dft_control%qs_control%eps_pgf_orb)
     422          12 :             oce_basis_set_list(ikind)%gto_basis_set => ocebasis
     423          16 :             IF (unit_nr > 0) THEN
     424           6 :                qs_kind => qs_kind_set(ikind)
     425           6 :                CALL get_qs_kind(qs_kind, zeff=zval, element_symbol=element_symbol)
     426           6 :                CALL get_gto_basis_set(ocebasis, name=bname, nsgf=nsgf)
     427           6 :                WRITE (unit_nr, '(T2,A,A,T14,A,I4,T40,A,A30)') "Kind: ", element_symbol, "NBasFun: ", nsgf, &
     428          12 :                   "OCE Basis: ", ADJUSTL(TRIM(bname))
     429             :             END IF
     430             :          END DO
     431           4 :          IF (unit_nr > 0) WRITE (unit_nr, *)
     432             :          ! OCE basis overlap
     433          24 :          ALLOCATE (smat_kind(nkind))
     434          16 :          DO ikind = 1, nkind
     435          12 :             ocebasis => oce_basis_set_list(ikind)%gto_basis_set
     436          12 :             CALL get_gto_basis_set(gto_basis_set=ocebasis, nsgf=nsgf)
     437          52 :             ALLOCATE (smat_kind(ikind)%array(nsgf, nsgf))
     438             :          END DO
     439           4 :          CALL oce_overlap_matrix(smat_kind, oce_basis_set_list)
     440             :          ! overlap between IAO OCE basis and orbital basis
     441           4 :          NULLIFY (sxo, sxo_list)
     442           4 :          CALL setup_neighbor_list(sxo_list, oce_basis_set_list, orb_basis_set_list, qs_env=qs_env)
     443           4 :          CALL get_qs_env(qs_env, ks_env=ks_env)
     444             :          CALL build_overlap_matrix_simple(ks_env, sxo, &
     445           4 :                                           oce_basis_set_list, orb_basis_set_list, sxo_list)
     446             :          !
     447             :          ! One Center Expansion of IAOs
     448           4 :          CALL get_qs_env(qs_env=qs_env, natom=natom)
     449          36 :          ALLOCATE (oce_atom(natom, nspin))
     450           4 :          CALL iao_oce_expansion(qs_env, oce_basis_set_list, smat_kind, sxo, iao_coef, oce_atom, unit_nr)
     451             :          !
     452          16 :          DO ikind = 1, nkind
     453          12 :             ocebasis => oce_basis_set_list(ikind)%gto_basis_set
     454          16 :             CALL deallocate_gto_basis_set(ocebasis)
     455             :          END DO
     456           4 :          DEALLOCATE (oce_basis_set_list, orb_basis_set_list)
     457             :          !
     458           4 :          CALL release_neighbor_list_sets(sxo_list)
     459           4 :          IF (ASSOCIATED(sxo)) CALL dbcsr_deallocate_matrix_set(sxo)
     460          16 :          DO ikind = 1, nkind
     461          16 :             DEALLOCATE (smat_kind(ikind)%array)
     462             :          END DO
     463           4 :          DEALLOCATE (smat_kind)
     464           8 :          DO ispin = 1, nspin
     465          24 :             DO iatom = 1, natom
     466          20 :                DEALLOCATE (oce_atom(iatom, ispin)%array)
     467             :             END DO
     468             :          END DO
     469           4 :          DEALLOCATE (oce_atom)
     470             :       END IF
     471             :       !
     472          34 :       IF (molden_iao) THEN
     473             :          ! Print basis functions: molden file
     474           4 :          CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
     475           4 :          CALL get_ks_env(ks_env=ks_env, particle_set=particle_set)
     476           4 :          IF (unit_nr > 0) THEN
     477           2 :             WRITE (unit_nr, '(T2,A)') '  Write IAO in MOLDEN Format'
     478             :          END IF
     479          16 :          ALLOCATE (mo_iao(nspin))
     480           8 :          DO ispin = 1, nspin
     481           4 :             CALL get_mo_set(my_mos(ispin), nao=nao)
     482           4 :             CALL allocate_mo_set(mo_iao(ispin), nao, nref, nref, 0.0_dp, 1.0_dp, 0.0_dp)
     483           4 :             CALL init_mo_set(mo_iao(ispin), fm_ref=iao_coef(ispin), name="iao_set")
     484           4 :             CALL cp_fm_to_fm(iao_coef(ispin), mo_iao(ispin)%mo_coeff)
     485           4 :             CALL set_mo_set(mo_iao(ispin), homo=nref)
     486          56 :             mo_iao(ispin)%occupation_numbers = 1.0_dp
     487             :          END DO
     488             :          ! Print IAO basis functions: molden format
     489           4 :          CALL write_mos_molden(mo_iao, qs_kind_set, particle_set, iao_molden_section)
     490           8 :          DO ispin = 1, nspin
     491           8 :             CALL deallocate_mo_set(mo_iao(ispin))
     492             :          END DO
     493           4 :          DEALLOCATE (mo_iao)
     494             :       END IF
     495          34 :       IF (cubes_iao) THEN
     496           4 :          IF (unit_nr > 0) THEN
     497           2 :             WRITE (unit_nr, '(T2,A)') '  Write IAO as CUBE Files'
     498             :          END IF
     499             :          ! Print basis functions: cube file
     500           4 :          CALL print_iao_cubes(qs_env, iao_cubes_section, iao_coef, ref_basis_set_list)
     501             :       END IF
     502             :       !
     503             :       ! Intrinsic bond orbitals
     504          34 :       IF (iao_env%do_bondorbitals) THEN
     505          32 :          IF (unit_nr > 0) THEN
     506          16 :             WRITE (unit_nr, '(/,T2,A)') 'Intrinsic Bond Orbital Generation'
     507             :          END IF
     508             :          ! MOs in IAO basis -> ciao
     509          98 :          ALLOCATE (ciao(nspin))
     510          66 :          DO ispin = 1, nspin
     511          34 :             CALL get_mo_set(my_mos(ispin), mo_coeff=mo_coeff, nao=nao, nmo=norb)
     512          34 :             CALL cp_fm_create(smo, mo_coeff%matrix_struct)
     513          34 :             NULLIFY (fm_struct)
     514          34 :             CALL cp_fm_struct_create(fm_struct, nrow_global=nref, template_fmstruct=mo_coeff%matrix_struct)
     515          34 :             CALL cp_fm_create(ciao(ispin), fm_struct)
     516          34 :             CALL cp_fm_struct_release(fm_struct)
     517             :             ! CIAO = A(T)*S*C
     518          34 :             CALL cp_dbcsr_sm_fm_multiply(smat, mo_coeff, smo, ncol=norb)
     519          34 :             CALL parallel_gemm('T', 'N', nref, norb, nao, 1.0_dp, iao_coef(ispin), smo, 0.0_dp, ciao(ispin))
     520         100 :             CALL cp_fm_release(smo)
     521             :          END DO
     522             :          !
     523             :          ! localize occupied orbitals nocc(ispin), see IAO generation
     524             :          !
     525         164 :          ALLOCATE (cloc(nspin), c_loc_orb(nspin))
     526          66 :          DO ispin = 1, nspin
     527          34 :             NULLIFY (fm_struct)
     528             :             CALL cp_fm_struct_create(fm_struct, ncol_global=nocc(ispin), &
     529          34 :                                      template_fmstruct=ciao(ispin)%matrix_struct)
     530          34 :             CALL cp_fm_create(cloc(ispin), fm_struct)
     531          34 :             CALL cp_fm_struct_release(fm_struct)
     532          66 :             CALL cp_fm_to_fm(ciao(ispin), cloc(ispin), ncol=nocc(ispin))
     533             :          END DO
     534          32 :          CALL cp_fm_release(ciao)
     535          32 :          CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, natom=natom)
     536         160 :          ALLOCATE (first_sgf(natom), last_sgf(natom), nsgfat(natom))
     537          32 :          CALL get_ks_env(ks_env=ks_env, particle_set=particle_set)
     538             :          CALL get_particle_set(particle_set, qs_kind_set, first_sgf=first_sgf, last_sgf=last_sgf, &
     539          32 :                                nsgf=nsgfat, basis=ref_basis_set_list)
     540             : 
     541          32 :          IF (iao_env%loc_operator /= do_iaoloc_pm2) THEN
     542           0 :             CPABORT("IAO localization operator NYA")
     543             :          END IF
     544          32 :          IF (iao_env%eloc_function /= do_iaoloc_enone) THEN
     545           0 :             CPABORT("IAO energy weight localization NYA")
     546             :          END IF
     547             : 
     548          66 :          DO ispin = 1, nspin
     549          34 :             nvec = nocc(ispin)
     550          66 :             IF (nvec > 0) THEN
     551         326 :                ALLOCATE (zij_atom(natom, 1), fdiag(nvec))
     552          34 :                NULLIFY (fm_struct)
     553             :                CALL cp_fm_struct_create(fm_struct, nrow_global=nvec, ncol_global=nvec, &
     554          34 :                                         template_fmstruct=cloc(ispin)%matrix_struct)
     555         156 :                DO iatom = 1, natom
     556         122 :                   CALL cp_fm_create(zij_atom(iatom, 1), fm_struct)
     557         122 :                   isgf = first_sgf(iatom)
     558             :                   CALL parallel_gemm('T', 'N', nvec, nvec, nsgfat(iatom), 1.0_dp, cloc(ispin), cloc(ispin), &
     559             :                                      0.0_dp, zij_atom(iatom, 1), &
     560         156 :                                      a_first_col=1, a_first_row=isgf, b_first_col=1, b_first_row=isgf)
     561             :                END DO
     562          34 :                CALL cp_fm_struct_release(fm_struct)
     563             :                !
     564          34 :                t1 = m_walltime()
     565          34 :                order = 4
     566          34 :                fin = 0.0_dp
     567         156 :                DO iatom = 1, natom
     568         122 :                   CALL cp_fm_get_diag(zij_atom(iatom, 1), fdiag)
     569        1028 :                   fin = fin + SUM(fdiag**order)
     570             :                END DO
     571          34 :                fin = fin**(1._dp/order)
     572             :                ! QR localization
     573          34 :                CALL scdm_qrfact(cloc(ispin))
     574             :                !
     575         156 :                DO iatom = 1, natom
     576         122 :                   isgf = first_sgf(iatom)
     577             :                   CALL parallel_gemm('T', 'N', nvec, nvec, nsgfat(iatom), 1.0_dp, cloc(ispin), cloc(ispin), &
     578             :                                      0.0_dp, zij_atom(iatom, 1), &
     579         156 :                                      a_first_col=1, a_first_row=isgf, b_first_col=1, b_first_row=isgf)
     580             :                END DO
     581          34 :                fout = 0.0_dp
     582         156 :                DO iatom = 1, natom
     583         122 :                   CALL cp_fm_get_diag(zij_atom(iatom, 1), fdiag)
     584        1028 :                   fout = fout + SUM(fdiag**order)
     585             :                END DO
     586          34 :                fout = fout**(1._dp/order)
     587          34 :                DEALLOCATE (fdiag)
     588          34 :                t2 = m_walltime()
     589          34 :                IF (unit_nr > 0) THEN
     590             :                   WRITE (unit_nr, '(T2,A,F14.8,A,F14.8,A,F8.2)') &
     591          17 :                      'SCDM pre-localization: fin=', fin, "  fout=", fout, "    Time=", t2 - t1
     592             :                END IF
     593             :                !
     594          34 :                CALL pm_localization(zij_atom, cloc(ispin), order, 1.E-12_dp, unit_nr)
     595             :                !
     596          34 :                CALL cp_fm_release(zij_atom)
     597          34 :                CALL get_mo_set(my_mos(ispin), nao=nao)
     598          34 :                NULLIFY (fm_struct)
     599             :                CALL cp_fm_struct_create(fm_struct, nrow_global=nao, &
     600          34 :                                         template_fmstruct=cloc(ispin)%matrix_struct)
     601          34 :                CALL cp_fm_create(c_loc_orb(ispin), fm_struct)
     602          34 :                CALL cp_fm_struct_release(fm_struct)
     603             :                CALL parallel_gemm('N', 'N', nao, nvec, nref, 1.0_dp, iao_coef(ispin), cloc(ispin), &
     604          68 :                                   0.0_dp, c_loc_orb(ispin))
     605             :             END IF
     606             :          END DO
     607          32 :          DEALLOCATE (first_sgf, last_sgf, nsgfat)
     608          32 :          CALL cp_fm_release(cloc)
     609             :          !
     610          32 :          IF (iao_env%do_center) THEN
     611          32 :             IF (unit_nr > 0) THEN
     612          16 :                WRITE (unit_nr, '(T2,A)') '  Calculate Localized Orbital Centers and Spread'
     613          16 :                IF (iao_env%pos_periodic) THEN
     614          13 :                   WRITE (unit_nr, '(T2,A)') '    Use Berry Phase Position Operator'
     615             :                ELSE
     616           3 :                   WRITE (unit_nr, '(T2,A)') '    Use Local Position Operator'
     617             :                END IF
     618             :             END IF
     619          96 :             nvec = MAXVAL(nocc)
     620             :             ! x  y  z  m2(1)  m2(2)
     621         128 :             ALLOCATE (moments(5, nvec, nspin))
     622        1230 :             moments = 0.0_dp
     623          32 :             IF (iao_env%pos_periodic) THEN
     624          26 :                CALL center_spread_berry(qs_env, c_loc_orb, moments)
     625             :             ELSE
     626           6 :                CALL center_spread_loc(qs_env, c_loc_orb, moments)
     627             :             END IF
     628             :             !
     629          32 :             IF (ASSOCIATED(ibo_cc_section)) THEN
     630           4 :                CALL print_center_spread(moments, nocc, ibo_cc_section)
     631             :             END IF
     632             :             !
     633          32 :             IF (PRESENT(bond_centers)) THEN
     634          28 :                nx = SIZE(bond_centers, 1)
     635          28 :                no = SIZE(bond_centers, 2)
     636          28 :                ns = SIZE(bond_centers, 3)
     637          28 :                CPASSERT(no >= nvec)
     638          28 :                CPASSERT(ns == nspin)
     639          28 :                CPASSERT(nx >= 3)
     640          28 :                nx = MIN(nx, 5)
     641        1054 :                bond_centers(1:nx, 1:nvec, 1:ns) = moments(1:nx, 1:nvec, 1:ns)
     642             :             END IF
     643          32 :             DEALLOCATE (moments)
     644             :          END IF
     645             :          !
     646          32 :          IF (molden_ibo) THEN
     647           4 :             CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
     648           4 :             CALL get_ks_env(ks_env=ks_env, particle_set=particle_set)
     649           4 :             IF (unit_nr > 0) THEN
     650           2 :                WRITE (unit_nr, '(T2,A)') '  Write IBO in MOLDEN Format'
     651             :             END IF
     652          16 :             ALLOCATE (mo_loc(nspin))
     653           8 :             DO ispin = 1, nspin
     654           4 :                CALL get_mo_set(my_mos(ispin), nao=nao)
     655           4 :                nvec = nocc(ispin)
     656           4 :                CALL allocate_mo_set(mo_loc(ispin), nao, nvec, nvec, 0.0_dp, 1.0_dp, 0.0_dp)
     657           4 :                CALL init_mo_set(mo_loc(ispin), fm_ref=c_loc_orb(ispin), name="ibo_orb")
     658           4 :                CALL cp_fm_to_fm(c_loc_orb(ispin), mo_loc(ispin)%mo_coeff)
     659           4 :                CALL set_mo_set(mo_loc(ispin), homo=nvec)
     660          40 :                mo_loc(ispin)%occupation_numbers = 1.0_dp
     661             :             END DO
     662             :             ! Print IBO functions: molden format
     663           4 :             CALL write_mos_molden(mo_loc, qs_kind_set, particle_set, ibo_molden_section)
     664           8 :             DO ispin = 1, nspin
     665           8 :                CALL deallocate_mo_set(mo_loc(ispin))
     666             :             END DO
     667           4 :             DEALLOCATE (mo_loc)
     668             :          END IF
     669             :          !
     670          32 :          IF (cubes_ibo) THEN
     671           4 :             IF (unit_nr > 0) THEN
     672           2 :                WRITE (unit_nr, '(T2,A)') '  Write IBO on CUBE files'
     673             :             END IF
     674             :             ! Print localized orbital functions: cube file
     675           4 :             CALL print_ibo_cubes(qs_env, ibo_cubes_section, c_loc_orb)
     676             :          END IF
     677             :          !
     678          32 :          IF (PRESENT(mos) .AND. ALLOCATED(c_loc_orb)) THEN
     679             :             ! c_loc_orb -> mos
     680          58 :             DO ispin = 1, nspin
     681          30 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
     682          30 :                nvec = nocc(ispin)
     683          58 :                CALL cp_fm_to_fm(c_loc_orb(ispin), mo_coeff, ncol=nvec)
     684             :             END DO
     685             :          END IF
     686          32 :          CALL cp_fm_release(c_loc_orb)
     687             :       END IF
     688          34 :       DEALLOCATE (ref_basis_set_list)
     689             : 
     690          34 :       IF (PRESENT(c_iao_coef)) THEN
     691          30 :          CALL cp_fm_release(c_iao_coef)
     692          92 :          ALLOCATE (c_iao_coef(nspin))
     693          62 :          DO ispin = 1, nspin
     694          32 :             CALL cp_fm_create(c_iao_coef(ispin), iao_coef(ispin)%matrix_struct)
     695          62 :             CALL cp_fm_to_fm(iao_coef(ispin), c_iao_coef(ispin))
     696             :          END DO
     697             :       END IF
     698          34 :       CALL cp_fm_release(iao_coef)
     699             : 
     700          34 :       IF (unit_nr > 0) THEN
     701             :          WRITE (unit_nr, '(T2,A)') &
     702          17 :             '!----------------------------END OF IAO ANALYSIS------------------------------!'
     703             :       END IF
     704             : 
     705          34 :       CALL timestop(handle)
     706             : 
     707         204 :    END SUBROUTINE iao_wfn_analysis
     708             : 
     709             : ! **************************************************************************************************
     710             : !> \brief Computes projector matrices for ref to orb basis and reverse
     711             : !> \param smat ...
     712             : !> \param sref ...
     713             : !> \param s_r_o ...
     714             : !> \param p_o_r ...
     715             : !> \param p_r_o ...
     716             : !> \param eps_svd ...
     717             : ! **************************************************************************************************
     718         238 :    SUBROUTINE iao_projectors(smat, sref, s_r_o, p_o_r, p_r_o, eps_svd)
     719             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: smat, sref, s_r_o
     720             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: p_o_r, p_r_o
     721             :       REAL(KIND=dp), INTENT(IN)                          :: eps_svd
     722             : 
     723             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'iao_projectors'
     724             : 
     725             :       INTEGER                                            :: handle, norb, nref
     726             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     727             :       TYPE(cp_fm_type)                                   :: fm_inv, fm_s, fm_sro
     728             : 
     729          34 :       CALL timeset(routineN, handle)
     730             : 
     731          34 :       CALL cp_fm_get_info(p_r_o, nrow_global=nref, ncol_global=norb)
     732          34 :       CALL cp_fm_create(fm_sro, p_r_o%matrix_struct)
     733          34 :       CALL copy_dbcsr_to_fm(s_r_o, fm_sro)
     734             : 
     735          34 :       NULLIFY (fm_struct)
     736             :       CALL cp_fm_struct_create(fm_struct, nrow_global=norb, ncol_global=norb, &
     737          34 :                                template_fmstruct=p_r_o%matrix_struct)
     738          34 :       CALL cp_fm_create(fm_s, fm_struct, name="smat")
     739          34 :       CALL cp_fm_create(fm_inv, fm_struct, name="sinv")
     740          34 :       CALL cp_fm_struct_release(fm_struct)
     741          34 :       CALL copy_dbcsr_to_fm(smat, fm_s)
     742          34 :       CALL cp_fm_invert(fm_s, fm_inv, eps_svd=eps_svd)
     743          34 :       CALL parallel_gemm('N', 'T', norb, nref, norb, 1.0_dp, fm_inv, fm_sro, 0.0_dp, p_o_r)
     744          34 :       CALL cp_fm_release(fm_s)
     745          34 :       CALL cp_fm_release(fm_inv)
     746             : 
     747          34 :       NULLIFY (fm_struct)
     748             :       CALL cp_fm_struct_create(fm_struct, nrow_global=nref, ncol_global=nref, &
     749          34 :                                template_fmstruct=p_r_o%matrix_struct)
     750          34 :       CALL cp_fm_create(fm_s, fm_struct, name="sref")
     751          34 :       CALL cp_fm_create(fm_inv, fm_struct, name="sinv")
     752          34 :       CALL cp_fm_struct_release(fm_struct)
     753          34 :       CALL copy_dbcsr_to_fm(sref, fm_s)
     754          34 :       CALL cp_fm_invert(fm_s, fm_inv, eps_svd=eps_svd)
     755          34 :       CALL parallel_gemm('N', 'N', nref, norb, nref, 1.0_dp, fm_inv, fm_sro, 0.0_dp, p_r_o)
     756          34 :       CALL cp_fm_release(fm_s)
     757          34 :       CALL cp_fm_release(fm_inv)
     758             : 
     759          34 :       CALL cp_fm_release(fm_sro)
     760             : 
     761          34 :       CALL timestop(handle)
     762             : 
     763          34 :    END SUBROUTINE iao_projectors
     764             : 
     765             : ! **************************************************************************************************
     766             : !> \brief Computes intrinsic orbitals for a given MO vector set
     767             : !> \param smat ...
     768             : !> \param p_o_r ...
     769             : !> \param p_r_o ...
     770             : !> \param cvec ...
     771             : !> \param avec ...
     772             : ! **************************************************************************************************
     773         324 :    SUBROUTINE intrinsic_ao_calc(smat, p_o_r, p_r_o, cvec, avec)
     774             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: smat
     775             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: p_o_r, p_r_o, cvec, avec
     776             : 
     777             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'intrinsic_ao_calc'
     778             : 
     779             :       INTEGER                                            :: handle, nao, norb, nref
     780             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     781             :       TYPE(cp_fm_type)                                   :: ctvec, pc, sc, sct, vec1
     782             : 
     783          36 :       CALL timeset(routineN, handle)
     784             : 
     785             :       ! number of orbitals
     786          36 :       CALL cp_fm_get_info(cvec, ncol_global=norb)
     787             :       ! basis set sizes
     788          36 :       CALL cp_fm_get_info(p_r_o, nrow_global=nref, ncol_global=nao)
     789             :       ! temp array
     790          36 :       NULLIFY (fm_struct)
     791             :       CALL cp_fm_struct_create(fm_struct, nrow_global=nref, ncol_global=norb, &
     792          36 :                                template_fmstruct=cvec%matrix_struct)
     793          36 :       CALL cp_fm_create(pc, fm_struct)
     794          36 :       CALL cp_fm_struct_release(fm_struct)
     795             :       ! CT = orth(Por.Pro.C)
     796          36 :       CALL parallel_gemm('N', 'N', nref, norb, nao, 1.0_dp, p_r_o, cvec, 0.0_dp, pc)
     797          36 :       CALL cp_fm_create(ctvec, cvec%matrix_struct)
     798          36 :       CALL parallel_gemm('N', 'N', nao, norb, nref, 1.0_dp, p_o_r, pc, 0.0_dp, ctvec)
     799          36 :       CALL cp_fm_release(pc)
     800          36 :       CALL make_basis_lowdin(ctvec, norb, smat)
     801             :       ! S*C and S*CT
     802          36 :       CALL cp_fm_create(sc, cvec%matrix_struct)
     803          36 :       CALL cp_dbcsr_sm_fm_multiply(smat, cvec, sc, ncol=norb)
     804          36 :       CALL cp_fm_create(sct, cvec%matrix_struct)
     805          36 :       CALL cp_dbcsr_sm_fm_multiply(smat, ctvec, sct, ncol=norb)
     806             :       CALL cp_fm_struct_create(fm_struct, nrow_global=norb, ncol_global=nref, &
     807          36 :                                template_fmstruct=cvec%matrix_struct)
     808          36 :       CALL cp_fm_create(pc, fm_struct)
     809          36 :       CALL cp_fm_struct_release(fm_struct)
     810             :       ! V1 = (CT*SCT(T))Por
     811          36 :       CALL parallel_gemm('T', 'N', norb, nref, nao, 1.0_dp, sct, p_o_r, 0.0_dp, pc)
     812          36 :       NULLIFY (fm_struct)
     813             :       CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nref, &
     814          36 :                                template_fmstruct=cvec%matrix_struct)
     815          36 :       CALL cp_fm_create(vec1, fm_struct)
     816          36 :       CALL cp_fm_struct_release(fm_struct)
     817          36 :       CALL parallel_gemm('N', 'N', nao, nref, norb, 1.0_dp, ctvec, pc, 0.0_dp, vec1)
     818             :       ! A = C*SC(T)*V1
     819          36 :       CALL parallel_gemm('T', 'N', norb, nref, nao, 1.0_dp, sc, vec1, 0.0_dp, pc)
     820          36 :       CALL parallel_gemm('N', 'N', nao, nref, norb, 1.0_dp, cvec, pc, 0.0_dp, avec)
     821             :       ! V1 = Por - V1
     822          36 :       CALL cp_fm_geadd(1.0_dp, 'N', p_o_r, -1.0_dp, vec1)
     823             :       ! A = A + V1
     824          36 :       CALL cp_fm_geadd(1.0_dp, 'N', vec1, 1.0_dp, avec)
     825             :       ! A = A - C*SC(T)*V1
     826          36 :       CALL parallel_gemm('T', 'N', norb, nref, nao, 1.0_dp, sc, vec1, 0.0_dp, pc)
     827          36 :       CALL parallel_gemm('N', 'N', nao, nref, norb, -1.0_dp, cvec, pc, 1.0_dp, avec)
     828             :       ! A = orth(A)
     829          36 :       CALL make_basis_lowdin(avec, nref, smat)
     830             : 
     831             :       ! clean up
     832          36 :       CALL cp_fm_release(pc)
     833          36 :       CALL cp_fm_release(vec1)
     834          36 :       CALL cp_fm_release(sc)
     835          36 :       CALL cp_fm_release(sct)
     836          36 :       CALL cp_fm_release(ctvec)
     837             : 
     838          36 :       CALL timestop(handle)
     839             : 
     840          36 :    END SUBROUTINE intrinsic_ao_calc
     841             : 
     842             : ! **************************************************************************************************
     843             : !> \brief Calculate the density matrix from fm vectors using occupation numbers
     844             : !> \param cvec ...
     845             : !> \param density_matrix ...
     846             : !> \param occupation ...
     847             : !> \param uniform_occupation ...
     848             : ! **************************************************************************************************
     849         132 :    SUBROUTINE iao_calculate_dmat_diag(cvec, density_matrix, occupation, uniform_occupation)
     850             : 
     851             :       TYPE(cp_fm_type), INTENT(IN)                       :: cvec
     852             :       TYPE(dbcsr_type)                                   :: density_matrix
     853             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: occupation
     854             :       LOGICAL, INTENT(IN)                                :: uniform_occupation
     855             : 
     856             :       CHARACTER(len=*), PARAMETER :: routineN = 'iao_calculate_dmat_diag'
     857             : 
     858             :       INTEGER                                            :: handle, ncol
     859             :       REAL(KIND=dp)                                      :: alpha
     860             :       TYPE(cp_fm_type)                                   :: fm_tmp
     861             : 
     862         132 :       CALL timeset(routineN, handle)
     863             : 
     864         132 :       CALL dbcsr_set(density_matrix, 0.0_dp)
     865             : 
     866         132 :       CALL cp_fm_get_info(cvec, ncol_global=ncol)
     867         132 :       IF (.NOT. uniform_occupation) THEN
     868          98 :          CALL cp_fm_create(fm_tmp, cvec%matrix_struct)
     869          98 :          CALL cp_fm_to_fm(cvec, fm_tmp)
     870          98 :          CALL cp_fm_column_scale(fm_tmp, occupation(1:ncol))
     871          98 :          alpha = 1.0_dp
     872             :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix, &
     873             :                                     matrix_v=cvec, matrix_g=fm_tmp, &
     874          98 :                                     ncol=ncol, alpha=alpha)
     875          98 :          CALL cp_fm_release(fm_tmp)
     876             :       ELSE
     877          34 :          alpha = occupation(1)
     878             :          CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix, &
     879          34 :                                     matrix_v=cvec, ncol=ncol, alpha=alpha)
     880             :       END IF
     881             : 
     882         132 :       CALL timestop(handle)
     883             : 
     884         132 :    END SUBROUTINE iao_calculate_dmat_diag
     885             : 
     886             : ! **************************************************************************************************
     887             : !> \brief Calculate the density matrix from fm vectors using an occupation matrix
     888             : !> \param cvec ...
     889             : !> \param density_matrix ...
     890             : !> \param weight ...
     891             : !> \param occmat ...
     892             : ! **************************************************************************************************
     893          16 :    SUBROUTINE iao_calculate_dmat_full(cvec, density_matrix, weight, occmat)
     894             : 
     895             :       TYPE(cp_fm_type), INTENT(IN)                       :: cvec
     896             :       TYPE(dbcsr_type)                                   :: density_matrix
     897             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: weight
     898             :       TYPE(cp_fm_type), INTENT(IN)                       :: occmat
     899             : 
     900             :       CHARACTER(len=*), PARAMETER :: routineN = 'iao_calculate_dmat_full'
     901             : 
     902             :       INTEGER                                            :: handle, ic, jc, ncol
     903             :       REAL(KIND=dp)                                      :: alpha
     904             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     905             :       TYPE(cp_fm_type)                                   :: fm1, fm2
     906             : 
     907          16 :       CALL timeset(routineN, handle)
     908             : 
     909          16 :       CALL dbcsr_set(density_matrix, 0.0_dp)
     910             : 
     911             :       CALL cp_fm_struct_create(fm_struct, ncol_global=1, &
     912          16 :                                template_fmstruct=cvec%matrix_struct)
     913          16 :       CALL cp_fm_create(fm1, fm_struct)
     914          16 :       CALL cp_fm_create(fm2, fm_struct)
     915          16 :       CALL cp_fm_struct_release(fm_struct)
     916             : 
     917          16 :       CALL cp_fm_get_info(cvec, ncol_global=ncol)
     918         432 :       DO ic = 1, ncol
     919         416 :          CALL cp_fm_to_fm(cvec, fm1, ncol=1, source_start=ic, target_start=1)
     920       11248 :          DO jc = 1, ncol
     921       10816 :             CALL cp_fm_to_fm(cvec, fm2, ncol=1, source_start=jc, target_start=1)
     922       10816 :             CALL cp_fm_get_element(occmat, ic, jc, alpha)
     923       10816 :             alpha = weight(ic)*alpha
     924             :             CALL cp_dbcsr_plus_fm_fm_t(density_matrix, fm1, fm2, ncol=1, &
     925       11232 :                                        alpha=alpha, symmetry_mode=1)
     926             :          END DO
     927             :       END DO
     928          16 :       CALL cp_fm_release(fm1)
     929          16 :       CALL cp_fm_release(fm2)
     930             : 
     931          16 :       CALL timestop(handle)
     932             : 
     933          16 :    END SUBROUTINE iao_calculate_dmat_full
     934             : 
     935             : ! **************************************************************************************************
     936             : !> \brief compute the atomic charges (orthogonal basis)
     937             : !> \param p_matrix ...
     938             : !> \param charges ...
     939             : ! **************************************************************************************************
     940         208 :    SUBROUTINE iao_charges(p_matrix, charges)
     941             :       TYPE(dbcsr_type)                                   :: p_matrix
     942             :       REAL(KIND=dp), DIMENSION(:)                        :: charges
     943             : 
     944             :       INTEGER                                            :: i, iblock_col, iblock_row
     945             :       REAL(kind=dp)                                      :: trace
     946         208 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: p_block
     947             :       TYPE(dbcsr_iterator_type)                          :: iter
     948             :       TYPE(mp_comm_type)                                 :: group
     949             : 
     950        1120 :       charges = 0.0_dp
     951             : 
     952         208 :       CALL dbcsr_iterator_start(iter, p_matrix)
     953         664 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     954         456 :          NULLIFY (p_block)
     955         456 :          CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, p_block)
     956         456 :          CPASSERT(iblock_row == iblock_col)
     957         456 :          trace = 0.0_dp
     958        1758 :          DO i = 1, SIZE(p_block, 1)
     959        1758 :             trace = trace + p_block(i, i)
     960             :          END DO
     961         456 :          charges(iblock_row) = trace
     962             :       END DO
     963         208 :       CALL dbcsr_iterator_stop(iter)
     964             : 
     965         208 :       CALL dbcsr_get_info(p_matrix, group=group)
     966        2032 :       CALL group%sum(charges)
     967             : 
     968         208 :    END SUBROUTINE iao_charges
     969             : 
     970             : ! **************************************************************************************************
     971             : !> \brief Computes and prints the Cube Files for the intrinsic atomic orbitals
     972             : !> \param qs_env ...
     973             : !> \param print_section ...
     974             : !> \param iao_coef ...
     975             : !> \param basis_set_list ...
     976             : ! **************************************************************************************************
     977           4 :    SUBROUTINE print_iao_cubes(qs_env, print_section, iao_coef, basis_set_list)
     978             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     979             :       TYPE(section_vals_type), POINTER                   :: print_section
     980             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: iao_coef
     981             :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     982             : 
     983             :       CHARACTER(LEN=default_path_length)                 :: filename, title
     984             :       INTEGER                                            :: i, i_rep, ispin, ivec, iw, j, n_rep, &
     985             :                                                             nat, natom, norb, nspins, nstart
     986           4 :       INTEGER, DIMENSION(:), POINTER                     :: atom_list, blk_sizes, first_bas, stride
     987             :       LOGICAL                                            :: mpi_io
     988           4 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     989             :       TYPE(cell_type), POINTER                           :: cell
     990             :       TYPE(cp_logger_type), POINTER                      :: logger
     991             :       TYPE(dft_control_type), POINTER                    :: dft_control
     992             :       TYPE(particle_list_type), POINTER                  :: particles
     993           4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     994             :       TYPE(pw_c1d_gs_type)                               :: wf_g
     995             :       TYPE(pw_env_type), POINTER                         :: pw_env
     996             :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     997             :       TYPE(pw_r3d_rs_type)                               :: wf_r
     998           4 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     999             :       TYPE(qs_subsys_type), POINTER                      :: subsys
    1000             : 
    1001           8 :       logger => cp_get_default_logger()
    1002           4 :       stride => section_get_ivals(print_section, "STRIDE")
    1003           4 :       CALL section_vals_val_get(print_section, "ATOM_LIST", n_rep_val=n_rep)
    1004             : 
    1005             :       CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    1006           4 :                       subsys=subsys, cell=cell, particle_set=particle_set, pw_env=pw_env, dft_control=dft_control)
    1007           4 :       CALL qs_subsys_get(subsys, particles=particles)
    1008             : 
    1009           4 :       CALL get_qs_env(qs_env=qs_env, natom=natom)
    1010          20 :       ALLOCATE (blk_sizes(natom), first_bas(0:natom))
    1011           4 :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_sizes, basis=basis_set_list)
    1012           4 :       first_bas(0) = 0
    1013          20 :       DO i = 1, natom
    1014          20 :          first_bas(i) = first_bas(i - 1) + blk_sizes(i)
    1015             :       END DO
    1016             : 
    1017           4 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
    1018           4 :       CALL auxbas_pw_pool%create_pw(wf_r)
    1019           4 :       CALL auxbas_pw_pool%create_pw(wf_g)
    1020             : 
    1021           4 :       nspins = SIZE(iao_coef)
    1022           4 :       nstart = MIN(1, n_rep)
    1023             : 
    1024           8 :       DO ispin = 1, nspins
    1025          12 :          DO i_rep = nstart, n_rep
    1026           4 :             CALL cp_fm_get_info(iao_coef(ispin), ncol_global=norb)
    1027           4 :             IF (i_rep == 0) THEN
    1028           0 :                nat = natom
    1029             :             ELSE
    1030           4 :                CALL section_vals_val_get(print_section, "ATOM_LIST", i_rep_val=i_rep, i_vals=atom_list)
    1031           4 :                nat = SIZE(atom_list)
    1032             :             END IF
    1033          20 :             DO i = 1, nat
    1034           8 :                IF (i_rep == 0) THEN
    1035           0 :                   j = i
    1036             :                ELSE
    1037           8 :                   j = atom_list(i)
    1038             :                END IF
    1039           8 :                CPASSERT(j >= 1 .AND. j <= natom)
    1040          34 :                DO ivec = first_bas(j - 1) + 1, first_bas(j)
    1041          22 :                   WRITE (filename, '(a4,I5.5,a1,I1.1)') "IAO_", ivec, "_", ispin
    1042          22 :                   WRITE (title, *) "Intrinsic Atomic Orbitals ", ivec, " atom ", j, " spin ", ispin
    1043          22 :                   mpi_io = .TRUE.
    1044             :                   iw = cp_print_key_unit_nr(logger, print_section, "", extension=".cube", &
    1045             :                                             middle_name=TRIM(filename), file_position="REWIND", log_filename=.FALSE., &
    1046          22 :                                             mpi_io=mpi_io)
    1047             :                   CALL calculate_wavefunction(iao_coef(ispin), ivec, wf_r, wf_g, atomic_kind_set, qs_kind_set, &
    1048          22 :                                               cell, dft_control, particle_set, pw_env)
    1049          22 :                   CALL cp_pw_to_cube(wf_r, iw, title, particles=particles, stride=stride, mpi_io=mpi_io)
    1050          30 :                   CALL cp_print_key_finished_output(iw, logger, print_section, "", mpi_io=mpi_io)
    1051             :                END DO
    1052             :             END DO
    1053             :          END DO
    1054             :       END DO
    1055           4 :       DEALLOCATE (blk_sizes, first_bas)
    1056           4 :       CALL auxbas_pw_pool%give_back_pw(wf_r)
    1057           4 :       CALL auxbas_pw_pool%give_back_pw(wf_g)
    1058             : 
    1059           8 :    END SUBROUTINE print_iao_cubes
    1060             : 
    1061             : ! **************************************************************************************************
    1062             : !> \brief Computes and prints the Cube Files for the intrinsic bond orbitals
    1063             : !> \param qs_env ...
    1064             : !> \param print_section ...
    1065             : !> \param ibo_coef ...
    1066             : ! **************************************************************************************************
    1067           4 :    SUBROUTINE print_ibo_cubes(qs_env, print_section, ibo_coef)
    1068             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1069             :       TYPE(section_vals_type), POINTER                   :: print_section
    1070             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: ibo_coef
    1071             : 
    1072             :       CHARACTER(LEN=default_path_length)                 :: filename, title
    1073             :       INTEGER                                            :: i, i_rep, ispin, iw, j, n_rep, norb, &
    1074             :                                                             nspins, nstart, nstate
    1075           4 :       INTEGER, DIMENSION(:), POINTER                     :: state_list, stride
    1076             :       LOGICAL                                            :: mpi_io
    1077           4 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1078             :       TYPE(cell_type), POINTER                           :: cell
    1079             :       TYPE(cp_logger_type), POINTER                      :: logger
    1080             :       TYPE(dft_control_type), POINTER                    :: dft_control
    1081             :       TYPE(particle_list_type), POINTER                  :: particles
    1082           4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1083             :       TYPE(pw_c1d_gs_type)                               :: wf_g
    1084             :       TYPE(pw_env_type), POINTER                         :: pw_env
    1085             :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
    1086             :       TYPE(pw_r3d_rs_type)                               :: wf_r
    1087           4 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1088             :       TYPE(qs_subsys_type), POINTER                      :: subsys
    1089             : 
    1090           0 :       CPASSERT(ASSOCIATED(print_section))
    1091             : 
    1092           4 :       logger => cp_get_default_logger()
    1093           4 :       stride => section_get_ivals(print_section, "STRIDE")
    1094           4 :       CALL section_vals_val_get(print_section, "STATE_LIST", n_rep_val=n_rep)
    1095             : 
    1096             :       CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
    1097           4 :                       subsys=subsys, cell=cell, particle_set=particle_set, pw_env=pw_env, dft_control=dft_control)
    1098           4 :       CALL qs_subsys_get(subsys, particles=particles)
    1099             : 
    1100           4 :       CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
    1101           4 :       CALL auxbas_pw_pool%create_pw(wf_r)
    1102           4 :       CALL auxbas_pw_pool%create_pw(wf_g)
    1103             : 
    1104           4 :       nspins = SIZE(ibo_coef)
    1105           4 :       nstart = MIN(1, n_rep)
    1106             : 
    1107           8 :       DO ispin = 1, nspins
    1108          12 :          DO i_rep = nstart, n_rep
    1109           4 :             CALL cp_fm_get_info(ibo_coef(ispin), ncol_global=norb)
    1110           4 :             IF (i_rep == 0) THEN
    1111           0 :                nstate = norb
    1112             :             ELSE
    1113           4 :                CALL section_vals_val_get(print_section, "STATE_LIST", i_rep_val=i_rep, i_vals=state_list)
    1114           4 :                nstate = SIZE(state_list)
    1115             :             END IF
    1116          16 :             DO i = 1, nstate
    1117           4 :                IF (i_rep == 0) THEN
    1118           0 :                   j = i
    1119             :                ELSE
    1120           4 :                   j = state_list(i)
    1121             :                END IF
    1122           4 :                CPASSERT(j >= 1 .AND. j <= norb)
    1123           4 :                WRITE (filename, '(a4,I5.5,a1,I1.1)') "IBO_", j, "_", ispin
    1124           4 :                WRITE (title, *) "Intrinsic Atomic Orbitals ", j, " spin ", ispin
    1125           4 :                mpi_io = .TRUE.
    1126             :                iw = cp_print_key_unit_nr(logger, print_section, "", extension=".cube", &
    1127             :                                          middle_name=TRIM(filename), file_position="REWIND", log_filename=.FALSE., &
    1128           4 :                                          mpi_io=mpi_io)
    1129             :                CALL calculate_wavefunction(ibo_coef(ispin), j, wf_r, wf_g, atomic_kind_set, qs_kind_set, &
    1130           4 :                                            cell, dft_control, particle_set, pw_env)
    1131           4 :                CALL cp_pw_to_cube(wf_r, iw, title, particles=particles, stride=stride, mpi_io=mpi_io)
    1132           8 :                CALL cp_print_key_finished_output(iw, logger, print_section, "", mpi_io=mpi_io)
    1133             :             END DO
    1134             :          END DO
    1135             :       END DO
    1136             : 
    1137           4 :       CALL auxbas_pw_pool%give_back_pw(wf_r)
    1138           4 :       CALL auxbas_pw_pool%give_back_pw(wf_g)
    1139             : 
    1140           4 :    END SUBROUTINE print_ibo_cubes
    1141             : 
    1142             : ! **************************************************************************************************
    1143             : !> \brief prints charge center and spreads for all orbitals
    1144             : !> \param moments ...
    1145             : !> \param nocc ...
    1146             : !> \param print_section ...
    1147             : !> \param iounit ...
    1148             : ! **************************************************************************************************
    1149          32 :    SUBROUTINE print_center_spread(moments, nocc, print_section, iounit)
    1150             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: moments
    1151             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: nocc
    1152             :       TYPE(section_vals_type), OPTIONAL, POINTER         :: print_section
    1153             :       INTEGER, INTENT(IN), OPTIONAL                      :: iounit
    1154             : 
    1155             :       CHARACTER(LEN=default_path_length)                 :: filename
    1156             :       INTEGER                                            :: is, ispin, iw, nspin
    1157             :       TYPE(cp_logger_type), POINTER                      :: logger
    1158             : 
    1159          32 :       logger => cp_get_default_logger()
    1160          32 :       nspin = SIZE(moments, 3)
    1161             : 
    1162          32 :       IF (PRESENT(print_section)) THEN
    1163           4 :          WRITE (filename, '(A18,I1.1)') "IBO_CENTERS_SPREAD"
    1164             :          iw = cp_print_key_unit_nr(logger, print_section, "", extension=".csp", &
    1165           4 :                                    middle_name=TRIM(filename), file_position="REWIND", log_filename=.FALSE.)
    1166          28 :       ELSEIF (PRESENT(iounit)) THEN
    1167          28 :          iw = iounit
    1168             :       ELSE
    1169           0 :          iw = -1
    1170             :       END IF
    1171          32 :       IF (iw > 0) THEN
    1172          33 :          DO ispin = 1, nspin
    1173          17 :             WRITE (iw, "(T2,A,i1)") "Intrinsic Bond Orbitals: Centers and Spread for Spin ", ispin
    1174          17 :             WRITE (iw, "(A7,T30,A6,T68,A7)") "State", "Center", "Spreads"
    1175         133 :             DO is = 1, nocc(ispin)
    1176         117 :                WRITE (iw, "(i7,3F15.8,8X,2F10.5)") is, moments(:, is, ispin)
    1177             :             END DO
    1178             :          END DO
    1179             :       END IF
    1180          32 :       IF (PRESENT(print_section)) THEN
    1181           4 :          CALL cp_print_key_finished_output(iw, logger, print_section, "")
    1182             :       END IF
    1183             : 
    1184          32 :    END SUBROUTINE print_center_spread
    1185             : 
    1186             : ! **************************************************************************************************
    1187             : !> \brief ...
    1188             : !> \param qs_env ...
    1189             : !> \param c_loc_orb ...
    1190             : !> \param moments ...
    1191             : ! **************************************************************************************************
    1192           6 :    SUBROUTINE center_spread_loc(qs_env, c_loc_orb, moments)
    1193             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1194             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: c_loc_orb
    1195             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: moments
    1196             : 
    1197             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'center_spread_loc'
    1198             :       INTEGER, DIMENSION(6), PARAMETER                   :: list = (/1, 2, 3, 4, 7, 9/)
    1199             : 
    1200             :       INTEGER                                            :: handle, i, iop, iorb, ispin, nao, norb, &
    1201             :                                                             nspin
    1202             :       REAL(KIND=dp)                                      :: xmii
    1203             :       REAL(KIND=dp), DIMENSION(3)                        :: rpoint
    1204             :       TYPE(cell_type), POINTER                           :: cell
    1205             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1206             :       TYPE(cp_fm_type)                                   :: ccmat, ocvec
    1207           6 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: dipmat
    1208           6 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s
    1209             :       TYPE(dbcsr_type), POINTER                          :: omat, smat
    1210             : 
    1211           6 :       CALL timeset(routineN, handle)
    1212             : 
    1213           6 :       CALL get_qs_env(qs_env=qs_env, matrix_s_kp=matrix_s)
    1214           6 :       smat => matrix_s(1, 1)%matrix
    1215           6 :       rpoint = 0.0_dp
    1216           6 :       nspin = SIZE(c_loc_orb)
    1217         228 :       moments = 0.0_dp
    1218             : 
    1219          60 :       ALLOCATE (dipmat(9))
    1220          60 :       DO i = 1, 9
    1221          54 :          ALLOCATE (dipmat(i)%matrix)
    1222          54 :          CALL dbcsr_copy(dipmat(i)%matrix, smat)
    1223          60 :          CALL dbcsr_set(dipmat(i)%matrix, 0.0_dp)
    1224             :       END DO
    1225             : 
    1226           6 :       CALL build_local_moment_matrix(qs_env, dipmat, 2, rpoint)
    1227             : 
    1228          12 :       DO ispin = 1, nspin
    1229           6 :          CALL cp_fm_get_info(c_loc_orb(ispin), nrow_global=nao, ncol_global=norb)
    1230           6 :          CALL cp_fm_create(ocvec, c_loc_orb(ispin)%matrix_struct)
    1231           6 :          NULLIFY (fm_struct)
    1232             :          CALL cp_fm_struct_create(fm_struct, nrow_global=norb, ncol_global=norb, &
    1233           6 :                                   template_fmstruct=c_loc_orb(ispin)%matrix_struct)
    1234           6 :          CALL cp_fm_create(ccmat, fm_struct)
    1235           6 :          CALL cp_fm_struct_release(fm_struct)
    1236          42 :          DO i = 1, 6
    1237          36 :             iop = list(i)
    1238          36 :             omat => dipmat(iop)%matrix
    1239          36 :             CALL cp_dbcsr_sm_fm_multiply(omat, c_loc_orb(ispin), ocvec, ncol=norb)
    1240             :             CALL parallel_gemm('T', 'N', norb, norb, nao, 1.0_dp, c_loc_orb(ispin), ocvec, &
    1241          36 :                                0.0_dp, ccmat)
    1242         258 :             DO iorb = 1, norb
    1243         216 :                CALL cp_fm_get_element(ccmat, iorb, iorb, xmii)
    1244         252 :                IF (iop <= 3) THEN
    1245         108 :                   moments(iop, iorb, ispin) = moments(iop, iorb, ispin) + xmii
    1246         108 :                   moments(4, iorb, ispin) = moments(4, iorb, ispin) - xmii**2
    1247             :                ELSE
    1248         108 :                   moments(4, iorb, ispin) = moments(4, iorb, ispin) + xmii
    1249             :                END IF
    1250             :             END DO
    1251             :          END DO
    1252           6 :          CALL cp_fm_release(ocvec)
    1253          24 :          CALL cp_fm_release(ccmat)
    1254             :       END DO
    1255             : 
    1256          60 :       DO i = 1, 9
    1257          54 :          CALL dbcsr_release(dipmat(i)%matrix)
    1258          60 :          DEALLOCATE (dipmat(i)%matrix)
    1259             :       END DO
    1260           6 :       DEALLOCATE (dipmat)
    1261             : 
    1262           6 :       CALL get_qs_env(qs_env=qs_env, cell=cell)
    1263          12 :       DO ispin = 1, nspin
    1264          48 :          DO iorb = 1, norb
    1265         150 :             moments(1:3, iorb, ispin) = pbc(moments(1:3, iorb, ispin), cell)
    1266             :          END DO
    1267             :       END DO
    1268             : 
    1269           6 :       CALL timestop(handle)
    1270             : 
    1271           6 :    END SUBROUTINE center_spread_loc
    1272             : 
    1273             : ! **************************************************************************************************
    1274             : !> \brief ...
    1275             : !> \param qs_env ...
    1276             : !> \param c_loc_orb ...
    1277             : !> \param moments ...
    1278             : ! **************************************************************************************************
    1279          26 :    SUBROUTINE center_spread_berry(qs_env, c_loc_orb, moments)
    1280             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1281             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: c_loc_orb
    1282             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: moments
    1283             : 
    1284             :       CHARACTER(len=*), PARAMETER :: routineN = 'center_spread_berry'
    1285             : 
    1286             :       COMPLEX(KIND=dp)                                   :: z
    1287             :       INTEGER                                            :: dim_op, handle, i, idir, ispin, istate, &
    1288             :                                                             j, jdir, nao, norb, nspin
    1289             :       REAL(dp), DIMENSION(3)                             :: c, cpbc
    1290             :       REAL(dp), DIMENSION(6)                             :: weights
    1291             :       REAL(KIND=dp)                                      :: imagpart, realpart, spread_i, spread_ii
    1292             :       TYPE(cell_type), POINTER                           :: cell
    1293             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1294             :       TYPE(cp_fm_type)                                   :: opvec
    1295          26 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: zij
    1296          26 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    1297          26 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: op_sm_set
    1298             : 
    1299          26 :       CALL timeset(routineN, handle)
    1300             : 
    1301          26 :       CALL get_qs_env(qs_env=qs_env, matrix_s=matrix_s, cell=cell)
    1302             : 
    1303          26 :       IF (cell%orthorhombic) THEN
    1304          26 :          dim_op = 3
    1305             :       ELSE
    1306           0 :          dim_op = 6
    1307             :       END IF
    1308         312 :       ALLOCATE (op_sm_set(2, dim_op))
    1309         104 :       DO i = 1, dim_op
    1310         260 :          DO j = 1, 2
    1311         156 :             NULLIFY (op_sm_set(j, i)%matrix)
    1312         156 :             ALLOCATE (op_sm_set(j, i)%matrix)
    1313         156 :             CALL dbcsr_copy(op_sm_set(j, i)%matrix, matrix_s(1)%matrix)
    1314         234 :             CALL dbcsr_set(op_sm_set(j, i)%matrix, 0.0_dp)
    1315             :          END DO
    1316             :       END DO
    1317          26 :       CALL initialize_weights(cell, weights)
    1318             : 
    1319          26 :       CALL compute_berry_operator(qs_env, cell, op_sm_set, dim_op)
    1320             : 
    1321          26 :       nspin = SIZE(c_loc_orb, 1)
    1322          54 :       DO ispin = 1, nspin
    1323          28 :          CALL cp_fm_get_info(c_loc_orb(ispin), nrow_global=nao, ncol_global=norb)
    1324          28 :          CALL cp_fm_create(opvec, c_loc_orb(ispin)%matrix_struct)
    1325          28 :          NULLIFY (fm_struct)
    1326             :          CALL cp_fm_struct_create(fm_struct, nrow_global=norb, ncol_global=norb, &
    1327          28 :                                   template_fmstruct=c_loc_orb(ispin)%matrix_struct)
    1328         336 :          ALLOCATE (zij(2, dim_op))
    1329             : 
    1330             :          ! Compute zij here
    1331         112 :          DO i = 1, dim_op
    1332         280 :             DO j = 1, 2
    1333         168 :                CALL cp_fm_create(zij(j, i), fm_struct)
    1334         168 :                CALL cp_fm_set_all(zij(j, i), 0.0_dp)
    1335         168 :                CALL cp_dbcsr_sm_fm_multiply(op_sm_set(j, i)%matrix, c_loc_orb(ispin), opvec, ncol=norb)
    1336         252 :                CALL parallel_gemm("T", "N", norb, norb, nao, 1.0_dp, c_loc_orb(ispin), opvec, 0.0_dp, zij(j, i))
    1337             :             END DO
    1338             :          END DO
    1339             : 
    1340          28 :          CALL cp_fm_struct_release(fm_struct)
    1341          28 :          CALL cp_fm_release(opvec)
    1342             : 
    1343         184 :          DO istate = 1, norb
    1344         156 :             c = 0.0_dp
    1345         156 :             spread_i = 0.0_dp
    1346         156 :             spread_ii = 0.0_dp
    1347         624 :             DO jdir = 1, dim_op
    1348         468 :                CALL cp_fm_get_element(zij(1, jdir), istate, istate, realpart)
    1349         468 :                CALL cp_fm_get_element(zij(2, jdir), istate, istate, imagpart)
    1350         468 :                z = CMPLX(realpart, imagpart, dp)
    1351             :                spread_i = spread_i - weights(jdir)* &
    1352         468 :                           LOG(realpart*realpart + imagpart*imagpart)/twopi/twopi
    1353             :                spread_ii = spread_ii + weights(jdir)* &
    1354         468 :                            (1.0_dp - (realpart*realpart + imagpart*imagpart))/twopi/twopi
    1355         624 :                IF (jdir < 4) THEN
    1356        1872 :                   DO idir = 1, 3
    1357             :                      c(idir) = c(idir) + &
    1358        1872 :                                (cell%hmat(idir, jdir)/twopi)*AIMAG(LOG(z))
    1359             :                   END DO
    1360             :                END IF
    1361             :             END DO
    1362         156 :             cpbc = pbc(c, cell)
    1363         624 :             moments(1:3, istate, ispin) = cpbc(1:3)
    1364         156 :             moments(4, istate, ispin) = spread_i
    1365         184 :             moments(5, istate, ispin) = spread_ii
    1366             :          END DO
    1367             : 
    1368          82 :          CALL cp_fm_release(zij)
    1369             : 
    1370             :       END DO
    1371             : 
    1372         104 :       DO i = 1, dim_op
    1373         260 :          DO j = 1, 2
    1374         156 :             CALL dbcsr_release(op_sm_set(j, i)%matrix)
    1375         234 :             DEALLOCATE (op_sm_set(j, i)%matrix)
    1376             :          END DO
    1377             :       END DO
    1378          26 :       DEALLOCATE (op_sm_set)
    1379             : 
    1380          26 :       CALL timestop(handle)
    1381             : 
    1382          52 :    END SUBROUTINE center_spread_berry
    1383             : 
    1384             : ! **************************************************************************************************
    1385             : !> \brief ...
    1386             : !> \param qs_env ...
    1387             : !> \param oce_basis_set_list ...
    1388             : !> \param smat_kind ...
    1389             : !> \param sxo ...
    1390             : !> \param iao_coef ...
    1391             : !> \param oce_atom ...
    1392             : !> \param unit_nr ...
    1393             : ! **************************************************************************************************
    1394           4 :    SUBROUTINE iao_oce_expansion(qs_env, oce_basis_set_list, smat_kind, sxo, iao_coef, oce_atom, unit_nr)
    1395             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1396             :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: oce_basis_set_list
    1397             :       TYPE(cp_2d_r_p_type), DIMENSION(:)                 :: smat_kind
    1398             :       TYPE(dbcsr_p_type), DIMENSION(:)                   :: sxo
    1399             :       TYPE(cp_fm_type), DIMENSION(:)                     :: iao_coef
    1400             :       TYPE(cp_2d_r_p_type), DIMENSION(:, :)              :: oce_atom
    1401             :       INTEGER, INTENT(IN)                                :: unit_nr
    1402             : 
    1403             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'iao_oce_expansion'
    1404             : 
    1405             :       INTEGER                                            :: handle, i, i1, i2, iao, iatom, ikind, &
    1406             :                                                             iset, ishell, ispin, l, m, maxl, n, &
    1407             :                                                             natom, nkind, noce, ns, nset, nsgf, &
    1408             :                                                             nspin
    1409           4 :       INTEGER, DIMENSION(:), POINTER                     :: iao_blk_sizes, nshell, oce_blk_sizes, &
    1410           4 :                                                             orb_blk_sizes
    1411           4 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgf, last_sgf, lval
    1412             :       LOGICAL                                            :: found
    1413           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: ev, vector
    1414           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: amat, bmat, filter, oce_comp, prol, vec
    1415           4 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: ablock
    1416           4 :       TYPE(cp_2d_r_p_type), ALLOCATABLE, DIMENSION(:)    :: sinv_kind
    1417             :       TYPE(dbcsr_distribution_type)                      :: dbcsr_dist
    1418             :       TYPE(dbcsr_type)                                   :: iao_vec, sx_vec
    1419             :       TYPE(gto_basis_set_type), POINTER                  :: oce_basis
    1420             :       TYPE(mp_comm_type)                                 :: group
    1421           4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
    1422           4 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
    1423             :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
    1424             : 
    1425           4 :       CALL timeset(routineN, handle)
    1426             : 
    1427             :       ! basis sets: block sizes
    1428             :       CALL dbcsr_get_info(sxo(1)%matrix, row_blk_size=oce_blk_sizes, col_blk_size=orb_blk_sizes, &
    1429           4 :                           distribution=dbcsr_dist)
    1430           4 :       CALL get_qs_env(qs_env=qs_env, ks_env=ks_env, natom=natom)
    1431           4 :       CALL get_ks_env(ks_env=ks_env, particle_set=particle_set, qs_kind_set=qs_kind_set)
    1432          12 :       ALLOCATE (iao_blk_sizes(natom))
    1433          20 :       DO iatom = 1, natom
    1434          16 :          CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
    1435          16 :          CALL get_qs_kind(qs_kind_set(ikind), nsgf=ns, basis_type="MIN")
    1436          20 :          iao_blk_sizes(iatom) = ns
    1437             :       END DO
    1438             : 
    1439             :       CALL dbcsr_create(iao_vec, name="IAO_VEC", dist=dbcsr_dist, &
    1440             :                         matrix_type=dbcsr_type_no_symmetry, row_blk_size=orb_blk_sizes, &
    1441           4 :                         col_blk_size=iao_blk_sizes)
    1442             :       CALL dbcsr_create(sx_vec, name="SX_VEC", dist=dbcsr_dist, &
    1443             :                         matrix_type=dbcsr_type_no_symmetry, row_blk_size=oce_blk_sizes, &
    1444           4 :                         col_blk_size=iao_blk_sizes)
    1445           4 :       CALL dbcsr_reserve_diag_blocks(matrix=sx_vec)
    1446             : 
    1447           4 :       nkind = SIZE(smat_kind)
    1448          24 :       ALLOCATE (sinv_kind(nkind))
    1449          16 :       DO ikind = 1, nkind
    1450          12 :          noce = SIZE(smat_kind(ikind)%array, 1)
    1451          48 :          ALLOCATE (sinv_kind(ikind)%array(noce, noce))
    1452      125116 :          sinv_kind(ikind)%array = smat_kind(ikind)%array
    1453          16 :          CALL invmat_symm(sinv_kind(ikind)%array)
    1454             :       END DO
    1455           4 :       CALL dbcsr_get_info(iao_vec, group=group)
    1456             : 
    1457           4 :       nspin = SIZE(iao_coef, 1)
    1458          16 :       ALLOCATE (oce_comp(natom, nspin))
    1459          24 :       oce_comp = 0.0_dp
    1460           8 :       DO ispin = 1, nspin
    1461           4 :          CALL copy_fm_to_dbcsr(iao_coef(ispin), iao_vec)
    1462             :          CALL dbcsr_multiply("N", "N", 1.0_dp, sxo(1)%matrix, iao_vec, 0.0_dp, sx_vec, &
    1463           4 :                              retain_sparsity=.TRUE.)
    1464          20 :          DO iatom = 1, natom
    1465          16 :             CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
    1466             :             CALL dbcsr_get_block_p(matrix=sx_vec, &
    1467          16 :                                    row=iatom, col=iatom, BLOCK=ablock, found=found)
    1468          20 :             IF (found) THEN
    1469           8 :                n = SIZE(ablock, 1)
    1470           8 :                m = SIZE(ablock, 2)
    1471      213906 :                ablock = MATMUL(sinv_kind(ikind)%array, ablock)
    1472          88 :                ALLOCATE (amat(n, m), bmat(m, m), ev(m), vec(m, m))
    1473       25462 :                amat(1:n, 1:m) = MATMUL(smat_kind(ikind)%array(1:n, 1:n), ablock(1:n, 1:m))
    1474        9964 :                bmat(1:m, 1:m) = MATMUL(TRANSPOSE(ablock(1:n, 1:m)), amat(1:n, 1:m))
    1475           8 :                CALL jacobi(bmat, ev, vec)
    1476          30 :                oce_comp(iatom, ispin) = SUM(ev(1:m))/REAL(m, KIND=dp)
    1477          30 :                DO i = 1, m
    1478          22 :                   ev(i) = 1._dp/SQRT(ev(i))
    1479         116 :                   bmat(1:m, i) = vec(1:m, i)*ev(i)
    1480             :                END DO
    1481         714 :                bmat(1:m, 1:m) = MATMUL(bmat(1:m, 1:m), TRANSPOSE(vec(1:m, 1:m)))
    1482       14548 :                ablock(1:n, 1:m) = MATMUL(ablock(1:n, 1:m), bmat(1:m, 1:m))
    1483           8 :                DEALLOCATE (amat, bmat, ev, vec)
    1484             :             END IF
    1485             :          END DO
    1486           4 :          CALL dbcsr_replicate_all(sx_vec)
    1487          24 :          DO iatom = 1, natom
    1488          16 :             CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
    1489             :             CALL dbcsr_get_block_p(matrix=sx_vec, &
    1490          16 :                                    row=iatom, col=iatom, BLOCK=ablock, found=found)
    1491          16 :             CPASSERT(found)
    1492          16 :             n = SIZE(ablock, 1)
    1493          16 :             m = SIZE(ablock, 2)
    1494          64 :             ALLOCATE (oce_atom(iatom, ispin)%array(n, m))
    1495        4728 :             oce_atom(iatom, ispin)%array = ablock
    1496             :          END DO
    1497             :       END DO
    1498             : 
    1499           4 :       CALL group%sum(oce_comp)
    1500           4 :       IF (unit_nr > 0) THEN
    1501          10 :          DO iatom = 1, natom
    1502           8 :             WRITE (unit_nr, "(T4,A,I6,T30,A,2F12.4)") "Atom:", iatom, " Completeness: ", oce_comp(iatom, 1:nspin)
    1503           8 :             CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
    1504           8 :             oce_basis => oce_basis_set_list(ikind)%gto_basis_set
    1505             :             CALL get_gto_basis_set(oce_basis, nset=nset, nshell=nshell, nsgf=nsgf, maxl=maxl, &
    1506           8 :                                    l=lval, first_sgf=first_sgf, last_sgf=last_sgf)
    1507          72 :             ALLOCATE (filter(nsgf, 0:maxl), vector(nsgf), prol(0:maxl, nspin))
    1508        4496 :             filter = 0.0_dp
    1509          70 :             DO iset = 1, nset
    1510         238 :                DO ishell = 1, nshell(iset)
    1511         168 :                   l = lval(ishell, iset)
    1512         168 :                   i1 = first_sgf(ishell, iset)
    1513         168 :                   i2 = last_sgf(ishell, iset)
    1514         970 :                   filter(i1:i2, l) = 1.0_dp
    1515             :                END DO
    1516             :             END DO
    1517             :             !
    1518           8 :             n = SIZE(oce_atom(iatom, 1)%array, 1)
    1519           8 :             m = SIZE(oce_atom(iatom, 1)%array, 2)
    1520           8 :             CPASSERT(n == nsgf)
    1521          30 :             DO iao = 1, m
    1522         176 :                prol = 0.0_dp
    1523          44 :                DO ispin = 1, nspin
    1524         176 :                   DO l = 0, maxl
    1525       14076 :                      vector(1:n) = oce_atom(iatom, ispin)%array(1:n, iao)*filter(1:n, l)
    1526     1611250 :                      prol(l, ispin) = SUM(MATMUL(smat_kind(ikind)%array(1:n, 1:n), vector(1:n))*vector(1:n))
    1527             :                   END DO
    1528             :                END DO
    1529         294 :                WRITE (unit_nr, "(T4,I3,T15,A,T39,(6F7.4))") iao, " l-contributions:", (SUM(prol(l, :)), l=0, maxl)
    1530             :             END DO
    1531          18 :             DEALLOCATE (filter, vector, prol)
    1532             :          END DO
    1533           2 :          WRITE (unit_nr, *)
    1534             :       END IF
    1535             : 
    1536           4 :       DEALLOCATE (oce_comp)
    1537          16 :       DO ikind = 1, nkind
    1538          16 :          DEALLOCATE (sinv_kind(ikind)%array)
    1539             :       END DO
    1540           4 :       DEALLOCATE (sinv_kind)
    1541           4 :       DEALLOCATE (iao_blk_sizes)
    1542           4 :       CALL dbcsr_release(iao_vec)
    1543           4 :       CALL dbcsr_release(sx_vec)
    1544             : 
    1545           4 :       CALL timestop(handle)
    1546             : 
    1547          12 :    END SUBROUTINE iao_oce_expansion
    1548             : 
    1549             : ! **************************************************************************************************
    1550             : !> \brief ...
    1551             : !> \param smat_kind ...
    1552             : !> \param basis_set_list ...
    1553             : ! **************************************************************************************************
    1554           4 :    SUBROUTINE oce_overlap_matrix(smat_kind, basis_set_list)
    1555             :       TYPE(cp_2d_r_p_type), DIMENSION(:)                 :: smat_kind
    1556             :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
    1557             : 
    1558             :       CHARACTER(len=*), PARAMETER :: routineN = 'oce_overlap_matrix'
    1559             : 
    1560             :       INTEGER                                            :: handle, ikind, iset, jset, ldsab, m1, &
    1561             :                                                             m2, n1, n2, ncoa, ncob, nkind, nseta, &
    1562             :                                                             sgfa, sgfb
    1563           4 :       INTEGER, DIMENSION(:), POINTER                     :: la_max, la_min, npgfa, nsgfa
    1564           4 :       INTEGER, DIMENSION(:, :), POINTER                  :: first_sgfa
    1565           4 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: oint, owork
    1566             :       REAL(KIND=dp), DIMENSION(3)                        :: rab
    1567           4 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: rpgfa, scon_a, smat, zeta
    1568             :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
    1569             : 
    1570           4 :       CALL timeset(routineN, handle)
    1571             : 
    1572           4 :       rab(1:3) = 0.0_dp
    1573             : 
    1574           4 :       nkind = SIZE(smat_kind)
    1575           4 :       ldsab = 0
    1576          16 :       DO ikind = 1, nkind
    1577          12 :          basis_set => basis_set_list(ikind)%gto_basis_set
    1578          12 :          CPASSERT(ASSOCIATED(basis_set))
    1579          12 :          CALL get_gto_basis_set(gto_basis_set=basis_set, maxco=m1, nsgf=m2)
    1580          16 :          ldsab = MAX(m1, m2, ldsab)
    1581             :       END DO
    1582             : 
    1583          24 :       ALLOCATE (oint(ldsab, ldsab), owork(ldsab, ldsab))
    1584             : 
    1585          16 :       DO ikind = 1, nkind
    1586          12 :          basis_set => basis_set_list(ikind)%gto_basis_set
    1587          12 :          CPASSERT(ASSOCIATED(basis_set))
    1588          12 :          smat => smat_kind(ikind)%array
    1589      125116 :          smat = 0.0_dp
    1590             :          ! basis ikind
    1591          12 :          first_sgfa => basis_set%first_sgf
    1592          12 :          la_max => basis_set%lmax
    1593          12 :          la_min => basis_set%lmin
    1594          12 :          npgfa => basis_set%npgf
    1595          12 :          nseta = basis_set%nset
    1596          12 :          nsgfa => basis_set%nsgf_set
    1597          12 :          rpgfa => basis_set%pgf_radius
    1598          12 :          scon_a => basis_set%scon
    1599          12 :          zeta => basis_set%zet
    1600             : 
    1601         118 :          DO iset = 1, nseta
    1602             : 
    1603         102 :             ncoa = npgfa(iset)*ncoset(la_max(iset))
    1604         102 :             n1 = npgfa(iset)*(ncoset(la_max(iset)) - ncoset(la_min(iset) - 1))
    1605         102 :             sgfa = first_sgfa(1, iset)
    1606             : 
    1607        1236 :             DO jset = 1, nseta
    1608             : 
    1609        1122 :                ncob = npgfa(jset)*ncoset(la_max(jset))
    1610        1122 :                n2 = npgfa(jset)*(ncoset(la_max(jset)) - ncoset(la_min(jset) - 1))
    1611        1122 :                sgfb = first_sgfa(1, jset)
    1612             : 
    1613             :                ! calculate integrals and derivatives
    1614             :                CALL overlap_ab(la_max(iset), la_min(iset), npgfa(iset), rpgfa(:, iset), zeta(:, iset), &
    1615             :                                la_max(jset), la_min(jset), npgfa(jset), rpgfa(:, jset), zeta(:, jset), &
    1616        1122 :                                rab, sab=oint(:, :))
    1617             :                ! Contraction
    1618             :                CALL contraction(oint(:, :), owork, ca=scon_a(:, sgfa:), na=n1, ma=nsgfa(iset), &
    1619        1122 :                                 cb=scon_a(:, sgfb:), nb=n2, mb=nsgfa(jset), fscale=1.0_dp, trans=.FALSE.)
    1620             :                CALL block_add("IN", owork, nsgfa(iset), nsgfa(jset), smat, &
    1621        1224 :                               sgfa, sgfb, trans=.FALSE.)
    1622             : 
    1623             :             END DO
    1624             :          END DO
    1625             : 
    1626             :       END DO
    1627           4 :       DEALLOCATE (oint, owork)
    1628             : 
    1629           4 :       CALL timestop(handle)
    1630             : 
    1631           4 :    END SUBROUTINE oce_overlap_matrix
    1632             : 
    1633             : ! **************************************************************************************************
    1634             : !> \brief 2 by 2 rotation optimization for the Pipek-Mezey operator
    1635             : !> \param zij_fm_set ...
    1636             : !> \param vectors ...
    1637             : !> \param order ...
    1638             : !> \param accuracy ...
    1639             : !> \param unit_nr ...
    1640             : !> \par History
    1641             : !>       05-2005 created
    1642             : !>       10-2023 adapted from jacobi_rotation_pipek [JGH]
    1643             : !> \author MI
    1644             : ! **************************************************************************************************
    1645          34 :    SUBROUTINE pm_localization(zij_fm_set, vectors, order, accuracy, unit_nr)
    1646             : 
    1647             :       TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN)      :: zij_fm_set
    1648             :       TYPE(cp_fm_type), INTENT(IN)                       :: vectors
    1649             :       INTEGER, INTENT(IN)                                :: order
    1650             :       REAL(KIND=dp), INTENT(IN)                          :: accuracy
    1651             :       INTEGER, INTENT(IN)                                :: unit_nr
    1652             : 
    1653             :       INTEGER, PARAMETER                                 :: max_sweeps = 250
    1654             : 
    1655             :       INTEGER                                            :: iatom, istate, jstate, natom, nstate, &
    1656             :                                                             sweeps
    1657             :       REAL(KIND=dp)                                      :: aij, bij, ct, ftarget, mii, mij, mjj, &
    1658             :                                                             st, t1, t2, theta, tolerance, tt
    1659             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: fdiag
    1660             :       TYPE(cp_fm_type)                                   :: rmat
    1661             : 
    1662          34 :       CALL cp_fm_create(rmat, zij_fm_set(1, 1)%matrix_struct)
    1663          34 :       CALL cp_fm_set_all(rmat, 0.0_dp, 1.0_dp)
    1664             : 
    1665          34 :       CALL cp_fm_get_info(rmat, nrow_global=nstate)
    1666         102 :       ALLOCATE (fdiag(nstate))
    1667          34 :       tolerance = 1.0e10_dp
    1668          34 :       sweeps = 0
    1669          34 :       natom = SIZE(zij_fm_set, 1)
    1670          34 :       IF (unit_nr > 0) THEN
    1671             :          WRITE (unit_nr, '(A,T30,A,T45,A,T63,A,T77,A)') &
    1672          17 :             " Jacobi Localization  ", "Sweep", "Functional", "Gradient", "Time"
    1673             :       END IF
    1674             :       ! do jacobi sweeps until converged
    1675         484 :       DO sweeps = 1, max_sweeps
    1676         484 :          t1 = m_walltime()
    1677         484 :          tolerance = 0.0_dp
    1678        7794 :          DO istate = 1, nstate
    1679       76778 :             DO jstate = istate + 1, nstate
    1680             :                aij = 0.0_dp
    1681             :                bij = 0.0_dp
    1682      612858 :                DO iatom = 1, natom
    1683      543874 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, istate, mii)
    1684      543874 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), istate, jstate, mij)
    1685      543874 :                   CALL cp_fm_get_element(zij_fm_set(iatom, 1), jstate, jstate, mjj)
    1686      612858 :                   IF (order == 2) THEN
    1687           0 :                      aij = aij + 4._dp*mij**2 - (mii - mjj)**2
    1688           0 :                      bij = bij + 4._dp*mij*(mii - mjj)
    1689      543874 :                   ELSEIF (order == 4) THEN
    1690             :                      aij = aij - mii**4 - mjj**4 + 6._dp*(mii**2 + mjj**2)*mij**2 + &
    1691      543874 :                            mii**3*mjj + mii*mjj**3
    1692      543874 :                      bij = bij + 4._dp*mij*(mii**3 - mjj**3)
    1693             :                   ELSE
    1694           0 :                      CPABORT("PM order")
    1695             :                   END IF
    1696             :                END DO
    1697       68984 :                IF ((aij**2 + bij**2) < 1.E-10_dp) CYCLE
    1698       68830 :                tolerance = tolerance + bij**2
    1699       68830 :                theta = 0.25_dp*ATAN2(bij, -aij)
    1700       68830 :                ct = COS(theta)
    1701       68830 :                st = SIN(theta)
    1702             : 
    1703       68830 :                CALL cp_fm_rot_cols(rmat, istate, jstate, ct, st)
    1704             : 
    1705      619468 :                DO iatom = 1, natom
    1706      543328 :                   CALL cp_fm_rot_cols(zij_fm_set(iatom, 1), istate, jstate, ct, st)
    1707      612312 :                   CALL cp_fm_rot_rows(zij_fm_set(iatom, 1), istate, jstate, ct, st)
    1708             :                END DO
    1709             :             END DO
    1710             :          END DO
    1711         484 :          ftarget = 0.0_dp
    1712        3462 :          DO iatom = 1, natom
    1713        2978 :             CALL cp_fm_get_diag(zij_fm_set(iatom, 1), fdiag)
    1714       57876 :             ftarget = ftarget + SUM(fdiag**order)
    1715             :          END DO
    1716         484 :          ftarget = ftarget**(1._dp/order)
    1717         484 :          tolerance = SQRT(tolerance)
    1718         484 :          t2 = m_walltime()
    1719         484 :          tt = t2 - t1
    1720         484 :          IF (unit_nr > 0) THEN
    1721         242 :             WRITE (unit_nr, '(T31,I4,T39,F16.8,T55,G16.8,T71,F10.2)') sweeps, ftarget, tolerance, tt
    1722             :          END IF
    1723         484 :          IF (tolerance < accuracy) EXIT
    1724             :       END DO
    1725          34 :       DEALLOCATE (fdiag)
    1726             : 
    1727          34 :       CALL rotate_orbitals(rmat, vectors)
    1728          34 :       CALL cp_fm_release(rmat)
    1729             : 
    1730          68 :    END SUBROUTINE pm_localization
    1731             : ! **************************************************************************************************
    1732             : 
    1733         140 : END MODULE iao_analysis

Generated by: LCOV version 1.15