53 #if defined (__SCALAPACK)
56 #if defined (__HAS_IEEE_EXCEPTIONS)
57 USE ieee_exceptions,
ONLY: ieee_get_halting_mode, &
58 ieee_set_halting_mode, &
61 #include "../base/base_uses.f90"
67 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
73 INTEGER,
SAVE :: diag_type = 0
76 INTEGER,
SAVE :: elpa_neigvec_min = 0
80 INTEGER,
SAVE :: dlaf_neigvec_min = 0
84 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
91 #if defined(__CUSOLVERMP)
132 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
133 elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
134 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
135 LOGICAL,
INTENT(OUT) :: fallback_applied
136 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
137 LOGICAL,
INTENT(IN) :: elpa_qr, elpa_print, elpa_qr_unsafe
138 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
139 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
141 fallback_applied = .false.
143 IF (diag_lib ==
"ScaLAPACK")
THEN
145 ELSE IF (diag_lib ==
"ELPA")
THEN
152 fallback_applied = .true.
154 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
156 ELSE IF (diag_lib ==
"DLAF")
THEN
160 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
163 cpabort(
"ERROR in diag_init: Initialization of unknown diagonalization library requested")
174 elpa_neigvec_min = elpa_neigvec_min_input
176 dlaf_neigvec_min = dlaf_neigvec_min_input
178 mark_used(dlaf_neigvec_min_input)
180 eps_check_diag = eps_check_diag_input
209 TYPE(cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
210 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
211 INTEGER,
INTENT(OUT),
OPTIONAL :: info
213 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
218 IF (
PRESENT(info)) info = 0
221 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
224 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
226 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
232 IF (matrix%matrix_struct%nrow_global < 64)
THEN
234 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
241 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
243 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
250 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
253 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
263 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
265 TYPE(cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
266 INTEGER,
INTENT(IN) :: nvec
268 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
270 CHARACTER(LEN=default_string_length) :: diag_type_name
271 REAL(kind=
dp) :: eps_abort, eps_warning
272 INTEGER :: handle, i, j, ncol, nrow, output_unit
273 LOGICAL :: check_eigenvectors
274 #if defined(__SCALAPACK)
275 TYPE(cp_blacs_env_type),
POINTER :: context
276 INTEGER :: il, jl, ipcol, iprow, &
277 mypcol, myprow, npcol, nprow
278 INTEGER,
DIMENSION(9) :: desca
281 CALL timeset(routinen, handle)
284 diag_type_name =
"SYEVD"
286 diag_type_name =
"ELPA"
288 diag_type_name =
"CUSOLVER"
290 diag_type_name =
"DLAF"
292 cpabort(
"Unknown diag_type")
298 #if defined(__CHECK_DIAG)
299 check_eigenvectors = .true.
300 IF (eps_check_diag >= 0.0_dp)
THEN
301 eps_warning = eps_check_diag
304 IF (eps_check_diag >= 0.0_dp)
THEN
305 check_eigenvectors = .true.
306 eps_warning = eps_check_diag
308 check_eigenvectors = .false.
311 eps_abort = 10.0_dp*eps_warning
313 IF (check_eigenvectors)
THEN
314 #if defined(__SCALAPACK)
315 nrow = eigenvectors%matrix_struct%nrow_global
316 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
317 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
318 context => matrix%matrix_struct%context
319 myprow = context%mepos(1)
320 mypcol = context%mepos(2)
321 nprow = context%num_pe(1)
322 npcol = context%num_pe(2)
323 desca(:) = matrix%matrix_struct%descriptor(:)
326 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
327 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
329 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_warning)
THEN
330 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
331 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
332 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
333 "The deviation from the expected value 1 is", abs(matrix%local_data(il, jl) - 1.0_dp)
334 IF (abs(matrix%local_data(il, jl) - 1.0_dp) > eps_abort)
THEN
335 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
337 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
341 IF (abs(matrix%local_data(il, jl)) > eps_warning)
THEN
342 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
343 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
344 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(il, jl), &
345 "The deviation from the expected value 0 is", abs(matrix%local_data(il, jl))
346 IF (abs(matrix%local_data(il, jl)) > eps_abort)
THEN
347 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
349 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
357 nrow =
SIZE(eigenvectors%local_data, 1)
358 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
359 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
360 eigenvectors%local_data(1, 1), nrow, &
361 eigenvectors%local_data(1, 1), nrow, &
362 0.0_dp, matrix%local_data(1, 1), nrow)
366 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_warning)
THEN
367 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
368 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
369 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
370 "The deviation from the expected value 1 is", abs(matrix%local_data(i, j) - 1.0_dp)
371 IF (abs(matrix%local_data(i, j) - 1.0_dp) > eps_abort)
THEN
372 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
374 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
378 IF (abs(matrix%local_data(i, j)) > eps_warning)
THEN
379 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,ES10.3)") &
380 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
381 "Matrix element (", i,
", ", j,
") = ", matrix%local_data(i, j), &
382 "The deviation from the expected value 0 is", abs(matrix%local_data(i, j))
383 IF (abs(matrix%local_data(i, j)) > eps_abort)
THEN
384 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
386 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
395 CALL timestop(handle)
397 END SUBROUTINE check_diag
414 TYPE(cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
415 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
416 INTEGER,
INTENT(OUT),
OPTIONAL :: info
418 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd'
420 INTEGER :: handle, myinfo, n, nmo
421 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
422 #if defined(__SCALAPACK)
423 TYPE(cp_fm_type) :: eigenvectors_new, matrix_new
425 CHARACTER(LEN=2*default_string_length) :: message
426 INTEGER :: liwork, lwork, nl
427 INTEGER,
DIMENSION(:),
POINTER :: iwork
428 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
429 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
432 CALL timeset(routinen, handle)
436 n = matrix%matrix_struct%nrow_global
439 #if defined(__SCALAPACK)
447 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
448 IF (
PRESENT(info))
THEN
449 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
451 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
460 m => matrix%local_data
469 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
471 IF (myinfo /= 0)
THEN
472 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Work space query failed (INFO = ", myinfo,
")"
473 IF (
PRESENT(info))
THEN
474 cpwarn(trim(message))
476 cpabort(trim(message))
483 ALLOCATE (work(lwork))
488 ALLOCATE (iwork(liwork))
491 CALL dsyevd(
'V',
'U', n, m(1, 1), nl, eig(1), work(1), lwork, iwork(1), liwork, myinfo)
493 IF (myinfo /= 0)
THEN
494 WRITE (message,
"(A,I0,A)")
"ERROR in DSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
495 IF (
PRESENT(info))
THEN
496 cpwarn(trim(message))
498 cpabort(trim(message))
502 CALL cp_fm_to_fm(matrix, eigenvectors)
508 IF (
PRESENT(info)) info = myinfo
510 nmo =
SIZE(eigenvalues, 1)
512 eigenvalues(1:n) = eig(1:n)
514 eigenvalues(1:nmo) = eig(1:nmo)
519 CALL check_diag(matrix, eigenvectors, n)
521 CALL timestop(handle)
532 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
534 TYPE(cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
535 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
536 INTEGER,
INTENT(OUT),
OPTIONAL :: info
538 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
540 CHARACTER(LEN=2*default_string_length) :: message
541 INTEGER :: handle, myinfo
542 #if defined(__SCALAPACK)
543 TYPE(cp_blacs_env_type),
POINTER :: context
544 INTEGER :: liwork, lwork, &
546 INTEGER,
DIMENSION(9) :: descm, descv
547 INTEGER,
DIMENSION(:),
POINTER :: iwork
548 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
549 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
550 #if defined (__HAS_IEEE_EXCEPTIONS)
551 LOGICAL,
DIMENSION(5) :: halt
555 CALL timeset(routinen, handle)
559 #if defined(__SCALAPACK)
561 n = matrix%matrix_struct%nrow_global
562 m => matrix%local_data
563 context => matrix%matrix_struct%context
564 myprow = context%mepos(1)
565 mypcol = context%mepos(2)
566 descm(:) = matrix%matrix_struct%descriptor(:)
568 v => eigenvectors%local_data
569 descv(:) = eigenvectors%matrix_struct%descriptor(:)
571 liwork = 7*n + 8*context%num_pe(2) + 2
572 ALLOCATE (iwork(liwork))
578 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
579 work(1), lwork, iwork(1), liwork, myinfo)
581 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
582 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Work space query failed (INFO = ", myinfo,
")"
583 IF (
PRESENT(info))
THEN
584 cpwarn(trim(message))
586 cpabort(trim(message))
596 lwork = nint(work(1) + 100000)
599 ALLOCATE (work(lwork))
603 #if defined (__HAS_IEEE_EXCEPTIONS)
604 CALL ieee_get_halting_mode(ieee_all, halt)
605 CALL ieee_set_halting_mode(ieee_all, .false.)
608 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
609 work(1), lwork, iwork(1), liwork, myinfo)
611 #if defined (__HAS_IEEE_EXCEPTIONS)
612 CALL ieee_set_halting_mode(ieee_all, halt)
614 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
615 WRITE (message,
"(A,I0,A)")
"ERROR in PDSYEVD: Matrix diagonalization failed (INFO = ", myinfo,
")"
616 IF (
PRESENT(info))
THEN
617 cpwarn(trim(message))
619 cpabort(trim(message))
623 IF (
PRESENT(info)) info = myinfo
629 mark_used(eigenvectors)
630 mark_used(eigenvalues)
632 IF (
PRESENT(info)) info = myinfo
633 message =
"ERROR in "//trim(routinen)// &
634 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support"
635 cpabort(trim(message))
638 CALL timestop(handle)
640 END SUBROUTINE cp_fm_syevd_base
656 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
660 TYPE(cp_fm_type),
INTENT(IN) :: matrix
661 TYPE(cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
662 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
663 INTEGER,
INTENT(IN),
OPTIONAL :: neig
664 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
666 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
668 #if defined(__SCALAPACK)
669 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
671 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
674 TYPE(cp_blacs_env_type),
POINTER :: context
675 TYPE(cp_logger_type),
POINTER :: logger
676 CHARACTER(LEN=1) :: job_type
677 REAL(kind=
dp) :: abstol, work_syevx_local
678 INTEGER :: handle, info, &
679 liwork, lwork, m, mypcol, &
680 myprow, n, nb, npcol, &
681 nprow, output_unit, &
683 LOGICAL :: ionode, needs_evecs
684 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
685 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
686 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
688 REAL(kind=
dp),
EXTERNAL :: dlamch
690 #if defined(__SCALAPACK)
691 INTEGER :: nn, np0, npe, nq0, nz
692 INTEGER,
DIMENSION(9) :: desca, descz
693 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
694 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
695 INTEGER,
EXTERNAL :: iceil, numroc
696 #if defined (__HAS_IEEE_EXCEPTIONS)
697 LOGICAL,
DIMENSION(5) :: halt
701 INTEGER,
EXTERNAL :: ilaenv
705 n = matrix%matrix_struct%nrow_global
707 IF (
PRESENT(neig)) neig_local = neig
708 IF (neig_local == 0)
RETURN
710 CALL timeset(routinen, handle)
712 needs_evecs =
PRESENT(eigenvectors)
715 ionode = logger%para_env%is_source()
716 n = matrix%matrix_struct%nrow_global
719 work_syevx_local = 1.0_dp
720 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
723 IF (needs_evecs)
THEN
730 abstol = 2.0_dp*dlamch(
"S")
732 context => matrix%matrix_struct%context
733 myprow = context%mepos(1)
734 mypcol = context%mepos(2)
735 nprow = context%num_pe(1)
736 npcol = context%num_pe(2)
739 eigenvalues(:) = 0.0_dp
740 #if defined(__SCALAPACK)
742 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
743 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
746 a => matrix%local_data
747 desca(:) = matrix%matrix_struct%descriptor(:)
749 IF (needs_evecs)
THEN
750 z => eigenvectors%local_data
751 descz(:) = eigenvectors%matrix_struct%descriptor(:)
754 z => matrix%local_data
761 nb = matrix%matrix_struct%nrow_block
763 np0 = numroc(nn, nb, 0, 0, nprow)
764 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
766 IF (needs_evecs)
THEN
767 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
768 int(work_syevx_local*real((neig_local - 1)*n,
dp))
770 lwork = 5*n + max(5*nn, nb*(np0 + 1))
772 liwork = 6*max(n, npe + 1, 4)
776 ALLOCATE (iclustr(2*npe))
780 ALLOCATE (iwork(liwork))
781 ALLOCATE (work(lwork))
785 #if defined (__HAS_IEEE_EXCEPTIONS)
786 CALL ieee_get_halting_mode(ieee_all, halt)
787 CALL ieee_set_halting_mode(ieee_all, .false.)
790 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
791 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
793 #if defined (__HAS_IEEE_EXCEPTIONS)
794 CALL ieee_set_halting_mode(ieee_all, halt)
802 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
805 "liwork = ", liwork, &
808 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
810 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
811 "iclustr = ", iclustr
812 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
816 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
829 a => matrix%local_data
830 IF (needs_evecs)
THEN
831 z => eigenvectors%local_data
834 z => matrix%local_data
839 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
840 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
842 lwork = max((nb + 3)*n, 8*n) + n
847 ALLOCATE (iwork(liwork))
848 ALLOCATE (work(lwork))
853 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
854 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
860 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
863 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
866 cpabort(
"Error in DSYEVX (ScaLAPACK)")
876 eigenvalues(1:neig_local) = w(1:neig_local)
879 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
881 CALL timestop(handle)
895 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
904 TYPE(cp_fm_type),
INTENT(IN) :: matrix, work
905 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
906 INTEGER,
INTENT(OUT) :: n_dependent
907 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
908 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
911 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
913 INTEGER :: handle, icol_global, &
915 ncol_global, npcol, nprow, &
917 LOGICAL :: my_verbose
918 REAL(kind=
dp) :: condition_number, f, p
919 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
920 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
921 TYPE(cp_blacs_env_type),
POINTER :: context
923 #if defined(__SCALAPACK)
924 INTEGER :: icol_local, ipcol, iprow, irow_global, &
925 irow_local, ncol_block, nrow_block
926 INTEGER,
EXTERNAL :: indxg2l, indxg2p
929 CALL timeset(routinen, handle)
932 IF (
PRESENT(verbose)) my_verbose = verbose
934 context => matrix%matrix_struct%context
935 myprow = context%mepos(1)
936 mypcol = context%mepos(2)
937 nprow = context%num_pe(1)
938 npcol = context%num_pe(2)
942 nrow_global = matrix%matrix_struct%nrow_global
943 ncol_global = matrix%matrix_struct%ncol_global
945 ALLOCATE (eigenvalues(ncol_global))
947 eigenvalues(:) = 0.0_dp
953 IF (
PRESENT(eigvals))
THEN
954 eigvals(1) = eigenvalues(1)
955 eigvals(2) = eigenvalues(ncol_global)
958 #if defined(__SCALAPACK)
959 nrow_block = work%matrix_struct%nrow_block
960 ncol_block = work%matrix_struct%ncol_block
962 eigenvectors => work%local_data
966 DO icol_global = 1, ncol_global
968 IF (eigenvalues(icol_global) < threshold)
THEN
970 n_dependent = n_dependent + 1
972 ipcol = indxg2p(icol_global, ncol_block, mypcol, &
973 work%matrix_struct%first_p_pos(2), npcol)
975 IF (mypcol == ipcol)
THEN
976 icol_local = indxg2l(icol_global, ncol_block, mypcol, &
977 work%matrix_struct%first_p_pos(2), npcol)
978 DO irow_global = 1, nrow_global
979 iprow = indxg2p(irow_global, nrow_block, myprow, &
980 work%matrix_struct%first_p_pos(1), nprow)
981 IF (myprow == iprow)
THEN
982 irow_local = indxg2l(irow_global, nrow_block, myprow, &
983 work%matrix_struct%first_p_pos(1), nprow)
984 eigenvectors(irow_local, icol_local) = 0.0_dp
991 f = eigenvalues(icol_global)**p
993 ipcol = indxg2p(icol_global, ncol_block, mypcol, &
994 work%matrix_struct%first_p_pos(2), npcol)
996 IF (mypcol == ipcol)
THEN
997 icol_local = indxg2l(icol_global, ncol_block, mypcol, &
998 work%matrix_struct%first_p_pos(2), npcol)
999 DO irow_global = 1, nrow_global
1000 iprow = indxg2p(irow_global, nrow_block, myprow, &
1001 work%matrix_struct%first_p_pos(1), nprow)
1002 IF (myprow == iprow)
THEN
1003 irow_local = indxg2l(irow_global, nrow_block, myprow, &
1004 work%matrix_struct%first_p_pos(1), nprow)
1005 eigenvectors(irow_local, icol_local) = &
1006 f*eigenvectors(irow_local, icol_local)
1017 eigenvectors => work%local_data
1021 DO icol_global = 1, ncol_global
1023 IF (eigenvalues(icol_global) < threshold)
THEN
1025 n_dependent = n_dependent + 1
1026 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1030 f = eigenvalues(icol_global)**p
1031 eigenvectors(1:nrow_global, icol_global) = &
1032 f*eigenvectors(1:nrow_global, icol_global)
1039 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1043 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1044 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1046 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1047 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1048 "CP_FM_POWER: condition number: ", condition_number
1049 IF (eigenvalues(1) <= 0.0_dp)
THEN
1051 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1053 IF (condition_number > 1.0e12_dp)
THEN
1055 "WARNING: high condition number => possibly ill-conditioned matrix"
1059 DEALLOCATE (eigenvalues)
1061 CALL timestop(handle)
1085 TYPE(cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1086 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1087 INTEGER,
INTENT(IN) :: start_sec_block
1088 REAL(kind=
dp),
INTENT(IN) :: thresh
1090 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1093 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1095 REAL(kind=
dp) :: tan_theta, tau, c, s
1097 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1099 #if defined(__SCALAPACK)
1100 TYPE(cp_blacs_env_type),
POINTER :: context
1102 INTEGER :: myprow, mypcol, nprow, npcol, block_dim_row, block_dim_col, &
1103 info, ev_row_block_size, iam, mynumrows, mype, npe, &
1105 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1106 INTEGER,
DIMENSION(9) :: desca, descz, desc_a_block, &
1108 TYPE(mp_comm_type):: allgrp
1109 TYPE(cp_blacs_type) :: ictxt_loc
1110 INTEGER,
EXTERNAL :: numroc, indxl2g, indxg2l
1115 CALL timeset(routinen, handle)
1117 #if defined(__SCALAPACK)
1118 context => matrix%matrix_struct%context
1119 allgrp = matrix%matrix_struct%para_env
1121 myprow = context%mepos(1)
1122 mypcol = context%mepos(2)
1123 nprow = context%num_pe(1)
1124 npcol = context%num_pe(2)
1126 n = matrix%matrix_struct%nrow_global
1128 a => matrix%local_data
1129 desca(:) = matrix%matrix_struct%descriptor(:)
1130 ev => eigenvectors%local_data
1131 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1137 block_dim_row = start_sec_block - 1
1138 block_dim_col = n - block_dim_row
1139 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1141 mype = matrix%matrix_struct%para_env%mepos
1142 npe = matrix%matrix_struct%para_env%num_pe
1144 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1146 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1147 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1149 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1150 a_loc, 1, 1, desc_a_block, context%get_handle())
1152 CALL allgrp%bcast(a_loc, 0)
1159 ev_row_block_size = n/(nprow*npcol)
1160 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1162 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1164 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1167 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1173 DO q = start_sec_block, n
1175 DO p = 1, (start_sec_block - 1)
1177 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1179 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1181 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1184 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1192 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1193 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1194 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1195 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1196 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1204 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1207 DEALLOCATE (a_loc, ev_loc, c_ip)
1209 CALL ictxt_loc%gridexit()
1213 n = matrix%matrix_struct%nrow_global
1217 a => matrix%local_data
1218 ev => eigenvectors%local_data
1225 DO q = start_sec_block, n
1226 DO p = 1, (start_sec_block - 1)
1228 IF (abs(a(p, q)) > thresh)
THEN
1230 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1232 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1235 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1243 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1244 CALL dscal(n, c, ev(1, p), 1)
1245 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1246 CALL dscal(n, c, ev(1, q), 1)
1247 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1260 CALL timestop(handle)
1273 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1275 TYPE(cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1276 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1277 TYPE(cp_fm_type),
INTENT(IN) :: work
1279 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1281 INTEGER :: handle, nao, nmo
1283 CALL timeset(routinen, handle)
1286 nmo =
SIZE(eigenvalues)
1296 eigenvalues=eigenvalues)
1299 CALL cp_fm_to_fm(work, eigenvectors, nmo)
1301 CALL timestop(handle)
1317 TYPE(cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1318 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1319 TYPE(cp_fm_type),
INTENT(IN) :: work
1320 REAL(kind=
dp),
INTENT(IN) :: epseig
1322 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1324 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1326 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: seigval
1328 CALL timeset(routinen, handle)
1332 nmo =
SIZE(eigenvalues)
1333 ALLOCATE (seigval(nao))
1338 seigval(:) = -seigval(:)
1341 IF (seigval(i) < epseig)
THEN
1352 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1355 DO icol = nc + 1, nao
1361 seigval(nc + 1:nao) = 1.0_dp
1364 seigval(:) = 1.0_dp/sqrt(seigval(:))
1367 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1368 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1371 DO icol = nc + 1, nao
1376 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1379 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1381 DEALLOCATE (seigval)
1383 CALL timestop(handle)
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
methods related to the blacs parallel environment
wrappers for the actual blacs calls. all functionality needed in the code should actually be provide ...
basic linear algebra operations for full matrices
subroutine, public cp_fm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, c_first_row)
computes matrix_c = beta * matrix_c + alpha * ( matrix_a ** transa ) * ( matrix_b ** transb )
subroutine, public cp_fm_column_scale(matrixa, scaling)
scales column i of matrix a with scaling(i)
subroutine, public cp_fm_syrk(uplo, trans, k, alpha, matrix_a, ia, ja, beta, matrix_c)
performs a rank-k update of a symmetric matrix_c matrix_c = beta * matrix_c + alpha * matrix_a * tran...
subroutine, public cp_fm_upper_to_full(matrix, work)
given an upper triangular matrix computes the corresponding full matrix
subroutine, public cp_fm_scale(alpha, matrix_a)
scales a matrix matrix_a = alpha * matrix_b
subroutine, public cp_fm_triangular_invert(matrix_a, uplo_tr)
inverts a triangular matrix
subroutine, public cp_fm_triangular_multiply(triangular_matrix, matrix_b, side, transpose_tr, invert_tr, uplo_tr, unit_diag_tr, n_rows, n_cols, alpha)
multiplies in place by a triangular matrix: matrix_b = alpha op(triangular_matrix) matrix_b or (if si...
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_decompose(matrix, n, info_out)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
subroutine, public cp_fm_diag_cusolver(matrix, eigenvectors, eigenvalues)
Driver routine to diagonalize a FM matrix with the cuSOLVERMp library.
Auxiliary tools to redistribute cp_fm_type matrices before and after diagonalization....
subroutine, public cp_fm_redistribute_end(matrix, eigenvectors, eig, matrix_new, eigenvectors_new)
Redistributes eigenvectors and eigenvalues back to the original communicator group.
subroutine, public cp_fm_redistribute_start(matrix, eigenvectors, matrix_new, eigenvectors_new, caller_is_elpa, redist_info)
Determines the optimal number of CPUs for matrix diagonalization and redistributes the input matrices...
used for collecting some of the diagonalization schemes available for cp_fm_type. cp_fm_power also mo...
subroutine, public cp_fm_block_jacobi(matrix, eigenvectors, eigval, thresh, start_sec_block)
...
real(kind=dp), parameter, public eps_check_diag_default
subroutine, public cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
...
integer, parameter, public fm_diag_type_cusolver
integer, parameter, public fm_diag_type_dlaf
integer, parameter, public fm_diag_type_scalapack
subroutine, public cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
Computes all eigenvalues and vectors of a real symmetric matrix significantly faster than syevx,...
subroutine, public diag_finalize()
Finalize the diagonalization library.
subroutine, public diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
Setup the diagonalization library to be used.
integer, parameter, public fm_diag_type_default
subroutine, public cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
General Eigenvalue Problem AX = BXE Single option version: Cholesky decomposition of B.
subroutine, public choose_eigv_solver(matrix, eigenvectors, eigenvalues, info)
Choose the Eigensolver depending on which library is available ELPA seems to be unstable for small sy...
integer, parameter, public fm_diag_type_elpa
subroutine, public cp_fm_geeig_canon(amatrix, bmatrix, eigenvectors, eigenvalues, work, epseig)
General Eigenvalue Problem AX = BXE Use canonical diagonalization : U*s**(-1/2)
subroutine, public cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
compute eigenvalues and optionally eigenvectors of a real symmetric matrix using scalapack....
subroutine, public cp_fm_diag_dlaf(matrix, eigenvectors, eigenvalues)
...
subroutine, public set_elpa_print(flag)
Sets a flag that determines if additional information about the ELPA diagonalization should be printe...
subroutine, public set_elpa_kernel(requested_kernel)
Sets the active ELPA kernel.
subroutine, public cp_fm_diag_elpa(matrix, eigenvectors, eigenvalues)
Driver routine to diagonalize a FM matrix with the ELPA library.
subroutine, public set_elpa_qr(use_qr, use_qr_unsafe)
Sets flags that determines if ELPA should try to use QR during diagonalization If use_qr = ....
subroutine, public initialize_elpa_library()
Initialize the ELPA library.
subroutine, public finalize_elpa_library()
Finalize the ELPA library.
represent a full matrix distributed on many processors
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_set_element(matrix, irow_global, icol_global, alpha)
sets an element of a matrix
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
integer function, public cp_logger_get_unit_nr(logger, local)
returns the unit nr for the requested kind of log.
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_string_length
Machine interface based on Fortran 2003 and POSIX.
integer, parameter, public default_output_unit
subroutine, public m_memory(mem)
Returns the total amount of memory [bytes] in use, if known, zero otherwise.
Interface to the message passing library MPI.