LCOV - code coverage report
Current view: top level - src - preconditioner_apply.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:4dc5213) Lines: 84.4 % 288 243
Test Date: 2026-09-08 07:13:59 Functions: 86.7 % 15 13

            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_apply
      16              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_gemm
      17              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      18              :                                               cp_cfm_get_info,&
      19              :                                               cp_cfm_release,&
      20              :                                               cp_cfm_to_fm,&
      21              :                                               cp_cfm_type,&
      22              :                                               cp_fm_to_cfm
      23              :    USE cp_dbcsr_api,                    ONLY: &
      24              :         dbcsr_add, dbcsr_copy, dbcsr_get_info, dbcsr_iterator_blocks_left, &
      25              :         dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
      26              :         dbcsr_multiply, dbcsr_release, dbcsr_set, dbcsr_type
      27              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      28              :                                               copy_fm_to_dbcsr
      29              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale,&
      30              :                                               cp_fm_scale_and_add
      31              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_restore
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_release,&
      34              :                                               cp_fm_struct_type
      35              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      36              :                                               cp_fm_get_info,&
      37              :                                               cp_fm_release,&
      38              :                                               cp_fm_to_fm,&
      39              :                                               cp_fm_type
      40              :    USE input_constants,                 ONLY: &
      41              :         ot_low_rank_base_lattice_fft, ot_low_rank_base_overlap, ot_precond_fermi_low_rank, &
      42              :         ot_precond_full_all, ot_precond_full_kinetic, ot_precond_full_single, &
      43              :         ot_precond_full_single_inverse, ot_precond_s_inverse, ot_precond_solver_chebyshev, &
      44              :         ot_precond_solver_direct, ot_precond_solver_inv_chol, ot_precond_solver_update
      45              :    USE kinds,                           ONLY: dp
      46              :    USE lattice_low_rank_preconditioner, ONLY: apply_lattice_inverse_dense
      47              :    USE low_rank_preconditioner_model,   ONLY: low_rank_inverse_weight
      48              :    USE mathconstants,                   ONLY: z_one,&
      49              :                                               z_zero
      50              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      51              :    USE preconditioner_types,            ONLY: preconditioner_type
      52              : #include "./base/base_uses.f90"
      53              : 
      54              :    IMPLICIT NONE
      55              :    PRIVATE
      56              : 
      57              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'preconditioner_apply'
      58              : 
      59              :    PUBLIC :: apply_preconditioner_cfm_complex, apply_preconditioner_dbcsr_complex, &
      60              :              apply_preconditioner_fm, apply_preconditioner_dbcsr
      61              : 
      62              : CONTAINS
      63              : 
      64              : ! **************************************************************************************************
      65              : !> \brief applies a previously created preconditioner to a full matrix
      66              : !> \param preconditioner_env ...
      67              : !> \param matrix_in ...
      68              : !> \param matrix_out ...
      69              : ! **************************************************************************************************
      70        50898 :    SUBROUTINE apply_preconditioner_fm(preconditioner_env, matrix_in, matrix_out)
      71              : 
      72              :       TYPE(preconditioner_type)                          :: preconditioner_env
      73              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
      74              : 
      75              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_preconditioner_fm'
      76              : 
      77              :       INTEGER                                            :: handle
      78              : 
      79        50898 :       CALL timeset(routineN, handle)
      80              : 
      81        50898 :       SELECT CASE (preconditioner_env%in_use)
      82              :       CASE (0)
      83            0 :          CPABORT("No preconditioner in use")
      84              :       CASE (ot_precond_full_single)
      85         1320 :          CALL apply_full_single(preconditioner_env, matrix_in, matrix_out)
      86              :       CASE (ot_precond_full_all)
      87        28380 :          CALL apply_full_all(preconditioner_env, matrix_in, matrix_out)
      88              :       CASE (ot_precond_fermi_low_rank)
      89            0 :          CALL apply_low_rank_fm(preconditioner_env, matrix_in, matrix_out)
      90              :       CASE (ot_precond_full_kinetic, ot_precond_full_single_inverse, ot_precond_s_inverse)
      91        42396 :          SELECT CASE (preconditioner_env%solver)
      92              :          CASE (ot_precond_solver_inv_chol, ot_precond_solver_update)
      93        21198 :             CALL apply_full_single(preconditioner_env, matrix_in, matrix_out)
      94              :          CASE (ot_precond_solver_direct)
      95            0 :             CALL apply_full_direct(preconditioner_env, matrix_in, matrix_out)
      96              :          CASE (ot_precond_solver_chebyshev)
      97            0 :             CALL apply_chebyshev_fm(preconditioner_env, matrix_in, matrix_out)
      98              :          CASE DEFAULT
      99        21198 :             CPABORT("Solver not implemented")
     100              :          END SELECT
     101              :       CASE DEFAULT
     102        50898 :          CPABORT("Unknown preconditioner")
     103              :       END SELECT
     104              : 
     105        50898 :       CALL timestop(handle)
     106              : 
     107        50898 :    END SUBROUTINE apply_preconditioner_fm
     108              : 
     109              : ! **************************************************************************************************
     110              : !> \brief ...
     111              : !> \param preconditioner_env ...
     112              : !> \param matrix_in ...
     113              : !> \param matrix_out ...
     114              : ! **************************************************************************************************
     115        77787 :    SUBROUTINE apply_preconditioner_dbcsr(preconditioner_env, matrix_in, matrix_out)
     116              : 
     117              :       TYPE(preconditioner_type)                          :: preconditioner_env
     118              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     119              : 
     120              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_preconditioner_dbcsr'
     121              : 
     122              :       INTEGER                                            :: handle
     123              : 
     124        77787 :       CALL timeset(routineN, handle)
     125              : 
     126        77787 :       SELECT CASE (preconditioner_env%in_use)
     127              :       CASE (0)
     128            0 :          CPABORT("No preconditioner in use")
     129              :       CASE (ot_precond_full_single)
     130          202 :          CALL apply_single(preconditioner_env, matrix_in, matrix_out)
     131              :       CASE (ot_precond_full_all)
     132        24638 :          CALL apply_all(preconditioner_env, matrix_in, matrix_out)
     133              :       CASE (ot_precond_fermi_low_rank)
     134           96 :          CALL apply_low_rank_dbcsr(preconditioner_env, matrix_in, matrix_out)
     135              :       CASE (ot_precond_full_kinetic, ot_precond_full_single_inverse, ot_precond_s_inverse)
     136       105664 :          SELECT CASE (preconditioner_env%solver)
     137              :          CASE (ot_precond_solver_inv_chol, ot_precond_solver_update)
     138        52813 :             CALL apply_single(preconditioner_env, matrix_in, matrix_out)
     139              :          CASE (ot_precond_solver_direct)
     140            0 :             CPABORT("Apply_full_direct not supported with ot")
     141              :             !CALL apply_full_direct(preconditioner_env, matrix_in, matrix_out)
     142              :          CASE (ot_precond_solver_chebyshev)
     143           38 :             CALL apply_chebyshev_dbcsr(preconditioner_env, matrix_in, matrix_out)
     144              :          CASE DEFAULT
     145        52851 :             CPABORT("Wrong solver")
     146              :          END SELECT
     147              :       CASE DEFAULT
     148        77787 :          CPABORT("Wrong preconditioner")
     149              :       END SELECT
     150              : 
     151        77787 :       CALL timestop(handle)
     152              : 
     153        77787 :    END SUBROUTINE apply_preconditioner_dbcsr
     154              : 
     155              : ! **************************************************************************************************
     156              : !> \brief Apply a complex k-point orbital preconditioner.
     157              : !> \param preconditioner_env complex preconditioner storage
     158              : !> \param matrix_in complex input channel
     159              : !> \param matrix_out complex output channel
     160              : ! **************************************************************************************************
     161        57372 :    SUBROUTINE apply_preconditioner_cfm_complex(preconditioner_env, matrix_in, matrix_out)
     162              : 
     163              :       TYPE(preconditioner_type)                          :: preconditioner_env
     164              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_in, matrix_out
     165              : 
     166              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_preconditioner_cfm_complex'
     167              : 
     168              :       COMPLEX(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     169        19124 :          POINTER                                         :: local_data
     170              :       INTEGER                                            :: handle, i, j, k, n, ncol_local, npre, &
     171              :                                                             nrow_local
     172        19124 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     173              :       REAL(KIND=dp)                                      :: scale
     174              :       TYPE(cp_cfm_type)                                  :: matrix_spectral
     175              : 
     176        19124 :       CALL timeset(routineN, handle)
     177              : 
     178        19124 :       SELECT CASE (preconditioner_env%in_use)
     179              :       CASE (ot_precond_full_all, ot_precond_full_single, ot_precond_full_single_inverse, &
     180              :             ot_precond_full_kinetic, ot_precond_s_inverse)
     181              :       CASE DEFAULT
     182        19124 :          CPABORT("Unsupported complex K-point OT preconditioner")
     183              :       END SELECT
     184        19124 :       CPASSERT(ASSOCIATED(preconditioner_env%complex_fm))
     185        19124 :       CALL cp_cfm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     186        19124 :       CALL cp_cfm_get_info(preconditioner_env%complex_fm, nrow_global=npre)
     187        19124 :       CPASSERT(n == npre)
     188              : 
     189        19124 :       IF (preconditioner_env%in_use == ot_precond_full_all) THEN
     190        15177 :          CPASSERT(ASSOCIATED(preconditioner_env%full_evals))
     191        15177 :          CPASSERT(ASSOCIATED(preconditioner_env%occ_evals))
     192        15177 :          CPASSERT(n == SIZE(preconditioner_env%full_evals))
     193        15177 :          CPASSERT(k == SIZE(preconditioner_env%occ_evals))
     194              :          CALL cp_cfm_create(matrix_spectral, matrix_in%matrix_struct, &
     195        15177 :                             name='complex FULL_ALL spectral input')
     196              :          CALL cp_cfm_gemm('C', 'N', n, k, n, z_one, preconditioner_env%complex_fm, &
     197        15177 :                           matrix_in, z_zero, matrix_spectral)
     198              :          CALL cp_cfm_get_info(matrix_spectral, nrow_local=nrow_local, ncol_local=ncol_local, &
     199        15177 :                               row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     200       274434 :          DO j = 1, ncol_local
     201      7318945 :             DO i = 1, nrow_local
     202              :                scale = 1.0_dp/MAX(preconditioner_env%energy_gap, &
     203              :                                   preconditioner_env%full_evals(row_indices(i)) - &
     204      7044511 :                                   preconditioner_env%occ_evals(col_indices(j)))
     205      7303768 :                local_data(i, j) = scale*local_data(i, j)
     206              :             END DO
     207              :          END DO
     208              :          CALL cp_cfm_gemm('N', 'N', n, k, n, z_one, preconditioner_env%complex_fm, &
     209        15177 :                           matrix_spectral, z_zero, matrix_out)
     210        15177 :          CALL cp_cfm_release(matrix_spectral)
     211              :       ELSE
     212              :          CALL cp_cfm_gemm('N', 'N', n, k, n, z_one, preconditioner_env%complex_fm, &
     213         3947 :                           matrix_in, z_zero, matrix_out)
     214              :       END IF
     215              : 
     216        19124 :       CALL timestop(handle)
     217              : 
     218        19124 :    END SUBROUTINE apply_preconditioner_cfm_complex
     219              : 
     220              : ! **************************************************************************************************
     221              : !> \brief Apply a complex orbital preconditioner to paired real/imaginary DBCSR matrices.
     222              : !> \param preconditioner_env complex k-point preconditioner
     223              : !> \param matrix_in_re real input channel
     224              : !> \param matrix_in_im imaginary input channel
     225              : !> \param matrix_out_re real output channel
     226              : !> \param matrix_out_im imaginary output channel
     227              : ! **************************************************************************************************
     228        27784 :    SUBROUTINE apply_preconditioner_dbcsr_complex(preconditioner_env, matrix_in_re, matrix_in_im, &
     229              :                                                  matrix_out_re, matrix_out_im)
     230              : 
     231              :       TYPE(preconditioner_type)                          :: preconditioner_env
     232              :       TYPE(dbcsr_type)                                   :: matrix_in_re, matrix_in_im, &
     233              :                                                             matrix_out_re, matrix_out_im
     234              : 
     235              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_preconditioner_dbcsr_complex'
     236              : 
     237              :       INTEGER                                            :: handle, k, n
     238              :       TYPE(cp_cfm_type)                                  :: matrix_in, matrix_out
     239              :       TYPE(cp_fm_type)                                   :: matrix_in_im_fm, matrix_in_re_fm, &
     240              :                                                             matrix_out_im_fm, matrix_out_re_fm
     241              : 
     242         3473 :       CALL timeset(routineN, handle)
     243              : 
     244         3473 :       CALL dbcsr_get_info(matrix_in_re, nfullrows_total=n, nfullcols_total=k)
     245         3473 :       CPASSERT(ASSOCIATED(preconditioner_env%complex_fm))
     246              : 
     247              :       CALL cp_fm_create(matrix_in_re_fm, preconditioner_env%complex_fm%matrix_struct, &
     248         3473 :                         nrow=n, ncol=k, name='complex preconditioner input real')
     249              :       CALL cp_fm_create(matrix_in_im_fm, preconditioner_env%complex_fm%matrix_struct, &
     250         3473 :                         nrow=n, ncol=k, name='complex preconditioner input imaginary')
     251              :       CALL cp_fm_create(matrix_out_re_fm, preconditioner_env%complex_fm%matrix_struct, &
     252         3473 :                         nrow=n, ncol=k, name='complex preconditioner output real')
     253              :       CALL cp_fm_create(matrix_out_im_fm, preconditioner_env%complex_fm%matrix_struct, &
     254         3473 :                         nrow=n, ncol=k, name='complex preconditioner output imaginary')
     255         3473 :       CALL copy_dbcsr_to_fm(matrix_in_re, matrix_in_re_fm)
     256         3473 :       CALL copy_dbcsr_to_fm(matrix_in_im, matrix_in_im_fm)
     257              : 
     258              :       CALL cp_cfm_create(matrix_in, matrix_in_re_fm%matrix_struct, &
     259         3473 :                          name='complex preconditioner input')
     260              :       CALL cp_cfm_create(matrix_out, matrix_in_re_fm%matrix_struct, &
     261         3473 :                          name='complex preconditioner output')
     262         3473 :       CALL cp_fm_to_cfm(matrix_in_re_fm, matrix_in_im_fm, matrix_in)
     263         3473 :       CALL apply_preconditioner_cfm_complex(preconditioner_env, matrix_in, matrix_out)
     264         3473 :       CALL cp_cfm_to_fm(matrix_out, matrix_out_re_fm, matrix_out_im_fm)
     265         3473 :       CALL dbcsr_set(matrix_out_re, 0.0_dp)
     266         3473 :       CALL dbcsr_set(matrix_out_im, 0.0_dp)
     267         3473 :       CALL copy_fm_to_dbcsr(matrix_out_re_fm, matrix_out_re)
     268         3473 :       CALL copy_fm_to_dbcsr(matrix_out_im_fm, matrix_out_im)
     269              : 
     270         3473 :       CALL cp_cfm_release(matrix_out)
     271         3473 :       CALL cp_cfm_release(matrix_in)
     272         3473 :       CALL cp_fm_release(matrix_out_im_fm)
     273         3473 :       CALL cp_fm_release(matrix_out_re_fm)
     274         3473 :       CALL cp_fm_release(matrix_in_im_fm)
     275         3473 :       CALL cp_fm_release(matrix_in_re_fm)
     276              : 
     277         3473 :       CALL timestop(handle)
     278              : 
     279         3473 :    END SUBROUTINE apply_preconditioner_dbcsr_complex
     280              : 
     281              : ! **************************************************************************************************
     282              : !> \brief apply to full matrix, complete inversion has already been done
     283              : !> \param preconditioner_env ...
     284              : !> \param matrix_in ...
     285              : !> \param matrix_out ...
     286              : ! **************************************************************************************************
     287        45036 :    SUBROUTINE apply_full_single(preconditioner_env, matrix_in, matrix_out)
     288              : 
     289              :       TYPE(preconditioner_type)                          :: preconditioner_env
     290              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     291              : 
     292              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_full_single'
     293              : 
     294              :       INTEGER                                            :: handle, k, n
     295              : 
     296        22518 :       CALL timeset(routineN, handle)
     297              : 
     298        22518 :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     299              :       CALL parallel_gemm('N', 'N', n, k, n, 1.0_dp, preconditioner_env%fm, &
     300        22518 :                          matrix_in, 0.0_dp, matrix_out)
     301        22518 :       CALL timestop(handle)
     302              : 
     303        22518 :    END SUBROUTINE apply_full_single
     304              : 
     305              : ! **************************************************************************************************
     306              : !> \brief apply to dbcsr matrix, complete inversion has already been done
     307              : !> \param preconditioner_env ...
     308              : !> \param matrix_in ...
     309              : !> \param matrix_out ...
     310              : ! **************************************************************************************************
     311        53015 :    SUBROUTINE apply_single(preconditioner_env, matrix_in, matrix_out)
     312              : 
     313              :       TYPE(preconditioner_type)                          :: preconditioner_env
     314              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     315              : 
     316              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_single'
     317              : 
     318              :       INTEGER                                            :: handle
     319              : 
     320        53015 :       CALL timeset(routineN, handle)
     321              : 
     322        53015 :       IF (.NOT. ASSOCIATED(preconditioner_env%dbcsr_matrix)) THEN
     323            0 :          CPABORT("NOT ASSOCIATED preconditioner_env%dbcsr_matrix")
     324              :       END IF
     325              :       CALL dbcsr_multiply('N', 'N', 1.0_dp, preconditioner_env%dbcsr_matrix, matrix_in, &
     326        53015 :                           0.0_dp, matrix_out)
     327              : 
     328        53015 :       CALL timestop(handle)
     329              : 
     330        53015 :    END SUBROUTINE apply_single
     331              : 
     332              : ! **************************************************************************************************
     333              : !> \brief preconditioner contains the factorization, application done by
     334              : !>        solving the linear system
     335              : !> \param preconditioner_env ...
     336              : !> \param matrix_in ...
     337              : !> \param matrix_out ...
     338              : ! **************************************************************************************************
     339            0 :    SUBROUTINE apply_full_direct(preconditioner_env, matrix_in, matrix_out)
     340              : 
     341              :       TYPE(preconditioner_type)                          :: preconditioner_env
     342              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     343              : 
     344              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_full_direct'
     345              : 
     346              :       INTEGER                                            :: handle, k, n
     347              :       TYPE(cp_fm_type)                                   :: work
     348              : 
     349            0 :       CALL timeset(routineN, handle)
     350              : 
     351            0 :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     352            0 :       CALL cp_fm_create(work, matrix_in%matrix_struct, name="apply_full_single")
     353              :       CALL cp_fm_cholesky_restore(matrix_in, k, preconditioner_env%fm, work,&
     354            0 :            &                      "SOLVE", transa="T")
     355              :       CALL cp_fm_cholesky_restore(work, k, preconditioner_env%fm, matrix_out,&
     356            0 :            &                      "SOLVE", transa="N")
     357            0 :       CALL cp_fm_release(work)
     358              : 
     359            0 :       CALL timestop(handle)
     360              : 
     361            0 :    END SUBROUTINE apply_full_direct
     362              : 
     363              : ! **************************************************************************************************
     364              : !> \brief Apply a Chebyshev approximation to the inverse of the stored dense SPD operator.
     365              : !> \param preconditioner_env ...
     366              : !> \param matrix_in ...
     367              : !> \param matrix_out ...
     368              : ! **************************************************************************************************
     369            0 :    SUBROUTINE apply_chebyshev_fm(preconditioner_env, matrix_in, matrix_out)
     370              : 
     371              :       TYPE(preconditioner_type)                          :: preconditioner_env
     372              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     373              : 
     374              :       INTEGER                                            :: degree, iteration, k, n
     375              :       REAL(KIND=dp)                                      :: delta, rho, rho_previous, sigma, theta
     376              :       TYPE(cp_fm_type)                                   :: direction, residual
     377              : 
     378            0 :       CPASSERT(ASSOCIATED(preconditioner_env%fm))
     379            0 :       degree = preconditioner_env%polynomial_degree
     380            0 :       CPASSERT(degree >= 1)
     381            0 :       theta = 0.5_dp*(preconditioner_env%polynomial_max + preconditioner_env%polynomial_min)
     382            0 :       delta = 0.5_dp*(preconditioner_env%polynomial_max - preconditioner_env%polynomial_min)
     383            0 :       sigma = theta/delta
     384            0 :       rho_previous = 1.0_dp/sigma
     385            0 :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     386            0 :       CALL cp_fm_create(direction, matrix_in%matrix_struct, name='Chebyshev direction')
     387            0 :       CALL cp_fm_create(residual, matrix_in%matrix_struct, name='Chebyshev residual')
     388            0 :       CALL cp_fm_to_fm(matrix_in, direction)
     389            0 :       CALL cp_fm_scale(1.0_dp/theta, direction)
     390            0 :       CALL cp_fm_to_fm(direction, matrix_out)
     391            0 :       DO iteration = 2, degree
     392            0 :          CALL cp_fm_to_fm(matrix_in, residual)
     393              :          CALL parallel_gemm('N', 'N', n, k, n, -1.0_dp, preconditioner_env%fm, &
     394            0 :                             matrix_out, 1.0_dp, residual)
     395            0 :          rho = 1.0_dp/(2.0_dp*sigma - rho_previous)
     396            0 :          CALL cp_fm_scale(rho*rho_previous, direction)
     397            0 :          CALL cp_fm_scale_and_add(1.0_dp, direction, 2.0_dp*rho/delta, residual)
     398            0 :          CALL cp_fm_scale_and_add(1.0_dp, matrix_out, 1.0_dp, direction)
     399            0 :          rho_previous = rho
     400              :       END DO
     401            0 :       CALL cp_fm_release(residual)
     402            0 :       CALL cp_fm_release(direction)
     403              : 
     404            0 :    END SUBROUTINE apply_chebyshev_fm
     405              : 
     406              : ! **************************************************************************************************
     407              : !> \brief Apply a Chebyshev approximation to the inverse of the stored sparse SPD operator.
     408              : !> \param preconditioner_env ...
     409              : !> \param matrix_in ...
     410              : !> \param matrix_out ...
     411              : ! **************************************************************************************************
     412           38 :    SUBROUTINE apply_chebyshev_dbcsr(preconditioner_env, matrix_in, matrix_out)
     413              : 
     414              :       TYPE(preconditioner_type)                          :: preconditioner_env
     415              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     416              : 
     417              :       INTEGER                                            :: degree, iteration
     418              :       REAL(KIND=dp)                                      :: delta, rho, rho_previous, sigma, theta
     419              :       TYPE(dbcsr_type)                                   :: direction, residual
     420              : 
     421            0 :       CPASSERT(ASSOCIATED(preconditioner_env%dbcsr_matrix))
     422           38 :       degree = preconditioner_env%polynomial_degree
     423           38 :       CPASSERT(degree >= 1)
     424           38 :       theta = 0.5_dp*(preconditioner_env%polynomial_max + preconditioner_env%polynomial_min)
     425           38 :       delta = 0.5_dp*(preconditioner_env%polynomial_max - preconditioner_env%polynomial_min)
     426           38 :       sigma = theta/delta
     427           38 :       rho_previous = 1.0_dp/sigma
     428           38 :       CALL dbcsr_copy(direction, matrix_in, name='Chebyshev direction')
     429           38 :       CALL dbcsr_copy(residual, matrix_in, name='Chebyshev residual')
     430           38 :       CALL dbcsr_set(matrix_out, 0.0_dp)
     431           38 :       CALL dbcsr_add(matrix_out, direction, 1.0_dp, 1.0_dp/theta)
     432           38 :       CALL dbcsr_set(direction, 0.0_dp)
     433           38 :       CALL dbcsr_add(direction, matrix_in, 1.0_dp, 1.0_dp/theta)
     434          304 :       DO iteration = 2, degree
     435          266 :          CALL dbcsr_set(residual, 0.0_dp)
     436          266 :          CALL dbcsr_add(residual, matrix_in, 1.0_dp, 1.0_dp)
     437              :          CALL dbcsr_multiply('N', 'N', -1.0_dp, preconditioner_env%dbcsr_matrix, &
     438          266 :                              matrix_out, 1.0_dp, residual)
     439          266 :          rho = 1.0_dp/(2.0_dp*sigma - rho_previous)
     440          266 :          CALL dbcsr_add(direction, residual, rho*rho_previous, 2.0_dp*rho/delta)
     441          266 :          CALL dbcsr_add(matrix_out, direction, 1.0_dp, 1.0_dp)
     442          304 :          rho_previous = rho
     443              :       END DO
     444           38 :       CALL dbcsr_release(residual)
     445           38 :       CALL dbcsr_release(direction)
     446              : 
     447           38 :    END SUBROUTINE apply_chebyshev_dbcsr
     448              : 
     449              : ! **************************************************************************************************
     450              : !> \brief Applies the overlap-inverse base and a bounded low-rank spectral correction.
     451              : !> \param preconditioner_env ...
     452              : !> \param matrix_in ...
     453              : !> \param matrix_out ...
     454              : ! **************************************************************************************************
     455           96 :    SUBROUTINE apply_low_rank_fm(preconditioner_env, matrix_in, matrix_out)
     456              : 
     457              :       TYPE(preconditioner_type)                          :: preconditioner_env
     458              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     459              : 
     460              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_low_rank_fm'
     461              : 
     462              :       INTEGER                                            :: handle, i, j, k, n, ncol_local, nocc, &
     463              :                                                             nrow_local, rank_used
     464           48 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     465              :       REAL(KIND=dp)                                      :: correction
     466              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     467           48 :          POINTER                                         :: local_data
     468              :       TYPE(cp_fm_type)                                   :: matrix_tmp
     469              : 
     470           48 :       CALL timeset(routineN, handle)
     471              : 
     472           48 :       CPASSERT(ASSOCIATED(preconditioner_env%fm))
     473           48 :       CPASSERT(ASSOCIATED(preconditioner_env%full_evals))
     474           48 :       CPASSERT(ASSOCIATED(preconditioner_env%occ_evals))
     475              : 
     476           48 :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     477           48 :       nocc = SIZE(preconditioner_env%occ_evals)
     478           48 :       CPASSERT(n == SIZE(preconditioner_env%full_evals))
     479           48 :       rank_used = MIN(preconditioner_env%spectral_rank, n - nocc)
     480              : 
     481              :       ! With the exact base V V^T = S^-1. The optional lattice base replaces
     482              :       ! S^-1 by the inverse of its block-circulant translational projection:
     483              :       ! P = B^-1/window + V_r diag(1/max(gap, epsilon_a-mu) - 1/window) V_r^T.
     484              :       ! The common reference mu makes the operator right-covariant for any number
     485              :       ! of orbital columns. The lattice path retains only non-negative corrections.
     486           48 :       SELECT CASE (preconditioner_env%low_rank_base)
     487              :       CASE (ot_low_rank_base_overlap)
     488            0 :          CPASSERT(ASSOCIATED(preconditioner_env%base_fm))
     489              :          CALL parallel_gemm('N', 'N', n, k, n, preconditioner_env%spectral_base_scale, &
     490            0 :                             preconditioner_env%base_fm, matrix_in, 0.0_dp, matrix_out)
     491              :       CASE (ot_low_rank_base_lattice_fft)
     492           48 :          CALL apply_lattice_base_fm(preconditioner_env, matrix_in, matrix_out)
     493              :       CASE DEFAULT
     494           48 :          CPABORT("Unknown FERMI_LOW_RANK base operator during application")
     495              :       END SELECT
     496              : 
     497           48 :       IF (rank_used > 0) THEN
     498              :          CALL cp_fm_create(matrix_tmp, matrix_in%matrix_struct, name=routineN, &
     499           48 :                            nrow=rank_used, ncol=k)
     500              :          CALL cp_fm_get_info(matrix_tmp, nrow_local=nrow_local, ncol_local=ncol_local, &
     501           48 :                              row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     502              : 
     503              :          CALL parallel_gemm('T', 'N', rank_used, k, n, 1.0_dp, preconditioner_env%fm, &
     504           48 :                             matrix_in, 0.0_dp, matrix_tmp, a_first_col=nocc + 1)
     505              : 
     506          432 :          DO j = 1, ncol_local
     507         7344 :             DO i = 1, nrow_local
     508              :                correction = low_rank_inverse_weight( &
     509              :                             preconditioner_env%full_evals(nocc + row_indices(i)), &
     510              :                             preconditioner_env%spectral_reference, &
     511              :                             preconditioner_env%energy_gap) &
     512         6912 :                             - preconditioner_env%spectral_base_scale
     513         7296 :                local_data(i, j) = local_data(i, j)*correction
     514              :             END DO
     515              :          END DO
     516              : 
     517              :          CALL parallel_gemm('N', 'N', n, k, rank_used, 1.0_dp, preconditioner_env%fm, &
     518           48 :                             matrix_tmp, 1.0_dp, matrix_out, a_first_col=nocc + 1)
     519           48 :          CALL cp_fm_release(matrix_tmp)
     520              :       END IF
     521              : 
     522           48 :       CALL timestop(handle)
     523              : 
     524           48 :    END SUBROUTINE apply_low_rank_fm
     525              : 
     526              : ! **************************************************************************************************
     527              : !> \brief Apply the replicated-cell FFT base to a distributed full matrix.
     528              : !> \param preconditioner_env ...
     529              : !> \param matrix_in ...
     530              : !> \param matrix_out ...
     531              : ! **************************************************************************************************
     532           48 :    SUBROUTINE apply_lattice_base_fm(preconditioner_env, matrix_in, matrix_out)
     533              : 
     534              :       TYPE(preconditioner_type)                          :: preconditioner_env
     535              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     536              : 
     537              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_lattice_base_fm'
     538              : 
     539              :       INTEGER                                            :: handle, i, j, k, n, ncol_local, &
     540              :                                                             nrow_local
     541           48 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     542              :       LOGICAL                                            :: used_fft
     543              :       REAL(KIND=dp)                                      :: imaginary_residual, scale
     544              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: global_input, global_output
     545              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     546           48 :          POINTER                                         :: input_data, output_data
     547              : 
     548           48 :       CALL timeset(routineN, handle)
     549           48 :       CPASSERT(ALLOCATED(preconditioner_env%lattice_inverse_k))
     550              :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k, nrow_local=nrow_local, &
     551              :                           ncol_local=ncol_local, row_indices=row_indices, &
     552           48 :                           col_indices=col_indices, local_data=input_data)
     553           48 :       CALL cp_fm_get_info(matrix_out, local_data=output_data)
     554          192 :       ALLOCATE (global_input(n, k), source=0.0_dp)
     555          144 :       ALLOCATE (global_output(n, k))
     556          432 :       DO j = 1, ncol_local
     557        13104 :          DO i = 1, nrow_local
     558        13056 :             global_input(row_indices(i), col_indices(j)) = input_data(i, j)
     559              :          END DO
     560              :       END DO
     561           48 :       CALL preconditioner_env%para_env%sum(global_input)
     562              :       CALL apply_lattice_inverse_dense(preconditioner_env%lattice_inverse_k, &
     563              :                                        preconditioner_env%lattice_dims, global_input, global_output, &
     564           48 :                                        used_fft, imaginary_residual)
     565           48 :       IF (.NOT. used_fft) CPABORT("FERMI_LOW_RANK lattice inverse failed to use FFTs")
     566        25776 :       scale = MAX(1.0_dp, MAXVAL(ABS(global_output)))
     567           48 :       IF (imaginary_residual > 1.0E-10_dp*scale) THEN
     568            0 :          CPABORT("FERMI_LOW_RANK lattice inverse produced a non-real Gamma-point result")
     569              :       END IF
     570          432 :       DO j = 1, ncol_local
     571        13104 :          DO i = 1, nrow_local
     572              :             output_data(i, j) = preconditioner_env%spectral_base_scale* &
     573        13056 :                                 global_output(row_indices(i), col_indices(j))
     574              :          END DO
     575              :       END DO
     576           48 :       DEALLOCATE (global_input, global_output)
     577           48 :       CALL timestop(handle)
     578              : 
     579           96 :    END SUBROUTINE apply_lattice_base_fm
     580              : 
     581              : ! **************************************************************************************************
     582              : !> \brief DBCSR variant of the bounded low-rank spectral correction.
     583              : !> \param preconditioner_env ...
     584              : !> \param matrix_in ...
     585              : !> \param matrix_out ...
     586              : ! **************************************************************************************************
     587          144 :    SUBROUTINE apply_low_rank_dbcsr(preconditioner_env, matrix_in, matrix_out)
     588              : 
     589              :       TYPE(preconditioner_type)                          :: preconditioner_env
     590              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     591              : 
     592              :       CHARACTER(len=*), PARAMETER :: routineN = 'apply_low_rank_dbcsr'
     593              : 
     594              :       INTEGER                                            :: col, col_offset, col_size, handle, i, j, &
     595              :                                                             k, n, nocc, rank_used, row, &
     596              :                                                             row_offset, row_size
     597              :       REAL(KIND=dp)                                      :: correction
     598           96 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: DATA
     599              :       TYPE(dbcsr_iterator_type)                          :: iter
     600              :       TYPE(dbcsr_type)                                   :: matrix_tmp
     601              : 
     602           96 :       CALL timeset(routineN, handle)
     603              : 
     604           96 :       IF (preconditioner_env%low_rank_base == ot_low_rank_base_lattice_fft) THEN
     605           48 :          CALL apply_low_rank_dbcsr_via_fm(preconditioner_env, matrix_in, matrix_out)
     606           48 :          CALL timestop(handle)
     607           48 :          RETURN
     608              :       END IF
     609              : 
     610           48 :       CPASSERT(ASSOCIATED(preconditioner_env%base_dbcsr_matrix))
     611           48 :       CPASSERT(ASSOCIATED(preconditioner_env%dbcsr_matrix))
     612           48 :       CPASSERT(ASSOCIATED(preconditioner_env%full_evals))
     613           48 :       CPASSERT(ASSOCIATED(preconditioner_env%occ_evals))
     614              : 
     615           48 :       CALL dbcsr_get_info(matrix_in, nfullrows_total=n, nfullcols_total=k)
     616           48 :       nocc = SIZE(preconditioner_env%occ_evals)
     617           48 :       CPASSERT(n == SIZE(preconditioner_env%full_evals))
     618           48 :       rank_used = MIN(preconditioner_env%spectral_rank, n - nocc)
     619              : 
     620              :       ! DBCSR form of the same overlap-inverse base plus positive low-rank update.
     621              :       CALL dbcsr_multiply('N', 'N', preconditioner_env%spectral_base_scale, &
     622           48 :                           preconditioner_env%base_dbcsr_matrix, matrix_in, 0.0_dp, matrix_out)
     623              : 
     624           48 :       IF (rank_used > 0) THEN
     625           48 :          CALL dbcsr_copy(matrix_tmp, matrix_in, name=routineN)
     626           48 :          CALL dbcsr_set(matrix_tmp, 0.0_dp)
     627              :          CALL dbcsr_multiply('T', 'N', 1.0_dp, preconditioner_env%dbcsr_matrix, &
     628              :                              matrix_in, 0.0_dp, matrix_tmp, &
     629           48 :                              first_row=nocc + 1, last_row=nocc + rank_used)
     630              : 
     631           48 :          CALL dbcsr_iterator_start(iter, matrix_tmp)
     632          288 :          DO WHILE (dbcsr_iterator_blocks_left(iter))
     633              :             CALL dbcsr_iterator_next_block(iter, row, col, DATA, &
     634              :                                            row_size=row_size, col_size=col_size, &
     635          240 :                                            row_offset=row_offset, col_offset=col_offset)
     636         2208 :             DO j = 1, col_size
     637        14832 :                DO i = 1, row_size
     638        12672 :                   IF (row_offset + i - 1 >= nocc + 1 .AND. &
     639         1920 :                       row_offset + i - 1 <= nocc + rank_used) THEN
     640              :                      correction = low_rank_inverse_weight( &
     641              :                                   preconditioner_env%full_evals(row_offset + i - 1), &
     642              :                                   preconditioner_env%spectral_reference, &
     643              :                                   preconditioner_env%energy_gap) &
     644         9216 :                                   - preconditioner_env%spectral_base_scale
     645         9216 :                      DATA(i, j) = DATA(i, j)*correction
     646              :                   END IF
     647              :                END DO
     648              :             END DO
     649              :          END DO
     650           48 :          CALL dbcsr_iterator_stop(iter)
     651              : 
     652              :          CALL dbcsr_multiply('N', 'N', 1.0_dp, preconditioner_env%dbcsr_matrix, &
     653              :                              matrix_tmp, 1.0_dp, matrix_out, &
     654           48 :                              first_k=nocc + 1, last_k=nocc + rank_used)
     655           48 :          CALL dbcsr_release(matrix_tmp)
     656              :       END IF
     657              : 
     658           48 :       CALL timestop(handle)
     659              : 
     660           96 :    END SUBROUTINE apply_low_rank_dbcsr
     661              : 
     662              : ! **************************************************************************************************
     663              : !> \brief Bridge DBCSR OT gradients to the full-matrix lattice-FFT implementation.
     664              : !> \param preconditioner_env ...
     665              : !> \param matrix_in ...
     666              : !> \param matrix_out ...
     667              : ! **************************************************************************************************
     668          144 :    SUBROUTINE apply_low_rank_dbcsr_via_fm(preconditioner_env, matrix_in, matrix_out)
     669              : 
     670              :       TYPE(preconditioner_type)                          :: preconditioner_env
     671              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     672              : 
     673              :       INTEGER                                            :: k, n
     674              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     675              :       TYPE(cp_fm_type)                                   :: input_fm, output_fm
     676              : 
     677           48 :       NULLIFY (fm_struct)
     678           48 :       CALL dbcsr_get_info(matrix_in, nfullrows_total=n, nfullcols_total=k)
     679              :       CALL cp_fm_struct_create(fm_struct, nrow_global=n, ncol_global=k, &
     680              :                                context=preconditioner_env%ctxt, &
     681           48 :                                para_env=preconditioner_env%para_env)
     682           48 :       CALL cp_fm_create(input_fm, fm_struct, name="lattice low-rank input")
     683           48 :       CALL cp_fm_create(output_fm, fm_struct, name="lattice low-rank output")
     684           48 :       CALL cp_fm_struct_release(fm_struct)
     685           48 :       CALL copy_dbcsr_to_fm(matrix_in, input_fm)
     686           48 :       CALL apply_low_rank_fm(preconditioner_env, input_fm, output_fm)
     687           48 :       CALL copy_fm_to_dbcsr(output_fm, matrix_out)
     688           48 :       CALL cp_fm_release(input_fm)
     689           48 :       CALL cp_fm_release(output_fm)
     690              : 
     691           48 :    END SUBROUTINE apply_low_rank_dbcsr_via_fm
     692              : 
     693              : ! **************************************************************************************************
     694              : !> \brief full all to a full matrix
     695              : !> \param preconditioner_env ...
     696              : !> \param matrix_in ...
     697              : !> \param matrix_out ...
     698              : ! **************************************************************************************************
     699       113520 :    SUBROUTINE apply_full_all(preconditioner_env, matrix_in, matrix_out)
     700              : 
     701              :       TYPE(preconditioner_type)                          :: preconditioner_env
     702              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_in, matrix_out
     703              : 
     704              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_full_all'
     705              : 
     706              :       INTEGER                                            :: handle, i, j, k, n, ncol_local, &
     707              :                                                             nrow_local
     708        28380 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     709              :       REAL(KIND=dp)                                      :: dum
     710              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     711        28380 :          POINTER                                         :: local_data
     712              :       TYPE(cp_fm_type)                                   :: matrix_tmp
     713              : 
     714        28380 :       CALL timeset(routineN, handle)
     715              : 
     716        28380 :       CALL cp_fm_get_info(matrix_in, nrow_global=n, ncol_global=k)
     717              : 
     718        28380 :       CALL cp_fm_create(matrix_tmp, matrix_in%matrix_struct, name="apply_full_all")
     719              :       CALL cp_fm_get_info(matrix_tmp, nrow_local=nrow_local, ncol_local=ncol_local, &
     720        28380 :                           row_indices=row_indices, col_indices=col_indices, local_data=local_data)
     721              : 
     722              :       !
     723              :       CALL parallel_gemm('T', 'N', n, k, n, 1.0_dp, preconditioner_env%fm, &
     724        28380 :                          matrix_in, 0.0_dp, matrix_tmp)
     725              : 
     726              :       ! do the right scaling
     727       224454 :       DO j = 1, ncol_local
     728      2822205 :       DO i = 1, nrow_local
     729              :          dum = 1.0_dp/MAX(preconditioner_env%energy_gap, &
     730      2597751 :                           preconditioner_env%full_evals(row_indices(i)) - preconditioner_env%occ_evals(col_indices(j)))
     731      2793825 :          local_data(i, j) = local_data(i, j)*dum
     732              :       END DO
     733              :       END DO
     734              : 
     735              :       ! mult back
     736              :       CALL parallel_gemm('N', 'N', n, k, n, 1.0_dp, preconditioner_env%fm, &
     737        28380 :                          matrix_tmp, 0.0_dp, matrix_out)
     738              : 
     739        28380 :       CALL cp_fm_release(matrix_tmp)
     740              : 
     741        28380 :       CALL timestop(handle)
     742              : 
     743        28380 :    END SUBROUTINE apply_full_all
     744              : 
     745              : ! **************************************************************************************************
     746              : !> \brief full all to a dbcsr matrix
     747              : !> \param preconditioner_env ...
     748              : !> \param matrix_in ...
     749              : !> \param matrix_out ...
     750              : ! **************************************************************************************************
     751        49276 :    SUBROUTINE apply_all(preconditioner_env, matrix_in, matrix_out)
     752              : 
     753              :       TYPE(preconditioner_type)                          :: preconditioner_env
     754              :       TYPE(dbcsr_type)                                   :: matrix_in, matrix_out
     755              : 
     756              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'apply_all'
     757              : 
     758              :       INTEGER                                            :: col, col_offset, col_size, handle, i, j, &
     759              :                                                             row, row_offset, row_size
     760              :       REAL(KIND=dp)                                      :: dum
     761        24638 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: DATA
     762              :       TYPE(dbcsr_iterator_type)                          :: iter
     763              :       TYPE(dbcsr_type)                                   :: matrix_tmp
     764              : 
     765        24638 :       CALL timeset(routineN, handle)
     766              : 
     767        24638 :       CALL dbcsr_copy(matrix_tmp, matrix_in, name="apply_full_all")
     768              :       CALL dbcsr_multiply('T', 'N', 1.0_dp, preconditioner_env%dbcsr_matrix, &
     769        24638 :                           matrix_in, 0.0_dp, matrix_tmp)
     770              :       ! do the right scaling
     771        24638 :       CALL dbcsr_iterator_start(iter, matrix_tmp)
     772        69121 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     773              :          CALL dbcsr_iterator_next_block(iter, row, col, DATA, &
     774              :                                         row_size=row_size, col_size=col_size, &
     775        44483 :                                         row_offset=row_offset, col_offset=col_offset)
     776       431918 :          DO j = 1, col_size
     777      3266916 :          DO i = 1, row_size
     778              :             dum = 1.0_dp/MAX(preconditioner_env%energy_gap, &
     779              :                              preconditioner_env%full_evals(row_offset + i - 1) &
     780      2859636 :                              - preconditioner_env%occ_evals(col_offset + j - 1))
     781      3222433 :             DATA(i, j) = DATA(i, j)*dum
     782              :          END DO
     783              :          END DO
     784              :       END DO
     785        24638 :       CALL dbcsr_iterator_stop(iter)
     786              : 
     787              :       ! mult back
     788              :       CALL dbcsr_multiply('N', 'N', 1.0_dp, preconditioner_env%dbcsr_matrix, &
     789        24638 :                           matrix_tmp, 0.0_dp, matrix_out)
     790        24638 :       CALL dbcsr_release(matrix_tmp)
     791        24638 :       CALL timestop(handle)
     792              : 
     793        24638 :    END SUBROUTINE apply_all
     794              : 
     795              : END MODULE preconditioner_apply
        

Generated by: LCOV version 2.0-1