(git:21ef868)
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-2026 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#if defined (__HAS_IEEE_EXCEPTIONS)
18 USE ieee_exceptions, ONLY: ieee_get_halting_mode, &
19 ieee_set_halting_mode, &
20 ieee_all
21#endif
22 USE kinds, ONLY: dp
23#include "../base/base_uses.f90"
24
25 IMPLICIT NONE
26
27 PRIVATE
28
29 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'arnoldi_geev'
30
32
33CONTAINS
34
35! **************************************************************************************************
36!> \brief ...
37!> \param jobvr ...
38!> \param matrix ...
39!> \param ndim ...
40!> \param evals ...
41!> \param revec ...
42! **************************************************************************************************
43 SUBROUTINE arnoldi_symm_local_diag(jobvr, matrix, ndim, evals, revec)
44 CHARACTER(1) :: jobvr
45 REAL(dp), DIMENSION(:, :) :: matrix
46 INTEGER :: ndim
47 COMPLEX(dp), DIMENSION(:) :: evals
48 COMPLEX(dp), DIMENSION(:, :) :: revec
49
50 INTEGER :: i, info, liwork, lwork, iwork(3 + 5*ndim)
51 REAL(dp) :: tmp_array(ndim, ndim), &
52 work(1 + 6*ndim + 2*ndim**2)
53 REAL(dp), DIMENSION(ndim) :: eval
54
55 lwork = 1 + 6*ndim + 2*ndim**2
56 liwork = 3 + 5*ndim
57
58 tmp_array(:, :) = matrix(:, :)
59 CALL dsyevd(jobvr, "U", ndim, tmp_array, ndim, eval, work, lwork, iwork, liwork, info)
60
61 DO i = 1, ndim
62 revec(:, i) = cmplx(tmp_array(:, i), real(0.0, dp), dp)
63 evals(i) = cmplx(eval(i), 0.0, dp)
64 END DO
65
66 END SUBROUTINE arnoldi_symm_local_diag
67
68! **************************************************************************************************
69!> \brief ...
70!> \param jobvl ...
71!> \param jobvr ...
72!> \param matrix ...
73!> \param ndim ...
74!> \param evals ...
75!> \param revec ...
76!> \param levec ...
77! **************************************************************************************************
78 SUBROUTINE arnoldi_tridiag_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
79 CHARACTER(1) :: jobvl, jobvr
80 REAL(dp), DIMENSION(:, :) :: matrix
81 INTEGER :: ndim
82 COMPLEX(dp), DIMENSION(:) :: evals
83 COMPLEX(dp), DIMENSION(:, :) :: revec, levec
84#if defined (__HAS_IEEE_EXCEPTIONS)
85 LOGICAL, DIMENSION(5) :: halt
86#endif
87 INTEGER :: i, info
88 REAL(dp) :: work(20*ndim)
89 REAL(dp), DIMENSION(ndim) :: diag, offdiag
90 REAL(dp), DIMENSION(ndim, ndim) :: evec_r
91
92 mark_used(jobvl) !the argument has to be here for the template to work
93
94 levec(1, 1) = cmplx(0.0, 0.0, dp)
95 info = 0
96 diag(ndim) = matrix(ndim, ndim)
97 DO i = 1, ndim - 1
98 diag(i) = matrix(i, i)
99 offdiag(i) = matrix(i + 1, i)
100
101 END DO
102
103#if defined (__HAS_IEEE_EXCEPTIONS)
104 CALL ieee_get_halting_mode(ieee_all, halt)
105 CALL ieee_set_halting_mode(ieee_all, .false.)
106#endif
107
108 CALL dstev(jobvr, ndim, diag, offdiag, evec_r, ndim, work, info)
109
110#if defined (__HAS_IEEE_EXCEPTIONS)
111 CALL ieee_set_halting_mode(ieee_all, halt)
112#endif
113
114 cpassert(info == 0)
115
116 DO i = 1, ndim
117 revec(:, i) = cmplx(evec_r(:, i), real(0.0, dp), dp)
118 evals(i) = cmplx(diag(i), 0.0, dp)
119 END DO
120 END SUBROUTINE arnoldi_tridiag_local_diag
121
122! **************************************************************************************************
123!> \brief ...
124!> \param jobvl ...
125!> \param jobvr ...
126!> \param matrix ...
127!> \param ndim ...
128!> \param evals ...
129!> \param revec ...
130!> \param levec ...
131! **************************************************************************************************
132 SUBROUTINE arnoldi_general_local_diag(jobvl, jobvr, matrix, ndim, evals, revec, levec)
133 CHARACTER(1) :: jobvl, jobvr
134 REAL(dp), DIMENSION(:, :) :: matrix
135 INTEGER :: ndim
136 COMPLEX(dp), DIMENSION(:) :: evals
137 COMPLEX(dp), DIMENSION(:, :) :: revec, levec
138
139 INTEGER :: i, info, lwork
140 LOGICAL :: selects(ndim)
141 REAL(dp) :: norm, tmp_array(ndim, ndim), &
142 work(20*ndim)
143 REAL(dp), DIMENSION(ndim) :: eval1, eval2
144 REAL(dp), DIMENSION(ndim, ndim) :: evec_l, evec_r
145
146 mark_used(jobvr) !the argument has to be here for the template to work
147 mark_used(jobvl) !the argument has to be here for the template to work
148
149 eval1 = real(0.0, dp); eval2 = real(0.0, dp)
150 tmp_array(:, :) = matrix(:, :)
151 ! ask lapack how much space it would like in the work vector, don't ask me why
152 lwork = -1
153 CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
154
155 lwork = min(20*ndim, int(work(1)))
156 CALL dhseqr('S', 'I', ndim, 1, ndim, tmp_array, ndim, eval1, eval2, evec_r, ndim, work, lwork, info)
157 CALL dtrevc('R', 'B', selects, ndim, tmp_array, ndim, evec_l, ndim, evec_r, ndim, ndim, ndim, work, info)
158
159 ! compose the eigenvectors, lapacks way of storing them is a pain
160 ! if eval is complex, then the complex conj pair of evec can be constructed from the i and i+1st evec
161 ! Unfortunately dtrevc computes the ev such that the largest is set to one and not normalized
162 i = 1
163 DO WHILE (i <= ndim)
164 IF (abs(eval2(i)) < epsilon(real(0.0, dp))) THEN
165 evec_r(:, i) = evec_r(:, i)/norm2(evec_r(:, i))
166 revec(:, i) = cmplx(evec_r(:, i), real(0.0, dp), dp)
167 levec(:, i) = cmplx(evec_l(:, i), real(0.0, dp), dp)
168 i = i + 1
169 ELSE IF (eval2(i) > epsilon(real(0.0, dp))) THEN
170 norm = sqrt(sum(evec_r(:, i)**2.0_dp) + sum(evec_r(:, i + 1)**2.0_dp))
171 revec(:, i) = cmplx(evec_r(:, i), evec_r(:, i + 1), dp)/norm
172 revec(:, i + 1) = cmplx(evec_r(:, i), -evec_r(:, i + 1), dp)/norm
173 levec(:, i) = cmplx(evec_l(:, i), evec_l(:, i + 1), dp)
174 levec(:, i + 1) = cmplx(evec_l(:, i), -evec_l(:, i + 1), dp)
175 i = i + 2
176 ELSE
177 cpabort('something went wrong while sorting the EV in arnoldi_geev')
178 END IF
179 END DO
180
181 ! this is to keep the interface consistent with complex geev
182 DO i = 1, ndim
183 evals(i) = cmplx(eval1(i), eval2(i), dp)
184 END DO
185
186 END SUBROUTINE arnoldi_general_local_diag
187
188END 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