LCOV - code coverage report
Current view: top level - src - qs_fb_env_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b4bd748) Lines: 337 350 96.3 %
Date: 2025-03-09 07:56:22 Functions: 8 8 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             : MODULE qs_fb_env_methods
       9             : 
      10             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      11             :                                               get_atomic_kind
      12             :    USE basis_set_types,                 ONLY: get_gto_basis_set,&
      13             :                                               gto_basis_set_p_type,&
      14             :                                               gto_basis_set_type
      15             :    USE cell_types,                      ONLY: cell_type
      16             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      17             :    USE cp_control_types,                ONLY: dft_control_type
      18             :    USE cp_dbcsr_api,                    ONLY: &
      19             :         dbcsr_create, dbcsr_finalize, dbcsr_get_info, dbcsr_iterator_blocks_left, &
      20             :         dbcsr_iterator_next_block, dbcsr_iterator_readonly_start, dbcsr_iterator_stop, &
      21             :         dbcsr_iterator_type, dbcsr_multiply, dbcsr_p_type, dbcsr_release, dbcsr_reserve_blocks, &
      22             :         dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      23             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      24             :                                               dbcsr_allocate_matrix_set,&
      25             :                                               dbcsr_deallocate_matrix_set
      26             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_gemm,&
      27             :                                               cp_fm_symm,&
      28             :                                               cp_fm_triangular_invert,&
      29             :                                               cp_fm_triangular_multiply,&
      30             :                                               cp_fm_uplo_to_full
      31             :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      32             :                                               cp_fm_cholesky_reduce,&
      33             :                                               cp_fm_cholesky_restore
      34             :    USE cp_fm_diag,                      ONLY: choose_eigv_solver,&
      35             :                                               cp_fm_power
      36             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      37             :                                               cp_fm_struct_release,&
      38             :                                               cp_fm_struct_type
      39             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      40             :                                               cp_fm_release,&
      41             :                                               cp_fm_set_all,&
      42             :                                               cp_fm_to_fm,&
      43             :                                               cp_fm_type
      44             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      45             :                                               cp_logger_type
      46             :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      47             :                                               cp_print_key_unit_nr
      48             :    USE cp_units,                        ONLY: cp_unit_from_cp2k
      49             :    USE input_constants,                 ONLY: cholesky_dbcsr,&
      50             :                                               cholesky_inverse,&
      51             :                                               cholesky_off,&
      52             :                                               cholesky_reduce,&
      53             :                                               cholesky_restore
      54             :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      55             :                                               section_vals_type,&
      56             :                                               section_vals_val_get
      57             :    USE kinds,                           ONLY: default_string_length,&
      58             :                                               dp
      59             :    USE message_passing,                 ONLY: mp_para_env_type
      60             :    USE orbital_pointers,                ONLY: nco,&
      61             :                                               ncoset
      62             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      63             :    USE particle_types,                  ONLY: particle_type
      64             :    USE qs_density_matrices,             ONLY: calculate_density_matrix
      65             :    USE qs_diis,                         ONLY: qs_diis_b_step
      66             :    USE qs_environment_types,            ONLY: get_qs_env,&
      67             :                                               qs_environment_type
      68             :    USE qs_fb_atomic_halo_types,         ONLY: &
      69             :         fb_atomic_halo_build_halo_atoms, fb_atomic_halo_cost, fb_atomic_halo_create, &
      70             :         fb_atomic_halo_list_create, fb_atomic_halo_list_nullify, fb_atomic_halo_list_obj, &
      71             :         fb_atomic_halo_list_set, fb_atomic_halo_list_write_info, &
      72             :         fb_atomic_halo_nelectrons_estimate_Z, fb_atomic_halo_nullify, fb_atomic_halo_obj, &
      73             :         fb_atomic_halo_set, fb_atomic_halo_sort, fb_build_pair_radii
      74             :    USE qs_fb_env_types,                 ONLY: fb_env_get,&
      75             :                                               fb_env_has_data,&
      76             :                                               fb_env_obj,&
      77             :                                               fb_env_set
      78             :    USE qs_fb_filter_matrix_methods,     ONLY: fb_fltrmat_build,&
      79             :                                               fb_fltrmat_build_2
      80             :    USE qs_fb_trial_fns_types,           ONLY: fb_trial_fns_create,&
      81             :                                               fb_trial_fns_nullify,&
      82             :                                               fb_trial_fns_obj,&
      83             :                                               fb_trial_fns_release,&
      84             :                                               fb_trial_fns_set
      85             :    USE qs_integral_utils,               ONLY: basis_set_list_setup
      86             :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      87             :                                               qs_kind_type
      88             :    USE qs_mo_occupation,                ONLY: set_mo_occupation
      89             :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
      90             :                                               deallocate_mo_set,&
      91             :                                               get_mo_set,&
      92             :                                               init_mo_set,&
      93             :                                               mo_set_type,&
      94             :                                               set_mo_set
      95             :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      96             :    USE scf_control_types,               ONLY: scf_control_type
      97             :    USE string_utilities,                ONLY: compress,&
      98             :                                               uppercase
      99             : #include "./base/base_uses.f90"
     100             : 
     101             :    IMPLICIT NONE
     102             : 
     103             :    PRIVATE
     104             : 
     105             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_fb_env_methods'
     106             : 
     107             :    PUBLIC :: fb_env_do_diag, &
     108             :              fb_env_read_input, &
     109             :              fb_env_build_rcut_auto, &
     110             :              fb_env_build_atomic_halos, &
     111             :              fb_env_write_info
     112             : 
     113             : CONTAINS
     114             : 
     115             : ! **************************************************************************************************
     116             : !> \brief Do filtered matrix method diagonalisation
     117             : !> \param fb_env : the filter matrix environment
     118             : !> \param qs_env : quickstep environment
     119             : !> \param matrix_ks : DBCSR system (unfiltered) input KS matrix
     120             : !> \param matrix_s  : DBCSR system (unfiltered) input overlap matrix
     121             : !> \param scf_section : SCF input section
     122             : !> \param diis_step : whether we are doing a DIIS step
     123             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     124             : ! **************************************************************************************************
     125          80 :    SUBROUTINE fb_env_do_diag(fb_env, &
     126             :                              qs_env, &
     127             :                              matrix_ks, &
     128             :                              matrix_s, &
     129             :                              scf_section, &
     130             :                              diis_step)
     131             :       TYPE(fb_env_obj), INTENT(INOUT)                    :: fb_env
     132             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     133             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     134             :       TYPE(section_vals_type), POINTER                   :: scf_section
     135             :       LOGICAL, INTENT(INOUT)                             :: diis_step
     136             : 
     137             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'fb_env_do_diag'
     138             : 
     139             :       CHARACTER(len=2)                                   :: spin_string
     140             :       CHARACTER(len=default_string_length)               :: name
     141             :       INTEGER :: filtered_nfullrowsORcols_total, handle, homo_filtered, ispin, lfomo_filtered, &
     142             :          my_nmo, nao, ndep, nelectron, nmo, nmo_filtered, nspin, original_nfullrowsORcols_total
     143          80 :       INTEGER, DIMENSION(:), POINTER                     :: filtered_rowORcol_block_sizes, &
     144          80 :                                                             original_rowORcol_block_sizes
     145             :       LOGICAL                                            :: collective_com
     146             :       REAL(kind=dp) :: diis_error, eps_default, eps_diis, eps_eigval, fermi_level, filter_temp, &
     147             :          flexible_electron_count, KTS_filtered, maxocc, mu_filtered
     148          80 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues, eigenvalues_filtered, occ, &
     149          80 :                                                             occ_filtered
     150             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     151             :       TYPE(cp_fm_struct_type), POINTER                   :: filter_fm_struct, fm_struct
     152             :       TYPE(cp_fm_type)                                   :: fm_matrix_filter, fm_matrix_filtered_ks, &
     153             :                                                             fm_matrix_filtered_s, fm_matrix_ortho, &
     154             :                                                             fm_matrix_work
     155             :       TYPE(cp_fm_type), POINTER                          :: mo_coeff, mo_coeff_filtered
     156          80 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_filter
     157             :       TYPE(dbcsr_type)                                   :: matrix_filtered_ks, matrix_filtered_s, &
     158             :                                                             matrix_tmp
     159             :       TYPE(dbcsr_type), POINTER                          :: matrix_filtered_p
     160             :       TYPE(fb_atomic_halo_list_obj)                      :: atomic_halos
     161             :       TYPE(fb_trial_fns_obj)                             :: trial_fns
     162          80 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos, mos_filtered
     163             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     164          80 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     165             :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     166             :       TYPE(scf_control_type), POINTER                    :: scf_control
     167             : 
     168             : ! TYPE(neighbor_list_set_p_type), DIMENSION(:), POINTER :: sab_orb
     169             : 
     170          80 :       CALL timeset(routineN, handle)
     171             : 
     172          80 :       NULLIFY (scf_env, scf_control, para_env, blacs_env, particle_set)
     173          80 :       NULLIFY (eigenvalues, eigenvalues_filtered, occ, occ_filtered)
     174          80 :       NULLIFY (mos, mos_filtered)
     175          80 :       NULLIFY (matrix_filter, matrix_filtered_p)
     176          80 :       NULLIFY (fm_struct, filter_fm_struct)
     177          80 :       NULLIFY (mo_coeff_filtered, mo_coeff)
     178             :       ! NULLIFY(sab_orb)
     179          80 :       CALL fb_atomic_halo_list_nullify(atomic_halos)
     180          80 :       CALL fb_trial_fns_nullify(trial_fns)
     181          80 :       NULLIFY (original_rowORcol_block_sizes, filtered_rowORcol_block_sizes)
     182             : 
     183             :       ! get qs_env information
     184             :       CALL get_qs_env(qs_env=qs_env, &
     185             :                       scf_env=scf_env, &
     186             :                       scf_control=scf_control, &
     187             :                       para_env=para_env, &
     188             :                       blacs_env=blacs_env, &
     189             :                       particle_set=particle_set, &
     190          80 :                       mos=mos)
     191             : 
     192          80 :       nspin = SIZE(matrix_ks)
     193             : 
     194             :       ! ----------------------------------------------------------------------
     195             :       ! DIIS step - based on non-filtered matrices and MOs
     196             :       ! ----------------------------------------------------------------------
     197             : 
     198         160 :       DO ispin = 1, nspin
     199             :          CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, &
     200         160 :                                scf_env%scf_work1(ispin))
     201             :       END DO
     202             : 
     203          80 :       eps_diis = scf_control%eps_diis
     204          80 :       eps_eigval = EPSILON(0.0_dp)
     205             : 
     206          80 :       IF (scf_env%iter_count > 1 .AND. .NOT. scf_env%skip_diis) THEN
     207             :          CALL qs_diis_b_step(scf_env%scf_diis_buffer, mos, scf_env%scf_work1, &
     208             :                              scf_env%scf_work2, scf_env%iter_delta, &
     209             :                              diis_error, diis_step, eps_diis, scf_control%nmixing, &
     210           0 :                              s_matrix=matrix_s, scf_section=scf_section)
     211             :       ELSE
     212          80 :          diis_step = .FALSE.
     213             :       END IF
     214             : 
     215          80 :       IF (diis_step) THEN
     216           0 :          scf_env%iter_param = diis_error
     217           0 :          scf_env%iter_method = "DIIS/Filter"
     218             :       ELSE
     219          80 :          IF (scf_env%mixing_method == 0) THEN
     220           0 :             scf_env%iter_method = "NoMix/Filter"
     221          80 :          ELSE IF (scf_env%mixing_method == 1) THEN
     222           0 :             scf_env%iter_param = scf_env%p_mix_alpha
     223           0 :             scf_env%iter_method = "P_Mix/Filter"
     224          80 :          ELSE IF (scf_env%mixing_method > 1) THEN
     225          80 :             scf_env%iter_param = scf_env%mixing_store%alpha
     226          80 :             scf_env%iter_method = TRIM(scf_env%mixing_store%iter_method)//"/Filter"
     227             :          END IF
     228             :       END IF
     229             : 
     230             :       ! ----------------------------------------------------------------------
     231             :       ! Construct Filter Matrix
     232             :       ! ----------------------------------------------------------------------
     233             : 
     234             :       CALL fb_env_get(fb_env=fb_env, &
     235             :                       filter_temperature=filter_temp, &
     236             :                       atomic_halos=atomic_halos, &
     237          80 :                       eps_default=eps_default)
     238             : 
     239             :       ! construct trial functions
     240          80 :       CALL get_mo_set(mo_set=mos(1), maxocc=maxocc)
     241          80 :       CALL fb_env_build_trial_fns_auto(fb_env, qs_env, maxocc)
     242             :       CALL fb_env_get(fb_env=fb_env, &
     243          80 :                       trial_fns=trial_fns)
     244             : 
     245             :       ! allocate filter matrix (matrix_filter(ispin)%matrix are
     246             :       ! nullified by dbcsr_allocate_matrix_set)
     247          80 :       CALL dbcsr_allocate_matrix_set(matrix_filter, nspin)
     248         160 :       DO ispin = 1, nspin
     249             :          ! get system-wide fermi energy and occupancy, we use this to
     250             :          ! define the filter function used for the filter matrix
     251             :          CALL get_mo_set(mo_set=mos(ispin), &
     252             :                          mu=fermi_level, &
     253          80 :                          maxocc=maxocc)
     254             :          ! get filter matrix name
     255          80 :          WRITE (spin_string, FMT="(I1)") ispin
     256          80 :          name = TRIM("FILTER MATRIX SPIN "//spin_string)
     257          80 :          CALL compress(name)
     258          80 :          CALL uppercase(name)
     259             :          ! calculate filter matrix (matrix_s(1) is the overlap, the rest
     260             :          ! in the array are its derivatives)
     261             :          CALL fb_env_get(fb_env=fb_env, &
     262          80 :                          collective_com=collective_com)
     263         240 :          IF (collective_com) THEN
     264             :             CALL fb_fltrmat_build_2(H_mat=matrix_ks(ispin)%matrix, &
     265             :                                     S_mat=matrix_s(1)%matrix, &
     266             :                                     atomic_halos=atomic_halos, &
     267             :                                     trial_fns=trial_fns, &
     268             :                                     para_env=para_env, &
     269             :                                     particle_set=particle_set, &
     270             :                                     fermi_level=fermi_level, &
     271             :                                     filter_temp=filter_temp, &
     272             :                                     name=name, &
     273             :                                     filter_mat=matrix_filter(ispin)%matrix, &
     274          16 :                                     tolerance=eps_default)
     275             :          ELSE
     276             :             CALL fb_fltrmat_build(H_mat=matrix_ks(ispin)%matrix, &
     277             :                                   S_mat=matrix_s(1)%matrix, &
     278             :                                   atomic_halos=atomic_halos, &
     279             :                                   trial_fns=trial_fns, &
     280             :                                   para_env=para_env, &
     281             :                                   particle_set=particle_set, &
     282             :                                   fermi_level=fermi_level, &
     283             :                                   filter_temp=filter_temp, &
     284             :                                   name=name, &
     285             :                                   filter_mat=matrix_filter(ispin)%matrix, &
     286          64 :                                   tolerance=eps_default)
     287             :          END IF
     288             :       END DO ! ispin
     289             : 
     290             :       ! ----------------------------------------------------------------------
     291             :       ! Do Filtered Diagonalisation
     292             :       ! ----------------------------------------------------------------------
     293             : 
     294             :       ! Obtain matrix dimensions. KS and S matrices are symmetric, so
     295             :       ! row_block_sizes and col_block_sizes should be identical. The
     296             :       ! same applies to the filtered block sizes. Note that filter
     297             :       ! matrix will have row_block_sizes equal to that of the original,
     298             :       ! and col_block_sizes equal to that of the filtered.  We assume
     299             :       ! also that the matrix dimensions are identical for both spin
     300             :       ! channels.
     301             :       CALL dbcsr_get_info(matrix_ks(1)%matrix, &
     302             :                           row_blk_size=original_rowORcol_block_sizes, &
     303          80 :                           nfullrows_total=original_nfullrowsORcols_total)
     304             :       CALL dbcsr_get_info(matrix_filter(1)%matrix, &
     305             :                           col_blk_size=filtered_rowORcol_block_sizes, &
     306          80 :                           nfullcols_total=filtered_nfullrowsORcols_total)
     307             : 
     308             :       ! filter diagonalisation works on a smaller basis set, and thus
     309             :       ! requires a new mo_set (molecular orbitals | eigenvectors) and
     310             :       ! the corresponding matrix pools for the eigenvector coefficients
     311         320 :       ALLOCATE (mos_filtered(nspin))
     312         160 :       DO ispin = 1, nspin
     313             :          CALL get_mo_set(mo_set=mos(ispin), &
     314             :                          maxocc=maxocc, &
     315             :                          nelectron=nelectron, &
     316          80 :                          flexible_electron_count=flexible_electron_count)
     317             :          CALL allocate_mo_set(mo_set=mos_filtered(ispin), &
     318             :                               nao=filtered_nfullrowsORcols_total, &
     319             :                               nmo=filtered_nfullrowsORcols_total, &
     320             :                               nelectron=nelectron, &
     321             :                               n_el_f=REAL(nelectron, dp), &
     322             :                               maxocc=maxocc, &
     323         160 :                               flexible_electron_count=flexible_electron_count)
     324             :       END DO ! ispin
     325             : 
     326             :       ! create DBCSR filtered KS matrix, this is reused for each spin
     327             :       ! channel
     328             :       ! both row_blk_size and col_blk_size should be that of
     329             :       ! col_blk_size of the filter matrix
     330             :       CALL dbcsr_create(matrix=matrix_filtered_ks, template=matrix_ks(1)%matrix, &
     331             :                         name=TRIM("FILTERED_KS_MATRIX"), &
     332             :                         matrix_type=dbcsr_type_no_symmetry, &
     333             :                         row_blk_size=filtered_rowORcol_block_sizes, &
     334          80 :                         col_blk_size=filtered_rowORcol_block_sizes)
     335          80 :       CALL dbcsr_finalize(matrix_filtered_ks)
     336             : 
     337             :       ! create DBCSR filtered S (overlap) matrix. Note that
     338             :       ! matrix_s(1)%matrix is the original overlap matrix---the rest in
     339             :       ! the array are derivatives, and it should not depend on
     340             :       ! spin. HOWEVER, since the filter matrix is constructed from KS
     341             :       ! matrix, and does depend on spin, the filtered S also becomes
     342             :       ! spin dependent. Nevertheless this matrix is reused for each spin
     343             :       ! channel
     344             :       ! both row_blk_size and col_blk_size should be that of
     345             :       ! col_blk_size of the filter matrix
     346             :       CALL dbcsr_create(matrix=matrix_filtered_s, template=matrix_s(1)%matrix, &
     347             :                         name=TRIM("FILTERED_S_MATRIX"), &
     348             :                         matrix_type=dbcsr_type_no_symmetry, &
     349             :                         row_blk_size=filtered_rowORcol_block_sizes, &
     350          80 :                         col_blk_size=filtered_rowORcol_block_sizes)
     351          80 :       CALL dbcsr_finalize(matrix_filtered_s)
     352             : 
     353             :       ! create temporary matrix for constructing filtered KS and S
     354             :       ! the temporary matrix won't be square
     355             :       CALL dbcsr_create(matrix=matrix_tmp, template=matrix_s(1)%matrix, &
     356             :                         name=TRIM("TEMPORARY_MATRIX"), &
     357             :                         matrix_type=dbcsr_type_no_symmetry, &
     358             :                         row_blk_size=original_rowORcol_block_sizes, &
     359          80 :                         col_blk_size=filtered_rowORcol_block_sizes)
     360          80 :       CALL dbcsr_finalize(matrix_tmp)
     361             : 
     362             :       ! create fm format matrices used for diagonalisation
     363             :       CALL cp_fm_struct_create(fmstruct=fm_struct, &
     364             :                                para_env=para_env, &
     365             :                                context=blacs_env, &
     366             :                                nrow_global=filtered_nfullrowsORcols_total, &
     367          80 :                                ncol_global=filtered_nfullrowsORcols_total)
     368             :       ! both fm_matrix_filtered_s and fm_matrix_filtered_ks are reused
     369             :       ! for each spin channel
     370             :       CALL cp_fm_create(fm_matrix_filtered_s, &
     371             :                         fm_struct, &
     372          80 :                         name="FM_MATRIX_FILTERED_S")
     373             :       CALL cp_fm_create(fm_matrix_filtered_ks, &
     374             :                         fm_struct, &
     375          80 :                         name="FM_MATRIX_FILTERED_KS")
     376             :       ! creaate work matrix
     377          80 :       CALL cp_fm_create(fm_matrix_work, fm_struct, name="FM_MATRIX_WORK")
     378          80 :       CALL cp_fm_create(fm_matrix_ortho, fm_struct, name="FM_MATRIX_ORTHO")
     379             :       ! all fm matrices are created, so can release fm_struct
     380          80 :       CALL cp_fm_struct_release(fm_struct)
     381             : 
     382             :       ! construct filtered KS, S matrix and diagonalise
     383         160 :       DO ispin = 1, nspin
     384             : 
     385             :          ! construct filtered KS matrix
     386             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     387             :                              matrix_ks(ispin)%matrix, matrix_filter(ispin)%matrix, &
     388          80 :                              0.0_dp, matrix_tmp)
     389             :          CALL dbcsr_multiply("T", "N", 1.0_dp, &
     390             :                              matrix_filter(ispin)%matrix, matrix_tmp, &
     391          80 :                              0.0_dp, matrix_filtered_ks)
     392             :          ! construct filtered S_matrix
     393             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     394             :                              matrix_s(1)%matrix, matrix_filter(ispin)%matrix, &
     395          80 :                              0.0_dp, matrix_tmp)
     396             :          CALL dbcsr_multiply("T", "N", 1.0_dp, &
     397             :                              matrix_filter(ispin)%matrix, matrix_tmp, &
     398          80 :                              0.0_dp, matrix_filtered_s)
     399             : 
     400             :          ! now that we have the filtered KS and S matrices for this spin
     401             :          ! channel, perform ordinary diagonalisation
     402             : 
     403             :          ! convert DBCSR matrices to fm format
     404          80 :          CALL copy_dbcsr_to_fm(matrix_filtered_s, fm_matrix_filtered_s)
     405          80 :          CALL copy_dbcsr_to_fm(matrix_filtered_ks, fm_matrix_filtered_ks)
     406             : 
     407          80 :          CALL get_mo_set(mos_filtered(ispin), nmo=nmo, nao=nao)
     408             : 
     409             :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao, &
     410             :                                   ncol_global=nmo, para_env=para_env, &
     411          80 :                                   context=blacs_env)
     412             : 
     413             :          ! setup matrix pools for the molecular orbitals
     414             :          CALL init_mo_set(mos_filtered(ispin), &
     415             :                           fm_struct=fm_struct, &
     416          80 :                           name="FILTERED_MOS")
     417          80 :          CALL cp_fm_struct_release(fm_struct)
     418             : 
     419             :          ! now diagonalise
     420             :          CALL fb_env_eigensolver(fm_matrix_filtered_ks, &
     421             :                                  fm_matrix_filtered_s, &
     422             :                                  mos_filtered(ispin), &
     423             :                                  fm_matrix_ortho, &
     424             :                                  fm_matrix_work, &
     425             :                                  eps_eigval, &
     426             :                                  ndep, &
     427         240 :                                  scf_env%cholesky_method)
     428             :       END DO ! ispin
     429             : 
     430             :       ! release temporary matrices
     431          80 :       CALL dbcsr_release(matrix_filtered_s)
     432          80 :       CALL dbcsr_release(matrix_filtered_ks)
     433          80 :       CALL cp_fm_release(fm_matrix_filtered_s)
     434          80 :       CALL cp_fm_release(fm_matrix_filtered_ks)
     435          80 :       CALL cp_fm_release(fm_matrix_work)
     436          80 :       CALL cp_fm_release(fm_matrix_ortho)
     437             : 
     438             :       ! ----------------------------------------------------------------------
     439             :       ! Construct New Density Matrix
     440             :       ! ----------------------------------------------------------------------
     441             : 
     442             :       ! calculate filtered molecular orbital occupation numbers and fermi
     443             :       ! level etc
     444             :       CALL set_mo_occupation(mo_array=mos_filtered, &
     445          80 :                              smear=scf_control%smear)
     446             : 
     447             :       ! get the filtered density matrix and then convert back to the
     448             :       ! full basis version in scf_env ready to be used outside this
     449             :       ! subroutine
     450          80 :       ALLOCATE (matrix_filtered_p)
     451             :       ! the filtered density matrix should have the same sparse
     452             :       ! structure as the original density matrix, we must copy the
     453             :       ! sparse structure here, since construction of the density matrix
     454             :       ! preserves its sparse form, and therefore matrix_filtered_p must
     455             :       ! have its blocks allocated here now. We assume the original
     456             :       ! density matrix scf_env%p_mix_new has the same sparse structure
     457             :       ! in both spin channels.
     458             :       CALL dbcsr_create(matrix=matrix_filtered_p, template=scf_env%p_mix_new(1, 1)%matrix, &
     459             :                         name=TRIM("FILTERED_MATRIX_P"), &
     460             :                         row_blk_size=filtered_rowORcol_block_sizes, &
     461          80 :                         col_blk_size=filtered_rowORcol_block_sizes)
     462          80 :       CALL dbcsr_finalize(matrix_filtered_p)
     463             :       CALL fb_dbcsr_copy_sparse_struct(matrix_filtered_p, &
     464          80 :                                        scf_env%p_mix_new(1, 1)%matrix)
     465             :       ! old implementation, using sab_orb to allocate the blocks in matrix_filtered_p
     466             :       ! CALL get_qs_env(qs_env=qs_env, sab_orb=sab_orb)
     467             :       ! CALL cp_dbcsr_alloc_block_from_nbl(matrix_filtered_p, sab_orb)
     468          80 :       CALL dbcsr_set(matrix_filtered_p, 0.0_dp)
     469             : 
     470         160 :       DO ispin = 1, nspin
     471             :          ! calculate matrix_filtered_p
     472             :          CALL calculate_density_matrix(mos_filtered(ispin), &
     473          80 :                                        matrix_filtered_p)
     474             :          ! convert back to full basis p
     475             :          CALL dbcsr_multiply("N", "N", 1.0_dp, &
     476             :                              matrix_filter(ispin)%matrix, matrix_filtered_p, &
     477          80 :                              0.0_dp, matrix_tmp)
     478             :          CALL dbcsr_multiply("N", "T", 1.0_dp, &
     479             :                              matrix_tmp, matrix_filter(ispin)%matrix, &
     480             :                              0.0_dp, scf_env%p_mix_new(ispin, 1)%matrix, &
     481         160 :                              retain_sparsity=.TRUE.)
     482             :          ! note that we want to retain the sparse structure of
     483             :          ! scf_env%p_mix_new
     484             :       END DO ! ispin
     485             : 
     486             :       ! release temporary matrices
     487          80 :       CALL dbcsr_release(matrix_tmp)
     488          80 :       CALL dbcsr_release(matrix_filtered_p)
     489          80 :       DEALLOCATE (matrix_filtered_p)
     490             : 
     491             :       ! ----------------------------------------------------------------------
     492             :       ! Update MOs
     493             :       ! ----------------------------------------------------------------------
     494             : 
     495             :       ! we still need to convert mos_filtered back to the full basis
     496             :       ! version (mos) for this, we need to update mo_coeff (and/or
     497             :       ! mo_coeff_b --- the DBCSR version, if used) of mos
     498             : 
     499             :       ! note also that mo_eigenvalues cannot be fully updated, given
     500             :       ! that the eigenvalues are computed in a smaller basis, and thus
     501             :       ! do not give the full spectron. Printing of molecular states
     502             :       ! (molecular DOS) at each SCF step is therefore not recommended
     503             :       ! when using this method. The idea is that if one wants a full
     504             :       ! molecular DOS, then one should perform a full diagonalisation
     505             :       ! without the filters once the SCF has been achieved.
     506             : 
     507             :       ! NOTE: from reading the source code, it appears that mo_coeff_b
     508             :       ! is actually never used by default (DOUBLE CHECK?!). Even
     509             :       ! subroutine eigensolver_dbcsr updates mo_coeff, and not
     510             :       ! mo_coeff_b.
     511             : 
     512             :       ! create FM format filter matrix
     513             :       CALL cp_fm_struct_create(fmstruct=filter_fm_struct, &
     514             :                                para_env=para_env, &
     515             :                                context=blacs_env, &
     516             :                                nrow_global=original_nfullrowsORcols_total, &
     517          80 :                                ncol_global=filtered_nfullrowsORcols_total)
     518             :       CALL cp_fm_create(fm_matrix_filter, &
     519             :                         filter_fm_struct, &
     520          80 :                         name="FM_MATRIX_FILTER")
     521          80 :       CALL cp_fm_struct_release(filter_fm_struct)
     522             : 
     523         160 :       DO ispin = 1, nspin
     524             :          ! now the full basis mo_set should only contain the reduced
     525             :          ! number of eigenvectors and eigenvalues
     526             :          CALL get_mo_set(mo_set=mos_filtered(ispin), &
     527             :                          homo=homo_filtered, &
     528             :                          lfomo=lfomo_filtered, &
     529             :                          nmo=nmo_filtered, &
     530             :                          eigenvalues=eigenvalues_filtered, &
     531             :                          occupation_numbers=occ_filtered, &
     532             :                          mo_coeff=mo_coeff_filtered, &
     533             :                          kTS=kTS_filtered, &
     534          80 :                          mu=mu_filtered)
     535             :          ! first set all the relevant scalars
     536             :          CALL set_mo_set(mo_set=mos(ispin), &
     537             :                          homo=homo_filtered, &
     538             :                          lfomo=lfomo_filtered, &
     539             :                          kTS=kTS_filtered, &
     540          80 :                          mu=mu_filtered)
     541             :          ! now set the arrays and fm_matrices
     542             :          CALL get_mo_set(mo_set=mos(ispin), &
     543             :                          nmo=nmo, &
     544             :                          occupation_numbers=occ, &
     545             :                          eigenvalues=eigenvalues, &
     546          80 :                          mo_coeff=mo_coeff)
     547             :          ! number of mos in original mo_set may sometimes be less than
     548             :          ! nmo_filtered, so we must make sure we do not go out of bounds
     549          80 :          my_nmo = MIN(nmo, nmo_filtered)
     550        2640 :          eigenvalues(:) = 0.0_dp
     551        5200 :          eigenvalues(1:my_nmo) = eigenvalues_filtered(1:my_nmo)
     552        2640 :          occ(:) = 0.0_dp
     553        5200 :          occ(1:my_nmo) = occ_filtered(1:my_nmo)
     554             :          ! convert mo_coeff_filtered back to original basis
     555          80 :          CALL cp_fm_set_all(matrix=mo_coeff, alpha=0.0_dp)
     556          80 :          CALL copy_dbcsr_to_fm(matrix_filter(ispin)%matrix, fm_matrix_filter)
     557             :          CALL cp_fm_gemm("N", "N", &
     558             :                          original_nfullrowsORcols_total, &
     559             :                          my_nmo, &
     560             :                          filtered_nfullrowsORcols_total, &
     561             :                          1.0_dp, fm_matrix_filter, mo_coeff_filtered, &
     562         320 :                          0.0_dp, mo_coeff)
     563             : 
     564             :       END DO ! ispin
     565             : 
     566             :       ! release temporary matrices
     567          80 :       CALL cp_fm_release(fm_matrix_filter)
     568             : 
     569             :       ! ----------------------------------------------------------------------
     570             :       ! Final Clean Up
     571             :       ! ----------------------------------------------------------------------
     572             : 
     573         160 :       DO ispin = 1, nspin
     574         160 :          CALL deallocate_mo_set(mo_set=mos_filtered(ispin))
     575             :       END DO
     576          80 :       DEALLOCATE (mos_filtered)
     577          80 :       CALL dbcsr_deallocate_matrix_set(matrix_filter)
     578             : 
     579          80 :       CALL timestop(handle)
     580             : 
     581         480 :    END SUBROUTINE fb_env_do_diag
     582             : 
     583             : ! **************************************************************************************************
     584             : !> \brief The main parallel eigensolver engine for filter matrix diagonalisation
     585             : !> \param fm_KS : the BLACS distributed Kohn-Sham matrix, input only
     586             : !> \param fm_S  : the BLACS distributed overlap matrix, input only
     587             : !> \param mo_set : upon output contains the molecular orbitals (eigenvectors)
     588             : !>                 and eigenvalues
     589             : !> \param fm_ortho : one of the work matrices, on output, the BLACS distributed
     590             : !>                   matrix for orthogalising the eigen problem. E.g. if using
     591             : !>                   Cholesky inversse, then the upper triangle part contains
     592             : !>                   the inverse of Cholesky U; if not using Cholesky, then it
     593             : !>                   contains the S^-1/2.
     594             : !> \param fm_work : work matrix used by eigen solver
     595             : !> \param eps_eigval : used for quenching the small numbers when computing S^-1/2
     596             : !>                     any values less than eps_eigval is truncated to zero.
     597             : !> \param ndep : if the overlap is not positive definite, then ndep > 0,
     598             : !>               and equals to the number of linear dependent basis functions
     599             : !>               in the filtered basis set
     600             : !> \param method : method for solving generalised eigenvalue problem
     601             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     602             : ! **************************************************************************************************
     603         160 :    SUBROUTINE fb_env_eigensolver(fm_KS, fm_S, mo_set, fm_ortho, &
     604             :                                  fm_work, eps_eigval, ndep, method)
     605             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_KS, fm_S
     606             :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     607             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_ortho, fm_work
     608             :       REAL(KIND=dp), INTENT(IN)                          :: eps_eigval
     609             :       INTEGER, INTENT(OUT)                               :: ndep
     610             :       INTEGER, INTENT(IN)                                :: method
     611             : 
     612             :       CHARACTER(len=*), PARAMETER :: routineN = 'fb_env_eigensolver'
     613             : 
     614             :       CHARACTER(len=8)                                   :: ndep_string
     615             :       INTEGER                                            :: handle, info, my_method, nao, nmo
     616          80 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: mo_eigenvalues
     617             :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     618             : 
     619          80 :       CALL timeset(routineN, handle)
     620             : 
     621             :       CALL get_mo_set(mo_set=mo_set, &
     622             :                       nao=nao, &
     623             :                       nmo=nmo, &
     624             :                       eigenvalues=mo_eigenvalues, &
     625          80 :                       mo_coeff=mo_coeff)
     626          80 :       my_method = method
     627          80 :       ndep = 0
     628             : 
     629             :       ! first, obtain orthogonalisation (ortho) matrix
     630          80 :       IF (my_method .NE. cholesky_off) THEN
     631          64 :          CALL cp_fm_to_fm(fm_S, fm_ortho)
     632          64 :          CALL cp_fm_cholesky_decompose(fm_ortho, info_out=info)
     633          64 :          IF (info .NE. 0) THEN
     634             :             CALL cp_warn(__LOCATION__, &
     635             :                          "Unable to perform Cholesky decomposition on the overlap "// &
     636             :                          "matrix. The new filtered basis may not be linearly "// &
     637             :                          "independent set. Revert to using inverse square-root "// &
     638             :                          "of the overlap. To avoid this warning, you can try "// &
     639           0 :                          "to use a higher filter termperature.")
     640             :             my_method = cholesky_off
     641             :          ELSE
     642           0 :             SELECT CASE (my_method)
     643             :             CASE (cholesky_dbcsr)
     644             :                CALL cp_abort(__LOCATION__, &
     645           0 :                              "filter matrix method with CHOLESKY_DBCSR is not yet implemented")
     646             :             CASE (cholesky_reduce)
     647          16 :                CALL cp_fm_cholesky_reduce(fm_KS, fm_ortho)
     648          16 :                CALL choose_eigv_solver(fm_KS, fm_work, mo_eigenvalues)
     649          16 :                CALL cp_fm_cholesky_restore(fm_work, nmo, fm_ortho, mo_coeff, "SOLVE")
     650             :             CASE (cholesky_restore)
     651          32 :                CALL cp_fm_uplo_to_full(fm_KS, fm_work)
     652             :                CALL cp_fm_cholesky_restore(fm_KS, nao, fm_ortho, fm_work, "SOLVE", &
     653          32 :                                            pos="RIGHT")
     654             :                CALL cp_fm_cholesky_restore(fm_work, nao, fm_ortho, fm_KS, "SOLVE", &
     655          32 :                                            pos="LEFT", transa="T")
     656          32 :                CALL choose_eigv_solver(fm_KS, fm_work, mo_eigenvalues)
     657          32 :                CALL cp_fm_cholesky_restore(fm_work, nmo, fm_ortho, mo_coeff, "SOLVE")
     658             :             CASE (cholesky_inverse)
     659          16 :                CALL cp_fm_triangular_invert(fm_ortho)
     660          16 :                CALL cp_fm_uplo_to_full(fm_KS, fm_work)
     661             :                CALL cp_fm_triangular_multiply(fm_ortho, &
     662             :                                               fm_KS, &
     663             :                                               side="R", &
     664             :                                               transpose_tr=.FALSE., &
     665             :                                               invert_tr=.FALSE., &
     666             :                                               uplo_tr="U", &
     667             :                                               n_rows=nao, &
     668             :                                               n_cols=nao, &
     669          16 :                                               alpha=1.0_dp)
     670             :                CALL cp_fm_triangular_multiply(fm_ortho, &
     671             :                                               fm_KS, &
     672             :                                               side="L", &
     673             :                                               transpose_tr=.TRUE., &
     674             :                                               invert_tr=.FALSE., &
     675             :                                               uplo_tr="U", &
     676             :                                               n_rows=nao, &
     677             :                                               n_cols=nao, &
     678          16 :                                               alpha=1.0_dp)
     679          16 :                CALL choose_eigv_solver(fm_KS, fm_work, mo_eigenvalues)
     680             :                CALL cp_fm_triangular_multiply(fm_ortho, &
     681             :                                               fm_work, &
     682             :                                               side="L", &
     683             :                                               transpose_tr=.FALSE., &
     684             :                                               invert_tr=.FALSE., &
     685             :                                               uplo_tr="U", &
     686             :                                               n_rows=nao, &
     687             :                                               n_cols=nmo, &
     688          16 :                                               alpha=1.0_dp)
     689          80 :                CALL cp_fm_to_fm(fm_work, mo_coeff, nmo, 1, 1)
     690             :             END SELECT
     691             :          END IF
     692             :       END IF
     693             :       IF (my_method == cholesky_off) THEN
     694             :          ! calculating ortho as S^-1/2 using diagonalisation of S, and
     695             :          ! solve accordingly
     696          16 :          CALL cp_fm_to_fm(fm_S, fm_ortho)
     697             :          CALL cp_fm_power(fm_ortho, fm_work, -0.5_dp, &
     698          16 :                           eps_eigval, ndep)
     699          16 :          IF (ndep > 0) THEN
     700           0 :             WRITE (ndep_string, FMT="(I8)") ndep
     701             :             CALL cp_warn(__LOCATION__, &
     702           0 :                          "Number of linearly dependent filtered orbitals: "//ndep_string)
     703             :          END IF
     704             :          ! solve eigen equatoin using S^-1/2
     705             :          CALL cp_fm_symm("L", "U", nao, nao, 1.0_dp, fm_KS, fm_ortho, &
     706          16 :                          0.0_dp, fm_work)
     707             :          CALL parallel_gemm("T", "N", nao, nao, nao, 1.0_dp, fm_ortho, &
     708          16 :                             fm_work, 0.0_dp, fm_KS)
     709          16 :          CALL choose_eigv_solver(fm_KS, fm_work, mo_eigenvalues)
     710             :          CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, fm_ortho, &
     711          16 :                             fm_work, 0.0_dp, mo_coeff)
     712             :       END IF
     713             : 
     714          80 :       CALL timestop(handle)
     715             : 
     716          80 :    END SUBROUTINE fb_env_eigensolver
     717             : 
     718             : ! **************************************************************************************************
     719             : !> \brief Read input sections for filter matrix method
     720             : !> \param fb_env : the filter matrix environment
     721             : !> \param scf_section : SCF input section
     722             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     723             : ! **************************************************************************************************
     724          50 :    SUBROUTINE fb_env_read_input(fb_env, scf_section)
     725             : 
     726             :       TYPE(fb_env_obj), INTENT(INOUT)                    :: fb_env
     727             :       TYPE(section_vals_type), POINTER                   :: scf_section
     728             : 
     729             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fb_env_read_input'
     730             : 
     731             :       INTEGER                                            :: handle
     732             :       LOGICAL                                            :: l_val
     733             :       REAL(KIND=dp)                                      :: r_val
     734             :       TYPE(section_vals_type), POINTER                   :: fb_section
     735             : 
     736          10 :       CALL timeset(routineN, handle)
     737             : 
     738          10 :       NULLIFY (fb_section)
     739             :       fb_section => section_vals_get_subs_vals(scf_section, &
     740          10 :                                                "DIAGONALIZATION%FILTER_MATRIX")
     741             :       ! filter_temperature
     742             :       CALL section_vals_val_get(fb_section, "FILTER_TEMPERATURE", &
     743          10 :                                 r_val=r_val)
     744             :       CALL fb_env_set(fb_env=fb_env, &
     745          10 :                       filter_temperature=r_val)
     746             :       ! auto_cutoff_scale
     747             :       CALL section_vals_val_get(fb_section, "AUTO_CUTOFF_SCALE", &
     748          10 :                                 r_val=r_val)
     749             :       CALL fb_env_set(fb_env=fb_env, &
     750          10 :                       auto_cutoff_scale=r_val)
     751             :       ! communication model
     752             :       CALL section_vals_val_get(fb_section, "COLLECTIVE_COMMUNICATION", &
     753          10 :                                 l_val=l_val)
     754             :       CALL fb_env_set(fb_env=fb_env, &
     755          10 :                       collective_com=l_val)
     756             :       ! eps_default
     757             :       CALL section_vals_val_get(fb_section, "EPS_FB", &
     758          10 :                                 r_val=r_val)
     759             :       CALL fb_env_set(fb_env=fb_env, &
     760          10 :                       eps_default=r_val)
     761             : 
     762          10 :       CALL timestop(handle)
     763             : 
     764          10 :    END SUBROUTINE fb_env_read_input
     765             : 
     766             : ! **************************************************************************************************
     767             : !> \brief Automatically generate the cutoff radii of atoms used for
     768             : !>        constructing the atomic halos, based on basis set cutoff
     769             : !>        ranges for each kind
     770             : !> \param fb_env : the filter matrix environment
     771             : !> \param qs_env : quickstep environment
     772             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     773             : ! **************************************************************************************************
     774          10 :    SUBROUTINE fb_env_build_rcut_auto(fb_env, qs_env)
     775             :       TYPE(fb_env_obj), INTENT(INOUT)                    :: fb_env
     776             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     777             : 
     778             :       CHARACTER(len=*), PARAMETER :: routineN = 'fb_env_build_rcut_auto'
     779             : 
     780             :       INTEGER                                            :: handle, ikind, nkinds
     781             :       REAL(KIND=dp)                                      :: auto_cutoff_scale, kind_radius
     782          10 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rcut
     783             :       TYPE(dft_control_type), POINTER                    :: dft_control
     784          10 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     785             :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     786          10 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     787             : 
     788          10 :       CALL timeset(routineN, handle)
     789             : 
     790          10 :       NULLIFY (rcut, qs_kind_set, dft_control)
     791             : 
     792             :       CALL get_qs_env(qs_env=qs_env, &
     793             :                       qs_kind_set=qs_kind_set, &
     794          10 :                       dft_control=dft_control)
     795             :       CALL fb_env_get(fb_env=fb_env, &
     796          10 :                       auto_cutoff_scale=auto_cutoff_scale)
     797             : 
     798          10 :       nkinds = SIZE(qs_kind_set)
     799          30 :       ALLOCATE (rcut(nkinds))
     800             : 
     801             :       ! reading from the other parts of the code, it seemed that
     802             :       ! aux_fit_basis_set is only used when do_admm is TRUE. This can be
     803             :       ! seen from the calls to generate_qs_task_list subroutine in
     804             :       ! qs_create_task_list, found in qs_environment_methods.F:
     805             :       ! basis_type is only set as input parameter for do_admm
     806             :       ! calculations, and if not set, the task list is generated using
     807             :       ! the default basis_set="ORB".
     808          40 :       ALLOCATE (basis_set_list(nkinds))
     809          10 :       IF (dft_control%do_admm) THEN
     810           0 :          CALL basis_set_list_setup(basis_set_list, "AUX_FIT", qs_kind_set)
     811             :       ELSE
     812          10 :          CALL basis_set_list_setup(basis_set_list, "ORB", qs_kind_set)
     813             :       END IF
     814             : 
     815          20 :       DO ikind = 1, nkinds
     816          10 :          basis_set => basis_set_list(ikind)%gto_basis_set
     817          10 :          CALL get_gto_basis_set(gto_basis_set=basis_set, kind_radius=kind_radius)
     818          20 :          rcut(ikind) = kind_radius*auto_cutoff_scale
     819             :       END DO
     820             : 
     821             :       CALL fb_env_set(fb_env=fb_env, &
     822          10 :                       rcut=rcut)
     823             : 
     824             :       ! cleanup
     825          10 :       DEALLOCATE (basis_set_list)
     826             : 
     827          10 :       CALL timestop(handle)
     828             : 
     829          20 :    END SUBROUTINE fb_env_build_rcut_auto
     830             : 
     831             : ! **************************************************************************************************
     832             : !> \brief Builds an fb_atomic_halo_list object using information
     833             : !>        from fb_env
     834             : !> \param fb_env the fb_env object
     835             : !> \param qs_env : quickstep environment (need this to access particle)
     836             : !>                 positions and their kinds as well as which particles
     837             : !>                 are local to this process
     838             : !> \param scf_section : SCF input section, for printing output
     839             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     840             : ! **************************************************************************************************
     841          10 :    SUBROUTINE fb_env_build_atomic_halos(fb_env, qs_env, scf_section)
     842             :       TYPE(fb_env_obj), INTENT(INOUT)                    :: fb_env
     843             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     844             :       TYPE(section_vals_type), POINTER                   :: scf_section
     845             : 
     846             :       CHARACTER(len=*), PARAMETER :: routineN = 'fb_env_build_atomic_halos'
     847             : 
     848             :       INTEGER :: handle, iatom, ihalo, max_natoms_local, natoms_global, natoms_local, nelectrons, &
     849             :          nhalo_atoms, nkinds_global, owner_id_in_halo
     850          10 :       INTEGER, DIMENSION(:), POINTER                     :: halo_atoms, local_atoms
     851             :       REAL(KIND=dp)                                      :: cost
     852          10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: pair_radii
     853          10 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rcut
     854             :       TYPE(cell_type), POINTER                           :: cell
     855             :       TYPE(fb_atomic_halo_list_obj)                      :: atomic_halos
     856          10 :       TYPE(fb_atomic_halo_obj), DIMENSION(:), POINTER    :: halos
     857             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     858          10 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     859          10 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     860             : 
     861          10 :       CALL timeset(routineN, handle)
     862             : 
     863          10 :       CPASSERT(fb_env_has_data(fb_env))
     864             : 
     865          10 :       NULLIFY (cell, halos, halo_atoms, rcut, particle_set, para_env, &
     866          10 :                qs_kind_set, local_atoms)
     867          10 :       CALL fb_atomic_halo_list_nullify(atomic_halos)
     868             : 
     869             :       ! get relevant data from fb_env
     870             :       CALL fb_env_get(fb_env=fb_env, &
     871             :                       rcut=rcut, &
     872             :                       local_atoms=local_atoms, &
     873          10 :                       nlocal_atoms=natoms_local)
     874             : 
     875             :       ! create atomic_halos
     876          10 :       CALL fb_atomic_halo_list_create(atomic_halos)
     877             : 
     878             :       ! get the number of atoms and kinds:
     879             :       CALL get_qs_env(qs_env=qs_env, &
     880             :                       natom=natoms_global, &
     881             :                       particle_set=particle_set, &
     882             :                       qs_kind_set=qs_kind_set, &
     883             :                       nkind=nkinds_global, &
     884             :                       para_env=para_env, &
     885          10 :                       cell=cell)
     886             : 
     887             :       ! get the maximum number of local atoms across the procs.
     888          10 :       max_natoms_local = natoms_local
     889          10 :       CALL para_env%max(max_natoms_local)
     890             : 
     891             :       ! create the halos, one for each local atom
     892          70 :       ALLOCATE (halos(natoms_local))
     893          50 :       DO ihalo = 1, natoms_local
     894          40 :          CALL fb_atomic_halo_nullify(halos(ihalo))
     895          50 :          CALL fb_atomic_halo_create(halos(ihalo))
     896             :       END DO
     897             :       CALL fb_atomic_halo_list_set(atomic_halos=atomic_halos, &
     898             :                                    nhalos=natoms_local, &
     899          10 :                                    max_nhalos=max_natoms_local)
     900             :       ! build halos
     901          40 :       ALLOCATE (pair_radii(nkinds_global, nkinds_global))
     902          10 :       CALL fb_build_pair_radii(rcut, nkinds_global, pair_radii)
     903          10 :       ihalo = 0
     904          50 :       DO iatom = 1, natoms_local
     905          40 :          ihalo = ihalo + 1
     906             :          CALL fb_atomic_halo_build_halo_atoms(local_atoms(iatom), &
     907             :                                               particle_set, &
     908             :                                               cell, &
     909             :                                               pair_radii, &
     910             :                                               halo_atoms, &
     911             :                                               nhalo_atoms, &
     912          40 :                                               owner_id_in_halo)
     913             :          CALL fb_atomic_halo_set(atomic_halo=halos(ihalo), &
     914             :                                  owner_atom=local_atoms(iatom), &
     915             :                                  owner_id_in_halo=owner_id_in_halo, &
     916             :                                  natoms=nhalo_atoms, &
     917          40 :                                  halo_atoms=halo_atoms)
     918             :          ! prepare halo_atoms for another halo, do not deallocate, as
     919             :          ! original data is being pointed at by the atomic halo data
     920             :          ! structure
     921          40 :          NULLIFY (halo_atoms)
     922             :          ! calculate the number of electrons in each halo
     923             :          nelectrons = fb_atomic_halo_nelectrons_estimate_Z(halos(ihalo), &
     924          40 :                                                            particle_set)
     925             :          ! calculate cost
     926          40 :          cost = fb_atomic_halo_cost(halos(ihalo), particle_set, qs_kind_set)
     927             :          CALL fb_atomic_halo_set(atomic_halo=halos(ihalo), &
     928             :                                  nelectrons=nelectrons, &
     929          40 :                                  cost=cost)
     930             :          ! sort atomic halo
     931          90 :          CALL fb_atomic_halo_sort(halos(ihalo))
     932             :       END DO ! iatom
     933          10 :       DEALLOCATE (pair_radii)
     934             : 
     935             :       ! finalise
     936             :       CALL fb_atomic_halo_list_set(atomic_halos=atomic_halos, &
     937          10 :                                    halos=halos)
     938             :       CALL fb_env_set(fb_env=fb_env, &
     939          10 :                       atomic_halos=atomic_halos)
     940             : 
     941             :       ! print info
     942             :       CALL fb_atomic_halo_list_write_info(atomic_halos, &
     943             :                                           para_env, &
     944          10 :                                           scf_section)
     945             : 
     946          10 :       CALL timestop(handle)
     947             : 
     948          20 :    END SUBROUTINE fb_env_build_atomic_halos
     949             : 
     950             : ! **************************************************************************************************
     951             : !> \brief Automatically construct the trial functiosn used for generating
     952             : !>        the filter matrix. It tries to use the single zeta subset from
     953             : !>        the system GTO basis set as the trial functions
     954             : !> \param fb_env : the filter matrix environment
     955             : !> \param qs_env : quickstep environment
     956             : !> \param maxocc : maximum occupancy for an orbital
     957             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
     958             : ! **************************************************************************************************
     959          80 :    SUBROUTINE fb_env_build_trial_fns_auto(fb_env, qs_env, maxocc)
     960             : 
     961             :       TYPE(fb_env_obj), INTENT(INOUT)                    :: fb_env
     962             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     963             :       REAL(KIND=dp), INTENT(IN)                          :: maxocc
     964             : 
     965             :       CHARACTER(len=*), PARAMETER :: routineN = 'fb_env_build_trial_fns_auto'
     966             : 
     967             :       INTEGER                                            :: counter, handle, icgf, ico, ikind, iset, &
     968             :                                                             ishell, itrial, lshell, max_n_trial, &
     969             :                                                             nkinds, nset, old_lshell
     970          80 :       INTEGER, DIMENSION(:), POINTER                     :: lmax, nfunctions, nshell
     971          80 :       INTEGER, DIMENSION(:, :), POINTER                  :: functions
     972             :       REAL(KIND=dp)                                      :: zeff
     973             :       TYPE(dft_control_type), POINTER                    :: dft_control
     974             :       TYPE(fb_trial_fns_obj)                             :: trial_fns
     975          80 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_list
     976             :       TYPE(gto_basis_set_type), POINTER                  :: basis_set
     977          80 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     978             : 
     979          80 :       CALL timeset(routineN, handle)
     980             : 
     981          80 :       CPASSERT(fb_env_has_data(fb_env))
     982          80 :       NULLIFY (nfunctions, functions, basis_set, basis_set_list, qs_kind_set, dft_control)
     983          80 :       CALL fb_trial_fns_nullify(trial_fns)
     984             : 
     985             :       ! create a new trial_fn object
     986          80 :       CALL fb_trial_fns_create(trial_fns)
     987             : 
     988             :       CALL get_qs_env(qs_env=qs_env, &
     989             :                       qs_kind_set=qs_kind_set, &
     990          80 :                       dft_control=dft_control)
     991             : 
     992          80 :       nkinds = SIZE(qs_kind_set)
     993             : 
     994             :       ! reading from the other parts of the code, it seemed that
     995             :       ! aux_fit_basis_set is only used when do_admm is TRUE. This can be
     996             :       ! seen from the calls to generate_qs_task_list subroutine in
     997             :       ! qs_create_task_list, found in qs_environment_methods.F:
     998             :       ! basis_type is only set as input parameter for do_admm
     999             :       ! calculations, and if not set, the task list is generated using
    1000             :       ! the default basis_set="ORB".
    1001         320 :       ALLOCATE (basis_set_list(nkinds))
    1002          80 :       IF (dft_control%do_admm) THEN
    1003           0 :          CALL basis_set_list_setup(basis_set_list, "AUX_FIT", qs_kind_set)
    1004             :       ELSE
    1005          80 :          CALL basis_set_list_setup(basis_set_list, "ORB", qs_kind_set)
    1006             :       END IF
    1007             : 
    1008         240 :       ALLOCATE (nfunctions(nkinds))
    1009         160 :       nfunctions = 0
    1010             : 
    1011         160 :       DO ikind = 1, nkinds
    1012             :          ! "gto = gaussian type orbital"
    1013          80 :          basis_set => basis_set_list(ikind)%gto_basis_set
    1014             :          CALL get_gto_basis_set(gto_basis_set=basis_set, &
    1015             :                                 nset=nset, &
    1016             :                                 lmax=lmax, &
    1017          80 :                                 nshell=nshell)
    1018             :          CALL get_qs_kind(qs_kind=qs_kind_set(ikind), &
    1019          80 :                           zeff=zeff)
    1020             : 
    1021         160 :          bset1: DO iset = 1, nset
    1022             : !          old_lshell = lmax(iset)
    1023          80 :             old_lshell = -1
    1024         320 :             DO ishell = 1, nshell(iset)
    1025         240 :                lshell = basis_set%l(ishell, iset)
    1026         240 :                counter = 0
    1027             :                ! loop over orbitals within the same l
    1028         640 :                DO ico = ncoset(lshell - 1) + 1, ncoset(lshell)
    1029         400 :                   counter = counter + 1
    1030             :                   ! only include the first zeta orbitals
    1031         640 :                   IF ((lshell .GT. old_lshell) .AND. (counter .LE. nco(lshell))) THEN
    1032         320 :                      nfunctions(ikind) = nfunctions(ikind) + 1
    1033             :                   END IF
    1034             :                END DO
    1035             :                ! we have got enough trial functions when we have enough
    1036             :                ! basis functions to accommodate the number of electrons,
    1037             :                ! AND that that we have included all the first zeta
    1038             :                ! orbitals of an angular momentum quantum number l
    1039         240 :                IF (((lshell .GT. old_lshell) .OR. (lshell .EQ. lmax(iset))) .AND. &
    1040             :                    (maxocc*REAL(nfunctions(ikind), dp) .GE. zeff)) THEN
    1041             :                   EXIT bset1
    1042             :                END IF
    1043         160 :                old_lshell = lshell
    1044             :             END DO
    1045             :          END DO bset1
    1046             :       END DO ! ikind
    1047             : 
    1048             :       ! now that we have the number of trial functions get the trial
    1049             :       ! functions
    1050         160 :       max_n_trial = MAXVAL(nfunctions)
    1051         320 :       ALLOCATE (functions(max_n_trial, nkinds))
    1052         480 :       functions(:, :) = 0
    1053             :       ! redo the loops to get the trial function indices within the basis set
    1054         160 :       DO ikind = 1, nkinds
    1055             :          ! "gto = gaussian type orbital"
    1056          80 :          basis_set => basis_set_list(ikind)%gto_basis_set
    1057             :          CALL get_gto_basis_set(gto_basis_set=basis_set, &
    1058             :                                 nset=nset, &
    1059             :                                 lmax=lmax, &
    1060          80 :                                 nshell=nshell)
    1061             :          CALL get_qs_kind(qs_kind=qs_kind_set(ikind), &
    1062          80 :                           zeff=zeff)
    1063          80 :          icgf = 0
    1064          80 :          itrial = 0
    1065         160 :          bset2: DO iset = 1, nset
    1066          80 :             old_lshell = -1
    1067         320 :             DO ishell = 1, nshell(iset)
    1068         240 :                lshell = basis_set%l(ishell, iset)
    1069         240 :                counter = 0
    1070             :                ! loop over orbitals within the same l
    1071         640 :                DO ico = ncoset(lshell - 1) + 1, ncoset(lshell)
    1072         400 :                   icgf = icgf + 1
    1073         400 :                   counter = counter + 1
    1074             :                   ! only include the first zeta orbitals
    1075         640 :                   IF ((lshell .GT. old_lshell) .AND. (counter .LE. nco(lshell))) THEN
    1076         320 :                      itrial = itrial + 1
    1077         320 :                      functions(itrial, ikind) = icgf
    1078             :                   END IF
    1079             :                END DO
    1080             :                ! we have got enough trial functions when we have more
    1081             :                ! basis functions than the number of electrons (obtained
    1082             :                ! from atomic z), AND that that we have included all the
    1083             :                ! first zeta orbitals of an angular momentum quantum
    1084             :                ! number l
    1085         240 :                IF (((lshell .GT. old_lshell) .OR. (lshell .EQ. lmax(iset))) .AND. &
    1086             :                    (maxocc*REAL(itrial, dp) .GE. zeff)) THEN
    1087             :                   EXIT bset2
    1088             :                END IF
    1089         160 :                old_lshell = lshell
    1090             :             END DO
    1091             :          END DO bset2
    1092             :       END DO ! ikind
    1093             : 
    1094             :       ! set trial_functions
    1095             :       CALL fb_trial_fns_set(trial_fns=trial_fns, &
    1096             :                             nfunctions=nfunctions, &
    1097          80 :                             functions=functions)
    1098             :       ! set fb_env
    1099             :       CALL fb_env_set(fb_env=fb_env, &
    1100          80 :                       trial_fns=trial_fns)
    1101          80 :       CALL fb_trial_fns_release(trial_fns)
    1102             : 
    1103             :       ! cleanup
    1104          80 :       DEALLOCATE (basis_set_list)
    1105             : 
    1106          80 :       CALL timestop(handle)
    1107             : 
    1108          80 :    END SUBROUTINE fb_env_build_trial_fns_auto
    1109             : 
    1110             : ! **************************************************************************************************
    1111             : !> \brief Copy the sparse structure of a DBCSR matrix to another, this
    1112             : !>        means the other matrix will have the same number of blocks
    1113             : !>        and their corresponding logical locations allocated, although
    1114             : !>        the blocks does not have to be the same size as the original
    1115             : !> \param matrix_out : DBCSR matrix whose blocks are to be allocated
    1116             : !> \param matrix_in  : DBCSR matrix with existing sparse structure that
    1117             : !>                     is to be copied
    1118             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
    1119             : ! **************************************************************************************************
    1120          80 :    SUBROUTINE fb_dbcsr_copy_sparse_struct(matrix_out, matrix_in)
    1121             : 
    1122             :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix_out
    1123             :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_in
    1124             : 
    1125             :       INTEGER                                            :: iatom, jatom, nblkcols_total, &
    1126             :                                                             nblkrows_total, nblks
    1127          80 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: cols, rows
    1128             :       TYPE(dbcsr_iterator_type)                          :: iter
    1129             : 
    1130             :       CALL dbcsr_get_info(matrix=matrix_in, &
    1131             :                           nblkrows_total=nblkrows_total, &
    1132          80 :                           nblkcols_total=nblkcols_total)
    1133             : 
    1134          80 :       nblks = nblkrows_total*nblkcols_total
    1135         240 :       ALLOCATE (rows(nblks))
    1136         160 :       ALLOCATE (cols(nblks))
    1137        5200 :       rows(:) = 0
    1138        5200 :       cols(:) = 0
    1139          80 :       nblks = 0
    1140          80 :       CALL dbcsr_iterator_readonly_start(iter, matrix_in)
    1141        1520 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
    1142        1440 :          CALL dbcsr_iterator_next_block(iter, iatom, jatom)
    1143        1440 :          nblks = nblks + 1
    1144        1440 :          rows(nblks) = iatom
    1145        1440 :          cols(nblks) = jatom
    1146             :       END DO
    1147          80 :       CALL dbcsr_iterator_stop(iter)
    1148          80 :       CALL dbcsr_reserve_blocks(matrix_out, rows(1:nblks), cols(1:nblks))
    1149          80 :       CALL dbcsr_finalize(matrix_out)
    1150             : 
    1151             :       ! cleanup
    1152          80 :       DEALLOCATE (rows)
    1153          80 :       DEALLOCATE (cols)
    1154             : 
    1155         160 :    END SUBROUTINE fb_dbcsr_copy_sparse_struct
    1156             : 
    1157             : ! **************************************************************************************************
    1158             : !> \brief Write out parameters used for the filter matrix method to
    1159             : !>        output
    1160             : !> \param fb_env : the filter matrix environment
    1161             : !> \param qs_env : quickstep environment
    1162             : !> \param scf_section : SCF input section
    1163             : !> \author Lianheng Tong (LT) lianheng.tong@kcl.ac.uk
    1164             : ! **************************************************************************************************
    1165          20 :    SUBROUTINE fb_env_write_info(fb_env, qs_env, scf_section)
    1166             :       TYPE(fb_env_obj), INTENT(IN)                       :: fb_env
    1167             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1168             :       TYPE(section_vals_type), POINTER                   :: scf_section
    1169             : 
    1170             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'fb_env_write_info'
    1171             : 
    1172             :       CHARACTER(LEN=2)                                   :: element_symbol
    1173             :       INTEGER                                            :: handle, ikind, nkinds, unit_nr
    1174             :       LOGICAL                                            :: collective_com
    1175             :       REAL(KIND=dp)                                      :: auto_cutoff_scale, filter_temperature
    1176          10 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: rcut
    1177          10 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
    1178             :       TYPE(cp_logger_type), POINTER                      :: logger
    1179             : 
    1180          10 :       CALL timeset(routineN, handle)
    1181             : 
    1182          10 :       NULLIFY (rcut, atomic_kind_set, logger)
    1183             : 
    1184             :       CALL get_qs_env(qs_env=qs_env, &
    1185          10 :                       atomic_kind_set=atomic_kind_set)
    1186             :       CALL fb_env_get(fb_env=fb_env, &
    1187             :                       filter_temperature=filter_temperature, &
    1188             :                       auto_cutoff_scale=auto_cutoff_scale, &
    1189             :                       rcut=rcut, &
    1190          10 :                       collective_com=collective_com)
    1191             : 
    1192          10 :       nkinds = SIZE(atomic_kind_set)
    1193             : 
    1194          10 :       logger => cp_get_default_logger()
    1195             :       unit_nr = cp_print_key_unit_nr(logger, scf_section, &
    1196             :                                      "PRINT%FILTER_MATRIX", &
    1197          10 :                                      extension="")
    1198          10 :       IF (unit_nr > 0) THEN
    1199           5 :          IF (collective_com) THEN
    1200             :             WRITE (UNIT=unit_nr, FMT="(/,A,T71,A)") &
    1201           1 :                " FILTER_MAT_DIAG| MPI communication method:", &
    1202           2 :                "Collective"
    1203             :          ELSE
    1204             :             WRITE (UNIT=unit_nr, FMT="(/,A,T71,A)") &
    1205           4 :                " FILTER_MAT_DIAG| MPI communication method:", &
    1206           8 :                "At each step"
    1207             :          END IF
    1208             :          WRITE (UNIT=unit_nr, FMT="(A,T71,g10.4)") &
    1209           5 :             " FILTER_MAT_DIAG| Filter temperature [K]:", &
    1210          10 :             cp_unit_from_cp2k(filter_temperature, "K")
    1211             :          WRITE (UNIT=unit_nr, FMT="(A,T71,f10.4)") &
    1212           5 :             " FILTER_MAT_DIAG| Filter temperature [a.u.]:", &
    1213          10 :             filter_temperature
    1214             :          WRITE (UNIT=unit_nr, FMT="(A,T71,f10.4)") &
    1215           5 :             " FILTER_MAT_DIAG| Auto atomic cutoff radius scale:", &
    1216          10 :             auto_cutoff_scale
    1217             :          WRITE (UNIT=unit_nr, FMT="(A)") &
    1218           5 :             " FILTER_MAT_DIAG| atomic cutoff radii [a.u.]"
    1219          10 :          DO ikind = 1, nkinds
    1220             :             CALL get_atomic_kind(atomic_kind=atomic_kind_set(ikind), &
    1221           5 :                                  element_symbol=element_symbol)
    1222             :             WRITE (UNIT=unit_nr, FMT="(A,A,T71,f10.4)") &
    1223          10 :                " FILTER_MAT_DIAG|   ", element_symbol, rcut(ikind)
    1224             :          END DO ! ikind
    1225             :       END IF
    1226             :       CALL cp_print_key_finished_output(unit_nr, logger, scf_section, &
    1227          10 :                                         "PRINT%FILTER_MATRIX")
    1228             : 
    1229          10 :       CALL timestop(handle)
    1230             : 
    1231          10 :    END SUBROUTINE fb_env_write_info
    1232             : 
    1233             : END MODULE qs_fb_env_methods

Generated by: LCOV version 1.15