LCOV - code coverage report
Current view: top level - src/fm - cp_cfm_basic_linalg.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:c24029e) Lines: 82.6 % 442 365
Test Date: 2026-07-04 06:36:57 Functions: 90.0 % 20 18

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief 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         1482 :       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          154 :    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          154 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b, c
     159              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     160              :                                                             myprow, ncol_local, nrow_local
     161              : 
     162          154 :       CALL timeset(routineN, handle)
     163              : 
     164          154 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     165          154 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     166              : 
     167          154 :       a => matrix_a%local_data
     168          154 :       b => matrix_b%local_data
     169          154 :       c => matrix_c%local_data
     170              : 
     171          154 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     172          154 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     173              : 
     174          462 :       DO icol_local = 1, ncol_local
     175          770 :          DO irow_local = 1, nrow_local
     176          616 :             c(irow_local, icol_local) = a(irow_local, icol_local)*b(irow_local, icol_local)
     177              :          END DO
     178              :       END DO
     179              : 
     180          154 :       CALL timestop(handle)
     181              : 
     182          154 :    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       414370 :    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       414370 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b
     249              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     250              :                                                             myprow, ncol_local, nrow_local
     251              : 
     252       414370 :       CALL timeset(routineN, handle)
     253              : 
     254       414370 :       my_beta = z_zero
     255       414370 :       IF (PRESENT(beta)) my_beta = beta
     256       414370 :       NULLIFY (a, b)
     257              : 
     258              :       ! to do: use dscal,dcopy,daxp
     259       414370 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     260       414370 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     261              : 
     262       414370 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     263       414370 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     264              : 
     265       414370 :       a => matrix_a%local_data
     266              : 
     267       414370 :       IF (my_beta == z_zero) THEN
     268              : 
     269        57268 :          IF (alpha == z_zero) THEN
     270            0 :             a(:, :) = z_zero
     271        57268 :          ELSE IF (alpha == z_one) THEN
     272        57268 :             CALL timestop(handle)
     273        57268 :             RETURN
     274              :          ELSE
     275            0 :             a(:, :) = alpha*a(:, :)
     276              :          END IF
     277              : 
     278              :       ELSE
     279       357102 :          CPASSERT(PRESENT(matrix_b))
     280       357102 :          IF (matrix_a%matrix_struct%context /= matrix_b%matrix_struct%context) &
     281            0 :             CPABORT("matrixes must be in the same blacs context")
     282              : 
     283       357102 :          IF (cp_fm_struct_equivalent(matrix_a%matrix_struct, &
     284              :                                      matrix_b%matrix_struct)) THEN
     285              : 
     286       357102 :             b => matrix_b%local_data
     287              : 
     288       357102 :             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       357102 :             ELSE IF (alpha == z_one) THEN
     305       352650 :                IF (my_beta == z_one) THEN
     306              :                   !a(:, :) = a(:, :)+b(:, :)
     307      2213680 :                   DO icol_local = 1, ncol_local
     308     49899371 :                      DO irow_local = 1, nrow_local
     309     49663699 :                         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      1646190 :                   DO icol_local = 1, ncol_local
     315     54488863 :                      DO irow_local = 1, nrow_local
     316     54371885 :                         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        34280 :                DO icol_local = 1, ncol_local
     323       347260 :                   DO irow_local = 1, nrow_local
     324       342808 :                      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              :             CALL cp_abort(__LOCATION__, &
     330              :                           "cp_cfm_scale_and_add is not yet implemented for cases "// &
     331            0 :                           "where input two matrix structures are not equivalent")
     332              :          END IF
     333              :       END IF
     334       357102 :       CALL timestop(handle)
     335       414370 :    END SUBROUTINE cp_cfm_scale_and_add
     336              : 
     337              : ! **************************************************************************************************
     338              : !> \brief Scale and add two BLACS matrices (a = alpha*a + beta*b).
     339              : !>        where b is a real matrix (adapted from cp_cfm_scale_and_add).
     340              : !> \param alpha ...
     341              : !> \param matrix_a ...
     342              : !> \param beta ...
     343              : !> \param matrix_b ...
     344              : !> \date    01.08.2014
     345              : !> \author  JGH
     346              : !> \version 1.0
     347              : ! **************************************************************************************************
     348       332170 :    SUBROUTINE cp_cfm_scale_and_add_fm(alpha, matrix_a, beta, matrix_b)
     349              :       COMPLEX(kind=dp), INTENT(in)                       :: alpha
     350              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     351              :       COMPLEX(kind=dp), INTENT(in)                       :: beta
     352              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix_b
     353              : 
     354              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_scale_and_add_fm'
     355              : 
     356       332170 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     357              :       INTEGER                                            :: handle, icol_local, irow_local, mypcol, &
     358              :                                                             myprow, ncol_local, nrow_local
     359       332170 :       REAL(kind=dp), DIMENSION(:, :), POINTER            :: b
     360              : 
     361       332170 :       CALL timeset(routineN, handle)
     362              : 
     363       332170 :       NULLIFY (a, b)
     364              : 
     365       332170 :       myprow = matrix_a%matrix_struct%context%mepos(1)
     366       332170 :       mypcol = matrix_a%matrix_struct%context%mepos(2)
     367              : 
     368       332170 :       nrow_local = matrix_a%matrix_struct%nrow_locals(myprow)
     369       332170 :       ncol_local = matrix_a%matrix_struct%ncol_locals(mypcol)
     370              : 
     371       332170 :       a => matrix_a%local_data
     372              : 
     373       332170 :       IF (beta == z_zero) THEN
     374              : 
     375            0 :          IF (alpha == z_zero) THEN
     376            0 :             a(:, :) = z_zero
     377            0 :          ELSE IF (alpha == z_one) THEN
     378            0 :             CALL timestop(handle)
     379            0 :             RETURN
     380              :          ELSE
     381            0 :             a(:, :) = alpha*a(:, :)
     382              :          END IF
     383              : 
     384              :       ELSE
     385       332170 :          IF (matrix_a%matrix_struct%context /= matrix_b%matrix_struct%context) &
     386            0 :             CPABORT("matrices must be in the same blacs context")
     387              : 
     388       332170 :          IF (cp_fm_struct_equivalent(matrix_a%matrix_struct, &
     389              :                                      matrix_b%matrix_struct)) THEN
     390              : 
     391       332170 :             b => matrix_b%local_data
     392              : 
     393       332170 :             IF (alpha == z_zero) THEN
     394       142928 :                IF (beta == z_one) THEN
     395              :                   !a(:, :) = b(:, :)
     396      4445712 :                   DO icol_local = 1, ncol_local
     397    195636924 :                      DO irow_local = 1, nrow_local
     398    195494020 :                         a(irow_local, icol_local) = b(irow_local, icol_local)
     399              :                      END DO
     400              :                   END DO
     401              :                ELSE
     402              :                   !a(:, :) = beta*b(:, :)
     403          456 :                   DO icol_local = 1, ncol_local
     404         4344 :                      DO irow_local = 1, nrow_local
     405         4320 :                         a(irow_local, icol_local) = beta*b(irow_local, icol_local)
     406              :                      END DO
     407              :                   END DO
     408              :                END IF
     409       189242 :             ELSE IF (alpha == z_one) THEN
     410       151240 :                IF (beta == z_one) THEN
     411              :                   !a(:, :) = a(:, :)+b(:, :)
     412       101076 :                   DO icol_local = 1, ncol_local
     413      1232604 :                      DO irow_local = 1, nrow_local
     414      1226544 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + b(irow_local, icol_local)
     415              :                      END DO
     416              :                   END DO
     417              :                ELSE
     418              :                   !a(:, :) = a(:, :)+beta*b(:, :)
     419      4498556 :                   DO icol_local = 1, ncol_local
     420    196279280 :                      DO irow_local = 1, nrow_local
     421    196134100 :                         a(irow_local, icol_local) = a(irow_local, icol_local) + beta*b(irow_local, icol_local)
     422              :                      END DO
     423              :                   END DO
     424              :                END IF
     425              :             ELSE
     426              :                !a(:, :) = alpha*a(:, :)+beta*b(:, :)
     427       241082 :                DO icol_local = 1, ncol_local
     428      2074842 :                   DO irow_local = 1, nrow_local
     429      2036840 :                      a(irow_local, icol_local) = alpha*a(irow_local, icol_local) + beta*b(irow_local, icol_local)
     430              :                   END DO
     431              :                END DO
     432              :             END IF
     433              :          ELSE
     434              :             CALL cp_abort(__LOCATION__, &
     435              :                           "cp_cfm_scale_and_add_fm is not yet implemented for cases "// &
     436            0 :                           "where two input matrix structures are not equivalent")
     437              :          END IF
     438              :       END IF
     439       332170 :       CALL timestop(handle)
     440       332170 :    END SUBROUTINE cp_cfm_scale_and_add_fm
     441              : 
     442              : ! **************************************************************************************************
     443              : !> \brief Computes LU decomposition of a given matrix.
     444              : !> \param matrix_a     full matrix
     445              : !> \param determinant  determinant
     446              : !> \date    11.06.2001
     447              : !> \author  Matthias Krack
     448              : !> \version 1.0
     449              : !> \note
     450              : !>    The actual purpose right now is to efficiently compute the determinant of a given matrix.
     451              : !>    The original content of the matrix is destroyed.
     452              : ! **************************************************************************************************
     453            0 :    SUBROUTINE cp_cfm_lu_decompose(matrix_a, determinant)
     454              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     455              :       COMPLEX(kind=dp), INTENT(out)                      :: determinant
     456              : 
     457              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_lu_decompose'
     458              : 
     459            0 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     460              :       INTEGER                                            :: counter, handle, info, irow, nrow_global
     461            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     462              : 
     463              : #if defined(__parallel)
     464              :       INTEGER                                            :: icol, ncol_local, nrow_local
     465              :       INTEGER, DIMENSION(9)                              :: desca
     466            0 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     467              : #else
     468              :       INTEGER                                            :: lda
     469              : #endif
     470              : 
     471            0 :       CALL timeset(routineN, handle)
     472              : 
     473            0 :       nrow_global = matrix_a%matrix_struct%nrow_global
     474            0 :       a => matrix_a%local_data
     475              : 
     476            0 :       ALLOCATE (ipivot(nrow_global))
     477              : #if defined(__parallel)
     478              :       CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, &
     479            0 :                            row_indices=row_indices, col_indices=col_indices)
     480              : 
     481            0 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     482            0 :       CALL pzgetrf(nrow_global, nrow_global, a(1, 1), 1, 1, desca, ipivot, info)
     483              : 
     484            0 :       counter = 0
     485            0 :       DO irow = 1, nrow_local
     486            0 :          IF (ipivot(irow) /= row_indices(irow)) counter = counter + 1
     487              :       END DO
     488              : 
     489            0 :       IF (MOD(counter, 2) == 0) THEN
     490            0 :          determinant = z_one
     491              :       ELSE
     492            0 :          determinant = -z_one
     493              :       END IF
     494              : 
     495              :       ! compute product of diagonal elements
     496              :       irow = 1
     497              :       icol = 1
     498            0 :       DO WHILE (irow <= nrow_local .AND. icol <= ncol_local)
     499            0 :          IF (row_indices(irow) < col_indices(icol)) THEN
     500            0 :             irow = irow + 1
     501            0 :          ELSE IF (row_indices(irow) > col_indices(icol)) THEN
     502            0 :             icol = icol + 1
     503              :          ELSE ! diagonal element
     504            0 :             determinant = determinant*a(irow, icol)
     505            0 :             irow = irow + 1
     506            0 :             icol = icol + 1
     507              :          END IF
     508              :       END DO
     509            0 :       CALL matrix_a%matrix_struct%para_env%prod(determinant)
     510              : #else
     511              :       lda = SIZE(a, 1)
     512              :       CALL zgetrf(nrow_global, nrow_global, a(1, 1), lda, ipivot, info)
     513              :       counter = 0
     514              :       determinant = z_one
     515              :       DO irow = 1, nrow_global
     516              :          IF (ipivot(irow) /= irow) counter = counter + 1
     517              :          determinant = determinant*a(irow, irow)
     518              :       END DO
     519              :       IF (MOD(counter, 2) == 1) determinant = -1.0_dp*determinant
     520              : #endif
     521              : 
     522              :       ! info is allowed to be zero
     523              :       ! this does just signal a zero diagonal element
     524            0 :       DEALLOCATE (ipivot)
     525              : 
     526            0 :       CALL timestop(handle)
     527            0 :    END SUBROUTINE cp_cfm_lu_decompose
     528              : 
     529              : ! **************************************************************************************************
     530              : !> \brief Performs one of the matrix-matrix operations:
     531              : !>        matrix_c = alpha * op1( matrix_a ) * op2( matrix_b ) + beta*matrix_c.
     532              : !> \param transa       form of op1( matrix_a ):
     533              : !>                     op1( matrix_a ) = matrix_a,   when transa == 'N' ,
     534              : !>                     op1( matrix_a ) = matrix_a^T, when transa == 'T' ,
     535              : !>                     op1( matrix_a ) = matrix_a^H, when transa == 'C' ,
     536              : !> \param transb       form of op2( matrix_b )
     537              : !> \param m            number of rows of the matrix op1( matrix_a )
     538              : !> \param n            number of columns of the matrix op2( matrix_b )
     539              : !> \param k            number of columns of the matrix op1( matrix_a ) as well as
     540              : !>                     number of rows of the matrix op2( matrix_b )
     541              : !> \param alpha        scale factor
     542              : !> \param matrix_a     matrix A
     543              : !> \param matrix_b     matrix B
     544              : !> \param beta         scale factor
     545              : !> \param matrix_c     matrix C
     546              : !> \param a_first_col  (optional) the first column of the matrix_a to multiply
     547              : !> \param a_first_row  (optional) the first row of the matrix_a to multiply
     548              : !> \param b_first_col  (optional) the first column of the matrix_b to multiply
     549              : !> \param b_first_row  (optional) the first row of the matrix_b to multiply
     550              : !> \param c_first_col  (optional) the first column of the matrix_c
     551              : !> \param c_first_row  (optional) the first row of the matrix_c
     552              : !> \date    07.06.2001
     553              : !> \author  Matthias Krack
     554              : !> \version 1.0
     555              : ! **************************************************************************************************
     556       525150 :    SUBROUTINE cp_cfm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, &
     557              :                           matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, &
     558              :                           c_first_row)
     559              :       CHARACTER(len=1), INTENT(in)                       :: transa, transb
     560              :       INTEGER, INTENT(in)                                :: m, n, k
     561              :       COMPLEX(kind=dp), INTENT(in)                       :: alpha
     562              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b
     563              :       COMPLEX(kind=dp), INTENT(in)                       :: beta
     564              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_c
     565              :       INTEGER, INTENT(in), OPTIONAL                      :: a_first_col, a_first_row, b_first_col, &
     566              :                                                             b_first_row, c_first_col, c_first_row
     567              : 
     568              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_gemm'
     569              : 
     570       525150 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, b, c
     571              :       INTEGER                                            :: handle, i_a, i_b, i_c, j_a, j_b, j_c
     572              : #if defined(__parallel)
     573              :       INTEGER, DIMENSION(9)                              :: desca, descb, descc
     574              : #else
     575              :       INTEGER                                            :: lda, ldb, ldc
     576              : #endif
     577              : 
     578       525150 :       CALL timeset(routineN, handle)
     579       525150 :       a => matrix_a%local_data
     580       525150 :       b => matrix_b%local_data
     581       525150 :       c => matrix_c%local_data
     582              : 
     583       525150 :       i_a = 1
     584       525150 :       IF (PRESENT(a_first_row)) i_a = a_first_row
     585              : 
     586       525150 :       j_a = 1
     587       525150 :       IF (PRESENT(a_first_col)) j_a = a_first_col
     588              : 
     589       525150 :       i_b = 1
     590       525150 :       IF (PRESENT(b_first_row)) i_b = b_first_row
     591              : 
     592       525150 :       j_b = 1
     593       525150 :       IF (PRESENT(b_first_col)) j_b = b_first_col
     594              : 
     595       525150 :       i_c = 1
     596       525150 :       IF (PRESENT(c_first_row)) i_c = c_first_row
     597              : 
     598       525150 :       j_c = 1
     599       525150 :       IF (PRESENT(c_first_col)) j_c = c_first_col
     600              : 
     601              : #if defined(__parallel)
     602      5251500 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     603      5251500 :       descb(:) = matrix_b%matrix_struct%descriptor(:)
     604      5251500 :       descc(:) = matrix_c%matrix_struct%descriptor(:)
     605              : 
     606              :       CALL pzgemm(transa, transb, m, n, k, alpha, a(1, 1), i_a, j_a, desca, &
     607       525150 :                   b(1, 1), i_b, j_b, descb, beta, c(1, 1), i_c, j_c, descc)
     608              : #else
     609              :       lda = SIZE(a, 1)
     610              :       ldb = SIZE(b, 1)
     611              :       ldc = SIZE(c, 1)
     612              : 
     613              :       ! consider zgemm3m
     614              :       CALL zgemm(transa, transb, m, n, k, alpha, a(i_a, j_a), &
     615              :                  lda, b(i_b, j_b), ldb, beta, c(i_c, j_c), ldc)
     616              : #endif
     617       525150 :       CALL timestop(handle)
     618       525150 :    END SUBROUTINE cp_cfm_gemm
     619              : 
     620              : ! **************************************************************************************************
     621              : !> \brief Scales columns of the full matrix by corresponding factors.
     622              : !> \param matrix_a matrix to scale
     623              : !> \param scaling  scale factors for every column. The actual number of scaled columns is
     624              : !>                 limited by the number of scale factors given or by the actual number of columns
     625              : !>                 whichever is smaller.
     626              : !> \author Joost VandeVondele
     627              : ! **************************************************************************************************
     628        10716 :    SUBROUTINE cp_cfm_column_scale(matrix_a, scaling)
     629              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     630              :       COMPLEX(kind=dp), DIMENSION(:), INTENT(in)         :: scaling
     631              : 
     632              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_column_scale'
     633              : 
     634        10716 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     635              :       INTEGER                                            :: handle, icol_local, ncol_local, &
     636              :                                                             nrow_local
     637              : #if defined(__parallel)
     638        10716 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices
     639              : #endif
     640              : 
     641        10716 :       CALL timeset(routineN, handle)
     642              : 
     643        10716 :       a => matrix_a%local_data
     644              : 
     645              : #if defined(__parallel)
     646        10716 :       CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, col_indices=col_indices)
     647        10716 :       ncol_local = MIN(ncol_local, SIZE(scaling))
     648              : 
     649       403890 :       DO icol_local = 1, ncol_local
     650       403890 :          CALL zscal(nrow_local, scaling(col_indices(icol_local)), a(1, icol_local), 1)
     651              :       END DO
     652              : #else
     653              :       nrow_local = SIZE(a, 1)
     654              :       ncol_local = MIN(SIZE(a, 2), SIZE(scaling))
     655              : 
     656              :       DO icol_local = 1, ncol_local
     657              :          CALL zscal(nrow_local, scaling(icol_local), a(1, icol_local), 1)
     658              :       END DO
     659              : #endif
     660              : 
     661        10716 :       CALL timestop(handle)
     662        10716 :    END SUBROUTINE cp_cfm_column_scale
     663              : 
     664              : ! **************************************************************************************************
     665              : !> \brief Scales a complex matrix by a real number.
     666              : !>      matrix_a = alpha * matrix_b
     667              : !> \param alpha    scale factor
     668              : !> \param matrix_a complex matrix to scale
     669              : ! **************************************************************************************************
     670        14490 :    SUBROUTINE cp_cfm_dscale(alpha, matrix_a)
     671              :       REAL(kind=dp), INTENT(in)                          :: alpha
     672              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     673              : 
     674              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_dscale'
     675              : 
     676        14490 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     677              :       INTEGER                                            :: handle
     678              : 
     679        14490 :       CALL timeset(routineN, handle)
     680              : 
     681        14490 :       NULLIFY (a)
     682              : 
     683        14490 :       a => matrix_a%local_data
     684              : 
     685        43470 :       CALL zdscal(SIZE(a), alpha, a(1, 1), 1)
     686              : 
     687        14490 :       CALL timestop(handle)
     688        14490 :    END SUBROUTINE cp_cfm_dscale
     689              : 
     690              : ! **************************************************************************************************
     691              : !> \brief Scales a complex matrix by a complex number.
     692              : !>      matrix_a = alpha * matrix_b
     693              : !> \param alpha    scale factor
     694              : !> \param matrix_a complex matrix to scale
     695              : !> \note
     696              : !>      use cp_fm_set_all to zero (avoids problems with nan)
     697              : ! **************************************************************************************************
     698        25569 :    SUBROUTINE cp_cfm_zscale(alpha, matrix_a)
     699              :       COMPLEX(kind=dp), INTENT(IN)                       :: alpha
     700              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a
     701              : 
     702              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_zscale'
     703              : 
     704        25569 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a
     705              :       INTEGER                                            :: handle, size_a
     706              : 
     707        25569 :       CALL timeset(routineN, handle)
     708              : 
     709        25569 :       NULLIFY (a)
     710              : 
     711        25569 :       a => matrix_a%local_data
     712        25569 :       size_a = SIZE(a, 1)*SIZE(a, 2)
     713              : 
     714        25569 :       CALL zscal(size_a, alpha, a(1, 1), 1)
     715              : 
     716        25569 :       CALL timestop(handle)
     717        25569 :    END SUBROUTINE cp_cfm_zscale
     718              : 
     719              : ! **************************************************************************************************
     720              : !> \brief Solve the system of linear equations A*b=A_general using LU decomposition.
     721              : !>        Pay attention that both matrices are overwritten on exit and that
     722              : !>        the result is stored into the matrix 'general_a'.
     723              : !> \param matrix_a     matrix A (overwritten on exit)
     724              : !> \param general_a    (input) matrix A_general, (output) matrix B
     725              : !> \param determinant  (optional) determinant
     726              : !> \author Florian Schiffmann
     727              : ! **************************************************************************************************
     728         7054 :    SUBROUTINE cp_cfm_solve(matrix_a, general_a, determinant)
     729              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, general_a
     730              :       COMPLEX(kind=dp), OPTIONAL                         :: determinant
     731              : 
     732              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_solve'
     733              : 
     734         7054 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: a, a_general
     735              :       INTEGER                                            :: counter, handle, info, irow, nrow_global
     736         7054 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     737              : 
     738              : #if defined(__parallel)
     739              :       INTEGER                                            :: icol, ncol_local, nrow_local
     740              :       INTEGER, DIMENSION(9)                              :: desca, descb
     741         7054 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     742              : #else
     743              :       INTEGER                                            :: lda, ldb
     744              : #endif
     745              : 
     746         7054 :       CALL timeset(routineN, handle)
     747              : 
     748         7054 :       a => matrix_a%local_data
     749         7054 :       a_general => general_a%local_data
     750         7054 :       nrow_global = matrix_a%matrix_struct%nrow_global
     751        21162 :       ALLOCATE (ipivot(nrow_global))
     752              : 
     753              : #if defined(__parallel)
     754        70540 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
     755        70540 :       descb(:) = general_a%matrix_struct%descriptor(:)
     756         7054 :       CALL pzgetrf(nrow_global, nrow_global, a(1, 1), 1, 1, desca, ipivot, info)
     757         7054 :       IF (PRESENT(determinant)) THEN
     758              :          CALL cp_cfm_get_info(matrix_a, nrow_local=nrow_local, ncol_local=ncol_local, &
     759         6356 :                               row_indices=row_indices, col_indices=col_indices)
     760              : 
     761         6356 :          counter = 0
     762        19116 :          DO irow = 1, nrow_local
     763        19116 :             IF (ipivot(irow) /= row_indices(irow)) counter = counter + 1
     764              :          END DO
     765              : 
     766         6356 :          IF (MOD(counter, 2) == 0) THEN
     767         6346 :             determinant = z_one
     768              :          ELSE
     769           10 :             determinant = -z_one
     770              :          END IF
     771              : 
     772              :          ! compute product of diagonal elements
     773              :          irow = 1
     774              :          icol = 1
     775        28662 :          DO WHILE (irow <= nrow_local .AND. icol <= ncol_local)
     776        28662 :             IF (row_indices(irow) < col_indices(icol)) THEN
     777            0 :                irow = irow + 1
     778        22306 :             ELSE IF (row_indices(irow) > col_indices(icol)) THEN
     779         9546 :                icol = icol + 1
     780              :             ELSE ! diagonal element
     781        12760 :                determinant = determinant*a(irow, icol)
     782        12760 :                irow = irow + 1
     783        12760 :                icol = icol + 1
     784              :             END IF
     785              :          END DO
     786         6356 :          CALL matrix_a%matrix_struct%para_env%prod(determinant)
     787              :       END IF
     788              : 
     789              :       CALL pzgetrs("N", nrow_global, nrow_global, a(1, 1), 1, 1, desca, &
     790         7054 :                    ipivot, a_general(1, 1), 1, 1, descb, info)
     791              : #else
     792              :       lda = SIZE(a, 1)
     793              :       ldb = SIZE(a_general, 1)
     794              :       CALL zgetrf(nrow_global, nrow_global, a(1, 1), lda, ipivot, info)
     795              :       IF (PRESENT(determinant)) THEN
     796              :          counter = 0
     797              :          determinant = z_one
     798              :          DO irow = 1, nrow_global
     799              :             IF (ipivot(irow) /= irow) counter = counter + 1
     800              :             determinant = determinant*a(irow, irow)
     801              :          END DO
     802              :          IF (MOD(counter, 2) == 1) determinant = -1.0_dp*determinant
     803              :       END IF
     804              :       CALL zgetrs("N", nrow_global, nrow_global, a(1, 1), lda, ipivot, a_general(1, 1), ldb, info)
     805              : #endif
     806              : 
     807              :       ! info is allowed to be zero
     808              :       ! this does just signal a zero diagonal element
     809         7054 :       DEALLOCATE (ipivot)
     810         7054 :       CALL timestop(handle)
     811              : 
     812         7054 :    END SUBROUTINE cp_cfm_solve
     813              : 
     814              : ! **************************************************************************************************
     815              : !> \brief Inverts a matrix using LU decomposition. The input matrix will be overwritten.
     816              : !> \param matrix     input a general square non-singular matrix, outputs its inverse
     817              : !> \param info_out   optional, if present outputs the info from (p)zgetri
     818              : !> \author Lianheng Tong
     819              : ! **************************************************************************************************
     820        62610 :    SUBROUTINE cp_cfm_lu_invert(matrix, info_out)
     821              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
     822              :       INTEGER, INTENT(out), OPTIONAL                     :: info_out
     823              : 
     824              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_lu_invert'
     825              : 
     826        62610 :       COMPLEX(kind=dp), ALLOCATABLE, DIMENSION(:)        :: work
     827              :       COMPLEX(kind=dp), DIMENSION(1)                     :: work1
     828        62610 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: mat
     829              :       INTEGER                                            :: handle, info, lwork, nrows_global
     830        62610 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: ipivot
     831              : 
     832              : #if defined(__parallel)
     833              :       INTEGER                                            :: liwork
     834        62610 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: iwork
     835              :       INTEGER, DIMENSION(1)                              :: iwork1
     836              :       INTEGER, DIMENSION(9)                              :: desca
     837              : #else
     838              :       INTEGER                                            :: lda
     839              : #endif
     840              : 
     841        62610 :       CALL timeset(routineN, handle)
     842              : 
     843        62610 :       mat => matrix%local_data
     844        62610 :       nrows_global = matrix%matrix_struct%nrow_global
     845        62610 :       CPASSERT(nrows_global == matrix%matrix_struct%ncol_global)
     846       187830 :       ALLOCATE (ipivot(nrows_global))
     847              : 
     848              :       ! do LU decomposition
     849              : #if defined(__parallel)
     850       626100 :       desca = matrix%matrix_struct%descriptor
     851              :       CALL pzgetrf(nrows_global, nrows_global, &
     852        62610 :                    mat(1, 1), 1, 1, desca, ipivot, info)
     853              : #else
     854              :       lda = SIZE(mat, 1)
     855              :       CALL zgetrf(nrows_global, nrows_global, &
     856              :                   mat(1, 1), lda, ipivot, info)
     857              : #endif
     858        62610 :       IF (info /= 0) THEN
     859            0 :          CALL cp_abort(__LOCATION__, "LU decomposition has failed")
     860              :       END IF
     861              : 
     862              :       ! do inversion
     863              : #if defined(__parallel)
     864              :       CALL pzgetri(nrows_global, mat(1, 1), 1, 1, desca, &
     865        62610 :                    ipivot, work1, -1, iwork1, -1, info)
     866        62610 :       lwork = INT(work1(1))
     867        62610 :       liwork = INT(iwork1(1))
     868       187830 :       ALLOCATE (work(lwork))
     869       187830 :       ALLOCATE (iwork(liwork))
     870              :       CALL pzgetri(nrows_global, mat(1, 1), 1, 1, desca, &
     871        62610 :                    ipivot, work, lwork, iwork, liwork, info)
     872        62610 :       DEALLOCATE (iwork)
     873              : #else
     874              :       CALL zgetri(nrows_global, mat(1, 1), lda, ipivot, work1, -1, info)
     875              :       lwork = INT(work1(1))
     876              :       ALLOCATE (work(lwork))
     877              :       CALL zgetri(nrows_global, mat(1, 1), lda, ipivot, work, lwork, info)
     878              : #endif
     879        62610 :       DEALLOCATE (work)
     880        62610 :       DEALLOCATE (ipivot)
     881              : 
     882        62610 :       IF (PRESENT(info_out)) THEN
     883            0 :          info_out = info
     884              :       ELSE
     885        62610 :          IF (info /= 0) &
     886            0 :             CALL cp_abort(__LOCATION__, "LU inversion has failed")
     887              :       END IF
     888              : 
     889        62610 :       CALL timestop(handle)
     890              : 
     891        62610 :    END SUBROUTINE cp_cfm_lu_invert
     892              : 
     893              : ! **************************************************************************************************
     894              : !> \brief Returns the trace of matrix_a^T matrix_b, i.e
     895              : !>      sum_{i,j}(matrix_a(i,j)*matrix_b(i,j)) .
     896              : !> \param matrix_a a complex matrix
     897              : !> \param matrix_b another complex matrix
     898              : !> \param trace    value of the trace operator
     899              : !> \par History
     900              : !>    * 09.2017 created [Sergey Chulkov]
     901              : !> \author Sergey Chulkov
     902              : !> \note
     903              : !>      Based on the subroutine cp_fm_trace(). Note the transposition of matrix_a!
     904              : ! **************************************************************************************************
     905       138505 :    SUBROUTINE cp_cfm_trace(matrix_a, matrix_b, trace)
     906              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix_a, matrix_b
     907              :       COMPLEX(kind=dp), INTENT(out)                      :: trace
     908              : 
     909              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'cp_cfm_trace'
     910              : 
     911              :       INTEGER                                            :: handle, mypcol, myprow, ncol_local, &
     912              :                                                             npcol, nprow, nrow_local
     913              :       TYPE(cp_blacs_env_type), POINTER                   :: context
     914              :       TYPE(mp_comm_type)                                 :: group
     915              : 
     916       138505 :       CALL timeset(routineN, handle)
     917              : 
     918       138505 :       context => matrix_a%matrix_struct%context
     919       138505 :       myprow = context%mepos(1)
     920       138505 :       mypcol = context%mepos(2)
     921       138505 :       nprow = context%num_pe(1)
     922       138505 :       npcol = context%num_pe(2)
     923              : 
     924       138505 :       group = matrix_a%matrix_struct%para_env
     925              : 
     926       138505 :       nrow_local = MIN(matrix_a%matrix_struct%nrow_locals(myprow), matrix_b%matrix_struct%nrow_locals(myprow))
     927       138505 :       ncol_local = MIN(matrix_a%matrix_struct%ncol_locals(mypcol), matrix_b%matrix_struct%ncol_locals(mypcol))
     928              : 
     929              :       ! compute an accurate dot-product
     930              :       trace = accurate_dot_product(matrix_a%local_data(1:nrow_local, 1:ncol_local), &
     931       138505 :                                    matrix_b%local_data(1:nrow_local, 1:ncol_local))
     932              : 
     933       138505 :       CALL group%sum(trace)
     934              : 
     935       138505 :       CALL timestop(handle)
     936              : 
     937       138505 :    END SUBROUTINE cp_cfm_trace
     938              : 
     939              : ! **************************************************************************************************
     940              : !> \brief Multiplies in place by a triangular matrix:
     941              : !>       matrix_b = alpha op(triangular_matrix) matrix_b
     942              : !>      or (if side='R')
     943              : !>       matrix_b = alpha matrix_b op(triangular_matrix)
     944              : !>      op(triangular_matrix) is:
     945              : !>       triangular_matrix (if transa="N" and invert_tr=.false.)
     946              : !>       triangular_matrix^T (if transa="T" and invert_tr=.false.)
     947              : !>       triangular_matrix^H (if transa="C" and invert_tr=.false.)
     948              : !>       triangular_matrix^(-1) (if transa="N" and invert_tr=.true.)
     949              : !>       triangular_matrix^(-T) (if transa="T" and invert_tr=.true.)
     950              : !>       triangular_matrix^(-H) (if transa="C" and invert_tr=.true.)
     951              : !> \param triangular_matrix the triangular matrix that multiplies the other
     952              : !> \param matrix_b the matrix that gets multiplied and stores the result
     953              : !> \param side on which side of matrix_b stays op(triangular_matrix)
     954              : !>        (defaults to 'L')
     955              : !> \param transa_tr ...
     956              : !> \param invert_tr if the triangular matrix should be inverted
     957              : !>        (defaults to false)
     958              : !> \param uplo_tr if triangular_matrix is stored in the upper ('U') or
     959              : !>        lower ('L') triangle (defaults to 'U')
     960              : !> \param unit_diag_tr if the diagonal elements of triangular_matrix should
     961              : !>        be assumed to be 1 (defaults to false)
     962              : !> \param n_rows the number of rows of the result (defaults to
     963              : !>        size(matrix_b,1))
     964              : !> \param n_cols the number of columns of the result (defaults to
     965              : !>        size(matrix_b,2))
     966              : !> \param alpha ...
     967              : !> \par History
     968              : !>      08.2002 created [fawzi]
     969              : !> \author Fawzi Mohamed
     970              : !> \note
     971              : !>      needs an mpi env
     972              : ! **************************************************************************************************
     973       334852 :    SUBROUTINE cp_cfm_triangular_multiply(triangular_matrix, matrix_b, side, &
     974              :                                          transa_tr, invert_tr, uplo_tr, unit_diag_tr, n_rows, n_cols, &
     975              :                                          alpha)
     976              :       TYPE(cp_cfm_type), INTENT(IN)                      :: triangular_matrix, matrix_b
     977              :       CHARACTER, INTENT(in), OPTIONAL                    :: side, transa_tr
     978              :       LOGICAL, INTENT(in), OPTIONAL                      :: invert_tr
     979              :       CHARACTER, INTENT(in), OPTIONAL                    :: uplo_tr
     980              :       LOGICAL, INTENT(in), OPTIONAL                      :: unit_diag_tr
     981              :       INTEGER, INTENT(in), OPTIONAL                      :: n_rows, n_cols
     982              :       COMPLEX(kind=dp), INTENT(in), OPTIONAL             :: alpha
     983              : 
     984              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_triangular_multiply'
     985              : 
     986              :       CHARACTER                                          :: side_char, transa, unit_diag, uplo
     987              :       COMPLEX(kind=dp)                                   :: al
     988              :       INTEGER                                            :: handle, m, n
     989              :       LOGICAL                                            :: invert
     990              : 
     991       167426 :       CALL timeset(routineN, handle)
     992       167426 :       side_char = 'L'
     993       167426 :       unit_diag = 'N'
     994       167426 :       uplo = 'U'
     995       167426 :       transa = 'N'
     996       167426 :       invert = .FALSE.
     997       167426 :       al = z_one
     998       167426 :       CALL cp_cfm_get_info(matrix_b, nrow_global=m, ncol_global=n)
     999       167426 :       IF (PRESENT(side)) side_char = side
    1000       167426 :       IF (PRESENT(invert_tr)) invert = invert_tr
    1001       167426 :       IF (PRESENT(uplo_tr)) uplo = uplo_tr
    1002       167426 :       IF (PRESENT(unit_diag_tr)) THEN
    1003            0 :          IF (unit_diag_tr) THEN
    1004            0 :             unit_diag = 'U'
    1005              :          ELSE
    1006              :             unit_diag = 'N'
    1007              :          END IF
    1008              :       END IF
    1009       167426 :       IF (PRESENT(transa_tr)) transa = transa_tr
    1010       167426 :       IF (PRESENT(alpha)) al = alpha
    1011       167426 :       IF (PRESENT(n_rows)) m = n_rows
    1012       167426 :       IF (PRESENT(n_cols)) n = n_cols
    1013              : 
    1014       167426 :       IF (invert) THEN
    1015              : 
    1016              : #if defined(__parallel)
    1017              :          CALL pztrsm(side_char, uplo, transa, unit_diag, m, n, al, &
    1018              :                      triangular_matrix%local_data(1, 1), 1, 1, &
    1019              :                      triangular_matrix%matrix_struct%descriptor, &
    1020              :                      matrix_b%local_data(1, 1), 1, 1, &
    1021         1844 :                      matrix_b%matrix_struct%descriptor(1))
    1022              : #else
    1023              :          CALL ztrsm(side_char, uplo, transa, unit_diag, m, n, al, &
    1024              :                     triangular_matrix%local_data(1, 1), &
    1025              :                     SIZE(triangular_matrix%local_data, 1), &
    1026              :                     matrix_b%local_data(1, 1), SIZE(matrix_b%local_data, 1))
    1027              : #endif
    1028              : 
    1029              :       ELSE
    1030              : 
    1031              : #if defined(__parallel)
    1032              :          CALL pztrmm(side_char, uplo, transa, unit_diag, m, n, al, &
    1033              :                      triangular_matrix%local_data(1, 1), 1, 1, &
    1034              :                      triangular_matrix%matrix_struct%descriptor, &
    1035              :                      matrix_b%local_data(1, 1), 1, 1, &
    1036       165582 :                      matrix_b%matrix_struct%descriptor(1))
    1037              : #else
    1038              :          CALL ztrmm(side_char, uplo, transa, unit_diag, m, n, al, &
    1039              :                     triangular_matrix%local_data(1, 1), &
    1040              :                     SIZE(triangular_matrix%local_data, 1), &
    1041              :                     matrix_b%local_data(1, 1), SIZE(matrix_b%local_data, 1))
    1042              : #endif
    1043              : 
    1044              :       END IF
    1045              : 
    1046       167426 :       CALL timestop(handle)
    1047              : 
    1048       167426 :    END SUBROUTINE cp_cfm_triangular_multiply
    1049              : 
    1050              : ! **************************************************************************************************
    1051              : !> \brief Inverts a triangular matrix.
    1052              : !> \param matrix_a ...
    1053              : !> \param uplo ...
    1054              : !> \param info_out ...
    1055              : !> \author MI
    1056              : ! **************************************************************************************************
    1057        55194 :    SUBROUTINE cp_cfm_triangular_invert(matrix_a, uplo, info_out)
    1058              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix_a
    1059              :       CHARACTER, INTENT(in), OPTIONAL          :: uplo
    1060              :       INTEGER, INTENT(out), OPTIONAL           :: info_out
    1061              : 
    1062              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_triangular_invert'
    1063              : 
    1064              :       CHARACTER                                :: unit_diag, my_uplo
    1065              :       INTEGER                                  :: handle, info, ncol_global
    1066              :       COMPLEX(kind=dp), DIMENSION(:, :), &
    1067        55194 :          POINTER                               :: a
    1068              : #if defined(__parallel)
    1069              :       INTEGER, DIMENSION(9)                    :: desca
    1070              : #endif
    1071              : 
    1072        55194 :       CALL timeset(routineN, handle)
    1073              : 
    1074        55194 :       unit_diag = 'N'
    1075        55194 :       my_uplo = 'U'
    1076        55194 :       IF (PRESENT(uplo)) my_uplo = uplo
    1077              : 
    1078        55194 :       ncol_global = matrix_a%matrix_struct%ncol_global
    1079              : 
    1080        55194 :       a => matrix_a%local_data
    1081              : 
    1082              : #if defined(__parallel)
    1083       551940 :       desca(:) = matrix_a%matrix_struct%descriptor(:)
    1084        55194 :       CALL pztrtri(my_uplo, unit_diag, ncol_global, a(1, 1), 1, 1, desca, info)
    1085              : #else
    1086              :       CALL ztrtri(my_uplo, unit_diag, ncol_global, a(1, 1), ncol_global, info)
    1087              : #endif
    1088              : 
    1089        55194 :       IF (PRESENT(info_out)) THEN
    1090            0 :          info_out = info
    1091              :       ELSE
    1092        55194 :          IF (info /= 0) &
    1093              :             CALL cp_abort(__LOCATION__, &
    1094            0 :                           "triangular invert failed: matrix is not positive definite  or ill-conditioned")
    1095              :       END IF
    1096              : 
    1097        55194 :       CALL timestop(handle)
    1098        55194 :    END SUBROUTINE cp_cfm_triangular_invert
    1099              : 
    1100              : ! **************************************************************************************************
    1101              : !> \brief Transposes a BLACS distributed complex matrix.
    1102              : !> \param matrix    input matrix
    1103              : !> \param trans     'T' for transpose, 'C' for Hermitian conjugate
    1104              : !> \param matrixt   output matrix
    1105              : !> \author Lianheng Tong
    1106              : ! **************************************************************************************************
    1107        16742 :    SUBROUTINE cp_cfm_transpose(matrix, trans, matrixt)
    1108              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1109              :       CHARACTER, INTENT(in)                              :: trans
    1110              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrixt
    1111              : 
    1112              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_transpose'
    1113              : 
    1114        16742 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: aa, cc
    1115              :       INTEGER                                            :: handle, ncol_global, nrow_global
    1116              : #if defined(__parallel)
    1117              :       INTEGER, DIMENSION(9)                              :: desca, descc
    1118              : #elif !defined(__MKL)
    1119              :       INTEGER                                            :: ii, jj
    1120              : #endif
    1121              : 
    1122        16742 :       CALL timeset(routineN, handle)
    1123              : 
    1124        16742 :       nrow_global = matrix%matrix_struct%nrow_global
    1125        16742 :       ncol_global = matrix%matrix_struct%ncol_global
    1126              : 
    1127        16742 :       CPASSERT(matrixt%matrix_struct%nrow_global == ncol_global)
    1128        16742 :       CPASSERT(matrixt%matrix_struct%ncol_global == nrow_global)
    1129              : 
    1130        16742 :       aa => matrix%local_data
    1131        16742 :       cc => matrixt%local_data
    1132              : 
    1133              : #if defined(__parallel)
    1134       167420 :       desca = matrix%matrix_struct%descriptor
    1135       167420 :       descc = matrixt%matrix_struct%descriptor
    1136         7496 :       SELECT CASE (trans)
    1137              :       CASE ('T')
    1138              :          CALL pztranu(nrow_global, ncol_global, &
    1139              :                       z_one, aa(1, 1), 1, 1, desca, &
    1140         7496 :                       z_zero, cc(1, 1), 1, 1, descc)
    1141              :       CASE ('C')
    1142              :          CALL pztranc(nrow_global, ncol_global, &
    1143              :                       z_one, aa(1, 1), 1, 1, desca, &
    1144         9246 :                       z_zero, cc(1, 1), 1, 1, descc)
    1145              :       CASE DEFAULT
    1146        16742 :          CPABORT("trans only accepts 'T' or 'C'")
    1147              :       END SELECT
    1148              : #elif defined(__MKL)
    1149              :       CALL mkl_zomatcopy('C', trans, nrow_global, ncol_global, 1.0_dp, aa(1, 1), nrow_global, cc(1, 1), ncol_global)
    1150              : #else
    1151              :       SELECT CASE (trans)
    1152              :       CASE ('T')
    1153              :          DO jj = 1, ncol_global
    1154              :             DO ii = 1, nrow_global
    1155              :                cc(ii, jj) = aa(jj, ii)
    1156              :             END DO
    1157              :          END DO
    1158              :       CASE ('C')
    1159              :          DO jj = 1, ncol_global
    1160              :             DO ii = 1, nrow_global
    1161              :                cc(ii, jj) = CONJG(aa(jj, ii))
    1162              :             END DO
    1163              :          END DO
    1164              :       CASE DEFAULT
    1165              :          CPABORT("trans only accepts 'T' or 'C'")
    1166              :       END SELECT
    1167              : #endif
    1168              : 
    1169        16742 :       CALL timestop(handle)
    1170        16742 :    END SUBROUTINE cp_cfm_transpose
    1171              : 
    1172              : ! **************************************************************************************************
    1173              : !> \brief Norm of matrix using (p)zlange.
    1174              : !> \param matrix     input a general matrix
    1175              : !> \param mode       'M' max abs element value,
    1176              : !>                   '1' or 'O' one norm, i.e. maximum column sum,
    1177              : !>                   'I' infinity norm, i.e. maximum row sum,
    1178              : !>                   'F' or 'E' Frobenius norm, i.e. sqrt of sum of all squares of elements
    1179              : !> \return the norm according to mode
    1180              : !> \author Lianheng Tong
    1181              : ! **************************************************************************************************
    1182       132150 :    FUNCTION cp_cfm_norm(matrix, mode) RESULT(res)
    1183              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1184              :       CHARACTER, INTENT(IN)                              :: mode
    1185              :       REAL(kind=dp)                                      :: res
    1186              : 
    1187              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_norm'
    1188              : 
    1189       132150 :       COMPLEX(kind=dp), DIMENSION(:, :), POINTER         :: aa
    1190              :       INTEGER                                            :: handle, lwork, ncols, ncols_local, &
    1191              :                                                             nrows, nrows_local
    1192       132150 :       REAL(kind=dp), ALLOCATABLE, DIMENSION(:)           :: work
    1193              : 
    1194              : #if defined(__parallel)
    1195              :       INTEGER, DIMENSION(9)                              :: desca
    1196              : #else
    1197              :       INTEGER                                            :: lda
    1198              : #endif
    1199              : 
    1200       132150 :       CALL timeset(routineN, handle)
    1201              : 
    1202              :       CALL cp_cfm_get_info(matrix=matrix, &
    1203              :                            nrow_global=nrows, &
    1204              :                            ncol_global=ncols, &
    1205              :                            nrow_local=nrows_local, &
    1206       132150 :                            ncol_local=ncols_local)
    1207       132150 :       aa => matrix%local_data
    1208              : 
    1209              :       SELECT CASE (mode)
    1210              :       CASE ('M', 'm')
    1211            0 :          lwork = 1
    1212              :       CASE ('1', 'O', 'o')
    1213              : #if defined(__parallel)
    1214            0 :          lwork = ncols_local
    1215              : #else
    1216              :          lwork = 1
    1217              : #endif
    1218              :       CASE ('I', 'i')
    1219              : #if defined(__parallel)
    1220            0 :          lwork = nrows_local
    1221              : #else
    1222              :          lwork = nrows
    1223              : #endif
    1224              :       CASE ('F', 'f', 'E', 'e')
    1225            0 :          lwork = 1
    1226              :       CASE DEFAULT
    1227       132150 :          CPABORT("mode input is not valid")
    1228              :       END SELECT
    1229              : 
    1230       396450 :       ALLOCATE (work(lwork))
    1231              : 
    1232              : #if defined(__parallel)
    1233      1321500 :       desca = matrix%matrix_struct%descriptor
    1234       132150 :       res = pzlange(mode, nrows, ncols, aa(1, 1), 1, 1, desca, work)
    1235              : #else
    1236              :       lda = SIZE(aa, 1)
    1237              :       res = zlange(mode, nrows, ncols, aa(1, 1), lda, work)
    1238              : #endif
    1239              : 
    1240       132150 :       DEALLOCATE (work)
    1241       132150 :       CALL timestop(handle)
    1242       132150 :    END FUNCTION cp_cfm_norm
    1243              : 
    1244              : ! **************************************************************************************************
    1245              : !> \brief Applies a planar rotation defined by cs and sn to the i'th and j'th rows.
    1246              : !> \param matrix ...
    1247              : !> \param irow ...
    1248              : !> \param jrow ...
    1249              : !> \param cs cosine of the rotation angle
    1250              : !> \param sn sinus of the rotation angle
    1251              : !> \author Ole Schuett
    1252              : ! **************************************************************************************************
    1253       375120 :    SUBROUTINE cp_cfm_rot_rows(matrix, irow, jrow, cs, sn)
    1254              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix
    1255              :       INTEGER, INTENT(IN)                      :: irow, jrow
    1256              :       REAL(dp), INTENT(IN)                     :: cs, sn
    1257              : 
    1258              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_rot_rows'
    1259              :       INTEGER                                  :: handle, ncol
    1260              :       COMPLEX(KIND=dp)                         :: sn_cmplx
    1261              : 
    1262              : #if defined(__parallel)
    1263              :       INTEGER                                  :: info, lwork
    1264              :       INTEGER, DIMENSION(9)                    :: desc
    1265       375120 :       REAL(dp), DIMENSION(:), ALLOCATABLE      :: work
    1266              : #endif
    1267       375120 :       CALL timeset(routineN, handle)
    1268       375120 :       CALL cp_cfm_get_info(matrix, ncol_global=ncol)
    1269       375120 :       sn_cmplx = CMPLX(sn, 0.0_dp, dp)
    1270              : #if defined(__parallel)
    1271       375120 :       IF (1 /= matrix%matrix_struct%context%n_pid) THEN
    1272       375120 :          lwork = 2*ncol + 1
    1273      1125360 :          ALLOCATE (work(lwork))
    1274      3751200 :          desc(:) = matrix%matrix_struct%descriptor(:)
    1275       375120 :          info = 0
    1276              :          CALL pzrot(ncol, &
    1277              :                     matrix%local_data(1, 1), irow, 1, desc, ncol, &
    1278              :                     matrix%local_data(1, 1), jrow, 1, desc, ncol, &
    1279       375120 :                     cs, sn_cmplx, work, lwork, info)
    1280       375120 :          CPASSERT(info == 0)
    1281       375120 :          DEALLOCATE (work)
    1282              :       ELSE
    1283              : #endif
    1284            0 :          CALL zrot(ncol, matrix%local_data(irow, 1), ncol, matrix%local_data(jrow, 1), ncol, cs, sn_cmplx)
    1285              : #if defined(__parallel)
    1286              :       END IF
    1287              : #endif
    1288       375120 :       CALL timestop(handle)
    1289       375120 :    END SUBROUTINE cp_cfm_rot_rows
    1290              : 
    1291              : ! **************************************************************************************************
    1292              : !> \brief Applies a planar rotation defined by cs and sn to the i'th and j'th columnns.
    1293              : !> \param matrix ...
    1294              : !> \param icol ...
    1295              : !> \param jcol ...
    1296              : !> \param cs cosine of the rotation angle
    1297              : !> \param sn sinus of the rotation angle
    1298              : !> \author Ole Schuett
    1299              : ! **************************************************************************************************
    1300       422760 :    SUBROUTINE cp_cfm_rot_cols(matrix, icol, jcol, cs, sn)
    1301              :       TYPE(cp_cfm_type), INTENT(IN)            :: matrix
    1302              :       INTEGER, INTENT(IN)                      :: icol, jcol
    1303              :       REAL(dp), INTENT(IN)                     :: cs, sn
    1304              : 
    1305              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_cfm_rot_cols'
    1306              :       INTEGER                                  :: handle, nrow
    1307              :       COMPLEX(KIND=dp)                         :: sn_cmplx
    1308              : 
    1309              : #if defined(__parallel)
    1310              :       INTEGER                                  :: info, lwork
    1311              :       INTEGER, DIMENSION(9)                    :: desc
    1312       422760 :       REAL(dp), DIMENSION(:), ALLOCATABLE      :: work
    1313              : #endif
    1314       422760 :       CALL timeset(routineN, handle)
    1315       422760 :       CALL cp_cfm_get_info(matrix, nrow_global=nrow)
    1316       422760 :       sn_cmplx = CMPLX(sn, 0.0_dp, dp)
    1317              : #if defined(__parallel)
    1318       422760 :       IF (1 /= matrix%matrix_struct%context%n_pid) THEN
    1319       422760 :          lwork = 2*nrow + 1
    1320      1268280 :          ALLOCATE (work(lwork))
    1321      4227600 :          desc(:) = matrix%matrix_struct%descriptor(:)
    1322       422760 :          info = 0
    1323              :          CALL pzrot(nrow, &
    1324              :                     matrix%local_data(1, 1), 1, icol, desc, 1, &
    1325              :                     matrix%local_data(1, 1), 1, jcol, desc, 1, &
    1326       422760 :                     cs, sn_cmplx, work, lwork, info)
    1327       422760 :          CPASSERT(info == 0)
    1328       422760 :          DEALLOCATE (work)
    1329              :       ELSE
    1330              : #endif
    1331            0 :          CALL zrot(nrow, matrix%local_data(1, icol), 1, matrix%local_data(1, jcol), 1, cs, sn_cmplx)
    1332              : #if defined(__parallel)
    1333              :       END IF
    1334              : #endif
    1335       422760 :       CALL timestop(handle)
    1336       422760 :    END SUBROUTINE cp_cfm_rot_cols
    1337              : 
    1338              : ! **************************************************************************************************
    1339              : !> \brief ...
    1340              : !> \param matrix ...
    1341              : !> \param workspace ...
    1342              : !> \param uplo triangular format; defaults to 'U'
    1343              : !> \par History
    1344              : !>      12.2024 Added optional workspace as input [Rocco Meli]
    1345              : !> \author Jan Wilhelm
    1346              : ! **************************************************************************************************
    1347         9752 :    SUBROUTINE cp_cfm_uplo_to_full(matrix, workspace, uplo)
    1348              : 
    1349              :       TYPE(cp_cfm_type), INTENT(IN)                      :: matrix
    1350              :       TYPE(cp_cfm_type), INTENT(IN), OPTIONAL            :: workspace
    1351              :       CHARACTER, INTENT(IN), OPTIONAL                    :: uplo
    1352              : 
    1353              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_cfm_uplo_to_full'
    1354              : 
    1355              :       CHARACTER                                          :: myuplo
    1356              :       INTEGER                                            :: handle, i_global, iiB, j_global, jjB, &
    1357              :                                                             ncol_local, nrow_local
    1358         4876 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1359              :       TYPE(cp_cfm_type)                                  :: work
    1360              : 
    1361         4876 :       CALL timeset(routineN, handle)
    1362              : 
    1363         4876 :       IF (.NOT. PRESENT(workspace)) THEN
    1364         4254 :          CALL cp_cfm_create(work, matrix%matrix_struct)
    1365              :       ELSE
    1366          622 :          work = workspace
    1367              :       END IF
    1368              : 
    1369         4876 :       myuplo = 'U'
    1370         4876 :       IF (PRESENT(uplo)) myuplo = uplo
    1371              : 
    1372              :       ! get info of fm_mat_Q
    1373              :       CALL cp_cfm_get_info(matrix=matrix, &
    1374              :                            nrow_local=nrow_local, &
    1375              :                            ncol_local=ncol_local, &
    1376              :                            row_indices=row_indices, &
    1377         4876 :                            col_indices=col_indices)
    1378              : 
    1379       201894 :       DO jjB = 1, ncol_local
    1380       197018 :          j_global = col_indices(jjB)
    1381      7200178 :          DO iiB = 1, nrow_local
    1382      6998284 :             i_global = row_indices(iiB)
    1383      7195302 :             IF (MERGE(j_global < i_global, j_global > i_global, (myuplo == "U") .OR. (myuplo == "u"))) THEN
    1384      3448489 :                matrix%local_data(iiB, jjB) = z_zero
    1385      3549795 :             ELSE IF (j_global == i_global) THEN
    1386       101306 :                matrix%local_data(iiB, jjB) = matrix%local_data(iiB, jjB)/(2.0_dp, 0.0_dp)
    1387              :             END IF
    1388              :          END DO
    1389              :       END DO
    1390              : 
    1391         4876 :       CALL cp_cfm_transpose(matrix, 'C', work)
    1392              : 
    1393         4876 :       CALL cp_cfm_scale_and_add(z_one, matrix, z_one, work)
    1394              : 
    1395         4876 :       IF (.NOT. PRESENT(workspace)) THEN
    1396         4254 :          CALL cp_cfm_release(work)
    1397              :       END IF
    1398              : 
    1399         4876 :       CALL timestop(handle)
    1400              : 
    1401         4876 :    END SUBROUTINE cp_cfm_uplo_to_full
    1402              : 
    1403              : END MODULE cp_cfm_basic_linalg
        

Generated by: LCOV version 2.0-1