LCOV - code coverage report
Current view: top level - src - qs_fb_env_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 96.3 % 350 337
Test Date: 2025-07-25 12:55:17 Functions: 100.0 % 8 8

            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 2.0-1