(git:ed6f26b)
Loading...
Searching...
No Matches
arnoldi_geev.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief provides a unified interface to lapack geev routines
10!> \par History
11!> 2014.09 created [Florian Schiffmann]
12!> 2023.12 Removed support for single-precision [Ole Schuett]
13!> 2024.12 Removed support for complex input matrices [Ole Schuett]
14!> \author Florian Schiffmann
15! **************************************************************************************************
17 USE kinds, ONLY: dp
18#include "../base/base_uses.f90"
19
20 IMPLICIT NONE
21
22 PRIVATE
23
24 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'arnoldi_geev'
25
27
28CONTAINS
29
30! **************************************************************************************************
31!> \brief ...
32!> \param jobvr ...
33!> \param matrix ...
34!> \param ndim ...
35!> \param evals ...
36!> \param revec ...
37! **************************************************************************************************
38 SUBROUTINE arnoldi_symm_local_diag(jobvr, matrix, ndim, evals, revec)
39 CHARACTER(1) :: jobvr
40 REAL(dp), DIMENSION(:, :) :: matrix
41 INTEGER :: ndim
42 COMPLEX(dp), DIMENSION(:) :: evals
43 COMPLEX(dp), DIMENSION(:, :) :: revec
44
45 INTEGER :: i, info, liwork, lwork, iwork(3 + 5*ndim)
46 REAL(dp) :: tmp_array(ndim, ndim), &
47 work(1 + 6*ndim + 2*ndim**2)
48 REAL(dp), DIMENSION(ndim) :: eval
49
50 lwork = 1 + 6*ndim + 2*ndim**2
51 liwork = 3 + 5*ndim
52
53 tmp_array(:, :) = matrix(:, :)
54 CALL dsyevd(jobvr, "U", ndim, tmp_array, ndim, eval, work, lwork, iwork, liwork, info)
55
56 DO i = 1, ndim
57 revec(:, i) = cmplx(tmp_array(:, i), real(0.0, dp), dp)
58 evals(i) = cmplx(eval(i), 0.0, dp)
59 END DO
60
61 END SUBROUTINE arnoldi_symm_local_diag
62
63! **************************************************************************************************
64!> \brief ...
65!> \param jobvl ...
66!> \param jobvr ...
67!> \param matrix ...
68!> \param ndim ...
69!> \param evals ...
70!> \param revec ...
71!> \param levec ...
72! **************************************************************************************************
73 SUBROUTINE arnoldi_tridiag_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
74 CHARACTER(1) :: jobvl, jobvr
75 REAL(dp), DIMENSION(:, :) :: matrix
76 INTEGER :: ndim
77 COMPLEX(dp), DIMENSION(:) :: evals
78 COMPLEX(dp), DIMENSION(:, :) :: revec, levec
79
80 INTEGER :: i, info
81 REAL(dp) :: work(20*ndim)
82 REAL(dp), DIMENSION(ndim) :: diag, offdiag
83 REAL(dp), DIMENSION(ndim, ndim) :: evec_r
84
85 mark_used(jobvl) !the argument has to be here for the template to work
86
87 levec(1, 1) = cmplx(0.0, 0.0, dp)
88 info = 0
89 diag(ndim) = matrix(ndim, ndim)
90 DO i = 1, ndim - 1
91 diag(i) = matrix(i, i)
92 offdiag(i) = matrix(i + 1, i)
93
94 END DO
95
96 CALL dstev(jobvr, ndim, diag, offdiag, evec_r, ndim, work, info)
97
98 DO i = 1, ndim
99 revec(:, i) = cmplx(evec_r(:, i), real(0.0, dp), dp)
100 evals(i) = cmplx(diag(i), 0.0, dp)
101 END DO
102 END SUBROUTINE arnoldi_tridiag_local_diag
103
104! **************************************************************************************************
105!> \brief ...
106!> \param jobvl ...
107!> \param jobvr ...
108!> \param matrix ...
109!> \param ndim ...
110!> \param evals ...
111!> \param revec ...
112!> \param levec ...
113! **************************************************************************************************
114 SUBROUTINE arnoldi_general_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
115 CHARACTER(1) :: jobvl, jobvr
116 REAL(dp), DIMENSION(:, :) :: matrix
117 INTEGER :: ndim
118 COMPLEX(dp), DIMENSION(:) :: evals
119 COMPLEX(dp), DIMENSION(:, :) :: revec, levec
120
121 INTEGER :: i, info, lwork
122 LOGICAL :: selects(ndim)
123 REAL(dp) :: norm, tmp_array(ndim, ndim), &
124 work(20*ndim)
125 REAL(dp), DIMENSION(ndim) :: eval1, eval2
126 REAL(dp), DIMENSION(ndim, ndim) :: evec_l, evec_r
127
128 mark_used(jobvr) !the argument has to be here for the template to work
129 mark_used(jobvl) !the argument has to be here for the template to work
130
131 eval1 = real(0.0, dp); eval2 = real(0.0, dp)
132 tmp_array(:, :) = matrix(:, :)
133 ! ask lapack how much space it would like in the work vector, don't ask me why
134 lwork = -1
135 CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
136
137 lwork = min(20*ndim, int(work(1)))
138 CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
139 CALL dtrevc('R', 'B', selects, ndim, tmp_array, ndim, evec_l, ndim, evec_r, ndim, ndim, ndim, work, info)
140
141 ! compose the eigenvectors, lapacks way of storing them is a pain
142 ! if eval is complex, then the complex conj pair of evec can be constructed from the i and i+1st evec
143 ! Unfortunately dtrevc computes the ev such that the largest is set to one and not normalized
144 i = 1
145 DO WHILE (i .LE. ndim)
146 IF (abs(eval2(i)) .LT. epsilon(real(0.0, dp))) THEN
147 evec_r(:, i) = evec_r(:, i)/sqrt(dot_product(evec_r(:, i), evec_r(:, i)))
148 revec(:, i) = cmplx(evec_r(:, i), real(0.0, dp), dp)
149 levec(:, i) = cmplx(evec_l(:, i), real(0.0, dp), dp)
150 i = i + 1
151 ELSE IF (eval2(i) .GT. epsilon(real(0.0, dp))) THEN
152 norm = sqrt(sum(evec_r(:, i)**2.0_dp) + sum(evec_r(:, i + 1)**2.0_dp))
153 revec(:, i) = cmplx(evec_r(:, i), evec_r(:, i + 1), dp)/norm
154 revec(:, i + 1) = cmplx(evec_r(:, i), -evec_r(:, i + 1), dp)/norm
155 levec(:, i) = cmplx(evec_l(:, i), evec_l(:, i + 1), dp)
156 levec(:, i + 1) = cmplx(evec_l(:, i), -evec_l(:, i + 1), dp)
157 i = i + 2
158 ELSE
159 cpabort('something went wrong while sorting the EV in arnoldi_geev')
160 END IF
161 END DO
162
163 ! this is to keep the interface consistent with complex geev
164 DO i = 1, ndim
165 evals(i) = cmplx(eval1(i), eval2(i), dp)
166 END DO
167
168 END SUBROUTINE arnoldi_general_local_diag
169
170END MODULE arnoldi_geev
provides a unified interface to lapack geev routines
subroutine, public arnoldi_general_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
...
subroutine, public arnoldi_symm_local_diag(jobvr, matrix, ndim, evals, revec)
...
subroutine, public arnoldi_tridiag_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
...
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34