68#if defined (__parallel)
71#if defined (__HAS_IEEE_EXCEPTIONS)
72 USE ieee_exceptions,
ONLY: ieee_get_halting_mode, &
73 ieee_set_halting_mode, &
76#include "../base/base_uses.f90"
81 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'cp_fm_diag'
90 INTEGER,
SAVE :: elpa_neigvec_min = 0
94 INTEGER,
SAVE,
PUBLIC :: dlaf_neigvec_min = 0
99 REAL(kind=
dp),
SAVE :: eps_check_diag = -1.0_dp
106#if defined(__CUSOLVERMP)
147 SUBROUTINE diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, &
148 elpa_print, elpa_one_stage, dlaf_neigvec_min_input, eps_check_diag_input, &
149 cusolver_generalized_input)
150 CHARACTER(LEN=*),
INTENT(IN) :: diag_lib
151 LOGICAL,
INTENT(OUT) :: fallback_applied
152 INTEGER,
INTENT(IN) :: elpa_kernel, elpa_neigvec_min_input
154 INTEGER,
INTENT(IN) :: dlaf_neigvec_min_input
155 REAL(kind=
dp),
INTENT(IN) :: eps_check_diag_input
156 LOGICAL,
INTENT(IN),
OPTIONAL :: cusolver_generalized_input
158 LOGICAL,
SAVE :: initialized = .false.
160 fallback_applied = .false.
162 IF (diag_lib ==
"ScaLAPACK")
THEN
164 ELSE IF (diag_lib ==
"ELPA")
THEN
171 fallback_applied = .true.
173 ELSE IF (diag_lib ==
"cuSOLVER")
THEN
175 ELSE IF (diag_lib ==
"DLAF")
THEN
179 cpabort(
"ERROR in diag_init: CP2K was not compiled with DLA-Future support")
182 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
203 IF (
PRESENT(cusolver_generalized_input))
THEN
240 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
241 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
242 INTEGER,
INTENT(OUT),
OPTIONAL :: info
244 CHARACTER(LEN=*),
PARAMETER :: routinen =
'choose_eigv_solver'
249 IF (
PRESENT(info)) info = 0
252 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
255 IF (matrix%matrix_struct%nrow_global < elpa_neigvec_min)
THEN
257 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
263 IF (matrix%matrix_struct%nrow_global < 64)
THEN
265 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
272 IF (matrix%matrix_struct%nrow_global < dlaf_neigvec_min)
THEN
274 CALL cp_fm_syevd(matrix, eigenvectors, eigenvalues, info)
281 cpabort(
"ERROR in "//routinen//
": Invalid diagonalization type requested")
284 CALL check_diag(matrix, eigenvectors, nvec=
SIZE(eigenvalues))
294 SUBROUTINE check_diag(matrix, eigenvectors, nvec)
296 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
297 INTEGER,
INTENT(IN) :: nvec
299 CHARACTER(LEN=*),
PARAMETER :: routinen =
'check_diag'
301 CHARACTER(LEN=default_string_length) :: diag_type_name
302 REAL(kind=
dp) :: eps, eps_abort, eps_warning, gold, test
303 INTEGER :: handle, i, j, ncol, nrow, output_unit
304 LOGICAL :: check_eigenvectors
305#if defined(__parallel)
307 INTEGER :: il, jl, ipcol, iprow, &
308 mypcol, myprow, npcol, nprow
309 INTEGER,
DIMENSION(9) :: desca
312 CALL timeset(routinen, handle)
316#if defined(__CHECK_DIAG)
317 check_eigenvectors = .true.
318 IF (eps_check_diag >= 0.0_dp)
THEN
319 eps_warning = eps_check_diag
322 IF (eps_check_diag >= 0.0_dp)
THEN
323 check_eigenvectors = .true.
324 eps_warning = eps_check_diag
326 check_eigenvectors = .false.
329 eps_abort = 10.0_dp*eps_warning
335 IF (check_eigenvectors)
THEN
336#if defined(__parallel)
337 nrow = eigenvectors%matrix_struct%nrow_global
338 ncol = min(eigenvectors%matrix_struct%ncol_global, nvec)
339 CALL cp_fm_gemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, eigenvectors, eigenvectors, 0.0_dp, matrix)
340 context => matrix%matrix_struct%context
341 myprow = context%mepos(1)
342 mypcol = context%mepos(2)
343 nprow = context%num_pe(1)
344 npcol = context%num_pe(2)
345 desca(:) = matrix%matrix_struct%descriptor(:)
346 outer:
DO j = 1, ncol
348 CALL infog2l(i, j, desca, nprow, npcol, myprow, mypcol, il, jl, iprow, ipcol)
349 IF ((iprow == myprow) .AND. (ipcol == mypcol))
THEN
350 gold = merge(0.0_dp, 1.0_dp, i /= j)
351 test = matrix%local_data(il, jl)
352 eps = abs(test - gold)
353 IF (eps > eps_warning)
EXIT outer
358 nrow =
SIZE(eigenvectors%local_data, 1)
359 ncol = min(
SIZE(eigenvectors%local_data, 2), nvec)
360 CALL dgemm(
"T",
"N", ncol, ncol, nrow, 1.0_dp, &
361 eigenvectors%local_data(1, 1), nrow, &
362 eigenvectors%local_data(1, 1), nrow, &
363 0.0_dp, matrix%local_data(1, 1), nrow)
364 outer:
DO j = 1, ncol
366 gold = merge(0.0_dp, 1.0_dp, i /= j)
367 test = matrix%local_data(i, j)
368 eps = abs(test - gold)
369 IF (eps > eps_warning)
EXIT outer
373 IF (eps > eps_warning)
THEN
375 diag_type_name =
"SYEVD"
377 diag_type_name =
"ELPA"
379 diag_type_name =
"CUSOLVER"
381 diag_type_name =
"DLAF"
383 cpabort(
"Unknown diag_type")
385 WRITE (unit=output_unit, fmt=
"(/,T2,A,/,T2,A,I0,A,I0,A,F0.15,/,T2,A,F0.0,A,ES10.3)") &
386 "The eigenvectors returned by "//trim(diag_type_name)//
" are not orthonormal", &
387 "Matrix element (", i,
", ", j,
") = ", test, &
388 "The deviation from the expected value ", gold,
" is", eps
389 IF (eps > eps_abort)
THEN
390 cpabort(
"ERROR in "//routinen//
": Check of matrix diagonalization failed")
392 cpwarn(
"Check of matrix diagonalization failed in routine "//routinen)
397 CALL timestop(handle)
399 END SUBROUTINE check_diag
407 SUBROUTINE cp_fm_error(mesg, info, warn)
408 CHARACTER(LEN=*),
INTENT(IN) :: mesg
409 INTEGER,
INTENT(IN),
OPTIONAL :: info
410 LOGICAL,
INTENT(IN),
OPTIONAL :: warn
412 CHARACTER(LEN=2*default_string_length) :: message
415 IF (
PRESENT(info))
THEN
416 WRITE (message,
"(A,A,I0,A)") mesg,
" (INFO = ", info,
")"
418 WRITE (message,
"(A)") mesg
421 IF (
PRESENT(warn))
THEN
428 cpwarn(trim(message))
430 cpabort(trim(message))
432 END SUBROUTINE cp_fm_error
449 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
450 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
451 INTEGER,
INTENT(OUT),
OPTIONAL :: info
453 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd'
455 INTEGER :: handle, myinfo, n, nmo
456 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
457#if defined(__parallel)
458 TYPE(
cp_fm_type) :: eigenvectors_new, matrix_new
460 INTEGER :: liwork, lwork
461 INTEGER,
DIMENSION(:),
POINTER :: iwork
462 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m
463 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
464 INTEGER,
TARGET :: v(1)
465 REAL(kind=
dp),
TARGET :: w(1)
468 CALL timeset(routinen, handle)
472 n = matrix%matrix_struct%nrow_global
475#if defined(__parallel)
483 IF (
ASSOCIATED(matrix_new%matrix_struct))
THEN
484 IF (
PRESENT(info))
THEN
485 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig, myinfo)
487 CALL cp_fm_syevd_base(matrix_new, eigenvectors_new, eig)
496 m => matrix%local_data
500 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
502 IF (myinfo /= 0)
THEN
503 CALL cp_fm_error(
"ERROR in DSYEVD: Work space query failed", myinfo,
PRESENT(info))
507 lwork = nint(work(1))
508 ALLOCATE (work(lwork))
511 ALLOCATE (iwork(liwork))
513 CALL dsyevd(
'V',
'U', n, m(1, 1),
SIZE(m, 1), eig(1), work(1), lwork, iwork(1), liwork, myinfo)
515 IF (myinfo /= 0)
THEN
516 CALL cp_fm_error(
"ERROR in DSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
525 IF (
PRESENT(info)) info = myinfo
527 nmo =
SIZE(eigenvalues, 1)
529 eigenvalues(1:n) = eig(1:n)
531 eigenvalues(1:nmo) = eig(1:nmo)
536 CALL check_diag(matrix, eigenvectors, n)
538 CALL timestop(handle)
549 SUBROUTINE cp_fm_syevd_base(matrix, eigenvectors, eigenvalues, info)
551 TYPE(
cp_fm_type),
INTENT(IN) :: matrix, eigenvectors
552 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
553 INTEGER,
INTENT(OUT),
OPTIONAL :: info
555 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_syevd_base'
557 INTEGER :: handle, myinfo
558#if defined(__parallel)
560 INTEGER :: liwork, lwork, n
561 INTEGER,
DIMENSION(9) :: descm, descv
562 INTEGER,
DIMENSION(:),
POINTER :: iwork
563 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
564 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: m, v
565 REAL(kind=
dp),
TARGET :: w(1)
566#if defined (__HAS_IEEE_EXCEPTIONS)
567 LOGICAL,
DIMENSION(5) :: halt
571 CALL timeset(routinen, handle)
575#if defined(__parallel)
577 n = matrix%matrix_struct%nrow_global
578 m => matrix%local_data
579 context => matrix%matrix_struct%context
580 descm(:) = matrix%matrix_struct%descriptor(:)
582 v => eigenvectors%local_data
583 descv(:) = eigenvectors%matrix_struct%descriptor(:)
585 liwork = 7*n + 8*context%num_pe(2) + 2
586 ALLOCATE (iwork(liwork))
592 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
593 work(1), lwork, iwork(1), liwork, myinfo)
595 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
596 CALL cp_fm_error(
"ERROR in PDSYEVD: Work space query failed", myinfo,
PRESENT(info))
599 lwork = nint(work(1))
600#if !defined(__SCALAPACK_NO_WA)
602 CALL pdormtr(
'L',
'U',
'N', n, n, m(1, 1), 1, 1, descm, m(1, 1), &
603 v(1, 1), 1, 1, descv, work(1), -1, myinfo)
605 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
606 CALL cp_fm_error(
"ERROR in PDORMTR: Work space query failed", myinfo,
PRESENT(info))
609 IF (lwork < (work(1) + 2*n))
THEN
610 lwork = nint(work(1)) + 2*n
613 ALLOCATE (work(lwork))
616 IF (liwork < iwork(1))
THEN
619 ALLOCATE (iwork(liwork))
624#if defined (__HAS_IEEE_EXCEPTIONS)
625 CALL ieee_get_halting_mode(ieee_all, halt)
626 CALL ieee_set_halting_mode(ieee_all, .false.)
629 CALL pdsyevd(
'V',
'U', n, m(1, 1), 1, 1, descm, eigenvalues(1), v(1, 1), 1, 1, descv, &
630 work(1), lwork, iwork(1), liwork, myinfo)
632#if defined (__HAS_IEEE_EXCEPTIONS)
633 CALL ieee_set_halting_mode(ieee_all, halt)
635 IF (matrix%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
636 CALL cp_fm_error(
"ERROR in PDSYEVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
639 IF (
PRESENT(info)) info = myinfo
645 mark_used(eigenvectors)
646 mark_used(eigenvalues)
648 IF (
PRESENT(info)) info = myinfo
649 CALL cp_fm_error(
"ERROR in "//trim(routinen)// &
650 ": Matrix diagonalization using PDSYEVD requested without ScaLAPACK support")
653 CALL timestop(handle)
655 END SUBROUTINE cp_fm_syevd_base
671 SUBROUTINE cp_fm_syevx(matrix, eigenvectors, eigenvalues, neig, work_syevx)
676 TYPE(
cp_fm_type),
OPTIONAL,
INTENT(IN) :: eigenvectors
677 REAL(kind=
dp),
OPTIONAL,
INTENT(IN) :: work_syevx
678 INTEGER,
INTENT(IN),
OPTIONAL :: neig
679 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
681 CHARACTER(LEN=*),
PARAMETER :: routinen =
"cp_fm_syevx"
683#if defined(__parallel)
684 REAL(kind=
dp),
PARAMETER :: orfac = -1.0_dp
686 REAL(kind=
dp),
PARAMETER :: vl = 0.0_dp, &
691 CHARACTER(LEN=1) :: job_type
692 REAL(kind=
dp) :: abstol, work_syevx_local
693 INTEGER :: handle, info, liwork, lwork, &
694 m, n, nb, npcol, nprow, &
695 output_unit, neig_local
696 LOGICAL :: ionode, needs_evecs
697 INTEGER,
DIMENSION(:),
ALLOCATABLE :: ifail, iwork
698 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: w, work
699 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, z
701 REAL(kind=
dp),
EXTERNAL :: dlamch
703#if defined(__parallel)
704 INTEGER :: nn, np0, npe, nq0, nz
705 INTEGER,
DIMENSION(9) :: desca, descz
706 INTEGER,
DIMENSION(:),
ALLOCATABLE :: iclustr
707 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: gap
708 INTEGER,
EXTERNAL :: iceil, numroc
711 INTEGER,
EXTERNAL :: ilaenv
713#if defined (__HAS_IEEE_EXCEPTIONS)
714 LOGICAL,
DIMENSION(5) :: halt
718 n = matrix%matrix_struct%nrow_global
720 IF (
PRESENT(neig)) neig_local = neig
721 IF (neig_local == 0)
RETURN
723 CALL timeset(routinen, handle)
725 needs_evecs =
PRESENT(eigenvectors)
728 ionode = logger%para_env%is_source()
729 n = matrix%matrix_struct%nrow_global
732 work_syevx_local = 1.0_dp
733 IF (
PRESENT(work_syevx)) work_syevx_local = work_syevx
736 IF (needs_evecs)
THEN
743 abstol = 2.0_dp*dlamch(
"S")
745 context => matrix%matrix_struct%context
746 nprow = context%num_pe(1)
747 npcol = context%num_pe(2)
750 eigenvalues(:) = 0.0_dp
751#if defined(__parallel)
753 IF (matrix%matrix_struct%nrow_block /= matrix%matrix_struct%ncol_block)
THEN
754 cpabort(
"ERROR in "//routinen//
": Invalid blocksize (no square blocks) found")
757 a => matrix%local_data
758 desca(:) = matrix%matrix_struct%descriptor(:)
760 IF (needs_evecs)
THEN
761 z => eigenvectors%local_data
762 descz(:) = eigenvectors%matrix_struct%descriptor(:)
765 z => matrix%local_data
772 nb = matrix%matrix_struct%nrow_block
774 np0 = numroc(nn, nb, 0, 0, nprow)
775 nq0 = max(numroc(nn, nb, 0, 0, npcol), nb)
777 IF (needs_evecs)
THEN
778 lwork = 5*n + max(5*nn, np0*nq0) + iceil(neig_local, npe)*nn + 2*nb*nb + &
779 int(work_syevx_local*real((neig_local - 1)*n,
dp))
781 lwork = 5*n + max(5*nn, nb*(np0 + 1))
783 liwork = 6*max(n, npe + 1, 4)
787 ALLOCATE (iclustr(2*npe))
791 ALLOCATE (iwork(liwork))
792 ALLOCATE (work(lwork))
796#if defined (__HAS_IEEE_EXCEPTIONS)
797 CALL ieee_get_halting_mode(ieee_all, halt)
798 CALL ieee_set_halting_mode(ieee_all, .false.)
800 CALL pdsyevx(job_type,
"I",
"U", n, a(1, 1), 1, 1, desca, vl, vu, 1, neig_local, abstol, m, nz, w(1), orfac, &
801 z(1, 1), 1, 1, descz, work(1), lwork, iwork(1), liwork, ifail(1), iclustr(1), gap, info)
802#if defined (__HAS_IEEE_EXCEPTIONS)
803 CALL ieee_set_halting_mode(ieee_all, halt)
810 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
813 "liwork = ", liwork, &
816 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
818 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
819 "iclustr = ", iclustr
820 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,E10.3)))") &
824 cpabort(
"ERROR in PDSYEVX (ScaLAPACK)")
833 a => matrix%local_data
834 IF (needs_evecs)
THEN
835 z => eigenvectors%local_data
838 z => matrix%local_data
843 nb = max(ilaenv(1,
"DSYTRD",
"U", n, -1, -1, -1), &
844 ilaenv(1,
"DORMTR",
"U", n, -1, -1, -1))
846 lwork = max((nb + 3)*n, 8*n) + n
851 ALLOCATE (iwork(liwork))
852 ALLOCATE (work(lwork))
859#if defined (__HAS_IEEE_EXCEPTIONS)
860 CALL ieee_get_halting_mode(ieee_all, halt)
861 CALL ieee_set_halting_mode(ieee_all, .false.)
863 CALL dsyevx(job_type,
"I",
"U", n, a(1, 1), nla, vl, vu, 1, neig_local, &
864 abstol, m, w, z(1, 1), nlz, work(1), lwork, iwork(1), ifail(1), info)
865#if defined (__HAS_IEEE_EXCEPTIONS)
866 CALL ieee_set_halting_mode(ieee_all, halt)
872 WRITE (unit=output_unit, fmt=
"(/,(T3,A,T12,1X,I10))") &
875 WRITE (unit=output_unit, fmt=
"(/,T3,A,(T12,6(1X,I10)))") &
878 cpabort(
"Error in DSYEVX (ScaLAPACK)")
886 eigenvalues(1:neig_local) = w(1:neig_local)
889 IF (needs_evecs)
CALL check_diag(matrix, eigenvectors, neig_local)
891 CALL timestop(handle)
904 SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
907 TYPE(
cp_fm_type),
INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
908 REAL(kind=
dp),
DIMENSION(:),
POINTER, &
909 INTENT(INOUT) :: eigval
910 INTEGER,
INTENT(OUT),
OPTIONAL :: info
912 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_svd'
914 INTEGER :: handle, n, m, myinfo, lwork
915 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a
917 REAL(kind=
dp),
DIMENSION(:),
POINTER :: work
918 REAL(kind=
dp),
TARGET :: w(1)
919#if defined(__parallel)
920 INTEGER,
DIMENSION(9) :: desca, descu, descvt
923 CALL timeset(routinen, handle)
926 matrix_struct=matrix_a%matrix_struct, &
929 a => matrix_lu%local_data
930 m = matrix_lu%matrix_struct%nrow_global
931 n = matrix_lu%matrix_struct%ncol_global
939#if defined(__parallel)
941 desca(:) = matrix_lu%matrix_struct%descriptor(:)
942 descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
943 descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
946 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
947 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
949 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
950 CALL cp_fm_error(
"ERROR in PDGESVD: Work space query failed", myinfo,
PRESENT(info))
953 lwork = nint(work(1))
954 ALLOCATE (work(lwork))
956 CALL pdgesvd(
'V',
'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
957 1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
959 IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0))
THEN
960 CALL cp_fm_error(
"ERROR in PDGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
964 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
965 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
967 IF (myinfo /= 0)
THEN
968 CALL cp_fm_error(
"ERROR in DGESVD: Work space query failed", myinfo,
PRESENT(info))
971 lwork = nint(work(1))
972 ALLOCATE (work(lwork))
974 CALL dgesvd(
'S',
'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
975 m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
977 IF (myinfo /= 0)
THEN
978 CALL cp_fm_error(
"ERROR in DGESVD: Matrix diagonalization failed", myinfo,
PRESENT(info))
986 IF (
PRESENT(info)) info = myinfo
988 CALL timestop(handle)
1001 SUBROUTINE cp_fm_power(matrix, work, exponent, threshold, n_dependent, verbose, eigvals)
1011 REAL(kind=
dp),
INTENT(IN) :: exponent, threshold
1012 INTEGER,
INTENT(OUT) :: n_dependent
1013 LOGICAL,
INTENT(IN),
OPTIONAL :: verbose
1014 REAL(kind=
dp),
DIMENSION(2),
INTENT(OUT), &
1017 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cp_fm_power'
1019 INTEGER :: handle, icol_global, &
1021 ncol_global, nrow_global
1022 LOGICAL :: my_verbose
1023 REAL(kind=
dp) :: condition_number, f, p
1024 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: eigenvalues
1025 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: eigenvectors
1028#if defined(__parallel)
1029 INTEGER :: icol_local, ipcol, iprow, irow_global, irow_local
1032 CALL timeset(routinen, handle)
1034 my_verbose = .false.
1035 IF (
PRESENT(verbose)) my_verbose = verbose
1037 context => matrix%matrix_struct%context
1038 myprow = context%mepos(1)
1039 mypcol = context%mepos(2)
1043 nrow_global = matrix%matrix_struct%nrow_global
1044 ncol_global = matrix%matrix_struct%ncol_global
1046 ALLOCATE (eigenvalues(ncol_global))
1047 eigenvalues(:) = 0.0_dp
1053 IF (
PRESENT(eigvals))
THEN
1054 eigvals(1) = eigenvalues(1)
1055 eigvals(2) = eigenvalues(ncol_global)
1058#if defined(__parallel)
1059 eigenvectors => work%local_data
1063 DO icol_global = 1, ncol_global
1065 IF (eigenvalues(icol_global) < threshold)
THEN
1067 n_dependent = n_dependent + 1
1069 ipcol = work%matrix_struct%g2p_col(icol_global)
1071 IF (mypcol == ipcol)
THEN
1072 icol_local = work%matrix_struct%g2l_col(icol_global)
1073 DO irow_global = 1, nrow_global
1074 iprow = work%matrix_struct%g2p_row(irow_global)
1075 IF (myprow == iprow)
THEN
1076 irow_local = work%matrix_struct%g2l_row(irow_global)
1077 eigenvectors(irow_local, icol_local) = 0.0_dp
1084 f = eigenvalues(icol_global)**p
1086 ipcol = work%matrix_struct%g2p_col(icol_global)
1088 IF (mypcol == ipcol)
THEN
1089 icol_local = work%matrix_struct%g2l_col(icol_global)
1090 DO irow_global = 1, nrow_global
1091 iprow = work%matrix_struct%g2p_row(irow_global)
1092 IF (myprow == iprow)
THEN
1093 irow_local = work%matrix_struct%g2l_row(irow_global)
1094 eigenvectors(irow_local, icol_local) = &
1095 f*eigenvectors(irow_local, icol_local)
1106 eigenvectors => work%local_data
1110 DO icol_global = 1, ncol_global
1112 IF (eigenvalues(icol_global) < threshold)
THEN
1114 n_dependent = n_dependent + 1
1115 eigenvectors(1:nrow_global, icol_global) = 0.0_dp
1119 f = eigenvalues(icol_global)**p
1120 eigenvectors(1:nrow_global, icol_global) = &
1121 f*eigenvectors(1:nrow_global, icol_global)
1128 CALL cp_fm_syrk(
"U",
"N", ncol_global, 1.0_dp, work, 1, 1, 0.0_dp, matrix)
1132 IF (matrix%matrix_struct%para_env%is_source() .AND. my_verbose)
THEN
1133 condition_number = abs(eigenvalues(ncol_global)/eigenvalues(1))
1135 "CP_FM_POWER: smallest eigenvalue:", eigenvalues(1), &
1136 "CP_FM_POWER: largest eigenvalue: ", eigenvalues(ncol_global), &
1137 "CP_FM_POWER: condition number: ", condition_number
1138 IF (eigenvalues(1) <= 0.0_dp)
THEN
1140 "WARNING: matrix has a negative eigenvalue, tighten EPS_DEFAULT"
1142 IF (condition_number > 1.0e12_dp)
THEN
1144 "WARNING: high condition number => possibly ill-conditioned matrix"
1148 DEALLOCATE (eigenvalues)
1150 CALL timestop(handle)
1173 TYPE(
cp_fm_type),
INTENT(IN) :: eigenvectors, matrix
1174 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigval
1175 INTEGER,
INTENT(IN) :: start_sec_block
1176 REAL(kind=
dp),
INTENT(IN) :: thresh
1178 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_block_jacobi'
1181 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: a, ev
1183 REAL(kind=
dp) :: tan_theta, tau, c, s
1185 REAL(kind=
dp),
DIMENSION(:),
ALLOCATABLE :: c_ip
1187#if defined(__parallel)
1190 INTEGER :: nprow, npcol, block_dim_row, block_dim_col, info, &
1191 ev_row_block_size, iam, mynumrows, mype, npe, q_loc
1192 REAL(kind=
dp),
DIMENSION(:, :),
ALLOCATABLE :: a_loc, ev_loc
1193 INTEGER,
DIMENSION(9) :: desca, descz, &
1198 INTEGER,
EXTERNAL :: numroc
1203 CALL timeset(routinen, handle)
1205#if defined(__parallel)
1206 context => matrix%matrix_struct%context
1207 allgrp = matrix%matrix_struct%para_env
1209 nprow = context%num_pe(1)
1210 npcol = context%num_pe(2)
1212 n = matrix%matrix_struct%nrow_global
1214 a => matrix%local_data
1215 desca(:) = matrix%matrix_struct%descriptor(:)
1216 ev => eigenvectors%local_data
1217 descz(:) = eigenvectors%matrix_struct%descriptor(:)
1223 block_dim_row = start_sec_block - 1
1224 block_dim_col = n - block_dim_row
1225 ALLOCATE (a_loc(block_dim_row, block_dim_col))
1227 mype = matrix%matrix_struct%para_env%mepos
1228 npe = matrix%matrix_struct%para_env%num_pe
1230 CALL ictxt_loc%gridinit(matrix%matrix_struct%para_env,
'Row-major', nprow*npcol, 1)
1232 CALL descinit(desc_a_block, block_dim_row, block_dim_col, block_dim_row, &
1233 block_dim_col, 0, 0, ictxt_loc%get_handle(), block_dim_row, info)
1235 CALL pdgemr2d(block_dim_row, block_dim_col, a, 1, start_sec_block, desca, &
1236 a_loc, 1, 1, desc_a_block, context%get_handle())
1238 CALL allgrp%bcast(a_loc, 0)
1245 ev_row_block_size = n/(nprow*npcol)
1246 mynumrows = numroc(n, ev_row_block_size, iam, 0, nprow*npcol)
1248 ALLOCATE (ev_loc(mynumrows, n), c_ip(mynumrows))
1250 CALL descinit(desc_ev_loc, n, n, ev_row_block_size, n, 0, 0, ictxt_loc%get_handle(), &
1253 CALL pdgemr2d(n, n, ev, 1, 1, descz, ev_loc, 1, 1, desc_ev_loc, context%get_handle())
1259 DO q = start_sec_block, n
1261 DO p = 1, (start_sec_block - 1)
1263 IF (abs(a_loc(p, q_loc)) > thresh)
THEN
1265 tau = (eigval(q) - eigval(p))/(2.0_dp*a_loc(p, q_loc))
1267 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1270 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1278 CALL dcopy(mynumrows, ev_loc(1, p), 1, c_ip(1), 1)
1279 CALL dscal(mynumrows, c, ev_loc(1, p), 1)
1280 CALL daxpy(mynumrows, -s, ev_loc(1, q), 1, ev_loc(1, p), 1)
1281 CALL dscal(mynumrows, c, ev_loc(1, q), 1)
1282 CALL daxpy(mynumrows, s, c_ip(1), 1, ev_loc(1, q), 1)
1290 CALL pdgemr2d(n, n, ev_loc, 1, 1, desc_ev_loc, ev, 1, 1, descz, context%get_handle())
1293 DEALLOCATE (a_loc, ev_loc, c_ip)
1295 CALL ictxt_loc%gridexit()
1299 n = matrix%matrix_struct%nrow_global
1303 a => matrix%local_data
1304 ev => eigenvectors%local_data
1311 DO q = start_sec_block, n
1312 DO p = 1, (start_sec_block - 1)
1314 IF (abs(a(p, q)) > thresh)
THEN
1316 tau = (eigval(q) - eigval(p))/(2.0_dp*a(p, q))
1318 tan_theta = sign(1.0_dp, tau)/(abs(tau) + sqrt(1.0_dp + tau*tau))
1321 c = 1.0_dp/sqrt(1.0_dp + tan_theta*tan_theta)
1329 CALL dcopy(n, ev(1, p), 1, c_ip(1), 1)
1330 CALL dscal(n, c, ev(1, p), 1)
1331 CALL daxpy(n, -s, ev(1, q), 1, ev(1, p), 1)
1332 CALL dscal(n, c, ev(1, q), 1)
1333 CALL daxpy(n, s, c_ip(1), 1, ev(1, q), 1)
1346 CALL timestop(handle)
1359 SUBROUTINE cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
1361 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1362 REAL(kind=
dp),
DIMENSION(:) :: eigenvalues
1365 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig'
1367 INTEGER :: handle, nao, nmo
1369 CALL timeset(routinen, handle)
1372 nmo =
SIZE(eigenvalues)
1394 eigenvalues=eigenvalues)
1400 CALL timestop(handle)
1416 TYPE(
cp_fm_type),
INTENT(IN) :: amatrix, bmatrix, eigenvectors
1417 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: eigenvalues
1419 REAL(kind=
dp),
INTENT(IN) :: epseig
1421 CHARACTER(len=*),
PARAMETER :: routinen =
'cp_fm_geeig_canon'
1423 INTEGER :: handle, i, icol, irow, nao, nc, ncol, &
1425 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: evals
1427 CALL timeset(routinen, handle)
1431 nmo =
SIZE(eigenvalues)
1432 ALLOCATE (evals(nao))
1437 evals(:) = -evals(:)
1440 IF (evals(i) < epseig)
THEN
1451 CALL cp_fm_to_fm(work, eigenvectors, ncol, nc + 1, nc + 1)
1454 DO icol = nc + 1, nao
1460 evals(nc + 1:nao) = 1.0_dp
1463 evals(:) = 1.0_dp/sqrt(evals(:))
1466 CALL cp_fm_gemm(
"T",
"N", nao, nao, nao, 1.0_dp, work, amatrix, 0.0_dp, bmatrix)
1467 CALL cp_fm_gemm(
"N",
"N", nao, nao, nao, 1.0_dp, bmatrix, work, 0.0_dp, amatrix)
1470 DO icol = nc + 1, nao
1475 CALL choose_eigv_solver(matrix=amatrix, eigenvectors=bmatrix, eigenvalues=eigenvalues)
1478 CALL cp_fm_gemm(
"N",
"N", nao, nx, nc, 1.0_dp, work, bmatrix, 0.0_dp, eigenvectors)
1482 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.
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
subroutine, public diag_init(diag_lib, fallback_applied, elpa_kernel, elpa_neigvec_min_input, elpa_qr, elpa_print, elpa_one_stage, dlaf_neigvec_min_input, eps_check_diag_input, cusolver_generalized_input)
Setup the diagonalization library to be used.
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....
logical, save, public cusolver_generalized
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_kernel(requested_kernel)
Sets the active ELPA kernel.
logical, save, public elpa_qr
subroutine, public cp_fm_diag_elpa(matrix, eigenvectors, eigenvalues)
Driver routine to diagonalize a FM matrix with the ELPA library.
logical, save, public elpa_print
subroutine, public finalize_elpa_library()
Finalize the ELPA library.
logical, save, public elpa_one_stage
subroutine, public initialize_elpa_library(one_stage, qr, should_print)
Initialize 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_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_create(matrix, matrix_struct, name, use_sp, nrow, ncol, set_zero)
creates a new full matrix with the given structure
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...