70#if defined (__parallel)
73#if defined (__HAS_IEEE_EXCEPTIONS)
74 USE ieee_exceptions,
ONLY: ieee_get_halting_mode, &
75 ieee_set_halting_mode, &
78#include "../base/base_uses.f90"
83 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
92 INTEGER,
SAVE :: elpa_neigvec_min = 0
96 INTEGER,
SAVE,
PUBLIC :: dlaf_neigvec_min = 0
100 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
107#if defined(__CUSOLVERMP)
147 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
148 elpa_print, elpa_qr_unsafe, dlaf_neigvec_min_input, eps_check_diag_input)
149 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
150 LOGICAL,
INTENT(OUT) :: fallback_applied
151 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
152 LOGICAL,
INTENT(IN) :: elpa_qr, elpa_print, elpa_qr_unsafe
153 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
154 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
156 LOGICAL,
SAVE :: initialized = .false.
158 fallback_applied = .false.
160 IF (diag_lib ==
"ScaLAPACK")
THEN
162 ELSE IF (diag_lib ==
"ELPA")
THEN
169 fallback_applied = .true.
171 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
173 ELSE IF (diag_lib ==
"DLAF")
THEN
177 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
180 cpabort(
"ERROR in diag_init: Initialization of unknown diagonalization library requested")
196 dlaf_neigvec_min = dlaf_neigvec_min_input
198 mark_used(dlaf_neigvec_min_input)
201 elpa_neigvec_min = elpa_neigvec_min_input
202 eps_check_diag = eps_check_diag_input
235 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
236 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
237 INTEGER,
INTENT(OUT),
OPTIONAL :: info
239 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
244 IF (
PRESENT(info)) info = 0
247 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
250 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
252 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
258 IF (matrix%matrix_struct%nrow_global < 64)
THEN
260 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
267 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
269 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
276 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
279 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
289 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
291 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
292 INTEGER,
INTENT(IN) :: nvec
294 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
296 CHARACTER(LEN=default_string_length) :: diag_type_name
297 REAL(kind=
dp) :: eps, eps_abort, eps_warning, gold, test
298 INTEGER :: handle, i, j, ncol, nrow, output_unit
299 LOGICAL :: check_eigenvectors
300#if defined(__parallel)
302 INTEGER :: il, jl, ipcol, iprow, &
303 mypcol, myprow, npcol, nprow
304 INTEGER,
DIMENSION(9) :: desca
307 CALL timeset(routinen, handle)
311#if defined(__CHECK_DIAG)
312 check_eigenvectors = .true.
313 IF (eps_check_diag >= 0.0_dp)
THEN
314 eps_warning = eps_check_diag
317 IF (eps_check_diag >= 0.0_dp)
THEN
318 check_eigenvectors = .true.
319 eps_warning = eps_check_diag
321 check_eigenvectors = .false.
324 eps_abort = 10.0_dp*eps_warning
330 IF (check_eigenvectors)
THEN
331#if defined(__parallel)
332 nrow = eigenvectors%matrix_struct%nrow_global
333 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
334 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
335 context => matrix%matrix_struct%context
336 myprow = context%mepos(1)
337 mypcol = context%mepos(2)
338 nprow = context%num_pe(1)
339 npcol = context%num_pe(2)
340 desca(:) = matrix%matrix_struct%descriptor(:)
341 outer:
DO j = 1, ncol
343 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
344 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
345 gold = merge(0.0_dp, 1.0_dp, i /= j)
346 test = matrix%local_data(il, jl)
347 eps = abs(test - gold)
348 IF (eps > eps_warning)
EXIT outer
353 nrow =
SIZE(eigenvectors%local_data, 1)
354 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
355 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
356 eigenvectors%local_data(1, 1), nrow, &
357 eigenvectors%local_data(1, 1), nrow, &
358 0.0_dp, matrix%local_data(1, 1), nrow)
359 outer:
DO j = 1, ncol
361 gold = merge(0.0_dp, 1.0_dp, i /= j)
362 test = matrix%local_data(i, j)
363 eps = abs(test - gold)
364 IF (eps > eps_warning)
EXIT outer
368 IF (eps > eps_warning)
THEN
370 diag_type_name =
"SYEVD"
372 diag_type_name =
"ELPA"
374 diag_type_name =
"CUSOLVER"
376 diag_type_name =
"DLAF"
378 cpabort(
"Unknown diag_type")
380 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,F0.0,A,ES10.3)") &
381 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
382 "Matrix element (", i,
", ", j,
") = ", test, &
383 "The deviation from the expected value ", gold,
" is", eps
384 IF (eps > eps_abort)
THEN
385 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
387 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
392 CALL timestop(handle)
394 END SUBROUTINE check_diag
402 SUBROUTINE cp_fm_error(mesg, info, warn)
403 CHARACTER(LEN=*),
INTENT(IN) :: mesg
404 INTEGER,
INTENT(IN),
OPTIONAL :: info
405 LOGICAL,
INTENT(IN),
OPTIONAL :: warn
407 CHARACTER(LEN=2*default_string_length) :: message
410 IF (
PRESENT(info))
THEN
411 WRITE (message,
"(A,A,I0,A)") mesg,
" (INFO = ", info,
")"
413 WRITE (message,
"(A)") mesg
416 IF (
PRESENT(warn))
THEN
423 cpwarn(trim(message))
425 cpabort(trim(message))
427 END SUBROUTINE cp_fm_error
444 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
445 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
446 INTEGER,
INTENT(OUT),
OPTIONAL :: info
448 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd'
450 INTEGER :: handle, myinfo, n, nmo
451 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
452#if defined(__parallel)
453 TYPE(
cp_fm_type) :: eigenvectors_new, matrix_new
455 INTEGER :: liwork, lwork
456 INTEGER,
DIMENSION(:),
POINTER :: iwork
457 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
458 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
459 INTEGER,
TARGET :: v(1)
460 REAL(kind=
dp),
TARGET :: w(1)
463 CALL timeset(routinen, handle)
467 n = matrix%matrix_struct%nrow_global
470#if defined(__parallel)
478 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
479 IF (
PRESENT(info))
THEN
480 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
482 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
491 m => matrix%local_data
495 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
497 IF (myinfo /= 0)
THEN
498 CALL cp_fm_error(
"ERROR in DSYEVD: Work space query failed", myinfo,
PRESENT(info))
502 lwork = nint(work(1))
503 ALLOCATE (work(lwork))
506 ALLOCATE (iwork(liwork))
508 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
510 IF (myinfo /= 0)
THEN
511 CALL cp_fm_error(
"ERROR in DSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
520 IF (
PRESENT(info)) info = myinfo
522 nmo =
SIZE(eigenvalues, 1)
524 eigenvalues(1:n) = eig(1:n)
526 eigenvalues(1:nmo) = eig(1:nmo)
531 CALL check_diag(matrix, eigenvectors, n)
533 CALL timestop(handle)
544 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
546 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
547 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
548 INTEGER,
INTENT(OUT),
OPTIONAL :: info
550 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
552 INTEGER :: handle, myinfo
553#if defined(__parallel)
555 INTEGER :: liwork, lwork, n
556 INTEGER,
DIMENSION(9) :: descm, descv
557 INTEGER,
DIMENSION(:),
POINTER :: iwork
558 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
559 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
560 REAL(kind=
dp),
TARGET :: w(1)
561#if defined (__HAS_IEEE_EXCEPTIONS)
562 LOGICAL,
DIMENSION(5) :: halt
566 CALL timeset(routinen, handle)
570#if defined(__parallel)
572 n = matrix%matrix_struct%nrow_global
573 m => matrix%local_data
574 context => matrix%matrix_struct%context
575 descm(:) = matrix%matrix_struct%descriptor(:)
577 v => eigenvectors%local_data
578 descv(:) = eigenvectors%matrix_struct%descriptor(:)
580 liwork = 7*n + 8*context%num_pe(2) + 2
581 ALLOCATE (iwork(liwork))
587 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
588 work(1), lwork, iwork(1), liwork, myinfo)
590 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
591 CALL cp_fm_error(
"ERROR in PDSYEVD: Work space query failed", myinfo,
PRESENT(info))
594 lwork = nint(work(1))
595#if !defined(__SCALAPACK_NO_WA)
597 CALL pdormtr(
'L',
'U',
'N', n, n, m(1, 1), 1, 1, descm, m(1, 1), &
598 v(1, 1), 1, 1, descv, work(1), -1, myinfo)
600 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
601 CALL cp_fm_error(
"ERROR in PDORMTR: Work space query failed", myinfo,
PRESENT(info))
604 IF (lwork < (work(1) + 2*n))
THEN
605 lwork = nint(work(1)) + 2*n
608 ALLOCATE (work(lwork))
611 IF (liwork < iwork(1))
THEN
614 ALLOCATE (iwork(liwork))
619#if defined (__HAS_IEEE_EXCEPTIONS)
620 CALL ieee_get_halting_mode(ieee_all, halt)
621 CALL ieee_set_halting_mode(ieee_all, .false.)
624 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
625 work(1), lwork, iwork(1), liwork, myinfo)
627#if defined (__HAS_IEEE_EXCEPTIONS)
628 CALL ieee_set_halting_mode(ieee_all, halt)
630 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
631 CALL cp_fm_error(
"ERROR in PDSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
634 IF (
PRESENT(info)) info = myinfo
640 mark_used(eigenvectors)
641 mark_used(eigenvalues)
643 IF (
PRESENT(info)) info = myinfo
644 CALL cp_fm_error(
"ERROR in "//trim(routinen)// &
645 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support")
648 CALL timestop(handle)
650 END SUBROUTINE cp_fm_syevd_base
666 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
671 TYPE(
cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
672 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
673 INTEGER,
INTENT(IN),
OPTIONAL :: neig
674 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
676 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
678#if defined(__parallel)
679 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
681 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
686 CHARACTER(LEN=1) :: job_type
687 REAL(kind=
dp) :: abstol, work_syevx_local
688 INTEGER :: handle, info, liwork, lwork, &
689 m, n, nb, npcol, nprow, &
690 output_unit, neig_local
691 LOGICAL :: ionode, needs_evecs
692 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
693 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
694 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
696 REAL(kind=
dp),
EXTERNAL :: dlamch
698#if defined(__parallel)
699 INTEGER :: nn, np0, npe, nq0, nz
700 INTEGER,
DIMENSION(9) :: desca, descz
701 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
702 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
703 INTEGER,
EXTERNAL :: iceil, numroc
706 INTEGER,
EXTERNAL :: ilaenv
708#if defined (__HAS_IEEE_EXCEPTIONS)
709 LOGICAL,
DIMENSION(5) :: halt
713 n = matrix%matrix_struct%nrow_global
715 IF (
PRESENT(neig)) neig_local = neig
716 IF (neig_local == 0)
RETURN
718 CALL timeset(routinen, handle)
720 needs_evecs =
PRESENT(eigenvectors)
723 ionode = logger%para_env%is_source()
724 n = matrix%matrix_struct%nrow_global
727 work_syevx_local = 1.0_dp
728 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
731 IF (needs_evecs)
THEN
738 abstol = 2.0_dp*dlamch(
"S")
740 context => matrix%matrix_struct%context
741 nprow = context%num_pe(1)
742 npcol = context%num_pe(2)
745 eigenvalues(:) = 0.0_dp
746#if defined(__parallel)
748 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
749 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
752 a => matrix%local_data
753 desca(:) = matrix%matrix_struct%descriptor(:)
755 IF (needs_evecs)
THEN
756 z => eigenvectors%local_data
757 descz(:) = eigenvectors%matrix_struct%descriptor(:)
760 z => matrix%local_data
767 nb = matrix%matrix_struct%nrow_block
769 np0 = numroc(nn, nb, 0, 0, nprow)
770 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
772 IF (needs_evecs)
THEN
773 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
774 int(work_syevx_local*real((neig_local - 1)*n,
dp))
776 lwork = 5*n + max(5*nn, nb*(np0 + 1))
778 liwork = 6*max(n, npe + 1, 4)
782 ALLOCATE (iclustr(2*npe))
786 ALLOCATE (iwork(liwork))
787 ALLOCATE (work(lwork))
791#if defined (__HAS_IEEE_EXCEPTIONS)
792 CALL ieee_get_halting_mode(ieee_all, halt)
793 CALL ieee_set_halting_mode(ieee_all, .false.)
795 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
796 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
797#if defined (__HAS_IEEE_EXCEPTIONS)
798 CALL ieee_set_halting_mode(ieee_all, halt)
805 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
808 "liwork = ", liwork, &
811 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
813 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
814 "iclustr = ", iclustr
815 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
819 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
828 a => matrix%local_data
829 IF (needs_evecs)
THEN
830 z => eigenvectors%local_data
833 z => matrix%local_data
838 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
839 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
841 lwork = max((nb + 3)*n, 8*n) + n
846 ALLOCATE (iwork(liwork))
847 ALLOCATE (work(lwork))
854#if defined (__HAS_IEEE_EXCEPTIONS)
855 CALL ieee_get_halting_mode(ieee_all, halt)
856 CALL ieee_set_halting_mode(ieee_all, .false.)
858 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
859 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
860#if defined (__HAS_IEEE_EXCEPTIONS)
861 CALL ieee_set_halting_mode(ieee_all, halt)
867 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
870 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
873 cpabort(
"Error in DSYEVX (ScaLAPACK)")
881 eigenvalues(1:neig_local) = w(1:neig_local)
884 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
886 CALL timestop(handle)
899 SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
902 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
903 REAL(kind=
dp),
DIMENSION(:),
POINTER, &
904 INTENT(INOUT) :: eigval
905 INTEGER,
INTENT(OUT),
OPTIONAL :: info
907 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_svd'
909 INTEGER :: handle, n, m, myinfo, lwork
910 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a
912 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
913 REAL(kind=
dp),
TARGET :: w(1)
914#if defined(__parallel)
915 INTEGER,
DIMENSION(9) :: desca, descu, descvt
918 CALL timeset(routinen, handle)
921 matrix_struct=matrix_a%matrix_struct, &
924 a => matrix_lu%local_data
925 m = matrix_lu%matrix_struct%nrow_global
926 n = matrix_lu%matrix_struct%ncol_global
934#if defined(__parallel)
936 desca(:) = matrix_lu%matrix_struct%descriptor(:)
937 descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
938 descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
941 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
942 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
944 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
945 CALL cp_fm_error(
"ERROR in PDGESVD: Work space query failed", myinfo,
PRESENT(info))
948 lwork = nint(work(1))
949 ALLOCATE (work(lwork))
951 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
952 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
954 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
955 CALL cp_fm_error(
"ERROR in PDGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
959 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
960 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
962 IF (myinfo /= 0)
THEN
963 CALL cp_fm_error(
"ERROR in DGESVD: Work space query failed", myinfo,
PRESENT(info))
966 lwork = nint(work(1))
967 ALLOCATE (work(lwork))
969 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
970 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
972 IF (myinfo /= 0)
THEN
973 CALL cp_fm_error(
"ERROR in DGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
981 IF (
PRESENT(info)) info = myinfo
983 CALL timestop(handle)
996 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
1006 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
1007 INTEGER,
INTENT(OUT) :: n_dependent
1008 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
1009 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
1012 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
1014 INTEGER :: handle, icol_global, &
1016 ncol_global, nrow_global
1017 LOGICAL :: my_verbose
1018 REAL(kind=
dp) :: condition_number, f, p
1019 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
1020 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
1023#if defined(__parallel)
1024 INTEGER :: icol_local, ipcol, iprow, irow_global, irow_local
1027 CALL timeset(routinen, handle)
1029 my_verbose = .false.
1030 IF (
PRESENT(verbose)) my_verbose = verbose
1032 context => matrix%matrix_struct%context
1033 myprow = context%mepos(1)
1034 mypcol = context%mepos(2)
1038 nrow_global = matrix%matrix_struct%nrow_global
1039 ncol_global = matrix%matrix_struct%ncol_global
1041 ALLOCATE (eigenvalues(ncol_global))
1042 eigenvalues(:) = 0.0_dp
1048 IF (
PRESENT(eigvals))
THEN
1049 eigvals(1) = eigenvalues(1)
1050 eigvals(2) = eigenvalues(ncol_global)
1053#if defined(__parallel)
1054 eigenvectors => work%local_data
1058 DO icol_global = 1, ncol_global
1060 IF (eigenvalues(icol_global) < threshold)
THEN
1062 n_dependent = n_dependent + 1
1064 ipcol = work%matrix_struct%g2p_col(icol_global)
1066 IF (mypcol == ipcol)
THEN
1067 icol_local = work%matrix_struct%g2l_col(icol_global)
1068 DO irow_global = 1, nrow_global
1069 iprow = work%matrix_struct%g2p_row(irow_global)
1070 IF (myprow == iprow)
THEN
1071 irow_local = work%matrix_struct%g2l_row(irow_global)
1072 eigenvectors(irow_local, icol_local) = 0.0_dp
1079 f = eigenvalues(icol_global)**p
1081 ipcol = work%matrix_struct%g2p_col(icol_global)
1083 IF (mypcol == ipcol)
THEN
1084 icol_local = work%matrix_struct%g2l_col(icol_global)
1085 DO irow_global = 1, nrow_global
1086 iprow = work%matrix_struct%g2p_row(irow_global)
1087 IF (myprow == iprow)
THEN
1088 irow_local = work%matrix_struct%g2l_row(irow_global)
1089 eigenvectors(irow_local, icol_local) = &
1090 f*eigenvectors(irow_local, icol_local)
1101 eigenvectors => work%local_data
1105 DO icol_global = 1, ncol_global
1107 IF (eigenvalues(icol_global) < threshold)
THEN
1109 n_dependent = n_dependent + 1
1110 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1114 f = eigenvalues(icol_global)**p
1115 eigenvectors(1:nrow_global, icol_global) = &
1116 f*eigenvectors(1:nrow_global, icol_global)
1123 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1127 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1128 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1130 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1131 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1132 "CP_FM_POWER: condition number: ", condition_number
1133 IF (eigenvalues(1) <= 0.0_dp)
THEN
1135 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1137 IF (condition_number > 1.0e12_dp)
THEN
1139 "WARNING: high condition number => possibly ill-conditioned matrix"
1143 DEALLOCATE (eigenvalues)
1145 CALL timestop(handle)
1168 TYPE(
cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1169 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1170 INTEGER,
INTENT(IN) :: start_sec_block
1171 REAL(kind=
dp),
INTENT(IN) :: thresh
1173 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1176 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1178 REAL(kind=
dp) :: tan_theta, tau, c, s
1180 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1182#if defined(__parallel)
1185 INTEGER :: nprow, npcol, block_dim_row, block_dim_col, info, &
1186 ev_row_block_size, iam, mynumrows, mype, npe, q_loc
1187 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1188 INTEGER,
DIMENSION(9) :: desca, descz, &
1193 INTEGER,
EXTERNAL :: numroc
1198 CALL timeset(routinen, handle)
1200#if defined(__parallel)
1201 context => matrix%matrix_struct%context
1202 allgrp = matrix%matrix_struct%para_env
1204 nprow = context%num_pe(1)
1205 npcol = context%num_pe(2)
1207 n = matrix%matrix_struct%nrow_global
1209 a => matrix%local_data
1210 desca(:) = matrix%matrix_struct%descriptor(:)
1211 ev => eigenvectors%local_data
1212 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1218 block_dim_row = start_sec_block - 1
1219 block_dim_col = n - block_dim_row
1220 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1222 mype = matrix%matrix_struct%para_env%mepos
1223 npe = matrix%matrix_struct%para_env%num_pe
1225 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1227 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1228 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1230 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1231 a_loc, 1, 1, desc_a_block, context%get_handle())
1233 CALL allgrp%bcast(a_loc, 0)
1240 ev_row_block_size = n/(nprow*npcol)
1241 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1243 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1245 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1248 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1254 DO q = start_sec_block, n
1256 DO p = 1, (start_sec_block - 1)
1258 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1260 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1262 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1265 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1273 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1274 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1275 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1276 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1277 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1285 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1288 DEALLOCATE (a_loc, ev_loc, c_ip)
1290 CALL ictxt_loc%gridexit()
1294 n = matrix%matrix_struct%nrow_global
1298 a => matrix%local_data
1299 ev => eigenvectors%local_data
1306 DO q = start_sec_block, n
1307 DO p = 1, (start_sec_block - 1)
1309 IF (abs(a(p, q)) > thresh)
THEN
1311 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1313 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1316 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1324 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1325 CALL dscal(n, c, ev(1, p), 1)
1326 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1327 CALL dscal(n, c, ev(1, q), 1)
1328 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1341 CALL timestop(handle)
1354 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1356 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1357 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1360 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1362 INTEGER :: handle, nao, nmo
1364 CALL timeset(routinen, handle)
1367 nmo =
SIZE(eigenvalues)
1387 eigenvalues=eigenvalues)
1393 CALL timestop(handle)
1409 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1410 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1412 REAL(kind=
dp),
INTENT(IN) :: epseig
1414 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1416 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1418 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: evals
1420 CALL timeset(routinen, handle)
1424 nmo =
SIZE(eigenvalues)
1425 ALLOCATE (evals(nao))
1430 evals(:) = -evals(:)
1433 IF (evals(i) < epseig)
THEN
1444 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1447 DO icol = nc + 1, nao
1453 evals(nc + 1:nao) = 1.0_dp
1456 evals(:) = 1.0_dp/sqrt(evals(:))
1459 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1460 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1463 DO icol = nc + 1, nao
1468 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1471 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1475 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 ...
subroutine, public cp_dlaf_finalize()
Finalize DLA-Future and pika runtime.
subroutine, public cp_dlaf_initialize()
Initialize DLA-Future and pika runtime.
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_uplo_to_full(matrix, work, uplo)
given a triangular matrix according to uplo, 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_general_cusolver(amatrix, bmatrix, eigenvectors, eigenvalues)
Driver routine to solve generalized eigenvalue problem A*x = lambda*B*x with cuSOLVERMp.
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
subroutine, public cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
decomposes a quadratic matrix into its singular value decomposition
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, save, public diag_type
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 cp_fm_diag_gen_dlaf(a_matrix, b_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 the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
logical function, public cp_fm_struct_equivalent(fmstruct1, fmstruct2)
returns true if the two matrix structures are equivalent, false otherwise.
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp, set_zero)
creates a new full matrix with the given structure
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_to_fm_submat(msource, mtarget, nrow, ncol, s_firstrow, s_firstcol, t_firstrow, t_firstcol)
copy just a part ot the matrix
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
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.
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
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.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...