LCOV - code coverage report
Current view: top level - src - preconditioner.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:24d69ee) Lines: 95.1 % 244 232
Test Date: 2026-09-03 07:32:15 Functions: 100.0 % 9 9

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief computes preconditioners, and implements methods to apply them
      10              : !>      currently used in qs_ot
      11              : !> \par History
      12              : !>      - [UB] 2009-05-13 Adding stable approximate inverse (full and sparse)
      13              : !> \author Joost VandeVondele (09.2002)
      14              : ! **************************************************************************************************
      15              : MODULE preconditioner
      16              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      17              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      18              :                                               cp_cfm_release,&
      19              :                                               cp_cfm_type,&
      20              :                                               cp_fm_to_cfm
      21              :    USE cp_control_types,                ONLY: dft_control_type
      22              :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      23              :                                               dbcsr_p_type,&
      24              :                                               dbcsr_type
      25              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      26              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      27              :                                               cp_fm_struct_release,&
      28              :                                               cp_fm_struct_type
      29              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      30              :                                               cp_fm_get_info,&
      31              :                                               cp_fm_release,&
      32              :                                               cp_fm_to_fm,&
      33              :                                               cp_fm_type
      34              :    USE input_constants,                 ONLY: &
      35              :         cholesky_reduce, ot_precond_full_all, ot_precond_full_kinetic, ot_precond_full_single, &
      36              :         ot_precond_full_single_inverse, ot_precond_none, ot_precond_s_inverse, &
      37              :         ot_precond_solver_default, ot_precond_solver_inv_chol, ot_precond_solver_update
      38              :    USE kinds,                           ONLY: default_string_length,&
      39              :                                               dp
      40              :    USE message_passing,                 ONLY: mp_para_env_type
      41              :    USE preconditioner_apply,            ONLY: apply_preconditioner_cfm_complex,&
      42              :                                               apply_preconditioner_dbcsr,&
      43              :                                               apply_preconditioner_dbcsr_complex,&
      44              :                                               apply_preconditioner_fm
      45              :    USE preconditioner_makes,            ONLY: make_complex_full_all,&
      46              :                                               make_complex_full_kinetic,&
      47              :                                               make_complex_full_s_inverse,&
      48              :                                               make_complex_full_single,&
      49              :                                               make_complex_full_single_inverse,&
      50              :                                               make_preconditioner_matrix
      51              :    USE preconditioner_solvers,          ONLY: solve_preconditioner,&
      52              :                                               transfer_dbcsr_to_fm,&
      53              :                                               transfer_fm_to_dbcsr
      54              :    USE preconditioner_types,            ONLY: destroy_preconditioner,&
      55              :                                               init_preconditioner,&
      56              :                                               preconditioner_p_type,&
      57              :                                               preconditioner_type
      58              :    USE qs_environment_types,            ONLY: get_qs_env,&
      59              :                                               qs_environment_type
      60              :    USE qs_mo_methods,                   ONLY: calculate_subspace_eigenvalues
      61              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      62              :                                               mo_set_type,&
      63              :                                               set_mo_set
      64              : #include "./base/base_uses.f90"
      65              : 
      66              :    IMPLICIT NONE
      67              : 
      68              :    PRIVATE
      69              : 
      70              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner'
      71              : 
      72              :    PUBLIC :: make_preconditioner, make_preconditioner_complex_full_all, &
      73              :              make_preconditioner_complex_full_kinetic, &
      74              :              make_preconditioner_complex_full_s_inverse, &
      75              :              make_preconditioner_complex_full_single, &
      76              :              make_preconditioner_complex_full_single_inverse, restart_preconditioner, &
      77              :              dbcsr_pair_to_cfm
      78              :    PUBLIC :: apply_preconditioner, prepare_preconditioner
      79              : 
      80              : ! The public interface for apply preconditioner, the routines can be found in preconditioner_apply.F
      81              :    INTERFACE apply_preconditioner
      82              :       MODULE PROCEDURE apply_preconditioner_cfm_complex
      83              :       MODULE PROCEDURE apply_preconditioner_dbcsr
      84              :       MODULE PROCEDURE apply_preconditioner_dbcsr_complex
      85              :       MODULE PROCEDURE apply_preconditioner_fm
      86              :    END INTERFACE
      87              : 
      88              : ! **************************************************************************************************
      89              : 
      90              : CONTAINS
      91              : 
      92              : ! **************************************************************************************************
      93              : 
      94              : ! creates a preconditioner for the system (H-energy_homo S)
      95              : ! this preconditioner is (must be) symmetric positive definite.
      96              : ! currently uses a atom-block-diagonal form
      97              : ! each block will be  ....
      98              : ! might overwrite matrix_h, matrix_t
      99              : 
     100              : ! **************************************************************************************************
     101              : !> \brief ...
     102              : !> \param preconditioner_env ...
     103              : !> \param precon_type ...
     104              : !> \param solver_type ...
     105              : !> \param matrix_h ...
     106              : !> \param matrix_s ...
     107              : !> \param matrix_t ...
     108              : !> \param mo_set ...
     109              : !> \param energy_gap ...
     110              : !> \param convert_precond_to_dbcsr ...
     111              : !> \param chol_type ...
     112              : !> \par History
     113              : !>      09.2014 removed some unused or unfinished methods
     114              : !>              removed sparse preconditioners and the
     115              : !>              sparse approximate inverse at rev 14341 [Florian Schiffmann]
     116              : ! **************************************************************************************************
     117         9592 :    SUBROUTINE make_preconditioner(preconditioner_env, precon_type, solver_type, matrix_h, matrix_s, &
     118              :                                   matrix_t, mo_set, energy_gap, convert_precond_to_dbcsr, chol_type)
     119              : 
     120              :       TYPE(preconditioner_type)                          :: preconditioner_env
     121              :       INTEGER, INTENT(IN)                                :: precon_type, solver_type
     122              :       TYPE(dbcsr_type), POINTER                          :: matrix_h
     123              :       TYPE(dbcsr_type), OPTIONAL, POINTER                :: matrix_s, matrix_t
     124              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     125              :       REAL(KIND=dp)                                      :: energy_gap
     126              :       LOGICAL, INTENT(IN), OPTIONAL                      :: convert_precond_to_dbcsr
     127              :       INTEGER, INTENT(IN), OPTIONAL                      :: chol_type
     128              : 
     129              :       CHARACTER(len=*), PARAMETER :: routineN = 'make_preconditioner'
     130              : 
     131              :       INTEGER                                            :: handle, k, my_solver_type, nao, nhomo
     132              :       LOGICAL                                            :: my_convert_precond_to_dbcsr, &
     133              :                                                             needs_full_spectrum, needs_homo, &
     134              :                                                             use_mo_coeff_b
     135              :       REAL(KIND=dp)                                      :: energy_homo
     136         9592 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenvalues_ot
     137              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     138              :       TYPE(cp_fm_type)                                   :: mo_occ
     139              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     140              :       TYPE(dbcsr_type), POINTER                          :: mo_coeff_b
     141              : 
     142         9592 :       CALL timeset(routineN, handle)
     143              : 
     144         9592 :       CALL get_mo_set(mo_set=mo_set, mo_coeff=mo_coeff, mo_coeff_b=mo_coeff_b, homo=nhomo)
     145         9592 :       use_mo_coeff_b = mo_set%use_mo_coeff_b
     146         9592 :       CALL cp_fm_get_info(mo_coeff, ncol_global=k, nrow_global=nao)
     147              : 
     148              :       ! Starting some matrix mess, check where to store the result in preconditioner_env, fm or dbcsr_matrix
     149         9592 :       my_convert_precond_to_dbcsr = .FALSE.
     150         9592 :       IF (PRESENT(convert_precond_to_dbcsr)) my_convert_precond_to_dbcsr = convert_precond_to_dbcsr
     151              : 
     152              :       ! Thanks to the mess with the matrices we need to make sure in this case that the
     153              :       ! Previous inverse is properly stored as a sparse matrix, fm gets deallocated here
     154              :       ! if it wasn't anyway
     155         9592 :       IF (preconditioner_env%solver == ot_precond_solver_update) THEN
     156            4 :          CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%dbcsr_matrix, matrix_h)
     157              :       END IF
     158              : 
     159         9592 :       needs_full_spectrum = .FALSE.
     160         9592 :       needs_homo = .FALSE.
     161              : 
     162        13306 :       SELECT CASE (precon_type)
     163              :       CASE (ot_precond_full_all)
     164         3714 :          needs_full_spectrum = .TRUE.
     165              :          ! both of them need the coefficients as fm's, more matrix mess
     166         3714 :          IF (use_mo_coeff_b) THEN
     167         3410 :             CALL copy_dbcsr_to_fm(mo_coeff_b, mo_coeff)
     168              :          END IF
     169              :       CASE (ot_precond_full_single)
     170           38 :          needs_homo = .TRUE.
     171              :          ! XXXX to be removed if homo estimate only is implemented
     172           38 :          needs_full_spectrum = .TRUE.
     173              :       CASE (ot_precond_full_kinetic, ot_precond_s_inverse, ot_precond_full_single_inverse)
     174              :          ! these should be happy without an estimate for the homo energy
     175              :          ! preconditioning can  not depend on an absolute eigenvalue, only on eigenvalue differences
     176              :       CASE DEFAULT
     177         9592 :          CPABORT("The preconditioner is unknown ...")
     178              :       END SELECT
     179              : 
     180        28592 :       ALLOCATE (eigenvalues_ot(k))
     181         9592 :       energy_homo = 0.0_dp
     182         9592 :       IF (needs_full_spectrum) THEN
     183              :          ! XXXXXXXXXXXXXXXX do not touch the initial MOs, could be harmful for either
     184              :          !                  the case of non-equivalent MOs but also for the derivate
     185              :          ! we could already have all eigenvalues e.g. full_all and we could skip this
     186              :          ! to be optimised later.
     187              :          ! one flaw is that not all SCF methods (i.e. that go over mo_derivs directly)
     188              :          ! have a 'valid' matrix_h... (we even don't know what evals are in that case)
     189         3752 :          IF (use_mo_coeff_b) THEN
     190              :             CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_h, &
     191              :                                                 eigenvalues_ot, do_rotation=.FALSE., &
     192              :                                                 para_env=mo_coeff%matrix_struct%para_env, &
     193         3440 :                                                 blacs_env=mo_coeff%matrix_struct%context)
     194              :          ELSE
     195              :             CALL calculate_subspace_eigenvalues(mo_coeff, matrix_h, &
     196          312 :                                                 eigenvalues_ot, do_rotation=.FALSE.)
     197              :          END IF
     198         3752 :          IF (k > 0) THEN
     199         3642 :             CPASSERT(nhomo > 0 .AND. nhomo <= k)
     200         3642 :             energy_homo = eigenvalues_ot(nhomo)
     201              :          END IF
     202              :       ELSE
     203         5840 :          IF (needs_homo) THEN
     204            0 :             CPABORT("Not yet implemented")
     205              :          END IF
     206              :       END IF
     207              : 
     208              :       ! After all bits and pieces of checking and initialization, here comes the
     209              :       ! part where the preconditioner matrix gets created and solved.
     210              :       ! This will give the matrices for later use
     211         9592 :       my_solver_type = solver_type
     212         9592 :       preconditioner_env%in_use = precon_type
     213         9592 :       preconditioner_env%cholesky_use = cholesky_reduce
     214         9592 :       IF (PRESENT(chol_type)) preconditioner_env%cholesky_use = chol_type
     215              :       preconditioner_env%in_use = precon_type
     216         9592 :       IF (nhomo == k) THEN
     217              :          CALL make_preconditioner_matrix(preconditioner_env, matrix_h, matrix_s, matrix_t, mo_coeff, &
     218         9504 :                                          energy_homo, eigenvalues_ot, energy_gap, my_solver_type)
     219              :       ELSE
     220              :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao, ncol_global=nhomo, &
     221              :                                   context=preconditioner_env%ctxt, &
     222           88 :                                   para_env=preconditioner_env%para_env)
     223           88 :          CALL cp_fm_create(mo_occ, fm_struct)
     224           88 :          CALL cp_fm_to_fm(mo_coeff, mo_occ, nhomo)
     225           88 :          CALL cp_fm_struct_release(fm_struct)
     226              :          !
     227              :          CALL make_preconditioner_matrix(preconditioner_env, matrix_h, matrix_s, matrix_t, mo_occ, &
     228           88 :                                          energy_homo, eigenvalues_ot(1:nhomo), energy_gap, my_solver_type)
     229              :          !
     230           88 :          CALL cp_fm_release(mo_occ)
     231              :       END IF
     232              : 
     233         9592 :       CALL solve_preconditioner(my_solver_type, preconditioner_env, matrix_s, matrix_h)
     234              : 
     235              :       ! Here comes more matrix mess, make sure to output the correct matrix format,
     236              :       ! A bit pointless to convert the cholesky factorized version as it doesn't work in
     237              :       ! dbcsr form and will crash later,...
     238         9592 :       IF (my_convert_precond_to_dbcsr) THEN
     239         7916 :          CALL transfer_fm_to_dbcsr(preconditioner_env%fm, preconditioner_env%dbcsr_matrix, matrix_h)
     240              :       ELSE
     241              :          CALL transfer_dbcsr_to_fm(preconditioner_env%dbcsr_matrix, preconditioner_env%fm, &
     242         1676 :                                    preconditioner_env%para_env, preconditioner_env%ctxt)
     243              :       END IF
     244              : 
     245         9592 :       DEALLOCATE (eigenvalues_ot)
     246              : 
     247         9592 :       CALL timestop(handle)
     248              : 
     249         9592 :    END SUBROUTINE make_preconditioner
     250              : 
     251              : ! **************************************************************************************************
     252              : !> \brief Construct FULL_ALL directly from one complex H(k), S(k), and C(k) channel.
     253              : !> \param preconditioner_env preconditioner storage
     254              : !> \param matrix_c_re real part of the active OT reference orbitals
     255              : !> \param matrix_c_im imaginary part of the active OT reference orbitals
     256              : !> \param matrix_h_re real part of H(k)
     257              : !> \param matrix_h_im imaginary part of H(k)
     258              : !> \param matrix_s_re real part of S(k)
     259              : !> \param matrix_s_im imaginary part of S(k)
     260              : !> \param mo_set reference-orbital energy labels
     261              : !> \param energy_gap denominator floor
     262              : !> \param solver_type inverse application selected in the OT input
     263              : ! **************************************************************************************************
     264          520 :    SUBROUTINE make_preconditioner_complex_full_all(preconditioner_env, &
     265              :                                                    matrix_c_re, matrix_c_im, &
     266              :                                                    matrix_h_re, matrix_h_im, &
     267              :                                                    matrix_s_re, matrix_s_im, &
     268              :                                                    mo_set, energy_gap, solver_type)
     269              : 
     270              :       TYPE(preconditioner_type)                          :: preconditioner_env
     271              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
     272              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
     273              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     274              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
     275              :       INTEGER, INTENT(IN)                                :: solver_type
     276              : 
     277              :       CHARACTER(len=*), PARAMETER :: routineN = 'make_preconditioner_complex_full_all'
     278              : 
     279              :       INTEGER                                            :: handle, k
     280          104 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
     281              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
     282              : 
     283          104 :       CALL timeset(routineN, handle)
     284              : 
     285          104 :       NULLIFY (eigenvalues)
     286          104 :       CPASSERT(ASSOCIATED(matrix_c_re))
     287          104 :       CPASSERT(ASSOCIATED(matrix_c_im))
     288          104 :       CPASSERT(ASSOCIATED(matrix_h_re))
     289          104 :       CPASSERT(ASSOCIATED(matrix_h_im))
     290          104 :       CPASSERT(ASSOCIATED(matrix_s_re))
     291          104 :       CPASSERT(ASSOCIATED(matrix_s_im))
     292          104 :       IF (solver_type /= ot_precond_solver_default) THEN
     293            0 :          CPABORT('Complex FULL_ALL supports only PRECOND_SOLVER DEFAULT')
     294              :       END IF
     295          104 :       CALL dbcsr_get_info(matrix_c_re, nfullcols_total=k)
     296          104 :       CPASSERT(k > 0)
     297          104 :       CALL get_mo_set(mo_set, eigenvalues=eigenvalues)
     298          104 :       CPASSERT(ASSOCIATED(eigenvalues))
     299          104 :       CPASSERT(SIZE(eigenvalues) >= k)
     300              : 
     301              :       CALL dbcsr_pair_to_cfm(matrix_c_re, matrix_c_im, preconditioner_env, &
     302          104 :                              'complex FULL_ALL C', matrix_c)
     303              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
     304          104 :                              'complex FULL_ALL H', matrix_h)
     305              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
     306          104 :                              'complex FULL_ALL S', matrix_s)
     307              :       CALL make_complex_full_all(preconditioner_env, matrix_c, matrix_h, matrix_s, &
     308          104 :                                  eigenvalues(1:k), energy_gap)
     309              : 
     310          104 :       CALL cp_cfm_release(matrix_c)
     311          104 :       CALL cp_cfm_release(matrix_s)
     312          104 :       CALL cp_cfm_release(matrix_h)
     313              : 
     314          104 :       CALL timestop(handle)
     315              : 
     316          104 :    END SUBROUTINE make_preconditioner_complex_full_all
     317              : 
     318              : ! **************************************************************************************************
     319              : !> \brief Construct a complex FULL_SINGLE preconditioner from H(k) and S(k).
     320              : !> \param preconditioner_env preconditioner storage
     321              : !> \param matrix_h_re real part of H(k)
     322              : !> \param matrix_h_im imaginary part of H(k)
     323              : !> \param matrix_s_re real part of S(k)
     324              : !> \param matrix_s_im imaginary part of S(k)
     325              : !> \param mo_set orbital energy labels defining the occupied edge
     326              : !> \param energy_gap denominator floor
     327              : !> \param solver_type requested inverse solver
     328              : ! **************************************************************************************************
     329          104 :    SUBROUTINE make_preconditioner_complex_full_single(preconditioner_env, &
     330              :                                                       matrix_h_re, matrix_h_im, &
     331              :                                                       matrix_s_re, matrix_s_im, &
     332              :                                                       mo_set, energy_gap, solver_type)
     333              : 
     334              :       TYPE(preconditioner_type)                          :: preconditioner_env
     335              :       TYPE(dbcsr_type), POINTER                          :: matrix_h_re, matrix_h_im, matrix_s_re, &
     336              :                                                             matrix_s_im
     337              :       TYPE(mo_set_type), INTENT(IN)                      :: mo_set
     338              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
     339              :       INTEGER, INTENT(IN)                                :: solver_type
     340              : 
     341              :       INTEGER                                            :: homo
     342           26 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
     343              :       TYPE(cp_cfm_type)                                  :: matrix_h, matrix_s
     344              : 
     345           26 :       NULLIFY (eigenvalues)
     346            0 :       CPASSERT(ASSOCIATED(matrix_h_re))
     347           26 :       CPASSERT(ASSOCIATED(matrix_h_im))
     348           26 :       CPASSERT(ASSOCIATED(matrix_s_re))
     349           26 :       CPASSERT(ASSOCIATED(matrix_s_im))
     350           26 :       IF (solver_type /= ot_precond_solver_default) THEN
     351            0 :          CPABORT('Complex FULL_SINGLE supports only PRECOND_SOLVER DEFAULT')
     352              :       END IF
     353           26 :       CALL get_mo_set(mo_set, homo=homo, eigenvalues=eigenvalues)
     354           26 :       CPASSERT(ASSOCIATED(eigenvalues))
     355           26 :       CPASSERT(homo > 0 .AND. homo <= SIZE(eigenvalues))
     356              : 
     357              :       CALL dbcsr_pair_to_cfm(matrix_h_re, matrix_h_im, preconditioner_env, &
     358           26 :                              'complex FULL_SINGLE H', matrix_h)
     359              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
     360           26 :                              'complex FULL_SINGLE S', matrix_s)
     361              :       CALL make_complex_full_single(preconditioner_env, matrix_h, matrix_s, &
     362           26 :                                     eigenvalues(homo), energy_gap)
     363           26 :       CALL cp_cfm_release(matrix_s)
     364           26 :       CALL cp_cfm_release(matrix_h)
     365              : 
     366           26 :    END SUBROUTINE make_preconditioner_complex_full_single
     367              : 
     368              : ! **************************************************************************************************
     369              : !> \brief Construct a complex FULL_SINGLE_INVERSE preconditioner without discarding Im(H,S,C).
     370              : !> \param preconditioner_env preconditioner storage
     371              : !> \param matrix_c_re real part of the occupied reference orbitals
     372              : !> \param matrix_c_im imaginary part of the occupied reference orbitals
     373              : !> \param matrix_h_re real part of H(k)
     374              : !> \param matrix_h_im imaginary part of H(k)
     375              : !> \param matrix_s_re real part of S(k)
     376              : !> \param matrix_s_im imaginary part of S(k)
     377              : !> \param energy_gap lower spectral bound
     378              : !> \param solver_type requested inverse solver
     379              : ! **************************************************************************************************
     380          484 :    SUBROUTINE make_preconditioner_complex_full_single_inverse(preconditioner_env, &
     381              :                                                               matrix_c_re, matrix_c_im, &
     382              :                                                               matrix_h_re, matrix_h_im, &
     383              :                                                               matrix_s_re, matrix_s_im, &
     384              :                                                               energy_gap, solver_type)
     385              : 
     386              :       TYPE(preconditioner_type)                          :: preconditioner_env
     387              :       TYPE(dbcsr_type), POINTER                          :: matrix_c_re, matrix_c_im, matrix_h_re, &
     388              :                                                             matrix_h_im, matrix_s_re, matrix_s_im
     389              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
     390              :       INTEGER, INTENT(IN)                                :: solver_type
     391              : 
     392              :       INTEGER                                            :: k, n
     393              :       TYPE(cp_cfm_type)                                  :: matrix_c, matrix_h, matrix_s
     394              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_mo, fm_struct_square
     395              :       TYPE(cp_fm_type)                                   :: matrix_c_im_fm, matrix_c_re_fm, &
     396              :                                                             matrix_h_im_fm, matrix_h_re_fm, &
     397              :                                                             matrix_s_im_fm, matrix_s_re_fm
     398              : 
     399           44 :       NULLIFY (fm_struct_mo, fm_struct_square)
     400            0 :       CPASSERT(ASSOCIATED(matrix_c_re))
     401           44 :       CPASSERT(ASSOCIATED(matrix_c_im))
     402           44 :       CPASSERT(ASSOCIATED(matrix_h_re))
     403           44 :       CPASSERT(ASSOCIATED(matrix_h_im))
     404           44 :       CPASSERT(ASSOCIATED(matrix_s_re))
     405           44 :       CPASSERT(ASSOCIATED(matrix_s_im))
     406           44 :       IF (solver_type /= ot_precond_solver_default .AND. &
     407              :           solver_type /= ot_precond_solver_inv_chol) THEN
     408            0 :          CPABORT("Complex FULL_SINGLE_INVERSE supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
     409              :       END IF
     410           44 :       CALL dbcsr_get_info(matrix_c_re, nfullrows_total=n, nfullcols_total=k)
     411           44 :       CPASSERT(n > 0 .AND. k > 0 .AND. k <= n)
     412              : 
     413              :       CALL cp_fm_struct_create(fm_struct_mo, nrow_global=n, ncol_global=k, &
     414              :                                context=preconditioner_env%ctxt, &
     415           44 :                                para_env=preconditioner_env%para_env)
     416              :       CALL cp_fm_struct_create(fm_struct_square, nrow_global=n, ncol_global=n, &
     417              :                                context=preconditioner_env%ctxt, &
     418           44 :                                para_env=preconditioner_env%para_env)
     419           44 :       CALL cp_fm_create(matrix_c_re_fm, fm_struct_mo, name='complex preconditioner C real')
     420           44 :       CALL cp_fm_create(matrix_c_im_fm, fm_struct_mo, name='complex preconditioner C imaginary')
     421           44 :       CALL cp_fm_create(matrix_h_re_fm, fm_struct_square, name='complex preconditioner H real')
     422           44 :       CALL cp_fm_create(matrix_h_im_fm, fm_struct_square, name='complex preconditioner H imaginary')
     423           44 :       CALL cp_fm_create(matrix_s_re_fm, fm_struct_square, name='complex preconditioner S real')
     424           44 :       CALL cp_fm_create(matrix_s_im_fm, fm_struct_square, name='complex preconditioner S imaginary')
     425           44 :       CALL cp_fm_struct_release(fm_struct_mo)
     426           44 :       CALL cp_fm_struct_release(fm_struct_square)
     427           44 :       CALL copy_dbcsr_to_fm(matrix_c_re, matrix_c_re_fm)
     428           44 :       CALL copy_dbcsr_to_fm(matrix_c_im, matrix_c_im_fm)
     429           44 :       CALL copy_dbcsr_to_fm(matrix_h_re, matrix_h_re_fm)
     430           44 :       CALL copy_dbcsr_to_fm(matrix_h_im, matrix_h_im_fm)
     431           44 :       CALL copy_dbcsr_to_fm(matrix_s_re, matrix_s_re_fm)
     432           44 :       CALL copy_dbcsr_to_fm(matrix_s_im, matrix_s_im_fm)
     433              : 
     434           44 :       CALL cp_cfm_create(matrix_c, matrix_c_re_fm%matrix_struct, name='complex preconditioner C')
     435           44 :       CALL cp_cfm_create(matrix_h, matrix_h_re_fm%matrix_struct, name='complex preconditioner H')
     436           44 :       CALL cp_cfm_create(matrix_s, matrix_s_re_fm%matrix_struct, name='complex preconditioner S')
     437           44 :       CALL cp_fm_to_cfm(matrix_c_re_fm, matrix_c_im_fm, matrix_c)
     438           44 :       CALL cp_fm_to_cfm(matrix_h_re_fm, matrix_h_im_fm, matrix_h)
     439           44 :       CALL cp_fm_to_cfm(matrix_s_re_fm, matrix_s_im_fm, matrix_s)
     440              :       CALL make_complex_full_single_inverse(preconditioner_env, matrix_c, matrix_h, matrix_s, &
     441           44 :                                             energy_gap)
     442           44 :       preconditioner_env%solver = solver_type
     443              : 
     444           44 :       CALL cp_cfm_release(matrix_s)
     445           44 :       CALL cp_cfm_release(matrix_h)
     446           44 :       CALL cp_cfm_release(matrix_c)
     447           44 :       CALL cp_fm_release(matrix_s_im_fm)
     448           44 :       CALL cp_fm_release(matrix_s_re_fm)
     449           44 :       CALL cp_fm_release(matrix_h_im_fm)
     450           44 :       CALL cp_fm_release(matrix_h_re_fm)
     451           44 :       CALL cp_fm_release(matrix_c_im_fm)
     452           44 :       CALL cp_fm_release(matrix_c_re_fm)
     453              : 
     454           44 :    END SUBROUTINE make_preconditioner_complex_full_single_inverse
     455              : 
     456              : ! **************************************************************************************************
     457              : !> \brief Construct a complex FULL_S_INVERSE preconditioner.
     458              : !> \param preconditioner_env preconditioner storage
     459              : !> \param matrix_s_re real part of S(k)
     460              : !> \param matrix_s_im imaginary part of S(k)
     461              : !> \param solver_type requested inverse solver
     462              : ! **************************************************************************************************
     463          180 :    SUBROUTINE make_preconditioner_complex_full_s_inverse(preconditioner_env, &
     464              :                                                          matrix_s_re, matrix_s_im, solver_type)
     465              : 
     466              :       TYPE(preconditioner_type)                          :: preconditioner_env
     467              :       TYPE(dbcsr_type), POINTER                          :: matrix_s_re, matrix_s_im
     468              :       INTEGER, INTENT(IN)                                :: solver_type
     469              : 
     470              :       TYPE(cp_cfm_type)                                  :: matrix_s
     471              : 
     472           90 :       IF (solver_type /= ot_precond_solver_default .AND. &
     473              :           solver_type /= ot_precond_solver_inv_chol) THEN
     474            0 :          CPABORT("Complex FULL_S_INVERSE supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
     475              :       END IF
     476              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
     477           90 :                              'complex preconditioner S', matrix_s)
     478           90 :       CALL make_complex_full_s_inverse(preconditioner_env, matrix_s)
     479           90 :       preconditioner_env%solver = solver_type
     480           90 :       CALL cp_cfm_release(matrix_s)
     481              : 
     482           90 :    END SUBROUTINE make_preconditioner_complex_full_s_inverse
     483              : 
     484              : ! **************************************************************************************************
     485              : !> \brief Construct a complex FULL_KINETIC preconditioner.
     486              : !> \param preconditioner_env preconditioner storage
     487              : !> \param matrix_t_re real part of T(k)
     488              : !> \param matrix_t_im imaginary part of T(k)
     489              : !> \param matrix_s_re real part of S(k)
     490              : !> \param matrix_s_im imaginary part of S(k)
     491              : !> \param energy_gap non-negative overlap shift
     492              : !> \param solver_type requested inverse solver
     493              : ! **************************************************************************************************
     494          360 :    SUBROUTINE make_preconditioner_complex_full_kinetic(preconditioner_env, &
     495              :                                                        matrix_t_re, matrix_t_im, &
     496              :                                                        matrix_s_re, matrix_s_im, &
     497              :                                                        energy_gap, solver_type)
     498              : 
     499              :       TYPE(preconditioner_type)                          :: preconditioner_env
     500              :       TYPE(dbcsr_type), POINTER                          :: matrix_t_re, matrix_t_im, matrix_s_re, &
     501              :                                                             matrix_s_im
     502              :       REAL(KIND=dp), INTENT(IN)                          :: energy_gap
     503              :       INTEGER, INTENT(IN)                                :: solver_type
     504              : 
     505              :       TYPE(cp_cfm_type)                                  :: matrix_s, matrix_t
     506              : 
     507          120 :       IF (solver_type /= ot_precond_solver_default .AND. &
     508              :           solver_type /= ot_precond_solver_inv_chol) THEN
     509            0 :          CPABORT("Complex FULL_KINETIC supports only PRECOND_SOLVER DEFAULT/INVERSE_CHOLESKY")
     510              :       END IF
     511              :       CALL dbcsr_pair_to_cfm(matrix_t_re, matrix_t_im, preconditioner_env, &
     512          120 :                              'complex preconditioner T', matrix_t)
     513              :       CALL dbcsr_pair_to_cfm(matrix_s_re, matrix_s_im, preconditioner_env, &
     514          120 :                              'complex preconditioner S', matrix_s)
     515          120 :       CALL make_complex_full_kinetic(preconditioner_env, matrix_t, matrix_s, energy_gap)
     516          120 :       preconditioner_env%solver = solver_type
     517          120 :       CALL cp_cfm_release(matrix_s)
     518          120 :       CALL cp_cfm_release(matrix_t)
     519              : 
     520          120 :    END SUBROUTINE make_preconditioner_complex_full_kinetic
     521              : 
     522              : ! **************************************************************************************************
     523              : !> \brief Copy a real/imaginary DBCSR pair to one distributed complex full matrix.
     524              : !> \param matrix_re real matrix component
     525              : !> \param matrix_im imaginary matrix component
     526              : !> \param preconditioner_env source of the distribution context
     527              : !> \param matrix_name matrix label
     528              : !> \param matrix complex output matrix
     529              : ! **************************************************************************************************
     530         2442 :    SUBROUTINE dbcsr_pair_to_cfm(matrix_re, matrix_im, preconditioner_env, matrix_name, matrix)
     531              : 
     532              :       TYPE(dbcsr_type), POINTER                          :: matrix_re, matrix_im
     533              :       TYPE(preconditioner_type)                          :: preconditioner_env
     534              :       CHARACTER(LEN=*), INTENT(IN)                       :: matrix_name
     535              :       TYPE(cp_cfm_type), INTENT(OUT)                     :: matrix
     536              : 
     537              :       INTEGER                                            :: ncol, nrow
     538              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     539              :       TYPE(cp_fm_type)                                   :: matrix_im_fm, matrix_re_fm
     540              : 
     541          814 :       NULLIFY (fm_struct)
     542            0 :       CPASSERT(ASSOCIATED(matrix_re))
     543          814 :       CPASSERT(ASSOCIATED(matrix_im))
     544          814 :       CALL dbcsr_get_info(matrix_re, nfullrows_total=nrow, nfullcols_total=ncol)
     545              :       CALL cp_fm_struct_create(fm_struct, nrow_global=nrow, ncol_global=ncol, &
     546              :                                context=preconditioner_env%ctxt, &
     547          814 :                                para_env=preconditioner_env%para_env)
     548          814 :       CALL cp_fm_create(matrix_re_fm, fm_struct, name=TRIM(matrix_name)//' real')
     549          814 :       CALL cp_fm_create(matrix_im_fm, fm_struct, name=TRIM(matrix_name)//' imaginary')
     550          814 :       CALL cp_fm_struct_release(fm_struct)
     551          814 :       CALL copy_dbcsr_to_fm(matrix_re, matrix_re_fm)
     552          814 :       CALL copy_dbcsr_to_fm(matrix_im, matrix_im_fm)
     553          814 :       CALL cp_cfm_create(matrix, matrix_re_fm%matrix_struct, name=matrix_name)
     554          814 :       CALL cp_fm_to_cfm(matrix_re_fm, matrix_im_fm, matrix)
     555          814 :       CALL cp_fm_release(matrix_im_fm)
     556          814 :       CALL cp_fm_release(matrix_re_fm)
     557              : 
     558          814 :    END SUBROUTINE dbcsr_pair_to_cfm
     559              : 
     560              : ! **************************************************************************************************
     561              : !> \brief Allows for a restart of the preconditioner
     562              : !>        depending on the method it purges all arrays or keeps them
     563              : !> \param qs_env ...
     564              : !> \param preconditioner ...
     565              : !> \param prec_type ...
     566              : !> \param nspins ...
     567              : ! **************************************************************************************************
     568         7443 :    SUBROUTINE restart_preconditioner(qs_env, preconditioner, prec_type, nspins)
     569              : 
     570              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     571              :       TYPE(preconditioner_p_type), DIMENSION(:), POINTER :: preconditioner
     572              :       INTEGER, INTENT(IN)                                :: prec_type, nspins
     573              : 
     574              :       INTEGER                                            :: ispin
     575              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     576              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     577              : 
     578         7443 :       NULLIFY (para_env, blacs_env)
     579         7443 :       CALL get_qs_env(qs_env, para_env=para_env, blacs_env=blacs_env)
     580              : 
     581         7443 :       IF (ASSOCIATED(preconditioner)) THEN
     582         6638 :          SELECT CASE (prec_type)
     583              :          CASE (ot_precond_full_all, ot_precond_full_single) ! these depend on the ks matrix
     584         3424 :             DO ispin = 1, SIZE(preconditioner)
     585         1908 :                CALL destroy_preconditioner(preconditioner(ispin)%preconditioner)
     586         3424 :                DEALLOCATE (preconditioner(ispin)%preconditioner)
     587              :             END DO
     588         1516 :             DEALLOCATE (preconditioner)
     589              :          CASE (ot_precond_none, ot_precond_full_kinetic, ot_precond_s_inverse, &
     590              :                ot_precond_full_single_inverse) ! these are 'independent'
     591              :             ! do nothing
     592              :          CASE DEFAULT
     593         5122 :             CPABORT("Unknown preconditioner type")
     594              :          END SELECT
     595              :       END IF
     596              : 
     597              :       ! add an OT preconditioner if none is present
     598         7443 :       IF (.NOT. ASSOCIATED(preconditioner)) THEN
     599         7033 :          SELECT CASE (prec_type)
     600              :          CASE (ot_precond_full_all, ot_precond_full_single_inverse)
     601        13683 :             ALLOCATE (preconditioner(nspins))
     602              :          CASE DEFAULT
     603         4478 :             ALLOCATE (preconditioner(1))
     604              :          END SELECT
     605         8573 :          DO ispin = 1, SIZE(preconditioner)
     606         4736 :             ALLOCATE (preconditioner(ispin)%preconditioner)
     607              :             CALL init_preconditioner(preconditioner(ispin)%preconditioner, &
     608              :                                      para_env=para_env, &
     609         8573 :                                      blacs_env=blacs_env)
     610              :          END DO
     611              :       END IF
     612              : 
     613         7443 :    END SUBROUTINE restart_preconditioner
     614              : 
     615              : ! **************************************************************************************************
     616              : !> \brief ...
     617              : !> \param qs_env ...
     618              : !> \param mos ...
     619              : !> \param matrix_ks ...
     620              : !> \param matrix_s ...
     621              : !> \param ot_preconditioner ...
     622              : !> \param prec_type ...
     623              : !> \param solver_type ...
     624              : !> \param energy_gap ...
     625              : !> \param nspins ...
     626              : !> \param has_unit_metric ...
     627              : !> \param convert_to_dbcsr ...
     628              : !> \param chol_type ...
     629              : !> \param full_mo_set ...
     630              : !> \param chebyshev_degree ...
     631              : ! **************************************************************************************************
     632         7443 :    SUBROUTINE prepare_preconditioner(qs_env, mos, matrix_ks, matrix_s, &
     633              :                                      ot_preconditioner, prec_type, solver_type, &
     634              :                                      energy_gap, nspins, has_unit_metric, &
     635              :                                      convert_to_dbcsr, chol_type, full_mo_set, chebyshev_degree)
     636              : 
     637              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     638              :       TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT)     :: mos
     639              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     640              :       TYPE(preconditioner_p_type), DIMENSION(:), POINTER :: ot_preconditioner
     641              :       INTEGER, INTENT(IN)                                :: prec_type, solver_type
     642              :       REAL(dp), INTENT(IN)                               :: energy_gap
     643              :       INTEGER, INTENT(IN)                                :: nspins
     644              :       LOGICAL, INTENT(IN), OPTIONAL                      :: has_unit_metric, convert_to_dbcsr
     645              :       INTEGER, INTENT(IN), OPTIONAL                      :: chol_type
     646              :       LOGICAL, INTENT(IN), OPTIONAL                      :: full_mo_set
     647              :       INTEGER, INTENT(IN), OPTIONAL                      :: chebyshev_degree
     648              : 
     649              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'prepare_preconditioner'
     650              : 
     651              :       CHARACTER(LEN=default_string_length)               :: msg
     652              :       INTEGER                                            :: handle, icall, ispin, &
     653              :                                                             my_chebyshev_degree, n_loops
     654              :       INTEGER, DIMENSION(5)                              :: nocc, norb
     655              :       LOGICAL                                            :: do_co_rotate, my_convert_to_dbcsr, &
     656              :                                                             my_full_mo_set, my_has_unit_metric, &
     657              :                                                             use_mo_coeff_b
     658              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     659              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     660         7443 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: kinetic
     661              :       TYPE(dbcsr_type), POINTER                          :: matrix_t, mo_coeff_b
     662              :       TYPE(dft_control_type), POINTER                    :: dft_control
     663              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     664              : 
     665         7443 :       CALL timeset(routineN, handle)
     666         7443 :       NULLIFY (matrix_t, mo_coeff_b, mo_coeff, kinetic, dft_control, para_env, blacs_env)
     667         7443 :       my_has_unit_metric = .FALSE.
     668         7443 :       IF (PRESENT(has_unit_metric)) my_has_unit_metric = has_unit_metric
     669         7443 :       my_convert_to_dbcsr = .TRUE.
     670         7443 :       IF (PRESENT(convert_to_dbcsr)) my_convert_to_dbcsr = convert_to_dbcsr
     671         7443 :       my_full_mo_set = .FALSE.
     672         7443 :       IF (PRESENT(full_mo_set)) my_full_mo_set = full_mo_set
     673         7443 :       my_chebyshev_degree = 8
     674         7443 :       IF (PRESENT(chebyshev_degree)) my_chebyshev_degree = chebyshev_degree
     675              : 
     676              :       CALL get_qs_env(qs_env, &
     677              :                       dft_control=dft_control, &
     678              :                       para_env=para_env, &
     679         7443 :                       blacs_env=blacs_env)
     680              : 
     681         7443 :       IF (dft_control%qs_control%semi_empirical .OR. dft_control%qs_control%dftb .OR. &
     682              :           dft_control%qs_control%xtb) THEN
     683         2148 :          IF (prec_type == ot_precond_full_kinetic) THEN
     684            0 :             msg = "Full_kinetic not available for semi-empirical methods"
     685            0 :             CPABORT(TRIM(msg))
     686              :          END IF
     687         2148 :          matrix_t => matrix_s(1)%matrix
     688              :       ELSE
     689         5295 :          CPASSERT(.NOT. my_has_unit_metric)
     690         5295 :          CALL get_qs_env(qs_env, kinetic=kinetic)
     691         5295 :          matrix_t => kinetic(1)%matrix
     692              :       END IF
     693              : 
     694              :       ! use full set of MOs or just occupied MOs
     695         7443 :       nocc = 0
     696         7443 :       norb = 0
     697         7443 :       IF (my_full_mo_set) THEN
     698           38 :          DO ispin = 1, nspins
     699           20 :             CALL get_mo_set(mo_set=mos(ispin), homo=nocc(ispin), nmo=norb(ispin))
     700           38 :             CALL set_mo_set(mo_set=mos(ispin), homo=norb(ispin))
     701              :          END DO
     702              :       END IF
     703              :       !determines how often make preconditioner is called, spin dependent methods have to be called twice
     704         7443 :       n_loops = 1
     705         7443 :       IF (prec_type == ot_precond_full_single_inverse) n_loops = nspins
     706              :       ! check whether we need the ev and rotate the MOs
     707         2524 :       SELECT CASE (prec_type)
     708              :       CASE (ot_precond_full_all)
     709              :          ! if one of these preconditioners is used every spin needs to call make_preconditioner
     710         2524 :          n_loops = nspins
     711              : 
     712         2524 :          do_co_rotate = ASSOCIATED(qs_env%mo_derivs)
     713        10745 :          DO ispin = 1, nspins
     714         3302 :             CALL get_mo_set(mo_set=mos(ispin), mo_coeff_b=mo_coeff_b, mo_coeff=mo_coeff)
     715         3302 :             use_mo_coeff_b = mos(ispin)%use_mo_coeff_b
     716         5826 :             IF (use_mo_coeff_b .AND. do_co_rotate) THEN
     717              :                CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_ks(ispin)%matrix, &
     718              :                                                    do_rotation=.TRUE., &
     719              :                                                    co_rotate=qs_env%mo_derivs(ispin)%matrix, &
     720              :                                                    para_env=para_env, &
     721         3282 :                                                    blacs_env=blacs_env)
     722           20 :             ELSE IF (use_mo_coeff_b) THEN
     723              :                CALL calculate_subspace_eigenvalues(mo_coeff_b, matrix_ks(ispin)%matrix, &
     724              :                                                    do_rotation=.TRUE., &
     725              :                                                    para_env=para_env, &
     726           20 :                                                    blacs_env=blacs_env)
     727              :             ELSE
     728              :                CALL calculate_subspace_eigenvalues(mo_coeff, matrix_ks(ispin)%matrix, &
     729            0 :                                                    do_rotation=.TRUE.)
     730              :             END IF
     731              :          END DO
     732              :       CASE DEFAULT
     733              :          ! No need to rotate the MOs
     734              :       END SELECT
     735              : 
     736              :       ! check whether we have a preconditioner
     737          724 :       SELECT CASE (prec_type)
     738              :       CASE (ot_precond_none)
     739         1448 :          DO ispin = 1, SIZE(ot_preconditioner)
     740         1448 :             ot_preconditioner(ispin)%preconditioner%in_use = 0
     741              :          END DO
     742              :       CASE DEFAULT
     743        22006 :          DO icall = 1, n_loops
     744         7844 :             ot_preconditioner(icall)%preconditioner%polynomial_degree = my_chebyshev_degree
     745        14563 :             IF (my_has_unit_metric) THEN
     746              :                CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
     747              :                                         prec_type, &
     748              :                                         solver_type, &
     749              :                                         matrix_h=matrix_ks(icall)%matrix, &
     750              :                                         mo_set=mos(icall), &
     751              :                                         energy_gap=energy_gap, &
     752          474 :                                         convert_precond_to_dbcsr=my_convert_to_dbcsr)
     753              :             ELSE
     754              :                CALL make_preconditioner(ot_preconditioner(icall)%preconditioner, &
     755              :                                         prec_type, &
     756              :                                         solver_type, &
     757              :                                         matrix_h=matrix_ks(icall)%matrix, &
     758              :                                         matrix_s=matrix_s(1)%matrix, &
     759              :                                         matrix_t=matrix_t, &
     760              :                                         mo_set=mos(icall), &
     761              :                                         energy_gap=energy_gap, &
     762         7370 :                                         convert_precond_to_dbcsr=my_convert_to_dbcsr, chol_type=chol_type)
     763              :             END IF
     764              :          END DO
     765              :       END SELECT
     766              : 
     767              :       ! reset homo values
     768         7443 :       IF (my_full_mo_set) THEN
     769           38 :          DO ispin = 1, nspins
     770           38 :             CALL set_mo_set(mo_set=mos(ispin), homo=nocc(ispin))
     771              :          END DO
     772              :       END IF
     773              : 
     774         7443 :       CALL timestop(handle)
     775              : 
     776         7443 :    END SUBROUTINE prepare_preconditioner
     777              : 
     778              : END MODULE preconditioner
        

Generated by: LCOV version 2.0-1