LCOV - code coverage report
Current view: top level - src/fm - cp_fm_cholesky.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 88.0 % 92 81
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 4 4

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief various cholesky decomposition related routines
      10              : !> \par History
      11              : !>      09.2002 created [fawzi]
      12              : !> \author Fawzi Mohamed
      13              : ! **************************************************************************************************
      14              : MODULE cp_fm_cholesky
      15              :    USE cp_dlaf_utils_api,               ONLY: cp_dlaf_create_grid,&
      16              :                                               cp_dlaf_initialize
      17              :    USE cp_fm_dlaf_api,                  ONLY: cp_pdpotrf_dlaf,&
      18              :                                               cp_pdpotri_dlaf,&
      19              :                                               cp_pspotrf_dlaf,&
      20              :                                               cp_pspotri_dlaf
      21              :    USE cp_fm_types,                     ONLY: cp_fm_type
      22              :    USE cp_log_handling,                 ONLY: cp_to_string
      23              :    USE kinds,                           ONLY: dp,&
      24              :                                               sp
      25              : #include "../base/base_uses.f90"
      26              : 
      27              :    IMPLICIT NONE
      28              :    PRIVATE
      29              : 
      30              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      31              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_fm_cholesky'
      32              : 
      33              :    PUBLIC :: cp_fm_cholesky_decompose, cp_fm_cholesky_invert, &
      34              :              cp_fm_cholesky_reduce, cp_fm_cholesky_restore
      35              : 
      36              :    ! The following saved variables are Cholesky decomposition global
      37              :    ! Stores the default library for Cholesky decomposition
      38              :    INTEGER, SAVE, PUBLIC   :: cholesky_type = 0
      39              :    ! Minimum matrix size for the use of the DLAF Cholesky decomposition.
      40              :    ! ScaLAPACK is used as fallback for all smaller cases.
      41              :    INTEGER, SAVE, PUBLIC    :: dlaf_cholesky_n_min = 0
      42              :    ! Constants for the diag_type above
      43              :    INTEGER, PARAMETER, PUBLIC  :: FM_CHOLESKY_TYPE_SCALAPACK = 101, &
      44              :                                   FM_CHOLESKY_TYPE_DLAF = 104
      45              :    INTEGER, PARAMETER, PUBLIC :: FM_CHOLESKY_TYPE_DEFAULT = FM_CHOLESKY_TYPE_SCALAPACK
      46              : 
      47              : !***
      48              : CONTAINS
      49              : 
      50              : ! **************************************************************************************************
      51              : !> \brief used to replace a symmetric positive def. matrix M with its cholesky
      52              : !>      decomposition U: M = U^T * U, with U upper triangular
      53              : !> \param matrix the matrix to replace with its cholesky decomposition
      54              : !> \param n the number of row (and columns) of the matrix &
      55              : !>        (defaults to the min(size(matrix)))
      56              : !> \param info_out ...
      57              : !> \par History
      58              : !>      05.2002 created [JVdV]
      59              : !>      12.2002 updated, added n optional parm [fawzi]
      60              : !> \author Joost
      61              : ! **************************************************************************************************
      62        56727 :    SUBROUTINE cp_fm_cholesky_decompose(matrix, n, info_out)
      63              :       TYPE(cp_fm_type), INTENT(IN)             :: matrix
      64              :       INTEGER, INTENT(in), OPTIONAL            :: n
      65              :       INTEGER, INTENT(out), OPTIONAL           :: info_out
      66              : 
      67              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_cholesky_decompose'
      68              : 
      69              :       INTEGER                                  :: handle, info, my_n
      70        56727 :       REAL(KIND=dp), DIMENSION(:, :), POINTER  :: a
      71        56727 :       REAL(KIND=sp), DIMENSION(:, :), POINTER  :: a_sp
      72              : #if defined(__parallel)
      73              :       INTEGER, DIMENSION(9)                    :: desca
      74              : #endif
      75              : 
      76        56727 :       CALL timeset(routineN, handle)
      77              : 
      78              :       my_n = MIN(matrix%matrix_struct%nrow_global, &
      79        56727 :                  matrix%matrix_struct%ncol_global)
      80        56727 :       IF (PRESENT(n)) THEN
      81        15496 :          CPASSERT(n <= my_n)
      82        15496 :          my_n = n
      83              :       END IF
      84              : 
      85        56727 :       a => matrix%local_data
      86        56727 :       a_sp => matrix%local_data_sp
      87              : 
      88              : #if defined(__parallel)
      89       567270 :       desca(:) = matrix%matrix_struct%descriptor(:)
      90              : #if defined(__DLAF)
      91              :       IF (cholesky_type == FM_CHOLESKY_TYPE_DLAF .AND. matrix%matrix_struct%nrow_global >= dlaf_cholesky_n_min) THEN
      92              :          ! Initialize DLA-Future on-demand; if already initialized, does nothing
      93              :          CALL cp_dlaf_initialize()
      94              : 
      95              :          ! Create DLAF grid from BLACS context; if already present, does nothing
      96              :          CALL cp_dlaf_create_grid(matrix%matrix_struct%context%get_handle())
      97              : 
      98              :          IF (matrix%use_sp) THEN
      99              :             CALL cp_pspotrf_dlaf('U', my_n, a_sp(:, :), 1, 1, desca, info)
     100              :          ELSE
     101              :             CALL cp_pdpotrf_dlaf('U', my_n, a(:, :), 1, 1, desca, info)
     102              :          END IF
     103              :       ELSE
     104              : #endif
     105        56727 :          IF (matrix%use_sp) THEN
     106            0 :             CALL pspotrf('U', my_n, a_sp(1, 1), 1, 1, desca, info)
     107              :          ELSE
     108        56727 :             CALL pdpotrf('U', my_n, a(1, 1), 1, 1, desca, info)
     109              :          END IF
     110              : #if defined(__DLAF)
     111              :       END IF
     112              : #endif
     113              : #else
     114              :       IF (matrix%use_sp) THEN
     115              :          CALL spotrf('U', my_n, a_sp(1, 1), SIZE(a_sp, 1), info)
     116              :       ELSE
     117              :          CALL dpotrf('U', my_n, a(1, 1), SIZE(a, 1), info)
     118              :       END IF
     119              : #endif
     120              : 
     121        56727 :       IF (PRESENT(info_out)) THEN
     122        20602 :          info_out = info
     123        36125 :       ELSE IF (info /= 0) THEN
     124              :          CALL cp_abort(__LOCATION__, &
     125            0 :                        "Cholesky decompose failed: the matrix is not positive definite or ill-conditioned.")
     126              :       END IF
     127              : 
     128        56727 :       CALL timestop(handle)
     129              : 
     130        56727 :    END SUBROUTINE cp_fm_cholesky_decompose
     131              : 
     132              : ! **************************************************************************************************
     133              : !> \brief used to replace the cholesky decomposition by the inverse
     134              : !> \param matrix the matrix to invert (must be an upper triangular matrix)
     135              : !> \param n size of the matrix to invert (defaults to the min(size(matrix)))
     136              : !> \param info_out ...
     137              : !> \par History
     138              : !>      05.2002 created [JVdV]
     139              : !> \author Joost VandeVondele
     140              : ! **************************************************************************************************
     141        17635 :    SUBROUTINE cp_fm_cholesky_invert(matrix, n, info_out)
     142              :       TYPE(cp_fm_type), INTENT(IN)              :: matrix
     143              :       INTEGER, INTENT(in), OPTIONAL             :: n
     144              :       INTEGER, INTENT(OUT), OPTIONAL            :: info_out
     145              : 
     146              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_cholesky_invert'
     147        17635 :       REAL(KIND=dp), DIMENSION(:, :), POINTER   :: a
     148        17635 :       REAL(KIND=sp), DIMENSION(:, :), POINTER   :: a_sp
     149              :       INTEGER                                   :: info, handle, my_n
     150              : #if defined(__parallel)
     151              :       INTEGER, DIMENSION(9)                     :: desca
     152              : #endif
     153              : 
     154        17635 :       CALL timeset(routineN, handle)
     155              : 
     156              :       my_n = MIN(matrix%matrix_struct%nrow_global, &
     157        17635 :                  matrix%matrix_struct%ncol_global)
     158        17635 :       IF (PRESENT(n)) THEN
     159            0 :          CPASSERT(n <= my_n)
     160            0 :          my_n = n
     161              :       END IF
     162              : 
     163        17635 :       a => matrix%local_data
     164        17635 :       a_sp => matrix%local_data_sp
     165              : 
     166              : #if defined(__parallel)
     167              : 
     168       176350 :       desca(:) = matrix%matrix_struct%descriptor(:)
     169              : 
     170              : #if defined(__DLAF)
     171              :       IF (cholesky_type == FM_CHOLESKY_TYPE_DLAF .AND. matrix%matrix_struct%nrow_global >= dlaf_cholesky_n_min) THEN
     172              :          ! Initialize DLA-Future on-demand; if already initialized, does nothing
     173              :          CALL cp_dlaf_initialize()
     174              : 
     175              :          ! Create DLAF grid from BLACS context; if already present, does nothing
     176              :          CALL cp_dlaf_create_grid(matrix%matrix_struct%context%get_handle())
     177              : 
     178              :          IF (matrix%use_sp) THEN
     179              :             CALL cp_pspotri_dlaf('U', my_n, a_sp(:, :), 1, 1, desca, info)
     180              :          ELSE
     181              :             CALL cp_pdpotri_dlaf('U', my_n, a(:, :), 1, 1, desca, info)
     182              :          END IF
     183              :       ELSE
     184              : #endif
     185        17635 :          IF (matrix%use_sp) THEN
     186            0 :             CALL pspotri('U', my_n, a_sp(1, 1), 1, 1, desca, info)
     187              :          ELSE
     188        17635 :             CALL pdpotri('U', my_n, a(1, 1), 1, 1, desca, info)
     189              :          END IF
     190              : #if defined(__DLAF)
     191              :       END IF
     192              : #endif
     193              : 
     194              : #else
     195              : 
     196              :       IF (matrix%use_sp) THEN
     197              :          CALL spotri('U', my_n, a_sp(1, 1), SIZE(a_sp, 1), info)
     198              :       ELSE
     199              :          CALL dpotri('U', my_n, a(1, 1), SIZE(a, 1), info)
     200              :       END IF
     201              : 
     202              : #endif
     203              : 
     204        17635 :       IF (PRESENT(info_out)) THEN
     205            0 :          info_out = info
     206              :       ELSE
     207        17635 :          IF (info /= 0) &
     208            0 :             CPABORT("Cholesky invert failed: the matrix is not positive definite or ill-conditioned.")
     209              :       END IF
     210              : 
     211        17635 :       CALL timestop(handle)
     212              : 
     213        17635 :    END SUBROUTINE cp_fm_cholesky_invert
     214              : 
     215              : ! **************************************************************************************************
     216              : !> \brief reduce a matrix pencil A,B to normal form
     217              : !>      B has to be cholesky decomposed with  cp_fm_cholesky_decompose
     218              : !>      before calling this routine
     219              : !>      A,B -> inv(U^T)*A*inv(U),1
     220              : !>      (AX=BX -> inv(U^T)*A*inv(U)*U*X=U*X hence evecs U*X)
     221              : !> \param matrix the symmetric matrix A
     222              : !> \param matrixb the cholesky decomposition of matrix B
     223              : !> \param itype ...
     224              : !> \par History
     225              : !>      05.2002 created [JVdV]
     226              : !> \author Joost VandeVondele
     227              : ! **************************************************************************************************
     228         4152 :    SUBROUTINE cp_fm_cholesky_reduce(matrix, matrixb, itype)
     229              :       TYPE(cp_fm_type), INTENT(IN)              :: matrix, matrixb
     230              :       INTEGER, OPTIONAL                         :: itype
     231              : 
     232              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_cholesky_reduce'
     233         4152 :       REAL(KIND=dp), DIMENSION(:, :), POINTER   :: a, b
     234              :       INTEGER                                   :: info, handle
     235              :       INTEGER                                   :: n, my_itype
     236              : #if defined(__parallel)
     237              :       REAL(KIND=dp)                             :: scale
     238              :       INTEGER, DIMENSION(9)                     :: desca, descb
     239              : #endif
     240              : 
     241         4152 :       CALL timeset(routineN, handle)
     242              : 
     243         4152 :       n = matrix%matrix_struct%nrow_global
     244              : 
     245         4152 :       my_itype = 1
     246         4152 :       IF (PRESENT(itype)) my_itype = itype
     247              : 
     248         4152 :       a => matrix%local_data
     249         4152 :       b => matrixb%local_data
     250              : 
     251              : #if defined(__parallel)
     252              : 
     253        41520 :       desca(:) = matrix%matrix_struct%descriptor(:)
     254        41520 :       descb(:) = matrixb%matrix_struct%descriptor(:)
     255              : 
     256         4152 :       CALL pdsygst(my_itype, 'U', n, a(1, 1), 1, 1, desca, b(1, 1), 1, 1, descb, scale, info)
     257              : 
     258              :       ! this is supposed to be one in current version of lapack
     259              :       ! if not, eigenvalues have to be scaled by this number
     260         4152 :       IF (scale /= 1.0_dp) &
     261            0 :          CPABORT("scale not equal 1 (scale="//cp_to_string(scale)//")")
     262              : #else
     263              : 
     264              :       CALL dsygst(my_itype, 'U', n, a(1, 1), n, b(1, 1), n, info)
     265              : 
     266              : #endif
     267              : 
     268         4152 :       CPASSERT(info == 0)
     269              : 
     270         4152 :       CALL timestop(handle)
     271              : 
     272         4152 :    END SUBROUTINE cp_fm_cholesky_reduce
     273              : 
     274              : ! **************************************************************************************************
     275              : !> \brief apply Cholesky decomposition
     276              : !>        op can be "SOLVE" (out = U^-1 * in) or "MULTIPLY"  (out = U * in)
     277              : !>        pos can be "LEFT" or "RIGHT" (U at the left or at the right)
     278              : !> \param fm_matrix ...
     279              : !> \param neig ...
     280              : !> \param fm_matrixb ...
     281              : !> \param fm_matrixout ...
     282              : !> \param op ...
     283              : !> \param pos ...
     284              : !> \param transa ...
     285              : ! **************************************************************************************************
     286       235137 :    SUBROUTINE cp_fm_cholesky_restore(fm_matrix, neig, fm_matrixb, fm_matrixout, op, pos, transa)
     287              :       TYPE(cp_fm_type), INTENT(IN)              :: fm_matrix, fm_matrixb, fm_matrixout
     288              :       INTEGER, INTENT(IN)                       :: neig
     289              :       CHARACTER(LEN=*), INTENT(IN)              :: op
     290              :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL    :: pos
     291              :       CHARACTER(LEN=*), INTENT(IN), OPTIONAL    :: transa
     292              : 
     293              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_cholesky_restore'
     294       235137 :       REAL(KIND=dp), DIMENSION(:, :), POINTER   :: a, b, outm
     295       235137 :       REAL(KIND=sp), DIMENSION(:, :), POINTER   :: a_sp, b_sp, outm_sp
     296              :       REAL(KIND=dp)                             :: alpha
     297              :       INTEGER                                   :: handle, mdim, n
     298              :       CHARACTER                                 :: chol_pos, chol_transa
     299              : #if defined(__parallel)
     300              :       INTEGER                                   :: i
     301              :       INTEGER, DIMENSION(9)                     :: desca, descb, descout
     302              : #elif defined(__MKL) && (2025 <= __INTEL_MKL__)
     303              :       REAL(KIND=dp)                             :: beta
     304              : #endif
     305              : 
     306       235137 :       CALL timeset(routineN, handle)
     307              : 
     308              :       ! wrong argument op
     309       235137 :       CPASSERT((op == "SOLVE") .OR. (op == "MULTIPLY"))
     310              :       ! not the same precision
     311       235137 :       CPASSERT(fm_matrix%use_sp .EQV. fm_matrixb%use_sp)
     312       235137 :       CPASSERT(fm_matrix%use_sp .EQV. fm_matrixout%use_sp)
     313              : 
     314       235137 :       chol_pos = 'L'
     315       235137 :       IF (PRESENT(pos)) chol_pos = pos(1:1)
     316       235137 :       CPASSERT((chol_pos == 'L') .OR. (chol_pos == 'R'))
     317              : 
     318       235137 :       chol_transa = 'N'
     319       235137 :       IF (PRESENT(transa)) chol_transa = transa
     320              : 
     321              :       ! notice b is the cholesky guy
     322       235137 :       a => fm_matrix%local_data
     323       235137 :       b => fm_matrixb%local_data
     324       235137 :       outm => fm_matrixout%local_data
     325       235137 :       a_sp => fm_matrix%local_data_sp
     326       235137 :       b_sp => fm_matrixb%local_data_sp
     327       235137 :       outm_sp => fm_matrixout%local_data_sp
     328       235137 :       n = fm_matrix%matrix_struct%nrow_global
     329              :       mdim = MERGE(1, 2, 'L' == chol_pos)
     330       235137 :       alpha = 1.0_dp
     331              : 
     332              : #if defined(__parallel)
     333      2351370 :       desca(:) = fm_matrix%matrix_struct%descriptor(:)
     334      2351370 :       descb(:) = fm_matrixb%matrix_struct%descriptor(:)
     335      2351370 :       descout(:) = fm_matrixout%matrix_struct%descriptor(:)
     336      4497331 :       DO i = 1, neig
     337      4497331 :          IF (fm_matrix%use_sp) THEN
     338            0 :             CALL pscopy(n, a_sp(1, 1), 1, i, desca, 1, outm_sp(1, 1), 1, i, descout, 1)
     339              :          ELSE
     340      4262194 :             CALL pdcopy(n, a(1, 1), 1, i, desca, 1, outm(1, 1), 1, i, descout, 1)
     341              :          END IF
     342              :       END DO
     343       235137 :       IF (op == "SOLVE") THEN
     344       233707 :          IF (fm_matrix%use_sp) THEN
     345              :             CALL pstrsm(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), 1, 1, descb, &
     346            0 :                         outm_sp(1, 1), 1, 1, descout)
     347              :          ELSE
     348       233707 :             CALL pdtrsm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), 1, 1, descb, outm(1, 1), 1, 1, descout)
     349              :          END IF
     350              :       ELSE
     351         1430 :          IF (fm_matrix%use_sp) THEN
     352              :             CALL pstrmm(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), 1, 1, descb, &
     353            0 :                         outm_sp(1, 1), 1, 1, descout)
     354              :          ELSE
     355         1430 :             CALL pdtrmm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), 1, 1, descb, outm(1, 1), 1, 1, descout)
     356              :          END IF
     357              :       END IF
     358              : #elif defined(__MKL) && (2025 <= __INTEL_MKL__)
     359              :       beta = 0.0_dp
     360              :       IF (op == "SOLVE") THEN
     361              :          IF (fm_matrix%use_sp) THEN
     362              :             CALL strsm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), a_sp(1, 1), n, REAL(beta, sp), outm_sp(1, 1), n)
     363              :          ELSE
     364              :             CALL dtrsm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), a(1, 1), n, beta, outm(1, 1), n)
     365              :          END IF
     366              :       ELSE
     367              :          IF (fm_matrix%use_sp) THEN
     368              :             CALL strmm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), a_sp(1, 1), n, REAL(beta, sp), outm_sp(1, 1), n)
     369              :          ELSE
     370              :             CALL dtrmm_oop(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), a(1, 1), n, beta, outm(1, 1), n)
     371              :          END IF
     372              :       END IF
     373              : #else
     374              :       IF (fm_matrix%use_sp) THEN
     375              :          CALL scopy(neig*n, a_sp(1, 1), 1, outm_sp(1, 1), 1)
     376              :       ELSE
     377              :          CALL dcopy(neig*n, a(1, 1), 1, outm(1, 1), 1)
     378              :       END IF
     379              :       IF (op == "SOLVE") THEN
     380              :          IF (fm_matrix%use_sp) THEN
     381              :             CALL strsm(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), outm_sp(1, 1), n)
     382              :          ELSE
     383              :             CALL dtrsm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), outm(1, 1), n)
     384              :          END IF
     385              :       ELSE
     386              :          IF (fm_matrix%use_sp) THEN
     387              :             CALL strmm(chol_pos, 'U', chol_transa, 'N', n, neig, REAL(alpha, sp), b_sp(1, 1), SIZE(b_sp, mdim), outm_sp(1, 1), n)
     388              :          ELSE
     389              :             CALL dtrmm(chol_pos, 'U', chol_transa, 'N', n, neig, alpha, b(1, 1), SIZE(b, mdim), outm(1, 1), n)
     390              :          END IF
     391              :       END IF
     392              : #endif
     393              : 
     394       235137 :       CALL timestop(handle)
     395              : 
     396       235137 :    END SUBROUTINE cp_fm_cholesky_restore
     397              : 
     398              : END MODULE cp_fm_cholesky
        

Generated by: LCOV version 2.0-1