LCOV - code coverage report
Current view: top level - src - mao_wfn_analysis.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 98.2 % 513 504
Test Date: 2026-07-25 06:35:44 Functions: 100.0 % 3 3

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Calculate MAO's and analyze wavefunctions
      10              : !> \par History
      11              : !>      03.2016 created [JGH]
      12              : !>      12.2016 split into four modules [JGH]
      13              : !> \author JGH
      14              : ! **************************************************************************************************
      15              : MODULE mao_wfn_analysis
      16              :    USE atomic_kind_types,               ONLY: get_atomic_kind
      17              :    USE basis_set_types,                 ONLY: gto_basis_set_p_type
      18              :    USE bibliography,                    ONLY: Ehrhardt1985,&
      19              :                                               Heinzmann1976,&
      20              :                                               cite_reference
      21              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      22              :    USE cp_control_types,                ONLY: dft_control_type
      23              :    USE cp_dbcsr_api,                    ONLY: &
      24              :         dbcsr_copy, dbcsr_create, dbcsr_desymmetrize, dbcsr_distribution_type, dbcsr_get_block_p, &
      25              :         dbcsr_get_info, dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, &
      26              :         dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, &
      27              :         dbcsr_p_type, dbcsr_release, dbcsr_replicate_all, dbcsr_type, dbcsr_type_no_symmetry, &
      28              :         dbcsr_type_symmetric
      29              :    USE cp_dbcsr_cholesky,               ONLY: cp_dbcsr_cholesky_decompose,&
      30              :                                               cp_dbcsr_cholesky_restore
      31              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_dot,&
      32              :                                               dbcsr_get_block_diag,&
      33              :                                               dbcsr_reserve_diag_blocks
      34              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      35              :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set,&
      36              :                                               dbcsr_deallocate_matrix_set
      37              :    USE input_section_types,             ONLY: section_vals_get,&
      38              :                                               section_vals_type,&
      39              :                                               section_vals_val_get
      40              :    USE iterate_matrix,                  ONLY: invert_Hotelling
      41              :    USE kinds,                           ONLY: dp
      42              :    USE kpoint_types,                    ONLY: kpoint_type
      43              :    USE mao_io,                          ONLY: mao_write_pao_restart
      44              :    USE mao_methods,                     ONLY: mao_basis_analysis,&
      45              :                                               mao_build_q,&
      46              :                                               mao_reference_basis
      47              :    USE mao_optimizer,                   ONLY: mao_optimize
      48              :    USE mathlib,                         ONLY: invmat_symm
      49              :    USE message_passing,                 ONLY: mp_para_env_type
      50              :    USE particle_methods,                ONLY: get_particle_set
      51              :    USE particle_types,                  ONLY: particle_type
      52              :    USE qs_environment_types,            ONLY: get_qs_env,&
      53              :                                               qs_environment_type
      54              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      55              :                                               qs_kind_type
      56              :    USE qs_ks_types,                     ONLY: get_ks_env,&
      57              :                                               qs_ks_env_type
      58              :    USE qs_neighbor_list_types,          ONLY: get_iterator_info,&
      59              :                                               neighbor_list_iterate,&
      60              :                                               neighbor_list_iterator_create,&
      61              :                                               neighbor_list_iterator_p_type,&
      62              :                                               neighbor_list_iterator_release,&
      63              :                                               neighbor_list_set_p_type,&
      64              :                                               release_neighbor_list_sets
      65              :    USE qs_neighbor_lists,               ONLY: setup_neighbor_list
      66              :    USE qs_overlap,                      ONLY: build_overlap_matrix_simple
      67              :    USE qs_rho_types,                    ONLY: qs_rho_get,&
      68              :                                               qs_rho_type
      69              : #include "./base/base_uses.f90"
      70              : 
      71              :    IMPLICIT NONE
      72              :    PRIVATE
      73              : 
      74              :    TYPE block_type
      75              :       REAL(KIND=dp), DIMENSION(:, :), ALLOCATABLE  :: mat
      76              :    END TYPE block_type
      77              : 
      78              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mao_wfn_analysis'
      79              : 
      80              :    PUBLIC ::  mao_analysis
      81              : 
      82              : ! **************************************************************************************************
      83              : 
      84              : CONTAINS
      85              : 
      86              : ! **************************************************************************************************
      87              : !> \brief ...
      88              : !> \param qs_env ...
      89              : !> \param input_section ...
      90              : !> \param unit_nr ...
      91              : ! **************************************************************************************************
      92           38 :    SUBROUTINE mao_analysis(qs_env, input_section, unit_nr)
      93              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      94              :       TYPE(section_vals_type), POINTER                   :: input_section
      95              :       INTEGER, INTENT(IN)                                :: unit_nr
      96              : 
      97              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'mao_analysis'
      98              : 
      99              :       CHARACTER(len=2)                                   :: element_symbol, esa, esb, esc
     100              :       INTEGER :: fall, handle, ia, iab, iabc, iatom, ib, ic, icol, ikind, irow, ispin, jatom, &
     101              :          mao_basis, max_iter, me, na, nab, nabc, natom, nb, nc, nimages, nspin, ssize
     102           38 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_sizes, mao_blk, mao_blk_sizes, &
     103           38 :                                                             orb_blk, row_blk_sizes
     104              :       LOGICAL                                            :: analyze_ua, explicit, fo, for, fos, &
     105              :                                                             found, neglect_abc, print_basis, &
     106              :                                                             print_pao
     107              :       REAL(KIND=dp) :: deltaq, electra(2), eps_ab, eps_abc, eps_filter, eps_fun, eps_grad, epsx, &
     108              :          senabc, senmax, threshold, total_charge, total_spin, ua_charge(2), zeff
     109           38 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: occnumA, occnumABC, qab, qmatab, qmatac, &
     110           38 :                                                             qmatbc, raq, sab, selnABC, sinv, &
     111           38 :                                                             smatab, smatac, smatbc, uaq
     112           38 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: occnumAB, selnAB
     113           38 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: block, cmao, diag, qblka, qblkb, qblkc, &
     114           38 :                                                             rblkl, rblku, sblk, sblka, sblkb, sblkc
     115           38 :       TYPE(block_type), ALLOCATABLE, DIMENSION(:)        :: rowblock
     116              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     117              :       TYPE(dbcsr_distribution_type), POINTER             :: dbcsr_dist
     118              :       TYPE(dbcsr_iterator_type)                          :: dbcsr_iter
     119           38 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: mao_coef, mao_dmat, mao_qmat, mao_smat, &
     120           38 :                                                             matrix_q, matrix_smm, matrix_smo
     121           38 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks, matrix_p, matrix_s
     122              :       TYPE(dbcsr_type)                                   :: amat, axmat, cgmat, cholmat, crumat, &
     123              :                                                             qmat, qmat_diag, rumat, smat_diag, &
     124              :                                                             sumat, tmat
     125              :       TYPE(dft_control_type), POINTER                    :: dft_control
     126           38 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: mao_basis_set_list, orb_basis_set_list
     127              :       TYPE(kpoint_type), POINTER                         :: kpoints
     128              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     129              :       TYPE(neighbor_list_iterator_p_type), &
     130           38 :          DIMENSION(:), POINTER                           :: nl_iterator
     131              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     132           38 :          POINTER                                         :: sab_all, sab_orb, smm_list, smo_list
     133           38 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     134           38 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     135              :       TYPE(qs_ks_env_type), POINTER                      :: ks_env
     136              :       TYPE(qs_rho_type), POINTER                         :: rho
     137              : 
     138              : ! only do MAO analysis if explicitely requested
     139              : 
     140           38 :       CALL section_vals_get(input_section, explicit=explicit)
     141           38 :       IF (.NOT. explicit) RETURN
     142              : 
     143           10 :       CALL timeset(routineN, handle)
     144              : 
     145           10 :       IF (unit_nr > 0) THEN
     146            5 :          WRITE (unit_nr, '(/,T2,A)') '!-----------------------------------------------------------------------------!'
     147            5 :          WRITE (UNIT=unit_nr, FMT="(T36,A)") "MAO ANALYSIS"
     148            5 :          WRITE (UNIT=unit_nr, FMT="(T12,A)") "Claus Ehrhardt and Reinhart Ahlrichs, TCA 68:231-245 (1985)"
     149            5 :          WRITE (unit_nr, '(T2,A)') '!-----------------------------------------------------------------------------!'
     150              :       END IF
     151           10 :       CALL cite_reference(Heinzmann1976)
     152           10 :       CALL cite_reference(Ehrhardt1985)
     153              : 
     154              :       ! input options
     155           10 :       CALL section_vals_val_get(input_section, "REFERENCE_BASIS", i_val=mao_basis)
     156           10 :       CALL section_vals_val_get(input_section, "EPS_FILTER", r_val=eps_filter)
     157           10 :       CALL section_vals_val_get(input_section, "EPS_FUNCTION", r_val=eps_fun)
     158           10 :       CALL section_vals_val_get(input_section, "EPS_GRAD", r_val=eps_grad)
     159           10 :       CALL section_vals_val_get(input_section, "MAX_ITER", i_val=max_iter)
     160           10 :       CALL section_vals_val_get(input_section, "PRINT_BASIS", l_val=print_basis)
     161           10 :       CALL section_vals_val_get(input_section, "PRINT_PAO", l_val=print_pao)
     162           10 :       CALL section_vals_val_get(input_section, "NEGLECT_ABC", l_val=neglect_abc)
     163           10 :       CALL section_vals_val_get(input_section, "AB_THRESHOLD", r_val=eps_ab)
     164           10 :       CALL section_vals_val_get(input_section, "ABC_THRESHOLD", r_val=eps_abc)
     165           10 :       CALL section_vals_val_get(input_section, "ANALYZE_UNASSIGNED_CHARGE", l_val=analyze_ua)
     166              : 
     167              :       ! k-points?
     168           10 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     169           10 :       nimages = dft_control%nimages
     170           10 :       IF (nimages > 1) THEN
     171            0 :          IF (unit_nr > 0) THEN
     172              :             WRITE (UNIT=unit_nr, FMT="(T2,A)") &
     173            0 :                "K-Points: MAO's determined and analyzed using Gamma-Point only."
     174              :          END IF
     175              :       END IF
     176              : 
     177              :       ! Reference basis set
     178           10 :       NULLIFY (mao_basis_set_list, orb_basis_set_list)
     179              :       CALL mao_reference_basis(qs_env, mao_basis, mao_basis_set_list, orb_basis_set_list, &
     180           10 :                                unit_nr, print_basis)
     181              : 
     182              :       ! neighbor lists
     183           10 :       NULLIFY (smm_list, smo_list)
     184           10 :       CALL setup_neighbor_list(smm_list, mao_basis_set_list, qs_env=qs_env)
     185           10 :       CALL setup_neighbor_list(smo_list, mao_basis_set_list, orb_basis_set_list, qs_env=qs_env)
     186              : 
     187              :       ! overlap matrices
     188           10 :       NULLIFY (matrix_smm, matrix_smo)
     189           10 :       CALL get_qs_env(qs_env, ks_env=ks_env)
     190              :       CALL build_overlap_matrix_simple(ks_env, matrix_smm, &
     191           10 :                                        mao_basis_set_list, mao_basis_set_list, smm_list)
     192              :       CALL build_overlap_matrix_simple(ks_env, matrix_smo, &
     193           10 :                                        mao_basis_set_list, orb_basis_set_list, smo_list)
     194              : 
     195              :       ! get reference density matrix and overlap matrix
     196           10 :       CALL get_qs_env(qs_env, rho=rho, matrix_s_kp=matrix_s)
     197           10 :       CALL qs_rho_get(rho, rho_ao_kp=matrix_p)
     198           10 :       nspin = SIZE(matrix_p, 1)
     199              :       !
     200              :       ! Q matrix
     201           10 :       IF (nimages == 1) THEN
     202           10 :          CALL mao_build_q(matrix_q, matrix_p, matrix_s, matrix_smm, matrix_smo, smm_list, electra, eps_filter)
     203              :       ELSE
     204            0 :          CALL get_qs_env(qs_env, matrix_ks_kp=matrix_ks, kpoints=kpoints)
     205              :          CALL mao_build_q(matrix_q, matrix_p, matrix_s, matrix_smm, matrix_smo, smm_list, electra, eps_filter, &
     206            0 :                           nimages=nimages, kpoints=kpoints, matrix_ks=matrix_ks, sab_orb=sab_orb)
     207              :       END IF
     208              : 
     209              :       ! check for extended basis sets
     210           10 :       fall = 0
     211           10 :       CALL neighbor_list_iterator_create(nl_iterator, smm_list)
     212           97 :       DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
     213           87 :          CALL get_iterator_info(nl_iterator, iatom=iatom, jatom=jatom)
     214           87 :          IF (iatom <= jatom) THEN
     215           53 :             irow = iatom
     216           53 :             icol = jatom
     217              :          ELSE
     218           34 :             irow = jatom
     219           34 :             icol = iatom
     220              :          END IF
     221              :          CALL dbcsr_get_block_p(matrix=matrix_p(1, 1)%matrix, &
     222           87 :                                 row=irow, col=icol, block=block, found=found)
     223           97 :          IF (.NOT. found) fall = fall + 1
     224              :       END DO
     225           10 :       CALL neighbor_list_iterator_release(nl_iterator)
     226              : 
     227           10 :       CALL get_qs_env(qs_env=qs_env, para_env=para_env)
     228           10 :       CALL para_env%sum(fall)
     229           10 :       IF (unit_nr > 0 .AND. fall > 0) THEN
     230              :          WRITE (UNIT=unit_nr, FMT="(/,T2,A,/,T2,A,/)") &
     231            0 :             "Warning: Extended MAO basis used with original basis filtered density matrix", &
     232            0 :             "Warning: Possible errors can be controlled with EPS_PGF_ORB"
     233              :       END IF
     234              : 
     235              :       ! MAO matrices
     236           10 :       CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set, natom=natom)
     237           10 :       CALL get_ks_env(ks_env=ks_env, particle_set=particle_set, dbcsr_dist=dbcsr_dist)
     238           10 :       NULLIFY (mao_coef)
     239           10 :       CALL dbcsr_allocate_matrix_set(mao_coef, nspin)
     240           40 :       ALLOCATE (row_blk_sizes(natom), col_blk_sizes(natom))
     241              :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=row_blk_sizes, &
     242           10 :                             basis=mao_basis_set_list)
     243           10 :       CALL get_particle_set(particle_set, qs_kind_set, nmao=col_blk_sizes)
     244              :       ! check if MAOs have been specified
     245           58 :       DO iab = 1, natom
     246           58 :          IF (col_blk_sizes(iab) < 0) THEN
     247            0 :             CPABORT("Number of MAOs has to be specified in KIND section for all elements")
     248              :          END IF
     249              :       END DO
     250           22 :       DO ispin = 1, nspin
     251              :          ! coeficients
     252           12 :          ALLOCATE (mao_coef(ispin)%matrix)
     253              :          CALL dbcsr_create(matrix=mao_coef(ispin)%matrix, &
     254              :                            name="MAO_COEF", dist=dbcsr_dist, matrix_type=dbcsr_type_no_symmetry, &
     255           12 :                            row_blk_size=row_blk_sizes, col_blk_size=col_blk_sizes)
     256           22 :          CALL dbcsr_reserve_diag_blocks(matrix=mao_coef(ispin)%matrix)
     257              :       END DO
     258           10 :       DEALLOCATE (row_blk_sizes, col_blk_sizes)
     259              : 
     260              :       ! optimize MAOs
     261           10 :       epsx = 1000.0_dp
     262              :       CALL mao_optimize(mao_coef, matrix_q, matrix_smm, electra, max_iter, eps_grad, epsx, &
     263           10 :                         3, unit_nr)
     264              : 
     265              :       ! Analyze the MAO basis
     266              :       CALL mao_basis_analysis(mao_coef, matrix_smm, mao_basis_set_list, particle_set, &
     267           10 :                               qs_kind_set, unit_nr, para_env)
     268              : 
     269              :       ! Calculate the overlap and density matrix in the new MAO basis
     270           10 :       NULLIFY (mao_dmat, mao_smat, mao_qmat)
     271           10 :       CALL dbcsr_allocate_matrix_set(mao_qmat, nspin)
     272           10 :       CALL dbcsr_allocate_matrix_set(mao_dmat, nspin)
     273           10 :       CALL dbcsr_allocate_matrix_set(mao_smat, nspin)
     274           10 :       CALL dbcsr_get_info(mao_coef(1)%matrix, col_blk_size=col_blk_sizes, distribution=dbcsr_dist)
     275           22 :       DO ispin = 1, nspin
     276           12 :          ALLOCATE (mao_dmat(ispin)%matrix)
     277              :          CALL dbcsr_create(mao_dmat(ispin)%matrix, name="MAO density", dist=dbcsr_dist, &
     278              :                            matrix_type=dbcsr_type_symmetric, row_blk_size=col_blk_sizes, &
     279           12 :                            col_blk_size=col_blk_sizes)
     280           12 :          ALLOCATE (mao_smat(ispin)%matrix)
     281              :          CALL dbcsr_create(mao_smat(ispin)%matrix, name="MAO overlap", dist=dbcsr_dist, &
     282              :                            matrix_type=dbcsr_type_symmetric, row_blk_size=col_blk_sizes, &
     283           12 :                            col_blk_size=col_blk_sizes)
     284           12 :          ALLOCATE (mao_qmat(ispin)%matrix)
     285              :          CALL dbcsr_create(mao_qmat(ispin)%matrix, name="MAO covar density", dist=dbcsr_dist, &
     286              :                            matrix_type=dbcsr_type_symmetric, row_blk_size=col_blk_sizes, &
     287           22 :                            col_blk_size=col_blk_sizes)
     288              :       END DO
     289           10 :       CALL dbcsr_create(amat, name="MAO overlap", template=mao_dmat(1)%matrix)
     290           10 :       CALL dbcsr_create(tmat, name="MAO Overlap Inverse", template=amat)
     291           10 :       CALL dbcsr_create(qmat, name="MAO covar density", template=amat)
     292           10 :       CALL dbcsr_create(cgmat, name="TEMP matrix", template=mao_coef(1)%matrix)
     293           10 :       CALL dbcsr_create(axmat, name="TEMP", template=amat, matrix_type=dbcsr_type_no_symmetry)
     294           22 :       DO ispin = 1, nspin
     295              :          ! calculate MAO overlap matrix
     296              :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_smm(1)%matrix, mao_coef(ispin)%matrix, &
     297           12 :                              0.0_dp, cgmat)
     298           12 :          CALL dbcsr_multiply("T", "N", 1.0_dp, mao_coef(ispin)%matrix, cgmat, 0.0_dp, amat)
     299              :          ! calculate inverse of MAO overlap
     300           12 :          threshold = 1.e-8_dp
     301           12 :          CALL invert_Hotelling(tmat, amat, threshold, norm_convergence=1.e-4_dp, silent=.TRUE.)
     302           12 :          CALL dbcsr_copy(mao_smat(ispin)%matrix, amat)
     303              :          ! calculate q-matrix q = C*Q*C
     304              :          CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_q(ispin)%matrix, mao_coef(ispin)%matrix, &
     305           12 :                              0.0_dp, cgmat, filter_eps=eps_filter)
     306              :          CALL dbcsr_multiply("T", "N", 1.0_dp, mao_coef(ispin)%matrix, cgmat, &
     307           12 :                              0.0_dp, qmat, filter_eps=eps_filter)
     308           12 :          CALL dbcsr_copy(mao_qmat(ispin)%matrix, qmat)
     309              :          ! calculate density matrix
     310           12 :          CALL dbcsr_multiply("N", "N", 1.0_dp, qmat, tmat, 0.0_dp, axmat, filter_eps=eps_filter)
     311              :          CALL dbcsr_multiply("N", "N", 1.0_dp, tmat, axmat, 0.0_dp, mao_dmat(ispin)%matrix, &
     312           22 :                              filter_eps=eps_filter)
     313              :       END DO
     314           10 :       CALL dbcsr_release(amat)
     315           10 :       CALL dbcsr_release(tmat)
     316           10 :       CALL dbcsr_release(qmat)
     317           10 :       CALL dbcsr_release(cgmat)
     318           10 :       CALL dbcsr_release(axmat)
     319              : 
     320              :       ! calculate unassigned charge : n - Tr PS
     321           22 :       DO ispin = 1, nspin
     322           12 :          CALL dbcsr_dot(mao_dmat(ispin)%matrix, mao_smat(ispin)%matrix, ua_charge(ispin))
     323           22 :          ua_charge(ispin) = electra(ispin) - ua_charge(ispin)
     324              :       END DO
     325           10 :       IF (unit_nr > 0) THEN
     326            5 :          WRITE (unit_nr, *)
     327           11 :          DO ispin = 1, nspin
     328              :             WRITE (UNIT=unit_nr, FMT="(T2,A,T32,A,i2,T55,A,F12.8)") &
     329           11 :                "Unassigned charge", "Spin ", ispin, "delta charge =", ua_charge(ispin)
     330              :          END DO
     331              :       END IF
     332              : 
     333              :       ! occupation numbers: single atoms
     334              :       ! We use S_A = 1
     335              :       ! At the gamma point we use an effective MIC
     336           10 :       CALL get_qs_env(qs_env, natom=natom)
     337           40 :       ALLOCATE (occnumA(natom, nspin))
     338           10 :       occnumA = 0.0_dp
     339           22 :       DO ispin = 1, nspin
     340           76 :          DO iatom = 1, natom
     341              :             CALL dbcsr_get_block_p(matrix=mao_qmat(ispin)%matrix, &
     342           54 :                                    row=iatom, col=iatom, block=block, found=found)
     343           66 :             IF (found) THEN
     344           81 :                DO iab = 1, SIZE(block, 1)
     345           81 :                   occnumA(iatom, ispin) = occnumA(iatom, ispin) + block(iab, iab)
     346              :                END DO
     347              :             END IF
     348              :          END DO
     349              :       END DO
     350           10 :       CALL para_env%sum(occnumA)
     351              : 
     352              :       ! occupation numbers: atom pairs
     353           50 :       ALLOCATE (occnumAB(natom, natom, nspin))
     354           10 :       occnumAB = 0.0_dp
     355           22 :       DO ispin = 1, nspin
     356           12 :          CALL dbcsr_create(qmat_diag, name="MAO diagonal density", template=mao_dmat(1)%matrix)
     357           12 :          CALL dbcsr_create(smat_diag, name="MAO diagonal overlap", template=mao_dmat(1)%matrix)
     358              :          ! replicate the diagonal blocks of the density and overlap matrices
     359           12 :          CALL dbcsr_get_block_diag(mao_qmat(ispin)%matrix, qmat_diag)
     360           12 :          CALL dbcsr_replicate_all(qmat_diag)
     361           12 :          CALL dbcsr_get_block_diag(mao_smat(ispin)%matrix, smat_diag)
     362           12 :          CALL dbcsr_replicate_all(smat_diag)
     363           66 :          DO ia = 1, natom
     364          174 :             DO ib = ia + 1, natom
     365          108 :                iab = 0
     366              :                CALL dbcsr_get_block_p(matrix=mao_qmat(ispin)%matrix, &
     367          108 :                                       row=ia, col=ib, block=block, found=found)
     368          108 :                IF (found) iab = 1
     369          108 :                CALL para_env%sum(iab)
     370          108 :                CPASSERT(iab <= 1)
     371          270 :                IF (iab == 0 .AND. para_env%is_source()) THEN
     372              :                   ! AB block is not available N_AB = N_A + N_B
     373              :                   ! Do this only on the "source" processor
     374            0 :                   occnumAB(ia, ib, ispin) = occnumA(ia, ispin) + occnumA(ib, ispin)
     375            0 :                   occnumAB(ib, ia, ispin) = occnumA(ia, ispin) + occnumA(ib, ispin)
     376          108 :                ELSE IF (found) THEN
     377              :                   ! owner of AB block performs calculation
     378           54 :                   na = SIZE(block, 1)
     379           54 :                   nb = SIZE(block, 2)
     380           54 :                   nab = na + nb
     381          432 :                   ALLOCATE (sab(nab, nab), qab(nab, nab), sinv(nab, nab))
     382              :                   ! qmat
     383          327 :                   qab(1:na, na + 1:nab) = block(1:na, 1:nb)
     384          375 :                   qab(na + 1:nab, 1:na) = TRANSPOSE(block(1:na, 1:nb))
     385           54 :                   CALL dbcsr_get_block_p(matrix=qmat_diag, row=ia, col=ia, block=diag, found=fo)
     386           54 :                   CPASSERT(fo)
     387          630 :                   qab(1:na, 1:na) = diag(1:na, 1:na)
     388           54 :                   CALL dbcsr_get_block_p(matrix=qmat_diag, row=ib, col=ib, block=diag, found=fo)
     389           54 :                   CPASSERT(fo)
     390          342 :                   qab(na + 1:nab, na + 1:nab) = diag(1:nb, 1:nb)
     391              :                   ! smat
     392              :                   CALL dbcsr_get_block_p(matrix=mao_smat(ispin)%matrix, &
     393           54 :                                          row=ia, col=ib, block=block, found=fo)
     394           54 :                   CPASSERT(fo)
     395          327 :                   sab(1:na, na + 1:nab) = block(1:na, 1:nb)
     396          375 :                   sab(na + 1:nab, 1:na) = TRANSPOSE(block(1:na, 1:nb))
     397           54 :                   CALL dbcsr_get_block_p(matrix=smat_diag, row=ia, col=ia, block=diag, found=fo)
     398           54 :                   CPASSERT(fo)
     399          630 :                   sab(1:na, 1:na) = diag(1:na, 1:na)
     400           54 :                   CALL dbcsr_get_block_p(matrix=smat_diag, row=ib, col=ib, block=diag, found=fo)
     401           54 :                   CPASSERT(fo)
     402          342 :                   sab(na + 1:nab, na + 1:nab) = diag(1:nb, 1:nb)
     403              :                   ! inv smat
     404         1296 :                   sinv(1:nab, 1:nab) = sab(1:nab, 1:nab)
     405           54 :                   CALL invmat_symm(sinv)
     406              :                   ! Tr(Q*Sinv)
     407         1296 :                   occnumAB(ia, ib, ispin) = SUM(qab*sinv)
     408           54 :                   occnumAB(ib, ia, ispin) = occnumAB(ia, ib, ispin)
     409              :                   !
     410          324 :                   DEALLOCATE (sab, qab, sinv)
     411              :                END IF
     412              :             END DO
     413              :          END DO
     414           12 :          CALL dbcsr_release(qmat_diag)
     415           22 :          CALL dbcsr_release(smat_diag)
     416              :       END DO
     417           10 :       CALL para_env%sum(occnumAB)
     418              : 
     419              :       ! calculate shared electron numbers (AB)
     420           50 :       ALLOCATE (selnAB(natom, natom, nspin))
     421           10 :       selnAB = 0.0_dp
     422           22 :       DO ispin = 1, nspin
     423           76 :          DO ia = 1, natom
     424          174 :             DO ib = ia + 1, natom
     425          108 :                selnAB(ia, ib, ispin) = occnumA(ia, ispin) + occnumA(ib, ispin) - occnumAB(ia, ib, ispin)
     426          162 :                selnAB(ib, ia, ispin) = selnAB(ia, ib, ispin)
     427              :             END DO
     428              :          END DO
     429              :       END DO
     430              : 
     431           10 :       IF (.NOT. neglect_abc) THEN
     432              :          ! calculate N_ABC
     433            8 :          nabc = (natom*(natom - 1)*(natom - 2))/6
     434           32 :          ALLOCATE (occnumABC(nabc, nspin))
     435          142 :          occnumABC = -1.0_dp
     436           18 :          DO ispin = 1, nspin
     437           10 :             CALL dbcsr_create(qmat_diag, name="MAO diagonal density", template=mao_dmat(1)%matrix)
     438           10 :             CALL dbcsr_create(smat_diag, name="MAO diagonal overlap", template=mao_dmat(1)%matrix)
     439              :             ! replicate the diagonal blocks of the density and overlap matrices
     440           10 :             CALL dbcsr_get_block_diag(mao_qmat(ispin)%matrix, qmat_diag)
     441           10 :             CALL dbcsr_replicate_all(qmat_diag)
     442           10 :             CALL dbcsr_get_block_diag(mao_smat(ispin)%matrix, smat_diag)
     443           10 :             CALL dbcsr_replicate_all(smat_diag)
     444           10 :             iabc = 0
     445           58 :             DO ia = 1, natom
     446           48 :                CALL dbcsr_get_block_p(matrix=qmat_diag, row=ia, col=ia, block=qblka, found=fo)
     447           48 :                CPASSERT(fo)
     448           48 :                CALL dbcsr_get_block_p(matrix=smat_diag, row=ia, col=ia, block=sblka, found=fo)
     449           48 :                CPASSERT(fo)
     450           48 :                na = SIZE(qblka, 1)
     451          256 :                DO ib = ia + 1, natom
     452              :                   ! screen with SEN(AB)
     453          102 :                   IF (selnAB(ia, ib, ispin) < eps_abc) THEN
     454           14 :                      iabc = iabc + (natom - ib)
     455           14 :                      CYCLE
     456              :                   END IF
     457           88 :                   CALL dbcsr_get_block_p(matrix=qmat_diag, row=ib, col=ib, block=qblkb, found=fo)
     458           88 :                   CPASSERT(fo)
     459           88 :                   CALL dbcsr_get_block_p(matrix=smat_diag, row=ib, col=ib, block=sblkb, found=fo)
     460           88 :                   CPASSERT(fo)
     461           88 :                   nb = SIZE(qblkb, 1)
     462           88 :                   nab = na + nb
     463          528 :                   ALLOCATE (qmatab(na, nb), smatab(na, nb))
     464              :                   CALL dbcsr_get_block_p(matrix=mao_qmat(ispin)%matrix, row=ia, col=ib, &
     465           88 :                                          block=block, found=found)
     466           88 :                   qmatab = 0.0_dp
     467          320 :                   IF (found) qmatab(1:na, 1:nb) = block(1:na, 1:nb)
     468           88 :                   CALL para_env%sum(qmatab)
     469              :                   CALL dbcsr_get_block_p(matrix=mao_smat(ispin)%matrix, row=ia, col=ib, &
     470           88 :                                          block=block, found=found)
     471           88 :                   smatab = 0.0_dp
     472          320 :                   IF (found) smatab(1:na, 1:nb) = block(1:na, 1:nb)
     473           88 :                   CALL para_env%sum(smatab)
     474          202 :                   DO ic = ib + 1, natom
     475              :                      ! screen with SEN(AB)
     476          114 :                      IF ((selnAB(ia, ic, ispin) < eps_abc) .OR. (selnAB(ib, ic, ispin) < eps_abc)) THEN
     477           24 :                         iabc = iabc + 1
     478           24 :                         CYCLE
     479              :                      END IF
     480           90 :                      CALL dbcsr_get_block_p(matrix=qmat_diag, row=ic, col=ic, block=qblkc, found=fo)
     481           90 :                      CPASSERT(fo)
     482           90 :                      CALL dbcsr_get_block_p(matrix=smat_diag, row=ic, col=ic, block=sblkc, found=fo)
     483           90 :                      CPASSERT(fo)
     484           90 :                      nc = SIZE(qblkc, 1)
     485          540 :                      ALLOCATE (qmatac(na, nc), smatac(na, nc))
     486              :                      CALL dbcsr_get_block_p(matrix=mao_qmat(ispin)%matrix, row=ia, col=ic, &
     487           90 :                                             block=block, found=found)
     488           90 :                      qmatac = 0.0_dp
     489          348 :                      IF (found) qmatac(1:na, 1:nc) = block(1:na, 1:nc)
     490           90 :                      CALL para_env%sum(qmatac)
     491              :                      CALL dbcsr_get_block_p(matrix=mao_smat(ispin)%matrix, row=ia, col=ic, &
     492           90 :                                             block=block, found=found)
     493           90 :                      smatac = 0.0_dp
     494          348 :                      IF (found) smatac(1:na, 1:nc) = block(1:na, 1:nc)
     495           90 :                      CALL para_env%sum(smatac)
     496          540 :                      ALLOCATE (qmatbc(nb, nc), smatbc(nb, nc))
     497              :                      CALL dbcsr_get_block_p(matrix=mao_qmat(ispin)%matrix, row=ib, col=ic, &
     498           90 :                                             block=block, found=found)
     499           90 :                      qmatbc = 0.0_dp
     500          258 :                      IF (found) qmatbc(1:nb, 1:nc) = block(1:nb, 1:nc)
     501           90 :                      CALL para_env%sum(qmatbc)
     502              :                      CALL dbcsr_get_block_p(matrix=mao_smat(ispin)%matrix, row=ib, col=ic, &
     503           90 :                                             block=block, found=found)
     504           90 :                      smatbc = 0.0_dp
     505          258 :                      IF (found) smatbc(1:nb, 1:nc) = block(1:nb, 1:nc)
     506           90 :                      CALL para_env%sum(smatbc)
     507              :                      !
     508           90 :                      nabc = na + nb + nc
     509          720 :                      ALLOCATE (sab(nabc, nabc), sinv(nabc, nabc), qab(nabc, nabc))
     510              :                      !
     511         1242 :                      qab(1:na, 1:na) = qblka(1:na, 1:na)
     512          702 :                      qab(na + 1:nab, na + 1:nab) = qblkb(1:nb, 1:nb)
     513          522 :                      qab(nab + 1:nabc, nab + 1:nabc) = qblkc(1:nc, 1:nc)
     514          648 :                      qab(1:na, na + 1:nab) = qmatab(1:na, 1:nb)
     515          738 :                      qab(na + 1:nab, 1:na) = TRANSPOSE(qmatab(1:na, 1:nb))
     516          606 :                      qab(1:na, nab + 1:nabc) = qmatac(1:na, 1:nc)
     517          726 :                      qab(nab + 1:nabc, 1:na) = TRANSPOSE(qmatac(1:na, 1:nc))
     518          426 :                      qab(na + 1:nab, nab + 1:nabc) = qmatbc(1:nb, 1:nc)
     519          456 :                      qab(nab + 1:nabc, na + 1:nab) = TRANSPOSE(qmatbc(1:nb, 1:nc))
     520              :                      !
     521         1242 :                      sab(1:na, 1:na) = sblka(1:na, 1:na)
     522          702 :                      sab(na + 1:nab, na + 1:nab) = sblkb(1:nb, 1:nb)
     523          522 :                      sab(nab + 1:nabc, nab + 1:nabc) = sblkc(1:nc, 1:nc)
     524          648 :                      sab(1:na, na + 1:nab) = smatab(1:na, 1:nb)
     525          738 :                      sab(na + 1:nab, 1:na) = TRANSPOSE(smatab(1:na, 1:nb))
     526          606 :                      sab(1:na, nab + 1:nabc) = smatac(1:na, 1:nc)
     527          726 :                      sab(nab + 1:nabc, 1:na) = TRANSPOSE(smatac(1:na, 1:nc))
     528          426 :                      sab(na + 1:nab, nab + 1:nabc) = smatbc(1:nb, 1:nc)
     529          456 :                      sab(nab + 1:nabc, na + 1:nab) = TRANSPOSE(smatbc(1:nb, 1:nc))
     530              :                      ! inv smat
     531         4254 :                      sinv(1:nabc, 1:nabc) = sab(1:nabc, 1:nabc)
     532           90 :                      CALL invmat_symm(sinv)
     533              :                      ! Tr(Q*Sinv)
     534           90 :                      iabc = iabc + 1
     535           90 :                      me = MOD(iabc, para_env%num_pe)
     536           90 :                      IF (me == para_env%mepos) THEN
     537         2127 :                         occnumABC(iabc, ispin) = SUM(qab*sinv)
     538              :                      ELSE
     539           45 :                         occnumABC(iabc, ispin) = 0.0_dp
     540              :                      END IF
     541              :                      !
     542           90 :                      DEALLOCATE (sab, sinv, qab)
     543           90 :                      DEALLOCATE (qmatac, smatac)
     544          718 :                      DEALLOCATE (qmatbc, smatbc)
     545              :                   END DO
     546          488 :                   DEALLOCATE (qmatab, smatab)
     547              :                END DO
     548              :             END DO
     549           10 :             CALL dbcsr_release(qmat_diag)
     550           18 :             CALL dbcsr_release(smat_diag)
     551              :          END DO
     552            8 :          CALL para_env%sum(occnumABC)
     553              :       END IF
     554              : 
     555           10 :       IF (.NOT. neglect_abc) THEN
     556              :          ! calculate shared electron numbers (ABC)
     557            8 :          nabc = (natom*(natom - 1)*(natom - 2))/6
     558           32 :          ALLOCATE (selnABC(nabc, nspin))
     559            8 :          selnABC = 0.0_dp
     560           18 :          DO ispin = 1, nspin
     561           10 :             iabc = 0
     562           66 :             DO ia = 1, natom
     563          160 :                DO ib = ia + 1, natom
     564          274 :                   DO ic = ib + 1, natom
     565          124 :                      iabc = iabc + 1
     566          226 :                      IF (occnumABC(iabc, ispin) >= 0.0_dp) THEN
     567              :                         selnABC(iabc, ispin) = occnumA(ia, ispin) + occnumA(ib, ispin) + occnumA(ic, ispin) - &
     568              :                                                occnumAB(ia, ib, ispin) - occnumAB(ia, ic, ispin) - occnumAB(ib, ic, ispin) + &
     569           90 :                                                occnumABC(iabc, ispin)
     570              :                      END IF
     571              :                   END DO
     572              :                END DO
     573              :             END DO
     574              :          END DO
     575              :       END IF
     576              : 
     577              :       ! calculate atomic charge
     578           40 :       ALLOCATE (raq(natom, nspin))
     579           10 :       raq = 0.0_dp
     580           22 :       DO ispin = 1, nspin
     581           66 :          DO ia = 1, natom
     582           54 :             raq(ia, ispin) = occnumA(ia, ispin)
     583          336 :             DO ib = 1, natom
     584          324 :                raq(ia, ispin) = raq(ia, ispin) - 0.5_dp*selnAB(ia, ib, ispin)
     585              :             END DO
     586              :          END DO
     587           22 :          IF (.NOT. neglect_abc) THEN
     588           10 :             iabc = 0
     589           58 :             DO ia = 1, natom
     590          160 :                DO ib = ia + 1, natom
     591          274 :                   DO ic = ib + 1, natom
     592          124 :                      iabc = iabc + 1
     593          124 :                      raq(ia, ispin) = raq(ia, ispin) + selnABC(iabc, ispin)/3._dp
     594          124 :                      raq(ib, ispin) = raq(ib, ispin) + selnABC(iabc, ispin)/3._dp
     595          226 :                      raq(ic, ispin) = raq(ic, ispin) + selnABC(iabc, ispin)/3._dp
     596              :                   END DO
     597              :                END DO
     598              :             END DO
     599              :          END IF
     600              :       END DO
     601              : 
     602              :       ! calculate unassigned charge (from sum over atomic charges)
     603           22 :       DO ispin = 1, nspin
     604           66 :          deltaq = (electra(ispin) - SUM(raq(1:natom, ispin))) - ua_charge(ispin)
     605           22 :          IF (unit_nr > 0) THEN
     606              :             WRITE (UNIT=unit_nr, FMT="(T2,A,T32,A,i2,T55,A,F12.8)") &
     607            6 :                "Cutoff error on charge", "Spin ", ispin, "error charge =", deltaq
     608              :          END IF
     609              :       END DO
     610              : 
     611              :       ! analyze unassigned charge
     612           40 :       ALLOCATE (uaq(natom, nspin))
     613           10 :       uaq = 0.0_dp
     614           10 :       IF (analyze_ua) THEN
     615            8 :          CALL get_qs_env(qs_env=qs_env, para_env=para_env, blacs_env=blacs_env)
     616            8 :          CALL get_qs_env(qs_env=qs_env, sab_orb=sab_orb, sab_all=sab_all)
     617              :          CALL dbcsr_get_info(mao_coef(1)%matrix, row_blk_size=mao_blk_sizes, &
     618            8 :                              col_blk_size=col_blk_sizes, distribution=dbcsr_dist)
     619            8 :          CALL dbcsr_get_info(matrix_s(1, 1)%matrix, row_blk_size=row_blk_sizes)
     620            8 :          CALL dbcsr_create(amat, name="temp", template=matrix_s(1, 1)%matrix)
     621            8 :          CALL dbcsr_create(tmat, name="temp", template=mao_coef(1)%matrix)
     622              :          ! replicate diagonal of smm matrix
     623            8 :          CALL dbcsr_get_block_diag(matrix_smm(1)%matrix, smat_diag)
     624            8 :          CALL dbcsr_replicate_all(smat_diag)
     625              : 
     626           32 :          ALLOCATE (orb_blk(natom), mao_blk(natom))
     627           50 :          DO ia = 1, natom
     628          510 :             orb_blk = row_blk_sizes
     629          510 :             mao_blk = row_blk_sizes
     630           42 :             mao_blk(ia) = col_blk_sizes(ia)
     631              :             CALL dbcsr_create(sumat, name="Smat", dist=dbcsr_dist, matrix_type=dbcsr_type_symmetric, &
     632           42 :                               row_blk_size=mao_blk, col_blk_size=mao_blk)
     633           42 :             CALL cp_dbcsr_alloc_block_from_nbl(sumat, sab_orb)
     634              :             CALL dbcsr_create(cholmat, name="Cholesky matrix", dist=dbcsr_dist, &
     635           42 :                               matrix_type=dbcsr_type_no_symmetry, row_blk_size=mao_blk, col_blk_size=mao_blk)
     636              :             CALL dbcsr_create(rumat, name="Rmat", dist=dbcsr_dist, matrix_type=dbcsr_type_no_symmetry, &
     637           42 :                               row_blk_size=orb_blk, col_blk_size=mao_blk)
     638           42 :             CALL cp_dbcsr_alloc_block_from_nbl(rumat, sab_orb, .TRUE.)
     639              :             CALL dbcsr_create(crumat, name="Rmat*Umat", dist=dbcsr_dist, matrix_type=dbcsr_type_no_symmetry, &
     640           42 :                               row_blk_size=orb_blk, col_blk_size=mao_blk)
     641              :             ! replicate row and col of smo matrix
     642          360 :             ALLOCATE (rowblock(natom))
     643          276 :             DO ib = 1, natom
     644          234 :                na = mao_blk_sizes(ia)
     645          234 :                nb = row_blk_sizes(ib)
     646          936 :                ALLOCATE (rowblock(ib)%mat(na, nb))
     647        20396 :                rowblock(ib)%mat = 0.0_dp
     648              :                CALL dbcsr_get_block_p(matrix=matrix_smo(1)%matrix, row=ia, col=ib, &
     649          234 :                                       block=block, found=found)
     650        10315 :                IF (found) rowblock(ib)%mat(1:na, 1:nb) = block(1:na, 1:nb)
     651          510 :                CALL para_env%sum(rowblock(ib)%mat)
     652              :             END DO
     653              :             !
     654           90 :             DO ispin = 1, nspin
     655           48 :                CALL dbcsr_copy(tmat, mao_coef(ispin)%matrix)
     656           48 :                CALL dbcsr_replicate_all(tmat)
     657           48 :                CALL dbcsr_iterator_start(dbcsr_iter, matrix_s(1, 1)%matrix)
     658          462 :                DO WHILE (dbcsr_iterator_blocks_left(dbcsr_iter))
     659          414 :                   CALL dbcsr_iterator_next_block(dbcsr_iter, iatom, jatom, block)
     660          414 :                   CALL dbcsr_get_block_p(matrix=sumat, row=iatom, col=jatom, block=sblk, found=fos)
     661          414 :                   CPASSERT(fos)
     662          414 :                   CALL dbcsr_get_block_p(matrix=rumat, row=iatom, col=jatom, block=rblku, found=for)
     663          414 :                   CPASSERT(for)
     664          414 :                   CALL dbcsr_get_block_p(matrix=rumat, row=jatom, col=iatom, block=rblkl, found=for)
     665          414 :                   CPASSERT(for)
     666          414 :                   CALL dbcsr_get_block_p(matrix=tmat, row=ia, col=ia, block=cmao, found=found)
     667          414 :                   CPASSERT(found)
     668          462 :                   IF (iatom /= ia .AND. jatom /= ia) THEN
     669              :                      ! copy original overlap matrix
     670        24864 :                      sblk = block
     671        24864 :                      rblku = block
     672        26008 :                      rblkl = TRANSPOSE(block)
     673          126 :                   ELSE IF (iatom /= ia) THEN
     674         3435 :                      rblkl = TRANSPOSE(block)
     675        51390 :                      sblk = MATMUL(TRANSPOSE(rowblock(iatom)%mat), cmao)
     676         1267 :                      rblku = sblk
     677           75 :                   ELSE IF (jatom /= ia) THEN
     678         3083 :                      rblku = block
     679        45327 :                      sblk = MATMUL(TRANSPOSE(cmao), rowblock(jatom)%mat)
     680         1203 :                      rblkl = TRANSPOSE(sblk)
     681              :                   ELSE
     682           24 :                      CALL dbcsr_get_block_p(matrix=smat_diag, row=ia, col=ia, block=block, found=found)
     683           24 :                      CPASSERT(found)
     684       202604 :                      sblk = MATMUL(TRANSPOSE(cmao), MATMUL(block, cmao))
     685        72928 :                      rblku = MATMUL(TRANSPOSE(rowblock(ia)%mat), cmao)
     686              :                   END IF
     687              :                END DO
     688           48 :                CALL dbcsr_iterator_stop(dbcsr_iter)
     689              :                ! Cholesky decomposition of SUMAT = U'U
     690           48 :                CALL dbcsr_desymmetrize(sumat, cholmat)
     691           48 :                CALL cp_dbcsr_cholesky_decompose(cholmat, para_env=para_env, blacs_env=blacs_env)
     692              :                ! T = R*inv(U)
     693          300 :                ssize = SUM(mao_blk)
     694              :                CALL cp_dbcsr_cholesky_restore(rumat, ssize, cholmat, crumat, op="SOLVE", pos="RIGHT", &
     695           48 :                                               transa="N", para_env=para_env, blacs_env=blacs_env)
     696              :                ! A = T*transpose(T)
     697              :                CALL dbcsr_multiply("N", "T", 1.0_dp, crumat, crumat, 0.0_dp, amat, &
     698           48 :                                    filter_eps=eps_filter)
     699              :                ! Tr(P*A)
     700           48 :                CALL dbcsr_dot(matrix_p(ispin, 1)%matrix, amat, uaq(ia, ispin))
     701          138 :                uaq(ia, ispin) = uaq(ia, ispin) - electra(ispin)
     702              :             END DO
     703              :             !
     704           42 :             CALL dbcsr_release(sumat)
     705           42 :             CALL dbcsr_release(cholmat)
     706           42 :             CALL dbcsr_release(rumat)
     707           42 :             CALL dbcsr_release(crumat)
     708              :             !
     709          276 :             DO ib = 1, natom
     710          276 :                DEALLOCATE (rowblock(ib)%mat)
     711              :             END DO
     712          284 :             DEALLOCATE (rowblock)
     713              :          END DO
     714            8 :          CALL dbcsr_release(smat_diag)
     715            8 :          CALL dbcsr_release(amat)
     716            8 :          CALL dbcsr_release(tmat)
     717           16 :          DEALLOCATE (orb_blk, mao_blk)
     718              :       END IF
     719              :       !
     720           76 :       raq(1:natom, 1:nspin) = raq(1:natom, 1:nspin) - uaq(1:natom, 1:nspin)
     721           22 :       DO ispin = 1, nspin
     722           66 :          deltaq = electra(ispin) - SUM(raq(1:natom, ispin))
     723           22 :          IF (unit_nr > 0) THEN
     724              :             WRITE (UNIT=unit_nr, FMT="(T2,A,T32,A,i2,T55,A,F12.8)") &
     725            6 :                "Charge/Atom redistributed", "Spin ", ispin, "delta charge =", &
     726           12 :                (deltaq + ua_charge(ispin))/REAL(natom, KIND=dp)
     727              :          END IF
     728              :       END DO
     729              : 
     730              :       ! output charges
     731           10 :       IF (unit_nr > 0) THEN
     732            5 :          IF (nspin == 1) THEN
     733            4 :             WRITE (unit_nr, "(/,T2,A,T40,A,T75,A)") "MAO atomic charges ", "Atom", "Charge"
     734              :          ELSE
     735            1 :             WRITE (unit_nr, "(/,T2,A,T40,A,T55,A,T70,A)") "MAO atomic charges ", "Atom", "Charge", "Spin Charge"
     736              :          END IF
     737           11 :          DO ispin = 1, nspin
     738           33 :             deltaq = electra(ispin) - SUM(raq(1:natom, ispin))
     739           38 :             raq(:, ispin) = raq(:, ispin) + deltaq/REAL(natom, KIND=dp)
     740              :          END DO
     741            5 :          total_charge = 0.0_dp
     742            5 :          total_spin = 0.0_dp
     743           29 :          DO iatom = 1, natom
     744              :             CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
     745           24 :                                  element_symbol=element_symbol, kind_number=ikind)
     746           24 :             CALL get_qs_kind(qs_kind_set(ikind), zeff=zeff)
     747           29 :             IF (nspin == 1) THEN
     748           21 :                WRITE (unit_nr, "(T30,I6,T42,A2,T69,F12.6)") iatom, element_symbol, zeff - raq(iatom, 1)
     749           21 :                total_charge = total_charge + (zeff - raq(iatom, 1))
     750              :             ELSE
     751            3 :                WRITE (unit_nr, "(T30,I6,T42,A2,T48,F12.6,T69,F12.6)") iatom, element_symbol, &
     752            6 :                   zeff - raq(iatom, 1) - raq(iatom, 2), raq(iatom, 1) - raq(iatom, 2)
     753            3 :                total_charge = total_charge + (zeff - raq(iatom, 1) - raq(iatom, 2))
     754            3 :                total_spin = total_spin + (raq(iatom, 1) - raq(iatom, 2))
     755              :             END IF
     756              :          END DO
     757            5 :          IF (nspin == 1) THEN
     758            4 :             WRITE (unit_nr, "(T2,A,T69,F12.6)") "Total Charge", total_charge
     759              :          ELSE
     760            1 :             WRITE (unit_nr, "(T2,A,T49,F12.6,T69,F12.6)") "Total Charge", total_charge, total_spin
     761              :          END IF
     762              :       END IF
     763              : 
     764           10 :       IF (analyze_ua) THEN
     765              :          ! output unassigned charges
     766            8 :          IF (unit_nr > 0) THEN
     767            4 :             IF (nspin == 1) THEN
     768            3 :                WRITE (unit_nr, "(/,T2,A,T40,A,T75,A)") "MAO hypervalent charges ", "Atom", "Charge"
     769              :             ELSE
     770            1 :                WRITE (unit_nr, "(/,T2,A,T40,A,T55,A,T70,A)") "MAO hypervalent charges ", "Atom", &
     771            2 :                   "Charge", "Spin Charge"
     772              :             END IF
     773            4 :             total_charge = 0.0_dp
     774            4 :             total_spin = 0.0_dp
     775           25 :             DO iatom = 1, natom
     776              :                CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
     777           21 :                                     element_symbol=element_symbol)
     778           25 :                IF (nspin == 1) THEN
     779           18 :                   WRITE (unit_nr, "(T30,I6,T42,A2,T69,F12.6)") iatom, element_symbol, uaq(iatom, 1)
     780           18 :                   total_charge = total_charge + uaq(iatom, 1)
     781              :                ELSE
     782            3 :                   WRITE (unit_nr, "(T30,I6,T42,A2,T48,F12.6,T69,F12.6)") iatom, element_symbol, &
     783            6 :                      uaq(iatom, 1) + uaq(iatom, 2), uaq(iatom, 1) - uaq(iatom, 2)
     784            3 :                   total_charge = total_charge + uaq(iatom, 1) + uaq(iatom, 2)
     785            3 :                   total_spin = total_spin + uaq(iatom, 1) - uaq(iatom, 2)
     786              :                END IF
     787              :             END DO
     788            4 :             IF (nspin == 1) THEN
     789            3 :                WRITE (unit_nr, "(T2,A,T69,F12.6)") "Total Charge", total_charge
     790              :             ELSE
     791            1 :                WRITE (unit_nr, "(T2,A,T49,F12.6,T69,F12.6)") "Total Charge", total_charge, total_spin
     792              :             END IF
     793              :          END IF
     794              :       END IF
     795              : 
     796              :       ! output shared electron numbers AB
     797           10 :       IF (unit_nr > 0) THEN
     798            5 :          IF (nspin == 1) THEN
     799            4 :             WRITE (unit_nr, "(/,T2,A,T31,A,T40,A,T78,A)") "Shared electron numbers ", "Atom", "Atom", "SEN"
     800              :          ELSE
     801            1 :             WRITE (unit_nr, "(/,T2,A,T31,A,T40,A,T51,A,T63,A,T71,A)") "Shared electron numbers ", "Atom", "Atom", &
     802            2 :                "SEN(1)", "SEN(2)", "SEN(total)"
     803              :          END IF
     804           29 :          DO ia = 1, natom
     805           80 :             DO ib = ia + 1, natom
     806           51 :                CALL get_atomic_kind(atomic_kind=particle_set(ia)%atomic_kind, element_symbol=esa)
     807           51 :                CALL get_atomic_kind(atomic_kind=particle_set(ib)%atomic_kind, element_symbol=esb)
     808           75 :                IF (nspin == 1) THEN
     809           48 :                   IF (selnAB(ia, ib, 1) > eps_ab) THEN
     810           31 :                      WRITE (unit_nr, "(T26,I6,' ',A2,T35,I6,' ',A2,T69,F12.6)") ia, esa, ib, esb, selnAB(ia, ib, 1)
     811              :                   END IF
     812              :                ELSE
     813            3 :                   IF ((selnAB(ia, ib, 1) + selnAB(ia, ib, 2)) > eps_ab) THEN
     814            3 :                      WRITE (unit_nr, "(T26,I6,' ',A2,T35,I6,' ',A2,T45,3F12.6)") ia, esa, ib, esb, &
     815            6 :                         selnAB(ia, ib, 1), selnAB(ia, ib, 2), (selnAB(ia, ib, 1) + selnAB(ia, ib, 2))
     816              :                   END IF
     817              :                END IF
     818              :             END DO
     819              :          END DO
     820              :       END IF
     821              : 
     822           10 :       IF (.NOT. neglect_abc) THEN
     823              :          ! output shared electron numbers ABC
     824            8 :          IF (unit_nr > 0) THEN
     825            4 :             WRITE (unit_nr, "(/,T2,A,T40,A,T49,A,T58,A,T78,A)") "Shared electron numbers ABC", &
     826            8 :                "Atom", "Atom", "Atom", "SEN"
     827            4 :             senmax = 0.0_dp
     828            4 :             iabc = 0
     829           25 :             DO ia = 1, natom
     830           73 :                DO ib = ia + 1, natom
     831          130 :                   DO ic = ib + 1, natom
     832           61 :                      iabc = iabc + 1
     833          123 :                      senabc = SUM(selnABC(iabc, :))
     834           61 :                      senmax = MAX(senmax, senabc)
     835          109 :                      IF (senabc > eps_abc) THEN
     836           43 :                         CALL get_atomic_kind(atomic_kind=particle_set(ia)%atomic_kind, element_symbol=esa)
     837           43 :                         CALL get_atomic_kind(atomic_kind=particle_set(ib)%atomic_kind, element_symbol=esb)
     838           43 :                         CALL get_atomic_kind(atomic_kind=particle_set(ic)%atomic_kind, element_symbol=esc)
     839              :                         WRITE (unit_nr, "(T35,I6,' ',A2,T44,I6,' ',A2,T53,I6,' ',A2,T69,F12.6)") &
     840           43 :                            ia, esa, ib, esb, ic, esc, senabc
     841              :                      END IF
     842              :                   END DO
     843              :                END DO
     844              :             END DO
     845            4 :             WRITE (unit_nr, "(T2,A,T69,F12.6)") "Maximum SEN value calculated", senmax
     846              :          END IF
     847              :       END IF
     848              : 
     849           10 :       IF (print_pao) THEN
     850            4 :          CALL mao_write_pao_restart(mao_coef, qs_env)
     851              :       END IF
     852              : 
     853           10 :       IF (unit_nr > 0) THEN
     854              :          WRITE (unit_nr, '(/,T2,A)') &
     855            5 :             '!---------------------------END OF MAO ANALYSIS-------------------------------!'
     856              :       END IF
     857              : 
     858              :       ! Deallocate temporary arrays
     859           10 :       DEALLOCATE (occnumA, occnumAB, selnAB, raq, uaq)
     860           10 :       IF (.NOT. neglect_abc) THEN
     861            8 :          DEALLOCATE (occnumABC, selnABC)
     862              :       END IF
     863              : 
     864              :       ! Deallocate the neighbor list structure
     865           10 :       CALL release_neighbor_list_sets(smm_list)
     866           10 :       CALL release_neighbor_list_sets(smo_list)
     867              : 
     868           10 :       DEALLOCATE (mao_basis_set_list, orb_basis_set_list)
     869              : 
     870           10 :       IF (ASSOCIATED(matrix_smm)) CALL dbcsr_deallocate_matrix_set(matrix_smm)
     871           10 :       IF (ASSOCIATED(matrix_smo)) CALL dbcsr_deallocate_matrix_set(matrix_smo)
     872           10 :       IF (ASSOCIATED(matrix_q)) CALL dbcsr_deallocate_matrix_set(matrix_q)
     873              : 
     874           10 :       IF (ASSOCIATED(mao_coef)) CALL dbcsr_deallocate_matrix_set(mao_coef)
     875           10 :       IF (ASSOCIATED(mao_dmat)) CALL dbcsr_deallocate_matrix_set(mao_dmat)
     876           10 :       IF (ASSOCIATED(mao_smat)) CALL dbcsr_deallocate_matrix_set(mao_smat)
     877           10 :       IF (ASSOCIATED(mao_qmat)) CALL dbcsr_deallocate_matrix_set(mao_qmat)
     878              : 
     879           10 :       CALL timestop(handle)
     880              : 
     881          106 :    END SUBROUTINE mao_analysis
     882              : 
     883           24 : END MODULE mao_wfn_analysis
        

Generated by: LCOV version 2.0-1