LCOV - code coverage report
Current view: top level - src/fm - cp_cfm_basic_linalg.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 76.1 % 440 335
Test Date: 2025-07-25 12:55:17 Functions: 80.0 % 20 16

            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 Basic linear algebra operations for complex full matrices.
      10              : !> \note
      11              : !>      - not all functionality implemented
      12              : !> \par History
      13              : !>      Nearly literal copy of Fawzi's routines
      14              : !> \author Joost VandeVondele
      15              : ! **************************************************************************************************
      16              : MODULE cp_cfm_basic_linalg
      17              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      18              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      19              :                                               cp_cfm_get_info,&
      20              :                                               cp_cfm_release,&
      21              :                                               cp_cfm_to_cfm,&
      22              :                                               cp_cfm_type
      23              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_equivalent
      24              :    USE cp_fm_types,                     ONLY: cp_fm_type
      25              :    USE cp_log_handling,                 ONLY: cp_to_string
      26              :    USE kahan_sum,                       ONLY: accurate_dot_product
      27              :    USE kinds,                           ONLY: dp
      28              :    USE mathconstants,                   ONLY: z_one,&
      29              :                                               z_zero
      30              :    USE message_passing,                 ONLY: mp_comm_type
      31              : #include "../base/base_uses.f90"
      32              : 
      33              :    IMPLICIT NONE
      34              :    PRIVATE
      35              : 
      36              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      37              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_cfm_basic_linalg'
      38              : 
      39              :    PUBLIC :: cp_cfm_column_scale, &
      40              :              cp_cfm_gemm, &
      41              :              cp_cfm_lu_decompose, &
      42              :              cp_cfm_lu_invert, &
      43              :              cp_cfm_norm, &
      44              :              cp_cfm_scale, &
      45              :              cp_cfm_scale_and_add, &
      46              :              cp_cfm_scale_and_add_fm, &
      47              :              cp_cfm_schur_product, &
      48              :              cp_cfm_solve, &
      49              :              cp_cfm_trace, &
      50              :              cp_cfm_transpose, &
      51              :              cp_cfm_triangular_invert, &
      52              :              cp_cfm_triangular_multiply, &
      53              :              cp_cfm_rot_rows, &
      54              :              cp_cfm_rot_cols, &
      55              :              cp_cfm_det, & ! determinant of a complex matrix with correct sign
      56              :              cp_cfm_uplo_to_full
      57              : 
      58              :    REAL(kind=dp), EXTERNAL :: zlange, pzlange
      59              : 
      60              :    INTERFACE cp_cfm_scale
      61              :       MODULE PROCEDURE cp_cfm_dscale, cp_cfm_zscale
      62              :    END INTERFACE cp_cfm_scale
      63              : 
      64              : ! **************************************************************************************************
      65              : 
      66              : CONTAINS
      67              : 
      68              : ! **************************************************************************************************
      69              : !> \brief Computes the determinant (with a correct sign even in parallel environment!) of a complex square matrix
      70              : !> \param matrix_a ...
      71              : !> \param det_a ...
      72              : !> \author A. Sinyavskiy (andrey.sinyavskiy@chem.uzh.ch)
      73              : ! **************************************************************************************************
      74         1482 :    SUBROUTINE cp_cfm_det(matrix_a, det_a)
      75              : 
      76              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix_a
      77              :       COMPLEX(KIND=dp), INTENT(OUT)            :: det_a
      78              :       COMPLEX(KIND=dp)                         :: determinant
      79              :       TYPE(cp_cfm_type)                        :: matrix_lu
      80         1482 :       COMPLEX(KIND=dp), DIMENSION(:, :), POINTER  :: a
      81              :       INTEGER                                  :: n, i, info, P
      82         1482 :       INTEGER, ALLOCATABLE, DIMENSION(:)       :: ipivot
      83         1482 :       COMPLEX(KIND=dp), DIMENSION(:), POINTER  :: diag
      84              : 
      85              : #if defined(__parallel)
      86              :       INTEGER                                  :: myprow, nprow, npcol, nrow_local, irow_local, &
      87              :                                                   mypcol, ncol_local, icol_local, j
      88              :       INTEGER, DIMENSION(9)                    :: desca
      89              : #endif
      90              : 
      91              :       CALL cp_cfm_create(matrix=matrix_lu, &
      92              :                          matrix_struct=matrix_a%matrix_struct, &
      93         1482 :                          name="A_lu"//TRIM(ADJUSTL(cp_to_string(1)))//"MATRIX")
      94         1482 :       CALL cp_cfm_to_cfm(matrix_a, matrix_lu)
      95              : 
      96         1482 :       a => matrix_lu%local_data
      97         1482 :       n = matrix_lu%matrix_struct%nrow_global
      98         4446 :       ALLOCATE (ipivot(n))
      99         8232 :       ipivot(:) = 0
     100         1482 :       P = 0
     101         4446 :       ALLOCATE (diag(n))
     102         8232 :       diag(:) = 0.0_dp
     103              : #if defined(__parallel)
     104              :       ! Use LU decomposition
     105        14820 :       desca(:) = matrix_lu%matrix_struct%descriptor(:)
     106         1482 :       CALL pzgetrf(n, n, a(1, 1), 1, 1, desca, ipivot, info)
     107         1482 :       myprow = matrix_lu%matrix_struct%context%mepos(1)
     108         1482 :       mypcol = matrix_lu%matrix_struct%context%mepos(2)
     109         1482 :       nprow = matrix_lu%matrix_struct%context%num_pe(1)
     110         1482 :       npcol = matrix_lu%matrix_struct%context%num_pe(2)
     111         1482 :       nrow_local = matrix_lu%matrix_struct%nrow_locals(myprow)
     112         1482 :       ncol_local = matrix_lu%matrix_struct%ncol_locals(mypcol)
     113              : 
     114         4977 :       DO irow_local = 1, nrow_local
     115         3495 :          i = matrix_lu%matrix_struct%row_indices(irow_local)
     116        40440 :          DO icol_local = 1, ncol_local
     117        35463 :             j = matrix_lu%matrix_struct%col_indices(icol_local)
     118        38958 :             IF (i == j) diag(i) = matrix_lu%local_data(irow_local, icol_local)
     119              :          END DO
     120              :       END DO
     121        14982 :       CALL matrix_lu%matrix_struct%para_env%sum(diag)
     122         8232 :       determinant = PRODUCT(diag)
     123         4977 :       DO irow_local = 1, nrow_local
     124         3495 :          i = matrix_lu%matrix_struct%row_indices(irow_local)
     125         4977 :          IF (ipivot(irow_local) /= i) P = P + 1
     126              :       END DO
     127         1482 :       CALL matrix_lu%matrix_struct%para_env%sum(P)
     128              :       ! very important fix
     129         1482 :       P = P/npcol
     130              : #else
     131              :       CALL zgetrf(n, n, a(1, 1), n, ipivot, info)
     132              :       DO i = 1, n
     133              :          diag(i) = matrix_lu%local_data(i, i)
     134              :       END DO
     135              :       determinant = PRODUCT(diag)
     136              :       DO i = 1, n
     137              :          IF (ipivot(i) /= i) P = P + 1
     138              :       END DO
     139              : #endif
     140         1482 :       DEALLOCATE (ipivot)
     141         1482 :       DEALLOCATE (diag)
     142         1482 :       CALL cp_cfm_release(matrix_lu)
     143         1482 :       det_a = determinant*(-2*MOD(P, 2) + 1.0_dp)
     144         1482 :    END SUBROUTINE cp_cfm_det
     145              : 
     146              : ! **************************************************************************************************
     147              : !> \brief Computes the element-wise (Schur) product of two matrices: C = A \circ B .
     148              : !> \param matrix_a the first input matrix
     149              : !> \param matrix_b the second input matrix
     150              : !> \param matrix_c matrix to store the result
     151              : ! **************************************************************************************************
     152          204 :    SUBROUTINE cp_cfm_schur_product(matrix_a, matrix_b, matrix_c)
     153              : 
     154              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b, matrix_c
     155              : 
     156              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_schur_product'
     157              : 
     158          204 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b, c
     159              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     160              :                                                             myprow, ncol_local, nrow_local
     161              : 
     162          204 :       CALL timeset(routineN, handle)
     163              : 
     164          204 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     165          204 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     166              : 
     167          204 :       a => matrix_a%local_data
     168          204 :       b => matrix_b%local_data
     169          204 :       c => matrix_c%local_data
     170              : 
     171          204 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     172          204 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     173              : 
     174         1020 :       DO icol_local = 1, ncol_local
     175         2652 :          DO irow_local = 1, nrow_local
     176         2448 :             c(irow_local, icol_local) = a(irow_local, icol_local)*b(irow_local, icol_local)
     177              :          END DO
     178              :       END DO
     179              : 
     180          204 :       CALL timestop(handle)
     181              : 
     182          204 :    END SUBROUTINE cp_cfm_schur_product
     183              : 
     184              : ! **************************************************************************************************
     185              : !> \brief Computes the element-wise (Schur) product of two matrices: C = A \circ conjg(B) .
     186              : !> \param matrix_a the first input matrix
     187              : !> \param matrix_b the second input matrix
     188              : !> \param matrix_c matrix to store the result
     189              : ! **************************************************************************************************
     190            0 :    SUBROUTINE cp_cfm_schur_product_cc(matrix_a, matrix_b, matrix_c)
     191              : 
     192              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b, matrix_c
     193              : 
     194              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_schur_product_cc'
     195              : 
     196            0 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b, c
     197              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     198              :                                                             myprow, ncol_local, nrow_local
     199              : 
     200            0 :       CALL timeset(routineN, handle)
     201              : 
     202            0 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     203            0 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     204              : 
     205            0 :       a => matrix_a%local_data
     206            0 :       b => matrix_b%local_data
     207            0 :       c => matrix_c%local_data
     208              : 
     209            0 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     210            0 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     211              : 
     212            0 :       DO icol_local = 1, ncol_local
     213            0 :          DO irow_local = 1, nrow_local
     214            0 :             c(irow_local, icol_local) = a(irow_local, icol_local)*CONJG(b(irow_local, icol_local))
     215              :          END DO
     216              :       END DO
     217              : 
     218            0 :       CALL timestop(handle)
     219              : 
     220            0 :    END SUBROUTINE cp_cfm_schur_product_cc
     221              : 
     222              : ! **************************************************************************************************
     223              : !> \brief Scale and add two BLACS matrices (a = alpha*a + beta*b).
     224              : !> \param alpha ...
     225              : !> \param matrix_a ...
     226              : !> \param beta ...
     227              : !> \param matrix_b ...
     228              : !> \date    11.06.2001
     229              : !> \author  Matthias Krack
     230              : !> \version 1.0
     231              : !> \note
     232              : !>    Use explicit loops to avoid temporary arrays, as a compiler reasonably assumes that arrays
     233              : !>    matrix_a%local_data and matrix_b%local_data may overlap (they are referenced by pointers).
     234              : !>    In general case (alpha*a + beta*b) explicit loops appears to be up to two times more efficient
     235              : !>    than equivalent LAPACK calls (zscale, zaxpy). This is because using LAPACK calls implies
     236              : !>    two passes through each array, so data need to be retrieved twice if arrays are large
     237              : !>    enough to not fit into the processor's cache.
     238              : ! **************************************************************************************************
     239       236168 :    SUBROUTINE cp_cfm_scale_and_add(alpha, matrix_a, beta, matrix_b)
     240              :       COMPLEX(kind=dp), INTENT(in)                       :: alpha
     241              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     242              :       COMPLEX(kind=dp), INTENT(in), OPTIONAL             :: beta
     243              :       TYPE(cp_cfm_type), INTENT(IN), OPTIONAL            :: matrix_b
     244              : 
     245              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_scale_and_add'
     246              : 
     247              :       COMPLEX(kind=dp)                                   :: my_beta
     248       236168 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b
     249              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     250              :                                                             myprow, ncol_local, nrow_local
     251              : 
     252       236168 :       CALL timeset(routineN, handle)
     253              : 
     254       236168 :       my_beta = z_zero
     255       236168 :       IF (PRESENT(beta)) my_beta = beta
     256       236168 :       NULLIFY (a, b)
     257              : 
     258              :       ! to do: use dscal,dcopy,daxp
     259       236168 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     260       236168 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     261              : 
     262       236168 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     263       236168 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     264              : 
     265       236168 :       a => matrix_a%local_data
     266              : 
     267       236168 :       IF (my_beta == z_zero) THEN
     268              : 
     269         9064 :          IF (alpha == z_zero) THEN
     270            0 :             a(:, :) = z_zero
     271         9064 :          ELSE IF (alpha == z_one) THEN
     272         9064 :             CALL timestop(handle)
     273         9064 :             RETURN
     274              :          ELSE
     275            0 :             a(:, :) = alpha*a(:, :)
     276              :          END IF
     277              : 
     278              :       ELSE
     279       227104 :          CPASSERT(PRESENT(matrix_b))
     280       227104 :          IF (matrix_a%matrix_struct%context /= matrix_b%matrix_struct%context) &
     281            0 :             CPABORT("matrixes must be in the same blacs context")
     282              : 
     283       227104 :          IF (cp_fm_struct_equivalent(matrix_a%matrix_struct, &
     284              :                                      matrix_b%matrix_struct)) THEN
     285              : 
     286       227104 :             b => matrix_b%local_data
     287              : 
     288       227104 :             IF (alpha == z_zero) THEN
     289            0 :                IF (my_beta == z_one) THEN
     290              :                   !a(:, :) = b(:, :)
     291            0 :                   DO icol_local = 1, ncol_local
     292            0 :                      DO irow_local = 1, nrow_local
     293            0 :                         a(irow_local, icol_local) = b(irow_local, icol_local)
     294              :                      END DO
     295              :                   END DO
     296              :                ELSE
     297              :                   !a(:, :) = my_beta*b(:, :)
     298            0 :                   DO icol_local = 1, ncol_local
     299            0 :                      DO irow_local = 1, nrow_local
     300            0 :                         a(irow_local, icol_local) = my_beta*b(irow_local, icol_local)
     301              :                      END DO
     302              :                   END DO
     303              :                END IF
     304       227104 :             ELSE IF (alpha == z_one) THEN
     305       223944 :                IF (my_beta == z_one) THEN
     306              :                   !a(:, :) = a(:, :)+b(:, :)
     307      1903721 :                   DO icol_local = 1, ncol_local
     308     27498250 :                      DO irow_local = 1, nrow_local
     309     27334509 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + b(irow_local, icol_local)
     310              :                      END DO
     311              :                   END DO
     312              :                ELSE
     313              :                   !a(:, :) = a(:, :)+my_beta*b(:, :)
     314       778273 :                   DO icol_local = 1, ncol_local
     315     11241766 :                      DO irow_local = 1, nrow_local
     316     11181563 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + my_beta*b(irow_local, icol_local)
     317              :                      END DO
     318              :                   END DO
     319              :                END IF
     320              :             ELSE
     321              :                !a(:, :) = alpha*a(:, :)+my_beta*b(:, :)
     322        38304 :                DO icol_local = 1, ncol_local
     323       782648 :                   DO irow_local = 1, nrow_local
     324       779488 :                      a(irow_local, icol_local) = alpha*a(irow_local, icol_local) + my_beta*b(irow_local, icol_local)
     325              :                   END DO
     326              :                END DO
     327              :             END IF
     328              :          ELSE
     329              : #if defined(__parallel)
     330            0 :             CPABORT("to do (pdscal,pdcopy,pdaxpy)")
     331              : #else
     332              :             CPABORT("")
     333              : #endif
     334              :          END IF
     335              :       END IF
     336       227104 :       CALL timestop(handle)
     337       236168 :    END SUBROUTINE cp_cfm_scale_and_add
     338              : 
     339              : ! **************************************************************************************************
     340              : !> \brief Scale and add two BLACS matrices (a = alpha*a + beta*b).
     341              : !>        where b is a real matrix (adapted from cp_cfm_scale_and_add).
     342              : !> \param alpha ...
     343              : !> \param matrix_a ...
     344              : !> \param beta ...
     345              : !> \param matrix_b ...
     346              : !> \date    01.08.2014
     347              : !> \author  JGH
     348              : !> \version 1.0
     349              : ! **************************************************************************************************
     350       136866 :    SUBROUTINE cp_cfm_scale_and_add_fm(alpha, matrix_a, beta, matrix_b)
     351              :       COMPLEX(kind=dp), INTENT(in)                       :: alpha
     352              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     353              :       COMPLEX(kind=dp), INTENT(in)                       :: beta
     354              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_b
     355              : 
     356              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_scale_and_add_fm'
     357              : 
     358       136866 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     359              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     360              :                                                             myprow, ncol_local, nrow_local
     361       136866 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: b
     362              : 
     363       136866 :       CALL timeset(routineN, handle)
     364              : 
     365       136866 :       NULLIFY (a, b)
     366              : 
     367       136866 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     368       136866 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     369              : 
     370       136866 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     371       136866 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     372              : 
     373       136866 :       a => matrix_a%local_data
     374              : 
     375       136866 :       IF (beta == z_zero) THEN
     376              : 
     377            0 :          IF (alpha == z_zero) THEN
     378            0 :             a(:, :) = z_zero
     379            0 :          ELSE IF (alpha == z_one) THEN
     380            0 :             CALL timestop(handle)
     381            0 :             RETURN
     382              :          ELSE
     383            0 :             a(:, :) = alpha*a(:, :)
     384              :          END IF
     385              : 
     386              :       ELSE
     387       136866 :          IF (matrix_a%matrix_struct%context /= matrix_b%matrix_struct%context) &
     388            0 :             CPABORT("matrices must be in the same blacs context")
     389              : 
     390       136866 :          IF (cp_fm_struct_equivalent(matrix_a%matrix_struct, &
     391              :                                      matrix_b%matrix_struct)) THEN
     392              : 
     393       136866 :             b => matrix_b%local_data
     394              : 
     395       136866 :             IF (alpha == z_zero) THEN
     396        50510 :                IF (beta == z_one) THEN
     397              :                   !a(:, :) = b(:, :)
     398      1717002 :                   DO icol_local = 1, ncol_local
     399     82207992 :                      DO irow_local = 1, nrow_local
     400     82157506 :                         a(irow_local, icol_local) = b(irow_local, icol_local)
     401              :                      END DO
     402              :                   END DO
     403              :                ELSE
     404              :                   !a(:, :) = beta*b(:, :)
     405          456 :                   DO icol_local = 1, ncol_local
     406         4344 :                      DO irow_local = 1, nrow_local
     407         4320 :                         a(irow_local, icol_local) = beta*b(irow_local, icol_local)
     408              :                      END DO
     409              :                   END DO
     410              :                END IF
     411        86356 :             ELSE IF (alpha == z_one) THEN
     412        55835 :                IF (beta == z_one) THEN
     413              :                   !a(:, :) = a(:, :)+b(:, :)
     414        80449 :                   DO icol_local = 1, ncol_local
     415      1438473 :                      DO irow_local = 1, nrow_local
     416      1435080 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + b(irow_local, icol_local)
     417              :                      END DO
     418              :                   END DO
     419              :                ELSE
     420              :                   !a(:, :) = a(:, :)+beta*b(:, :)
     421      1760566 :                   DO icol_local = 1, ncol_local
     422     82715628 :                      DO irow_local = 1, nrow_local
     423     82663186 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + beta*b(irow_local, icol_local)
     424              :                      END DO
     425              :                   END DO
     426              :                END IF
     427              :             ELSE
     428              :                !a(:, :) = alpha*a(:, :)+beta*b(:, :)
     429       346801 :                DO icol_local = 1, ncol_local
     430      5761521 :                   DO irow_local = 1, nrow_local
     431      5731000 :                      a(irow_local, icol_local) = alpha*a(irow_local, icol_local) + beta*b(irow_local, icol_local)
     432              :                   END DO
     433              :                END DO
     434              :             END IF
     435              :          ELSE
     436              : #if defined(__parallel)
     437            0 :             CPABORT("to do (pdscal,pdcopy,pdaxpy)")
     438              : #else
     439              :             CPABORT("")
     440              : #endif
     441              :          END IF
     442              :       END IF
     443       136866 :       CALL timestop(handle)
     444       136866 :    END SUBROUTINE cp_cfm_scale_and_add_fm
     445              : 
     446              : ! **************************************************************************************************
     447              : !> \brief Computes LU decomposition of a given matrix.
     448              : !> \param matrix_a     full matrix
     449              : !> \param determinant  determinant
     450              : !> \date    11.06.2001
     451              : !> \author  Matthias Krack
     452              : !> \version 1.0
     453              : !> \note
     454              : !>    The actual purpose right now is to efficiently compute the determinant of a given matrix.
     455              : !>    The original content of the matrix is destroyed.
     456              : ! **************************************************************************************************
     457            0 :    SUBROUTINE cp_cfm_lu_decompose(matrix_a, determinant)
     458              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     459              :       COMPLEX(kind=dp), INTENT(out)                      :: determinant
     460              : 
     461              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_lu_decompose'
     462              : 
     463            0 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     464              :       INTEGER                                            :: counter, handle, info, irow, nrow_global
     465            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     466              : 
     467              : #if defined(__parallel)
     468              :       INTEGER                                            :: icol, ncol_local, nrow_local
     469              :       INTEGER, DIMENSION(9)                              :: desca
     470            0 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     471              : #else
     472              :       INTEGER                                            :: lda
     473              : #endif
     474              : 
     475            0 :       CALL timeset(routineN, handle)
     476              : 
     477            0 :       nrow_global = matrix_a%matrix_struct%nrow_global
     478            0 :       a => matrix_a%local_data
     479              : 
     480            0 :       ALLOCATE (ipivot(nrow_global))
     481              : #if defined(__parallel)
     482              :       CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, &
     483            0 :                            row_indices=row_indices, col_indices=col_indices)
     484              : 
     485            0 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     486            0 :       CALL pzgetrf(nrow_global, nrow_global, a(1, 1), 1, 1, desca, ipivot, info)
     487              : 
     488            0 :       counter = 0
     489            0 :       DO irow = 1, nrow_local
     490            0 :          IF (ipivot(irow) .NE. row_indices(irow)) counter = counter + 1
     491              :       END DO
     492              : 
     493            0 :       IF (MOD(counter, 2) == 0) THEN
     494            0 :          determinant = z_one
     495              :       ELSE
     496            0 :          determinant = -z_one
     497              :       END IF
     498              : 
     499              :       ! compute product of diagonal elements
     500              :       irow = 1
     501              :       icol = 1
     502            0 :       DO WHILE (irow <= nrow_local .AND. icol <= ncol_local)
     503            0 :          IF (row_indices(irow) < col_indices(icol)) THEN
     504            0 :             irow = irow + 1
     505            0 :          ELSE IF (row_indices(irow) > col_indices(icol)) THEN
     506            0 :             icol = icol + 1
     507              :          ELSE ! diagonal element
     508            0 :             determinant = determinant*a(irow, icol)
     509            0 :             irow = irow + 1
     510            0 :             icol = icol + 1
     511              :          END IF
     512              :       END DO
     513            0 :       CALL matrix_a%matrix_struct%para_env%prod(determinant)
     514              : #else
     515              :       lda = SIZE(a, 1)
     516              :       CALL zgetrf(nrow_global, nrow_global, a(1, 1), lda, ipivot, info)
     517              :       counter = 0
     518              :       determinant = z_one
     519              :       DO irow = 1, nrow_global
     520              :          IF (ipivot(irow) .NE. irow) counter = counter + 1
     521              :          determinant = determinant*a(irow, irow)
     522              :       END DO
     523              :       IF (MOD(counter, 2) == 1) determinant = -1.0_dp*determinant
     524              : #endif
     525              : 
     526              :       ! info is allowed to be zero
     527              :       ! this does just signal a zero diagonal element
     528            0 :       DEALLOCATE (ipivot)
     529              : 
     530            0 :       CALL timestop(handle)
     531            0 :    END SUBROUTINE cp_cfm_lu_decompose
     532              : 
     533              : ! **************************************************************************************************
     534              : !> \brief Performs one of the matrix-matrix operations:
     535              : !>        matrix_c = alpha * op1( matrix_a ) * op2( matrix_b ) + beta*matrix_c.
     536              : !> \param transa       form of op1( matrix_a ):
     537              : !>                     op1( matrix_a ) = matrix_a,   when transa == 'N' ,
     538              : !>                     op1( matrix_a ) = matrix_a^T, when transa == 'T' ,
     539              : !>                     op1( matrix_a ) = matrix_a^H, when transa == 'C' ,
     540              : !> \param transb       form of op2( matrix_b )
     541              : !> \param m            number of rows of the matrix op1( matrix_a )
     542              : !> \param n            number of columns of the matrix op2( matrix_b )
     543              : !> \param k            number of columns of the matrix op1( matrix_a ) as well as
     544              : !>                     number of rows of the matrix op2( matrix_b )
     545              : !> \param alpha        scale factor
     546              : !> \param matrix_a     matrix A
     547              : !> \param matrix_b     matrix B
     548              : !> \param beta         scale factor
     549              : !> \param matrix_c     matrix C
     550              : !> \param a_first_col  (optional) the first column of the matrix_a to multiply
     551              : !> \param a_first_row  (optional) the first row of the matrix_a to multiply
     552              : !> \param b_first_col  (optional) the first column of the matrix_b to multiply
     553              : !> \param b_first_row  (optional) the first row of the matrix_b to multiply
     554              : !> \param c_first_col  (optional) the first column of the matrix_c
     555              : !> \param c_first_row  (optional) the first row of the matrix_c
     556              : !> \date    07.06.2001
     557              : !> \author  Matthias Krack
     558              : !> \version 1.0
     559              : ! **************************************************************************************************
     560        76128 :    SUBROUTINE cp_cfm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, &
     561              :                           matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, &
     562              :                           c_first_row)
     563              :       CHARACTER(len=1), INTENT(in)                       :: transa, transb
     564              :       INTEGER, INTENT(in)                                :: m, n, k
     565              :       COMPLEX(kind=dp), INTENT(in)                       :: alpha
     566              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b
     567              :       COMPLEX(kind=dp), INTENT(in)                       :: beta
     568              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_c
     569              :       INTEGER, INTENT(in), OPTIONAL                      :: a_first_col, a_first_row, b_first_col, &
     570              :                                                             b_first_row, c_first_col, c_first_row
     571              : 
     572              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_gemm'
     573              : 
     574        76128 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b, c
     575              :       INTEGER                                            :: handle, i_a, i_b, i_c, j_a, j_b, j_c
     576              : #if defined(__parallel)
     577              :       INTEGER, DIMENSION(9)                              :: desca, descb, descc
     578              : #else
     579              :       INTEGER                                            :: lda, ldb, ldc
     580              : #endif
     581              : 
     582        76128 :       CALL timeset(routineN, handle)
     583        76128 :       a => matrix_a%local_data
     584        76128 :       b => matrix_b%local_data
     585        76128 :       c => matrix_c%local_data
     586              : 
     587        76128 :       i_a = 1
     588        76128 :       IF (PRESENT(a_first_row)) i_a = a_first_row
     589              : 
     590        76128 :       j_a = 1
     591        76128 :       IF (PRESENT(a_first_col)) j_a = a_first_col
     592              : 
     593        76128 :       i_b = 1
     594        76128 :       IF (PRESENT(b_first_row)) i_b = b_first_row
     595              : 
     596        76128 :       j_b = 1
     597        76128 :       IF (PRESENT(b_first_col)) j_b = b_first_col
     598              : 
     599        76128 :       i_c = 1
     600        76128 :       IF (PRESENT(c_first_row)) i_c = c_first_row
     601              : 
     602        76128 :       j_c = 1
     603        76128 :       IF (PRESENT(c_first_col)) j_c = c_first_col
     604              : 
     605              : #if defined(__parallel)
     606       761280 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     607       761280 :       descb(:) = matrix_b%matrix_struct%descriptor(:)
     608       761280 :       descc(:) = matrix_c%matrix_struct%descriptor(:)
     609              : 
     610              :       CALL pzgemm(transa, transb, m, n, k, alpha, a(1, 1), i_a, j_a, desca, &
     611        76128 :                   b(1, 1), i_b, j_b, descb, beta, c(1, 1), i_c, j_c, descc)
     612              : #else
     613              :       lda = SIZE(a, 1)
     614              :       ldb = SIZE(b, 1)
     615              :       ldc = SIZE(c, 1)
     616              : 
     617              :       ! consider zgemm3m
     618              :       CALL zgemm(transa, transb, m, n, k, alpha, a(i_a, j_a), &
     619              :                  lda, b(i_b, j_b), ldb, beta, c(i_c, j_c), ldc)
     620              : #endif
     621        76128 :       CALL timestop(handle)
     622        76128 :    END SUBROUTINE cp_cfm_gemm
     623              : 
     624              : ! **************************************************************************************************
     625              : !> \brief Scales columns of the full matrix by corresponding factors.
     626              : !> \param matrix_a matrix to scale
     627              : !> \param scaling  scale factors for every column. The actual number of scaled columns is
     628              : !>                 limited by the number of scale factors given or by the actual number of columns
     629              : !>                 whichever is smaller.
     630              : !> \author Joost VandeVondele
     631              : ! **************************************************************************************************
     632         5816 :    SUBROUTINE cp_cfm_column_scale(matrix_a, scaling)
     633              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     634              :       COMPLEX(kind=dp), DIMENSION(:), INTENT(in)         :: scaling
     635              : 
     636              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_column_scale'
     637              : 
     638         5816 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     639              :       INTEGER                                            :: handle, icol_local, ncol_local, &
     640              :                                                             nrow_local
     641              : #if defined(__parallel)
     642         5816 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices
     643              : #endif
     644              : 
     645         5816 :       CALL timeset(routineN, handle)
     646              : 
     647         5816 :       a => matrix_a%local_data
     648              : 
     649              : #if defined(__parallel)
     650         5816 :       CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, col_indices=col_indices)
     651         5816 :       ncol_local = MIN(ncol_local, SIZE(scaling))
     652              : 
     653       284404 :       DO icol_local = 1, ncol_local
     654       284404 :          CALL zscal(nrow_local, scaling(col_indices(icol_local)), a(1, icol_local), 1)
     655              :       END DO
     656              : #else
     657              :       nrow_local = SIZE(a, 1)
     658              :       ncol_local = MIN(SIZE(a, 2), SIZE(scaling))
     659              : 
     660              :       DO icol_local = 1, ncol_local
     661              :          CALL zscal(nrow_local, scaling(icol_local), a(1, icol_local), 1)
     662              :       END DO
     663              : #endif
     664              : 
     665         5816 :       CALL timestop(handle)
     666         5816 :    END SUBROUTINE cp_cfm_column_scale
     667              : 
     668              : ! **************************************************************************************************
     669              : !> \brief Scales a complex matrix by a real number.
     670              : !>      matrix_a = alpha * matrix_b
     671              : !> \param alpha    scale factor
     672              : !> \param matrix_a complex matrix to scale
     673              : ! **************************************************************************************************
     674         8518 :    SUBROUTINE cp_cfm_dscale(alpha, matrix_a)
     675              :       REAL(kind=dp), INTENT(in)                          :: alpha
     676              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     677              : 
     678              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_dscale'
     679              : 
     680         8518 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     681              :       INTEGER                                            :: handle
     682              : 
     683         8518 :       CALL timeset(routineN, handle)
     684              : 
     685         8518 :       NULLIFY (a)
     686              : 
     687         8518 :       a => matrix_a%local_data
     688              : 
     689        25554 :       CALL zdscal(SIZE(a), alpha, a(1, 1), 1)
     690              : 
     691         8518 :       CALL timestop(handle)
     692         8518 :    END SUBROUTINE cp_cfm_dscale
     693              : 
     694              : ! **************************************************************************************************
     695              : !> \brief Scales a complex matrix by a complex number.
     696              : !>      matrix_a = alpha * matrix_b
     697              : !> \param alpha    scale factor
     698              : !> \param matrix_a complex matrix to scale
     699              : !> \note
     700              : !>      use cp_fm_set_all to zero (avoids problems with nan)
     701              : ! **************************************************************************************************
     702        16150 :    SUBROUTINE cp_cfm_zscale(alpha, matrix_a)
     703              :       COMPLEX(kind=dp), INTENT(IN)                       :: alpha
     704              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     705              : 
     706              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_zscale'
     707              : 
     708        16150 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     709              :       INTEGER                                            :: handle, size_a
     710              : 
     711        16150 :       CALL timeset(routineN, handle)
     712              : 
     713        16150 :       NULLIFY (a)
     714              : 
     715        16150 :       a => matrix_a%local_data
     716        16150 :       size_a = SIZE(a, 1)*SIZE(a, 2)
     717              : 
     718        16150 :       CALL zscal(size_a, alpha, a(1, 1), 1)
     719              : 
     720        16150 :       CALL timestop(handle)
     721        16150 :    END SUBROUTINE cp_cfm_zscale
     722              : 
     723              : ! **************************************************************************************************
     724              : !> \brief Solve the system of linear equations A*b=A_general using LU decomposition.
     725              : !>        Pay attention that both matrices are overwritten on exit and that
     726              : !>        the result is stored into the matrix 'general_a'.
     727              : !> \param matrix_a     matrix A (overwritten on exit)
     728              : !> \param general_a    (input) matrix A_general, (output) matrix B
     729              : !> \param determinant  (optional) determinant
     730              : !> \author Florian Schiffmann
     731              : ! **************************************************************************************************
     732         7644 :    SUBROUTINE cp_cfm_solve(matrix_a, general_a, determinant)
     733              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, general_a
     734              :       COMPLEX(kind=dp), OPTIONAL                         :: determinant
     735              : 
     736              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_solve'
     737              : 
     738         7644 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, a_general
     739              :       INTEGER                                            :: counter, handle, info, irow, nrow_global
     740         7644 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     741              : 
     742              : #if defined(__parallel)
     743              :       INTEGER                                            :: icol, ncol_local, nrow_local
     744              :       INTEGER, DIMENSION(9)                              :: desca, descb
     745         7644 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     746              : #else
     747              :       INTEGER                                            :: lda, ldb
     748              : #endif
     749              : 
     750         7644 :       CALL timeset(routineN, handle)
     751              : 
     752         7644 :       a => matrix_a%local_data
     753         7644 :       a_general => general_a%local_data
     754         7644 :       nrow_global = matrix_a%matrix_struct%nrow_global
     755        22932 :       ALLOCATE (ipivot(nrow_global))
     756              : 
     757              : #if defined(__parallel)
     758        76440 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     759        76440 :       descb(:) = general_a%matrix_struct%descriptor(:)
     760         7644 :       CALL pzgetrf(nrow_global, nrow_global, a(1, 1), 1, 1, desca, ipivot, info)
     761         7644 :       IF (PRESENT(determinant)) THEN
     762              :          CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, &
     763         6356 :                               row_indices=row_indices, col_indices=col_indices)
     764              : 
     765         6356 :          counter = 0
     766        19116 :          DO irow = 1, nrow_local
     767        19116 :             IF (ipivot(irow) .NE. row_indices(irow)) counter = counter + 1
     768              :          END DO
     769              : 
     770         6356 :          IF (MOD(counter, 2) == 0) THEN
     771         6346 :             determinant = z_one
     772              :          ELSE
     773           10 :             determinant = -z_one
     774              :          END IF
     775              : 
     776              :          ! compute product of diagonal elements
     777              :          irow = 1
     778              :          icol = 1
     779        28662 :          DO WHILE (irow <= nrow_local .AND. icol <= ncol_local)
     780        28662 :             IF (row_indices(irow) < col_indices(icol)) THEN
     781            0 :                irow = irow + 1
     782        22306 :             ELSE IF (row_indices(irow) > col_indices(icol)) THEN
     783         9546 :                icol = icol + 1
     784              :             ELSE ! diagonal element
     785        12760 :                determinant = determinant*a(irow, icol)
     786        12760 :                irow = irow + 1
     787        12760 :                icol = icol + 1
     788              :             END IF
     789              :          END DO
     790         6356 :          CALL matrix_a%matrix_struct%para_env%prod(determinant)
     791              :       END IF
     792              : 
     793              :       CALL pzgetrs("N", nrow_global, nrow_global, a(1, 1), 1, 1, desca, &
     794         7644 :                    ipivot, a_general(1, 1), 1, 1, descb, info)
     795              : #else
     796              :       lda = SIZE(a, 1)
     797              :       ldb = SIZE(a_general, 1)
     798              :       CALL zgetrf(nrow_global, nrow_global, a(1, 1), lda, ipivot, info)
     799              :       IF (PRESENT(determinant)) THEN
     800              :          counter = 0
     801              :          determinant = z_one
     802              :          DO irow = 1, nrow_global
     803              :             IF (ipivot(irow) .NE. irow) counter = counter + 1
     804              :             determinant = determinant*a(irow, irow)
     805              :          END DO
     806              :          IF (MOD(counter, 2) == 1) determinant = -1.0_dp*determinant
     807              :       END IF
     808              :       CALL zgetrs("N", nrow_global, nrow_global, a(1, 1), lda, ipivot, a_general(1, 1), ldb, info)
     809              : #endif
     810              : 
     811              :       ! info is allowed to be zero
     812              :       ! this does just signal a zero diagonal element
     813         7644 :       DEALLOCATE (ipivot)
     814         7644 :       CALL timestop(handle)
     815              : 
     816         7644 :    END SUBROUTINE cp_cfm_solve
     817              : 
     818              : ! **************************************************************************************************
     819              : !> \brief Inverts a matrix using LU decomposition. The input matrix will be overwritten.
     820              : !> \param matrix     input a general square non-singular matrix, outputs its inverse
     821              : !> \param info_out   optional, if present outputs the info from (p)zgetri
     822              : !> \author Lianheng Tong
     823              : ! **************************************************************************************************
     824        49793 :    SUBROUTINE cp_cfm_lu_invert(matrix, info_out)
     825              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
     826              :       INTEGER, INTENT(out), OPTIONAL                     :: info_out
     827              : 
     828              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_lu_invert'
     829              : 
     830        49793 :       COMPLEX(kind=dp), ALLOCATABLE, DIMENSION(:)        :: work
     831              :       COMPLEX(kind=dp), DIMENSION(1)                     :: work1
     832        49793 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: mat
     833              :       INTEGER                                            :: handle, info, lwork, nrows_global
     834        49793 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     835              : 
     836              : #if defined(__parallel)
     837              :       INTEGER                                            :: liwork
     838        49793 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: iwork
     839              :       INTEGER, DIMENSION(1)                              :: iwork1
     840              :       INTEGER, DIMENSION(9)                              :: desca
     841              : #else
     842              :       INTEGER                                            :: lda
     843              : #endif
     844              : 
     845        49793 :       CALL timeset(routineN, handle)
     846              : 
     847        49793 :       mat => matrix%local_data
     848        49793 :       nrows_global = matrix%matrix_struct%nrow_global
     849        49793 :       CPASSERT(nrows_global .EQ. matrix%matrix_struct%ncol_global)
     850       149379 :       ALLOCATE (ipivot(nrows_global))
     851              : 
     852              :       ! do LU decomposition
     853              : #if defined(__parallel)
     854       497930 :       desca = matrix%matrix_struct%descriptor
     855              :       CALL pzgetrf(nrows_global, nrows_global, &
     856        49793 :                    mat(1, 1), 1, 1, desca, ipivot, info)
     857              : #else
     858              :       lda = SIZE(mat, 1)
     859              :       CALL zgetrf(nrows_global, nrows_global, &
     860              :                   mat(1, 1), lda, ipivot, info)
     861              : #endif
     862        49793 :       IF (info /= 0) THEN
     863            0 :          CALL cp_abort(__LOCATION__, "LU decomposition has failed")
     864              :       END IF
     865              : 
     866              :       ! do inversion
     867              : #if defined(__parallel)
     868              :       CALL pzgetri(nrows_global, mat(1, 1), 1, 1, desca, &
     869        49793 :                    ipivot, work1, -1, iwork1, -1, info)
     870        49793 :       lwork = INT(work1(1))
     871        49793 :       liwork = INT(iwork1(1))
     872       149379 :       ALLOCATE (work(lwork))
     873       149379 :       ALLOCATE (iwork(liwork))
     874              :       CALL pzgetri(nrows_global, mat(1, 1), 1, 1, desca, &
     875        49793 :                    ipivot, work, lwork, iwork, liwork, info)
     876        49793 :       DEALLOCATE (iwork)
     877              : #else
     878              :       CALL zgetri(nrows_global, mat(1, 1), lda, ipivot, work1, -1, info)
     879              :       lwork = INT(work1(1))
     880              :       ALLOCATE (work(lwork))
     881              :       CALL zgetri(nrows_global, mat(1, 1), lda, ipivot, work, lwork, info)
     882              : #endif
     883        49793 :       DEALLOCATE (work)
     884        49793 :       DEALLOCATE (ipivot)
     885              : 
     886        49793 :       IF (PRESENT(info_out)) THEN
     887            0 :          info_out = info
     888              :       ELSE
     889        49793 :          IF (info /= 0) &
     890            0 :             CALL cp_abort(__LOCATION__, "LU inversion has failed")
     891              :       END IF
     892              : 
     893        49793 :       CALL timestop(handle)
     894              : 
     895        49793 :    END SUBROUTINE cp_cfm_lu_invert
     896              : 
     897              : ! **************************************************************************************************
     898              : !> \brief Returns the trace of matrix_a^T matrix_b, i.e
     899              : !>      sum_{i,j}(matrix_a(i,j)*matrix_b(i,j)) .
     900              : !> \param matrix_a a complex matrix
     901              : !> \param matrix_b another complex matrix
     902              : !> \param trace    value of the trace operator
     903              : !> \par History
     904              : !>    * 09.2017 created [Sergey Chulkov]
     905              : !> \author Sergey Chulkov
     906              : !> \note
     907              : !>      Based on the subroutine cp_fm_trace(). Note the transposition of matrix_a!
     908              : ! **************************************************************************************************
     909        31315 :    SUBROUTINE cp_cfm_trace(matrix_a, matrix_b, trace)
     910              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b
     911              :       COMPLEX(kind=dp), INTENT(out)                      :: trace
     912              : 
     913              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_trace'
     914              : 
     915              :       INTEGER                                            :: handle, mypcol, myprow, ncol_local, &
     916              :                                                             npcol, nprow, nrow_local
     917              :       TYPE(cp_blacs_env_type), POINTER                   :: context
     918              :       TYPE(mp_comm_type)                                 :: group
     919              : 
     920        31315 :       CALL timeset(routineN, handle)
     921              : 
     922        31315 :       context => matrix_a%matrix_struct%context
     923        31315 :       myprow = context%mepos(1)
     924        31315 :       mypcol = context%mepos(2)
     925        31315 :       nprow = context%num_pe(1)
     926        31315 :       npcol = context%num_pe(2)
     927              : 
     928        31315 :       group = matrix_a%matrix_struct%para_env
     929              : 
     930        31315 :       nrow_local = MIN(matrix_a%matrix_struct%nrow_locals(myprow), matrix_b%matrix_struct%nrow_locals(myprow))
     931        31315 :       ncol_local = MIN(matrix_a%matrix_struct%ncol_locals(mypcol), matrix_b%matrix_struct%ncol_locals(mypcol))
     932              : 
     933              :       ! compute an accurate dot-product
     934              :       trace = accurate_dot_product(matrix_a%local_data(1:nrow_local, 1:ncol_local), &
     935        31315 :                                    matrix_b%local_data(1:nrow_local, 1:ncol_local))
     936              : 
     937        31315 :       CALL group%sum(trace)
     938              : 
     939        31315 :       CALL timestop(handle)
     940              : 
     941        31315 :    END SUBROUTINE cp_cfm_trace
     942              : 
     943              : ! **************************************************************************************************
     944              : !> \brief Multiplies in place by a triangular matrix:
     945              : !>       matrix_b = alpha op(triangular_matrix) matrix_b
     946              : !>      or (if side='R')
     947              : !>       matrix_b = alpha matrix_b op(triangular_matrix)
     948              : !>      op(triangular_matrix) is:
     949              : !>       triangular_matrix (if transa="N" and invert_tr=.false.)
     950              : !>       triangular_matrix^T (if transa="T" and invert_tr=.false.)
     951              : !>       triangular_matrix^H (if transa="C" and invert_tr=.false.)
     952              : !>       triangular_matrix^(-1) (if transa="N" and invert_tr=.true.)
     953              : !>       triangular_matrix^(-T) (if transa="T" and invert_tr=.true.)
     954              : !>       triangular_matrix^(-H) (if transa="C" and invert_tr=.true.)
     955              : !> \param triangular_matrix the triangular matrix that multiplies the other
     956              : !> \param matrix_b the matrix that gets multiplied and stores the result
     957              : !> \param side on which side of matrix_b stays op(triangular_matrix)
     958              : !>        (defaults to 'L')
     959              : !> \param transa_tr ...
     960              : !> \param invert_tr if the triangular matrix should be inverted
     961              : !>        (defaults to false)
     962              : !> \param uplo_tr if triangular_matrix is stored in the upper ('U') or
     963              : !>        lower ('L') triangle (defaults to 'U')
     964              : !> \param unit_diag_tr if the diagonal elements of triangular_matrix should
     965              : !>        be assumed to be 1 (defaults to false)
     966              : !> \param n_rows the number of rows of the result (defaults to
     967              : !>        size(matrix_b,1))
     968              : !> \param n_cols the number of columns of the result (defaults to
     969              : !>        size(matrix_b,2))
     970              : !> \param alpha ...
     971              : !> \par History
     972              : !>      08.2002 created [fawzi]
     973              : !> \author Fawzi Mohamed
     974              : !> \note
     975              : !>      needs an mpi env
     976              : ! **************************************************************************************************
     977       101328 :    SUBROUTINE cp_cfm_triangular_multiply(triangular_matrix, matrix_b, side, &
     978              :                                          transa_tr, invert_tr, uplo_tr, unit_diag_tr, n_rows, n_cols, &
     979              :                                          alpha)
     980              :       TYPE(cp_cfm_type), INTENT(IN)                      :: triangular_matrix, matrix_b
     981              :       CHARACTER, INTENT(in), OPTIONAL                    :: side, transa_tr
     982              :       LOGICAL, INTENT(in), OPTIONAL                      :: invert_tr
     983              :       CHARACTER, INTENT(in), OPTIONAL                    :: uplo_tr
     984              :       LOGICAL, INTENT(in), OPTIONAL                      :: unit_diag_tr
     985              :       INTEGER, INTENT(in), OPTIONAL                      :: n_rows, n_cols
     986              :       COMPLEX(kind=dp), INTENT(in), OPTIONAL             :: alpha
     987              : 
     988              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_triangular_multiply'
     989              : 
     990              :       CHARACTER                                          :: side_char, transa, unit_diag, uplo
     991              :       COMPLEX(kind=dp)                                   :: al
     992              :       INTEGER                                            :: handle, m, n
     993              :       LOGICAL                                            :: invert
     994              : 
     995        50664 :       CALL timeset(routineN, handle)
     996        50664 :       side_char = 'L'
     997        50664 :       unit_diag = 'N'
     998        50664 :       uplo = 'U'
     999        50664 :       transa = 'N'
    1000        50664 :       invert = .FALSE.
    1001        50664 :       al = CMPLX(1.0_dp, 0.0_dp, dp)
    1002        50664 :       CALL cp_cfm_get_info(matrix_b, nrow_global=m, ncol_global=n)
    1003        50664 :       IF (PRESENT(side)) side_char = side
    1004        50664 :       IF (PRESENT(invert_tr)) invert = invert_tr
    1005        50664 :       IF (PRESENT(uplo_tr)) uplo = uplo_tr
    1006        50664 :       IF (PRESENT(unit_diag_tr)) THEN
    1007            0 :          IF (unit_diag_tr) THEN
    1008            0 :             unit_diag = 'U'
    1009              :          ELSE
    1010              :             unit_diag = 'N'
    1011              :          END IF
    1012              :       END IF
    1013        50664 :       IF (PRESENT(transa_tr)) transa = transa_tr
    1014        50664 :       IF (PRESENT(alpha)) al = alpha
    1015        50664 :       IF (PRESENT(n_rows)) m = n_rows
    1016        50664 :       IF (PRESENT(n_cols)) n = n_cols
    1017              : 
    1018        50664 :       IF (invert) THEN
    1019              : 
    1020              : #if defined(__parallel)
    1021              :          CALL pztrsm(side_char, uplo, transa, unit_diag, m, n, al, &
    1022              :                      triangular_matrix%local_data(1, 1), 1, 1, &
    1023              :                      triangular_matrix%matrix_struct%descriptor, &
    1024              :                      matrix_b%local_data(1, 1), 1, 1, &
    1025          534 :                      matrix_b%matrix_struct%descriptor(1))
    1026              : #else
    1027              :          CALL ztrsm(side_char, uplo, transa, unit_diag, m, n, al, &
    1028              :                     triangular_matrix%local_data(1, 1), &
    1029              :                     SIZE(triangular_matrix%local_data, 1), &
    1030              :                     matrix_b%local_data(1, 1), SIZE(matrix_b%local_data, 1))
    1031              : #endif
    1032              : 
    1033              :       ELSE
    1034              : 
    1035              : #if defined(__parallel)
    1036              :          CALL pztrmm(side_char, uplo, transa, unit_diag, m, n, al, &
    1037              :                      triangular_matrix%local_data(1, 1), 1, 1, &
    1038              :                      triangular_matrix%matrix_struct%descriptor, &
    1039              :                      matrix_b%local_data(1, 1), 1, 1, &
    1040        50130 :                      matrix_b%matrix_struct%descriptor(1))
    1041              : #else
    1042              :          CALL ztrmm(side_char, uplo, transa, unit_diag, m, n, al, &
    1043              :                     triangular_matrix%local_data(1, 1), &
    1044              :                     SIZE(triangular_matrix%local_data, 1), &
    1045              :                     matrix_b%local_data(1, 1), SIZE(matrix_b%local_data, 1))
    1046              : #endif
    1047              : 
    1048              :       END IF
    1049              : 
    1050        50664 :       CALL timestop(handle)
    1051              : 
    1052        50664 :    END SUBROUTINE cp_cfm_triangular_multiply
    1053              : 
    1054              : ! **************************************************************************************************
    1055              : !> \brief Inverts a triangular matrix.
    1056              : !> \param matrix_a ...
    1057              : !> \param uplo ...
    1058              : !> \param info_out ...
    1059              : !> \author MI
    1060              : ! **************************************************************************************************
    1061        16710 :    SUBROUTINE cp_cfm_triangular_invert(matrix_a, uplo, info_out)
    1062              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix_a
    1063              :       CHARACTER, INTENT(in), OPTIONAL          :: uplo
    1064              :       INTEGER, INTENT(out), OPTIONAL           :: info_out
    1065              : 
    1066              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_triangular_invert'
    1067              : 
    1068              :       CHARACTER                                :: unit_diag, my_uplo
    1069              :       INTEGER                                  :: handle, info, ncol_global
    1070              :       COMPLEX(kind=dp), DIMENSION(:, :), &
    1071        16710 :          POINTER                               :: a
    1072              : #if defined(__parallel)
    1073              :       INTEGER, DIMENSION(9)                    :: desca
    1074              : #endif
    1075              : 
    1076        16710 :       CALL timeset(routineN, handle)
    1077              : 
    1078        16710 :       unit_diag = 'N'
    1079        16710 :       my_uplo = 'U'
    1080        16710 :       IF (PRESENT(uplo)) my_uplo = uplo
    1081              : 
    1082        16710 :       ncol_global = matrix_a%matrix_struct%ncol_global
    1083              : 
    1084        16710 :       a => matrix_a%local_data
    1085              : 
    1086              : #if defined(__parallel)
    1087       167100 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
    1088        16710 :       CALL pztrtri(my_uplo, unit_diag, ncol_global, a(1, 1), 1, 1, desca, info)
    1089              : #else
    1090              :       CALL ztrtri(my_uplo, unit_diag, ncol_global, a(1, 1), ncol_global, info)
    1091              : #endif
    1092              : 
    1093        16710 :       IF (PRESENT(info_out)) THEN
    1094            0 :          info_out = info
    1095              :       ELSE
    1096        16710 :          IF (info /= 0) &
    1097              :             CALL cp_abort(__LOCATION__, &
    1098            0 :                           "triangular invert failed: matrix is not positive definite  or ill-conditioned")
    1099              :       END IF
    1100              : 
    1101        16710 :       CALL timestop(handle)
    1102        16710 :    END SUBROUTINE cp_cfm_triangular_invert
    1103              : 
    1104              : ! **************************************************************************************************
    1105              : !> \brief Transposes a BLACS distributed complex matrix.
    1106              : !> \param matrix    input matrix
    1107              : !> \param trans     'T' for transpose, 'C' for Hermitian conjugate
    1108              : !> \param matrixt   output matrix
    1109              : !> \author Lianheng Tong
    1110              : ! **************************************************************************************************
    1111        14506 :    SUBROUTINE cp_cfm_transpose(matrix, trans, matrixt)
    1112              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1113              :       CHARACTER, INTENT(in)                              :: trans
    1114              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrixt
    1115              : 
    1116              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_transpose'
    1117              : 
    1118        14506 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: aa, cc
    1119              :       INTEGER                                            :: handle, ncol_global, nrow_global
    1120              : #if defined(__parallel)
    1121              :       INTEGER, DIMENSION(9)                              :: desca, descc
    1122              : #elif !defined(__MKL)
    1123              :       INTEGER                                            :: ii, jj
    1124              : #endif
    1125              : 
    1126        14506 :       CALL timeset(routineN, handle)
    1127              : 
    1128        14506 :       nrow_global = matrix%matrix_struct%nrow_global
    1129        14506 :       ncol_global = matrix%matrix_struct%ncol_global
    1130              : 
    1131        14506 :       CPASSERT(matrixt%matrix_struct%nrow_global == ncol_global)
    1132        14506 :       CPASSERT(matrixt%matrix_struct%ncol_global == nrow_global)
    1133              : 
    1134        14506 :       aa => matrix%local_data
    1135        14506 :       cc => matrixt%local_data
    1136              : 
    1137              : #if defined(__parallel)
    1138       145060 :       desca = matrix%matrix_struct%descriptor
    1139       145060 :       descc = matrixt%matrix_struct%descriptor
    1140         6610 :       SELECT CASE (trans)
    1141              :       CASE ('T')
    1142              :          CALL pztranu(nrow_global, ncol_global, &
    1143              :                       z_one, aa(1, 1), 1, 1, desca, &
    1144         6610 :                       z_zero, cc(1, 1), 1, 1, descc)
    1145              :       CASE ('C')
    1146              :          CALL pztranc(nrow_global, ncol_global, &
    1147              :                       z_one, aa(1, 1), 1, 1, desca, &
    1148         7896 :                       z_zero, cc(1, 1), 1, 1, descc)
    1149              :       CASE DEFAULT
    1150        14506 :          CPABORT("trans only accepts 'T' or 'C'")
    1151              :       END SELECT
    1152              : #elif defined(__MKL)
    1153              :       CALL mkl_zomatcopy('C', trans, nrow_global, ncol_global, 1.0_dp, aa(1, 1), nrow_global, cc(1, 1), ncol_global)
    1154              : #else
    1155              :       SELECT CASE (trans)
    1156              :       CASE ('T')
    1157              :          DO jj = 1, ncol_global
    1158              :             DO ii = 1, nrow_global
    1159              :                cc(ii, jj) = aa(jj, ii)
    1160              :             END DO
    1161              :          END DO
    1162              :       CASE ('C')
    1163              :          DO jj = 1, ncol_global
    1164              :             DO ii = 1, nrow_global
    1165              :                cc(ii, jj) = CONJG(aa(jj, ii))
    1166              :             END DO
    1167              :          END DO
    1168              :       CASE DEFAULT
    1169              :          CPABORT("trans only accepts 'T' or 'C'")
    1170              :       END SELECT
    1171              : #endif
    1172              : 
    1173        14506 :       CALL timestop(handle)
    1174        14506 :    END SUBROUTINE cp_cfm_transpose
    1175              : 
    1176              : ! **************************************************************************************************
    1177              : !> \brief Norm of matrix using (p)zlange.
    1178              : !> \param matrix     input a general matrix
    1179              : !> \param mode       'M' max abs element value,
    1180              : !>                   '1' or 'O' one norm, i.e. maximum column sum,
    1181              : !>                   'I' infinity norm, i.e. maximum row sum,
    1182              : !>                   'F' or 'E' Frobenius norm, i.e. sqrt of sum of all squares of elements
    1183              : !> \return the norm according to mode
    1184              : !> \author Lianheng Tong
    1185              : ! **************************************************************************************************
    1186       104498 :    FUNCTION cp_cfm_norm(matrix, mode) RESULT(res)
    1187              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1188              :       CHARACTER, INTENT(IN)                              :: mode
    1189              :       REAL(kind=dp)                                      :: res
    1190              : 
    1191              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_norm'
    1192              : 
    1193       104498 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: aa
    1194              :       INTEGER                                            :: handle, lwork, ncols, ncols_local, &
    1195              :                                                             nrows, nrows_local
    1196       104498 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: work
    1197              : 
    1198              : #if defined(__parallel)
    1199              :       INTEGER, DIMENSION(9)                              :: desca
    1200              : #else
    1201              :       INTEGER                                            :: lda
    1202              : #endif
    1203              : 
    1204       104498 :       CALL timeset(routineN, handle)
    1205              : 
    1206              :       CALL cp_cfm_get_info(matrix=matrix, &
    1207              :                            nrow_global=nrows, &
    1208              :                            ncol_global=ncols, &
    1209              :                            nrow_local=nrows_local, &
    1210       104498 :                            ncol_local=ncols_local)
    1211       104498 :       aa => matrix%local_data
    1212              : 
    1213              :       SELECT CASE (mode)
    1214              :       CASE ('M', 'm')
    1215            0 :          lwork = 1
    1216              :       CASE ('1', 'O', 'o')
    1217              : #if defined(__parallel)
    1218            0 :          lwork = ncols_local
    1219              : #else
    1220              :          lwork = 1
    1221              : #endif
    1222              :       CASE ('I', 'i')
    1223              : #if defined(__parallel)
    1224            0 :          lwork = nrows_local
    1225              : #else
    1226              :          lwork = nrows
    1227              : #endif
    1228              :       CASE ('F', 'f', 'E', 'e')
    1229            0 :          lwork = 1
    1230              :       CASE DEFAULT
    1231       104498 :          CPABORT("mode input is not valid")
    1232              :       END SELECT
    1233              : 
    1234       313494 :       ALLOCATE (work(lwork))
    1235              : 
    1236              : #if defined(__parallel)
    1237      1044980 :       desca = matrix%matrix_struct%descriptor
    1238       104498 :       res = pzlange(mode, nrows, ncols, aa(1, 1), 1, 1, desca, work)
    1239              : #else
    1240              :       lda = SIZE(aa, 1)
    1241              :       res = zlange(mode, nrows, ncols, aa(1, 1), lda, work)
    1242              : #endif
    1243              : 
    1244       104498 :       DEALLOCATE (work)
    1245       104498 :       CALL timestop(handle)
    1246       104498 :    END FUNCTION cp_cfm_norm
    1247              : 
    1248              : ! **************************************************************************************************
    1249              : !> \brief Applies a planar rotation defined by cs and sn to the i'th and j'th rows.
    1250              : !> \param matrix ...
    1251              : !> \param irow ...
    1252              : !> \param jrow ...
    1253              : !> \param cs cosine of the rotation angle
    1254              : !> \param sn sinus of the rotation angle
    1255              : !> \author Ole Schuett
    1256              : ! **************************************************************************************************
    1257            0 :    SUBROUTINE cp_cfm_rot_rows(matrix, irow, jrow, cs, sn)
    1258              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix
    1259              :       INTEGER, INTENT(IN)                      :: irow, jrow
    1260              :       REAL(dp), INTENT(IN)                     :: cs, sn
    1261              : 
    1262              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_rot_rows'
    1263              :       INTEGER                                  :: handle, ncol
    1264              :       COMPLEX(KIND=dp)                         :: sn_cmplx
    1265              : 
    1266              : #if defined(__parallel)
    1267              :       INTEGER                                  :: info, lwork
    1268              :       INTEGER, DIMENSION(9)                    :: desc
    1269            0 :       REAL(dp), DIMENSION(:), ALLOCATABLE      :: work
    1270              : #endif
    1271            0 :       CALL timeset(routineN, handle)
    1272            0 :       CALL cp_cfm_get_info(matrix, ncol_global=ncol)
    1273            0 :       sn_cmplx = CMPLX(sn, 0.0_dp, dp)
    1274              : #if defined(__parallel)
    1275            0 :       IF (1 /= matrix%matrix_struct%context%n_pid) THEN
    1276            0 :          lwork = 2*ncol + 1
    1277            0 :          ALLOCATE (work(lwork))
    1278            0 :          desc(:) = matrix%matrix_struct%descriptor(:)
    1279              :          CALL pzrot(ncol, &
    1280              :                     matrix%local_data(1, 1), irow, 1, desc, ncol, &
    1281              :                     matrix%local_data(1, 1), jrow, 1, desc, ncol, &
    1282            0 :                     cs, sn_cmplx, work, lwork, info)
    1283            0 :          CPASSERT(info == 0)
    1284            0 :          DEALLOCATE (work)
    1285              :       ELSE
    1286              : #endif
    1287            0 :          CALL zrot(ncol, matrix%local_data(irow, 1), ncol, matrix%local_data(jrow, 1), ncol, cs, sn_cmplx)
    1288              : #if defined(__parallel)
    1289              :       END IF
    1290              : #endif
    1291            0 :       CALL timestop(handle)
    1292            0 :    END SUBROUTINE cp_cfm_rot_rows
    1293              : 
    1294              : ! **************************************************************************************************
    1295              : !> \brief Applies a planar rotation defined by cs and sn to the i'th and j'th columnns.
    1296              : !> \param matrix ...
    1297              : !> \param icol ...
    1298              : !> \param jcol ...
    1299              : !> \param cs cosine of the rotation angle
    1300              : !> \param sn sinus of the rotation angle
    1301              : !> \author Ole Schuett
    1302              : ! **************************************************************************************************
    1303            0 :    SUBROUTINE cp_cfm_rot_cols(matrix, icol, jcol, cs, sn)
    1304              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix
    1305              :       INTEGER, INTENT(IN)                      :: icol, jcol
    1306              :       REAL(dp), INTENT(IN)                     :: cs, sn
    1307              : 
    1308              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_rot_cols'
    1309              :       INTEGER                                  :: handle, nrow
    1310              :       COMPLEX(KIND=dp)                         :: sn_cmplx
    1311              : 
    1312              : #if defined(__parallel)
    1313              :       INTEGER                                  :: info, lwork
    1314              :       INTEGER, DIMENSION(9)                    :: desc
    1315            0 :       REAL(dp), DIMENSION(:), ALLOCATABLE      :: work
    1316              : #endif
    1317            0 :       CALL timeset(routineN, handle)
    1318            0 :       CALL cp_cfm_get_info(matrix, nrow_global=nrow)
    1319            0 :       sn_cmplx = CMPLX(sn, 0.0_dp, dp)
    1320              : #if defined(__parallel)
    1321            0 :       IF (1 /= matrix%matrix_struct%context%n_pid) THEN
    1322            0 :          lwork = 2*nrow + 1
    1323            0 :          ALLOCATE (work(lwork))
    1324            0 :          desc(:) = matrix%matrix_struct%descriptor(:)
    1325              :          CALL pzrot(nrow, &
    1326              :                     matrix%local_data(1, 1), 1, icol, desc, 1, &
    1327              :                     matrix%local_data(1, 1), 1, jcol, desc, 1, &
    1328            0 :                     cs, sn_cmplx, work, lwork, info)
    1329            0 :          CPASSERT(info == 0)
    1330            0 :          DEALLOCATE (work)
    1331              :       ELSE
    1332              : #endif
    1333            0 :          CALL zrot(nrow, matrix%local_data(1, icol), 1, matrix%local_data(1, jcol), 1, cs, sn_cmplx)
    1334              : #if defined(__parallel)
    1335              :       END IF
    1336              : #endif
    1337            0 :       CALL timestop(handle)
    1338            0 :    END SUBROUTINE cp_cfm_rot_cols
    1339              : 
    1340              : ! **************************************************************************************************
    1341              : !> \brief ...
    1342              : !> \param matrix ...
    1343              : !> \param workspace ...
    1344              : !> \param uplo triangular format; defaults to 'U'
    1345              : !> \par History
    1346              : !>      12.2024 Added optional workspace as input [Rocco Meli]
    1347              : !> \author Jan Wilhelm
    1348              : ! **************************************************************************************************
    1349         9636 :    SUBROUTINE cp_cfm_uplo_to_full(matrix, workspace, uplo)
    1350              : 
    1351              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1352              :       TYPE(cp_cfm_type), INTENT(IN), OPTIONAL            :: workspace
    1353              :       CHARACTER, INTENT(IN), OPTIONAL                    :: uplo
    1354              : 
    1355              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_cfm_uplo_to_full'
    1356              : 
    1357              :       CHARACTER                                          :: myuplo
    1358              :       INTEGER                                            :: handle, i_global, iiB, j_global, jjB, &
    1359              :                                                             ncol_local, nrow_local
    1360         4818 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1361              :       TYPE(cp_cfm_type)                                  :: work
    1362              : 
    1363         4818 :       CALL timeset(routineN, handle)
    1364              : 
    1365         4818 :       IF (.NOT. PRESENT(workspace)) THEN
    1366         4212 :          CALL cp_cfm_create(work, matrix%matrix_struct)
    1367              :       ELSE
    1368          606 :          work = workspace
    1369              :       END IF
    1370              : 
    1371         4818 :       myuplo = 'U'
    1372         4818 :       IF (PRESENT(uplo)) myuplo = uplo
    1373              : 
    1374              :       ! get info of fm_mat_Q
    1375              :       CALL cp_cfm_get_info(matrix=matrix, &
    1376              :                            nrow_local=nrow_local, &
    1377              :                            ncol_local=ncol_local, &
    1378              :                            row_indices=row_indices, &
    1379         4818 :                            col_indices=col_indices)
    1380              : 
    1381       200784 :       DO jjB = 1, ncol_local
    1382       195966 :          j_global = col_indices(jjB)
    1383      7187880 :          DO iiB = 1, nrow_local
    1384      6987096 :             i_global = row_indices(iiB)
    1385      7183062 :             IF (MERGE(j_global < i_global, j_global > i_global, (myuplo == "U") .OR. (myuplo == "u"))) THEN
    1386      3443190 :                matrix%local_data(iiB, jjB) = z_zero
    1387      3543906 :             ELSE IF (j_global == i_global) THEN
    1388       100716 :                matrix%local_data(iiB, jjB) = matrix%local_data(iiB, jjB)/(2.0_dp, 0.0_dp)
    1389              :             END IF
    1390              :          END DO
    1391              :       END DO
    1392              : 
    1393         4818 :       CALL cp_cfm_transpose(matrix, 'C', work)
    1394              : 
    1395         4818 :       CALL cp_cfm_scale_and_add(z_one, matrix, z_one, work)
    1396              : 
    1397         4818 :       IF (.NOT. PRESENT(workspace)) THEN
    1398         4212 :          CALL cp_cfm_release(work)
    1399              :       END IF
    1400              : 
    1401         4818 :       CALL timestop(handle)
    1402              : 
    1403         4818 :    END SUBROUTINE cp_cfm_uplo_to_full
    1404              : 
    1405              : END MODULE cp_cfm_basic_linalg
        

Generated by: LCOV version 2.0-1