Line data Source code
1 : !!****f* ABINIT/m_trace_estimation
2 : !! NAME
3 : !! m_trace_estimation
4 : !!
5 : !! FUNCTION
6 : !! This module contains routines used to compute the stochastic Lanczos trace estimation.
7 : !! It also computes cummulative eigenvalue counts using differences of trace estimation
8 : !! on consecutive intervals.
9 : !!
10 : !! COPYRIGHT
11 : !! Copyright (C) 2018-2026 ABINIT group (IML)
12 : !! This file is distributed under the terms of the
13 : !! gnu general public license, see ~abinit/COPYING
14 : !! or http://www.gnu.org/copyleft/gpl.txt .
15 : !! for the initials of contributors, see ~abinit/doc/developers/contributors.txt .
16 : !!
17 : !! SOURCE
18 :
19 : #if defined HAVE_CONFIG_H
20 : #include "config.h"
21 : #endif
22 :
23 : #include "abi_common.h"
24 :
25 : ! nvtx related macro definition
26 : #include "nvtx_macros.h"
27 :
28 : module m_trace_estimation
29 :
30 : use defs_basis
31 : use defs_abitypes
32 : use m_abicore
33 : use m_errors
34 : use m_time, only : timab
35 : use m_sort, only: sort_dp
36 :
37 : use m_cgtools
38 : use m_xg
39 : use m_xgTransposer
40 :
41 : use m_chebfi2
42 : use m_polynomial_filter
43 : use m_slice_task, only: matrixInfo_t
44 :
45 : use m_xmpi
46 : use m_xomp
47 : #ifdef HAVE_OPENMP
48 : use omp_lib
49 : #endif
50 :
51 : #if defined(HAVE_GPU_CUDA) && defined(HAVE_YAKL)
52 : use m_gpu_toolbox, only : CPU_DEVICE_ID, gpu_device_synchronize
53 : #endif
54 :
55 : #if defined(HAVE_GPU_MARKERS)
56 : use m_nvtx_data
57 : #endif
58 :
59 : implicit none
60 :
61 : private
62 :
63 : ! Timers
64 : !---------------------------------------------------
65 : integer, parameter :: tim_swap = 1761
66 : integer, parameter :: tim_RR_q = 1759
67 : integer, parameter :: tim_barrier = 1764
68 : integer, parameter :: tim_copy = 1765
69 : integer, parameter :: tim_getAX_BX = 1754
70 : integer, parameter :: tim_invovl = 1755
71 : integer, parameter :: tim_lanczos = 2167
72 : integer, parameter :: tim_trace = 2168
73 :
74 : ! Public methods
75 : !-------------------------------------------------
76 : public :: computeBLanczos ! for lower bound estimation
77 : public :: get_eigenvalue_count ! count eigenvalues for lowpass intervals
78 : public :: computeTraceEstimation ! compute moments etc
79 : public :: smallestTridiagEigenpair ! used in slice_cprj (experimental)
80 :
81 : CONTAINS
82 : !=====================================================================
83 : !!***
84 :
85 : !!****f* m_trace_estimation/computeBLanczos
86 : !! NAME
87 : !! computeBLanczos
88 : !!
89 : !! FUNCTION
90 : !! B-Lanczos three-term recurrence (using B-inner product).
91 : !! Performs k Lanczos iterations on a column vector.
92 : !!
93 : !! SOURCE
94 :
95 18 : subroutine computeBLanczos(minfo, paw, getAX_BX, getBm1X, k, lambda_min, res_norm)
96 :
97 : implicit none
98 :
99 : type(matrixInfo_t), intent(in) :: minfo
100 : logical, intent(in) :: paw
101 : integer, intent(in) :: k
102 : real(dp), intent(out) :: lambda_min, res_norm
103 : interface
104 : subroutine getAX_BX(X,AX,BX)
105 : use m_xg, only : xgBlock_t
106 : type(xgBlock_t), intent(inout) :: X
107 : type(xgBlock_t), intent(inout) :: AX
108 : type(xgBlock_t), intent(inout) :: BX
109 : end subroutine getAX_BX
110 : end interface
111 : interface
112 : subroutine getBm1X(X,Bm1X)
113 : use m_xg, only : xgBlock_t
114 : type(xgBlock_t), intent(inout) :: X
115 : type(xgBlock_t), intent(inout) :: Bm1X
116 : end subroutine getBm1X
117 : end interface
118 :
119 : type(xg_t) :: W_vcol
120 : type(xg_t) :: W_dot
121 : type(xgBlock_t) :: q, v, Bv, Bm1v, qprev
122 : type(xgBlock_t) :: dot_qTBv, dot_qTv, dot_vTBv
123 36 : real(dp) :: alpha(k), beta(k-1)
124 : real(dp) :: beta_prev
125 : real(dp) :: norml_q
126 : real(dp), pointer :: dot_qTBv_layout(:,:) => null()
127 : real(dp), pointer :: dot_qTv_layout(:,:) => null()
128 : real(dp), pointer :: dot_vTBv_layout(:,:) => null()
129 18 : real(dp), allocatable :: v_min(:)
130 :
131 : integer :: j
132 : integer :: rank
133 : integer :: me_g0, space, tot_spacedim, gpu_option
134 : real(dp) :: tsec(2)
135 :
136 : ! *********************************************************************
137 :
138 18 : call timab(tim_lanczos,1,tsec)
139 :
140 18 : tot_spacedim = minfo%total_spacedim
141 18 : gpu_option = minfo%gpu_option
142 18 : space = minfo%space
143 18 : me_g0 = minfo%me_g0
144 18 : if (minfo%paral_kgb==1) then
145 16 : me_g0 = minfo%me_g0_fft
146 : end if
147 18 : rank = xmpi_comm_rank(minfo%spacecom)
148 18 : beta_prev = 0.0_dp
149 :
150 54 : ABI_MALLOC(v_min, (tot_spacedim))
151 :
152 18 : write(std_out,*) 'Lanczos in rank=', rank; flush(std_out)
153 :
154 : ! workspace size (npw,5)
155 18 : call xg_init(W_vcol, space, tot_spacedim, 5, xmpi_comm_null, me_g0=me_g0, gpu_option=gpu_option)
156 18 : call xgBlock_setBlock(W_vcol%self, q, tot_spacedim, 1) ! q
157 18 : call xgBlock_setBlock(W_vcol%self, v, tot_spacedim, 1, fcol=2) ! Aq
158 18 : call xgBlock_setBlock(W_vcol%self, Bv, tot_spacedim, 1, fcol=3) ! Bq
159 18 : call xgBlock_setBlock(W_vcol%self, Bm1v, tot_spacedim, 1, fcol=4) ! Bm1 v
160 18 : call xgBlock_setBlock(W_vcol%self, qprev, tot_spacedim, 1, fcol=5) ! q_prev
161 :
162 18 : call xg_init(W_dot, space, 1, 3, xmpi_comm_null, me_g0=me_g0, gpu_option=gpu_option)
163 18 : call xgBlock_setBlock(W_dot%self, dot_qTBv, 1, 1)
164 18 : call xgBlock_setBlock(W_dot%self, dot_qTv, 1, 1, fcol=2)
165 18 : call xgBlock_setBlock(W_dot%self, dot_vTBv, 1, 1, fcol=3)
166 :
167 : ! q = random column vector
168 18 : call xgBlock_colwiseRandom(q, rank, 1)
169 : !write(std_out,*) 'Random id=', xgBlock_getid(q)
170 : !flush(std_out)
171 :
172 : ! Bv = B * q / norml_q
173 18 : call timab(tim_getAX_BX,1,tsec)
174 : ABI_NVTX_START_RANGE(NVTX_SLICE_GET_AX_BX)
175 18 : call getAX_BX(q, v, Bv)
176 18 : call xgBlock_zero_im_g0(v) ! v stores Aq
177 18 : call xgBlock_zero_im_g0(Bv) ! Bv stores Bq
178 : ABI_NVTX_END_RANGE()
179 18 : call timab(tim_getAX_BX,2,tsec)
180 :
181 18 : call xgBlock_colwiseDotProduct(q, Bv, dot_qTBv)
182 18 : call xgBlock_reverseMap(dot_qTBv,dot_qTBv_layout,rows=1,cols=1)
183 :
184 18 : norml_q = 1.d0 / sqrt(dot_qTBv_layout(1,1))
185 18 : call xgBlock_scale(q, norml_q, 1)
186 18 : call xgBlock_scale(v, norml_q, 1)
187 18 : call xgBlock_scale(Bv, norml_q, 1)
188 :
189 558 : alpha = 0.d0
190 540 : beta = 0.d0
191 :
192 558 : do j = 1, k
193 :
194 540 : if (j>1) then ! rewrite v
195 : ! v = A * q
196 522 : call timab(tim_getAX_BX,1,tsec)
197 : ABI_NVTX_START_RANGE(NVTX_SLICE_GET_AX_BX)
198 522 : call getAX_BX(q, v, Bv)
199 522 : call xgBlock_zero_im_g0(v) ! v stores Aq
200 522 : call xgBlock_zero_im_g0(Bv) ! Bv stores Bq
201 : ABI_NVTX_END_RANGE()
202 522 : call timab(tim_getAX_BX,2,tsec)
203 : end if
204 :
205 : ! alpha_j = q^T * Aq
206 540 : call xgBlock_colwiseDotProduct(q, v, dot_qTv)
207 540 : call xgBlock_reverseMap(dot_qTv,dot_qTv_layout,rows=1,cols=1)
208 540 : alpha(j) = dot_qTv_layout(1,1)
209 :
210 : ! v = B^{-1} * A * q
211 540 : if (paw) then
212 540 : call timab(tim_invovl, 1, tsec)
213 : ABI_NVTX_START_RANGE(NVTX_CHEBFI2_GET_BM1X)
214 540 : call getBm1X(v, Bm1v)
215 : ABI_NVTX_END_RANGE()
216 540 : call timab(tim_invovl, 2, tsec)
217 540 : call timab(tim_copy, 1, tsec)
218 540 : call xgBlock_copy(Bm1v, v)
219 540 : call timab(tim_copy, 2, tsec)
220 : end if
221 :
222 : ! v = B^{-1} A q - alpha q - beta_prev q_prev
223 540 : call xgBlock_saxpy(v, -1.d0 * alpha(j), q)
224 540 : if (j > 1) then
225 522 : call xgBlock_saxpy(v, -beta_prev, qprev)
226 : end if
227 :
228 : ! Compute beta_j if j<k
229 558 : if (j < k) then
230 :
231 : ! Bv = B * v
232 522 : call timab(tim_getAX_BX,1,tsec)
233 : ABI_NVTX_START_RANGE(NVTX_SLICE_GET_AX_BX)
234 522 : call getAX_BX(v, Bm1v, Bv)
235 522 : call xgBlock_zero_im_g0(Bm1v) ! Bm1v dummy workspace
236 522 : call xgBlock_zero_im_g0(Bv) ! Bv
237 : ABI_NVTX_END_RANGE()
238 522 : call timab(tim_getAX_BX,2,tsec)
239 :
240 522 : call xgBlock_colwiseDotProduct(v, Bv, dot_vTBv)
241 522 : call xgBlock_reverseMap(dot_vTBv,dot_vTBv_layout,rows=1,cols=1)
242 522 : beta(j) = sqrt(dot_vTBv_layout(1,1))
243 :
244 : ! Update q_prev, q=v/beta_j, beta_prev
245 522 : call xgBlock_copy(q, qprev)
246 522 : call xgBlock_scale(v, 1.d0/beta(j), 1)
247 522 : call xgBlock_copy(v, q)
248 522 : beta_prev = beta(j)
249 : end if
250 : end do
251 :
252 : ! Diagonalize T (always on CPU)
253 18 : call smallestTridiagEigenpair(k, alpha, beta, lambda_min, v_min)
254 :
255 : ! residual norm using Lanczos shortcut
256 18 : res_norm = abs(beta(k-1)*v_min(k))
257 :
258 18 : call xg_free(W_vcol)
259 18 : call xg_free(W_dot)
260 18 : ABI_FREE(v_min)
261 :
262 18 : call timab(tim_lanczos,2,tsec)
263 :
264 36 : end subroutine computeBLanczos
265 : !!***
266 :
267 : !----------------------------------------------------------------------
268 :
269 : !!****f* m_trace_estimation/computeChebyshevMoments
270 : !! NAME
271 : !! computeChebyshevMoments
272 : !!
273 : !! FUNCTION
274 : !! Compute Chebyshev moments up to maximal degree all centered in [A,B)
275 : !! Upper bound is computed as Rayleigh quotient
276 : !!
277 : !! OUTPUT
278 : !! M_n = <X, f_n(B^{-1}AX) X> for n=1,..,ndeg_filter_max
279 : !!
280 : !! SOURCE
281 :
282 18 : subroutine computeChebyshevMoments(minfo, tolerance, ecut, paw, X0, getAX_BX, getBm1X, &
283 18 : lambda_minus, lambda_plus, ndeg_filter, cheby_moments)
284 :
285 : implicit none
286 :
287 : type(matrixInfo_t), intent(in) :: minfo
288 : real(dp), intent(in) :: ecut, tolerance
289 : logical, intent(in) :: paw
290 : type(xgBlock_t), intent(inout) :: X0
291 : integer, intent(in) :: ndeg_filter
292 : real(dp), intent(in) :: lambda_minus, lambda_plus
293 : complex(dp), intent(out) :: cheby_moments(:,:)
294 : interface
295 : subroutine getAX_BX(X,AX,BX)
296 : use m_xg, only : xgBlock_t
297 : type(xgBlock_t), intent(inout) :: X
298 : type(xgBlock_t), intent(inout) :: AX
299 : type(xgBlock_t), intent(inout) :: BX
300 : end subroutine getAX_BX
301 : end interface
302 : interface
303 : subroutine getBm1X(X,Bm1X)
304 : use m_xg, only : xgBlock_t
305 : type(xgBlock_t), intent(inout) :: X
306 : type(xgBlock_t), intent(inout) :: Bm1X
307 : end subroutine getBm1X
308 : end interface
309 :
310 : integer :: ideg
311 : integer :: nband, tot_spacedim, space, me_g0, gpu_option
312 : real(dp) :: center, radius
313 : real(dp) :: one_over_r
314 : real(dp) :: two_over_r
315 : real(dp) :: tsec(2)
316 : type(xg_t) :: Moments
317 : type(xg_t) :: X0_backup
318 : type(xgBlock_t) :: Moment_ideg
319 18 : type(chebfi_t) :: chebfi
320 : complex(dp), pointer :: momvals(:,:) => null()
321 :
322 : ! *********************************************************************
323 :
324 : ! todo add timer
325 : ! tim_cheby_moments
326 :
327 18 : gpu_option = minfo%gpu_option
328 18 : tot_spacedim = minfo%total_spacedim
329 18 : space = minfo%space
330 18 : me_g0 = minfo%me_g0
331 18 : if (minfo%paral_kgb==1) then
332 16 : me_g0 = minfo%me_g0_fft
333 : end if
334 18 : nband = cols(X0)
335 :
336 : ! Moment workspace size (1, ndeg+1)
337 18 : call xg_init(Moments, space, 1, ndeg_filter+1, gpu_option=gpu_option) ! M_n=<X0,f_n(A)X0>
338 18 : call xg_init(X0_backup, space, tot_spacedim, nband, minfo%spacecom, me_g0=me_g0, gpu_option=gpu_option) ! X0
339 :
340 : ! Initialize chebfi object in MPI Colsrows distribution
341 : call chebfi_init(chebfi,nband,tot_spacedim,tolerance,ecut,minfo%paral_kgb,&
342 : nband,ndeg_filter,0,minfo%space,1,xmpi_comm_null,minfo%me_g0,minfo%me_g0_fft,&
343 : paw,minfo%comm_rows,minfo%comm_cols,0,1.d0,0.d0,minfo%gpu_option,&
344 : gpu_kokkos_nthrd=minfo%gpu_kokkos_nthrd,gpu_thread_limit=minfo%gpu_thread_limit,&
345 18 : from_linalg=.false.)
346 :
347 : ! Initialize Chebyshev recursion
348 18 : call xgBlock_copy(X0, X0_backup%self)
349 18 : chebfi%xXColsRows = X0
350 :
351 : ! Compute A*Psi
352 18 : call timab(tim_getAX_BX,1,tsec)
353 : ABI_NVTX_START_RANGE(NVTX_CHEBFI2_GET_AX_BX)
354 18 : call getAX_BX(chebfi%xXColsRows, chebfi%xAXColsRows, chebfi%xBXColsRows)
355 18 : call xgBlock_zero_im_g0(chebfi%xAXColsRows)
356 18 : call xgBlock_zero_im_g0(chebfi%xBXColsRows)
357 : ABI_NVTX_END_RANGE()
358 18 : call timab(tim_getAX_BX,2,tsec)
359 :
360 : ! Initialize Chebyshev moment at k=1
361 18 : call xgBlock_setBlock(Moments%self, Moment_ideg, 1, 1, fcol=1)
362 18 : call xgBlock_dot(X0_backup%self, chebfi%xXColsRows, Moment_ideg)
363 :
364 : ! Spectral interval to be amplified scaled to [-1,1)
365 18 : center = (lambda_plus + lambda_minus)/2.d0
366 18 : radius = (lambda_plus - lambda_minus)/2.d0
367 18 : one_over_r = 1.d0/radius
368 18 : two_over_r = 2.d0/radius
369 :
370 198 : do ideg = 0, ndeg_filter - 1
371 :
372 : !chebfi%paw = .false.
373 : ABI_NVTX_START_RANGE(NVTX_CHEBFI2_NEXT_ORDER)
374 180 : call chebfi_computeNextOrderChebfiPolynom(chebfi, ideg, center, one_over_r, two_over_r, getBm1X)
375 : ABI_NVTX_END_RANGE()
376 : !chebfi%paw = .true.
377 :
378 : ! chebfi%xXColsRows = f_ideg X0
379 : ABI_NVTX_START_RANGE(NVTX_CHEBFI2_SWAP_BUF)
380 180 : call timab(tim_swap,1,tsec)
381 180 : call chebfi_swapInnerBuffers(chebfi, tot_spacedim, nband)
382 180 : call timab(tim_swap,2,tsec)
383 : ABI_NVTX_END_RANGE()
384 :
385 : !A * Psi
386 180 : call timab(tim_getAX_BX,1,tsec)
387 : ABI_NVTX_START_RANGE(NVTX_SLICE_GET_AX_BX)
388 180 : call getAX_BX(chebfi%xXColsRows, chebfi%xAXColsRows, chebfi%xBXColsRows)
389 180 : call xgBlock_zero_im_g0(chebfi%xAXColsRows)
390 180 : call xgBlock_zero_im_g0(chebfi%xBXColsRows)
391 : ABI_NVTX_END_RANGE()
392 180 : call timab(tim_getAX_BX,2,tsec)
393 :
394 : ! M_ideg = < X0, f_ideg X0 >_B
395 180 : call xgBlock_setBlock(Moments%self, Moment_ideg, 1, 1, fcol=ideg+2)
396 198 : call xgBlock_dot(X0_backup%self, chebfi%xXColsRows, Moment_ideg)
397 :
398 : end do
399 :
400 18 : call xgBlock_reverseMap(Moments%self, momvals, 1, ndeg_filter+1)
401 414 : cheby_moments(:,:) = momvals(:,:)
402 :
403 : ! Free memory
404 18 : call xg_free(Moments)
405 18 : call chebfi_free(chebfi)
406 18 : call xg_free(X0_backup)
407 :
408 36 : end subroutine computeChebyshevMoments
409 : !!***
410 :
411 : !----------------------------------------------------------------------
412 :
413 : !!****f* m_trace_estimation/computeTraceEstimation
414 : !! NAME
415 : !! computeTraceEstimation
416 : !!
417 : !! FUNCTION
418 : !! Compute Girard-Hutchinson trace estimator
419 : !! ndeg_filter -> number of Chebyshev moments
420 : !! m_probe -> number of stochastic probes
421 : !! moments(1:ndeg_filter) -> Chebyshev moments computed with probes
422 : !! and B-inner product
423 : !!
424 : !! SOURCE
425 :
426 18 : subroutine computeTraceEstimation(minfo, ecut, paw, tolerance, getAX_BX, getBm1X, ndeg_filter, &
427 18 : m_probe, min_low_bound, moments)
428 :
429 : implicit none
430 :
431 : type(matrixInfo_t), intent(in) :: minfo
432 : integer, intent(in) :: ndeg_filter, m_probe
433 : logical, intent(in) :: paw
434 : real(dp), intent(in) :: ecut, min_low_bound, tolerance
435 : real(dp), intent(inout) :: moments(:)
436 : interface
437 : subroutine getAX_BX(X,AX,BX)
438 : use m_xg, only : xgBlock_t
439 : type(xgBlock_t), intent(inout) :: X
440 : type(xgBlock_t), intent(inout) :: AX
441 : type(xgBlock_t), intent(inout) :: BX
442 : end subroutine getAX_BX
443 : end interface
444 : interface
445 : subroutine getBm1X(X,Bm1X)
446 : use m_xg, only : xgBlock_t
447 : type(xgBlock_t), intent(inout) :: X
448 : type(xgBlock_t), intent(inout) :: Bm1X
449 : end subroutine getBm1X
450 : end interface
451 :
452 : !integer :: nband
453 : integer :: tot_spacedim, gpu_option
454 : integer :: ierr
455 : integer :: me_g0
456 : integer :: jcol
457 : integer :: my_rank
458 : integer :: seed
459 : integer :: m_probe_tot
460 : integer :: num_moments
461 : type(xg_t) :: X_probe
462 : complex(dp), allocatable :: cheby_moments(:,:)
463 : real(dp) :: tsec(2)
464 :
465 : ! *********************************************************************
466 :
467 18 : call timab(tim_trace,1,tsec)
468 :
469 18 : tot_spacedim = minfo%total_spacedim
470 18 : gpu_option = minfo%gpu_option
471 18 : my_rank = xmpi_comm_rank(minfo%spacecom)
472 18 : me_g0 = minfo%me_g0
473 18 : if (minfo%paral_kgb==1) then
474 16 : me_g0 = minfo%me_g0_fft
475 : end if
476 :
477 18 : num_moments = ndeg_filter + 1
478 54 : ABI_MALLOC(cheby_moments, (1, num_moments) )
479 :
480 : ! total number of probes is m_probes * number of MPI processes
481 : call xg_init(X_probe, minfo%space, tot_spacedim, m_probe, minfo%spacecom, &
482 18 : me_g0=me_g0, gpu_option=gpu_option)
483 :
484 : ! Define random isotropic probes (unit variance NOT unit norm!)
485 108 : do jcol = 1, m_probe
486 90 : seed = my_rank*(m_probe+10)+jcol ! seed depends on column index
487 108 : call xgBlock_colwiseRandomRademacher(X_probe%self, seed, jcol)
488 : end do
489 :
490 18 : write(std_out,*) 'moments are scaled in'
491 18 : write(std_out,*) min_low_bound, ecut
492 18 : flush(std_out)
493 :
494 : ! Lowpass scan - coarse resolution with low degree
495 : ! Chebyshev moments in maximal [a,ecut)
496 : ! todo <X_probe, f(A) X_probe> (trace) and <X0, f(A) X_probe> (principal angles)
497 : ! maybe <xX, f(A)X_probe> is useful for principal angles and column selection
498 : ! in that case incorporate it in the loop
499 : call computeChebyshevMoments(minfo, tolerance, ecut, paw, X_probe%self, &
500 18 : getAX_BX, getBm1X, min_low_bound, ecut, ndeg_filter, cheby_moments)
501 :
502 : ! Sum real part of moments and divide by number of probes
503 : ! moments(k) = 1/Nv * Sum_{i=1}^Nv v_i^T T_k(A)v_i
504 18 : m_probe_tot = m_probe
505 18 : call xmpi_sum(m_probe_tot, minfo%spacecom, ierr)
506 : !moments(1:num_moments) = (/ (real(cheby_moments(1,k)), k=1,num_moments) /)
507 216 : moments = real(cheby_moments(1,:))
508 18 : call xmpi_sum(moments, minfo%spacecom, ierr)
509 216 : moments(1:num_moments) = moments(1:num_moments)/m_probe_tot
510 :
511 : !write(std_out,*) 'moments k=0=', real(cheby_moments(1,1))
512 : !write(std_out,*) 'moments k=1=', real(cheby_moments(1,2))
513 : !write(std_out,*) 'moments k=3=', real(cheby_moments(1,3))
514 : !flush(std_out)
515 :
516 : ! Free memory
517 18 : ABI_FREE(cheby_moments)
518 18 : call xg_free(X_probe)
519 :
520 18 : call timab(tim_trace,2,tsec)
521 :
522 36 : end subroutine computeTraceEstimation
523 : !!***
524 :
525 : !----------------------------------------------------------------------
526 :
527 : !!****f* m_trace_estimation/get_eigenvalue_count
528 : !! NAME
529 : !! get_eigenvalue_count
530 : !!
531 : !! SOURCE
532 :
533 612 : function get_eigenvalue_count(b, moments, work) result(mass)
534 :
535 : implicit none
536 :
537 : real(dp), intent(in) :: b
538 : real(dp), intent(in) :: moments(:)
539 : real(dp), intent(inout) :: work(:)
540 : real(dp) :: mass
541 : integer :: ndeg_filter
542 : !real(dp) :: sigma, alpha
543 : !integer :: Ngrid
544 :
545 612 : ndeg_filter = size(moments)-1
546 :
547 : ! Erf damping coefficients
548 : !sigma = 4.d0 / ndeg_filter
549 : !Ngrid = 500
550 : !work = erf_step_coeffs(b, ndeg_filter, sigma, Ngrid)
551 :
552 : !alpha = 20
553 : !Ngrid = 500
554 : !work = smooth_step_coeffs(b, ndeg_filter, alpha, Ngrid)
555 :
556 : ! Steep Lanczos
557 7344 : work = lanczos_step_coeffs(b, ndeg_filter)
558 :
559 7344 : mass = dot_product(work, moments)
560 :
561 612 : end function get_eigenvalue_count
562 : !!***
563 :
564 : !----------------------------------------------------------------------
565 :
566 : !!****f* m_trace_estimation/smallestTridiagEigenpair
567 : !! NAME
568 : !! smallestTridiagEigenpair
569 : !!
570 : !! FUNCTION
571 : !! Smallest eigenvalue of symmetric tridiagonal
572 : !!
573 : !! SOURCE
574 :
575 18 : subroutine smallestTridiagEigenpair(n, d, e, lambda, v)
576 : implicit none
577 : integer, intent(in) :: n
578 : real(dp), intent(in) :: d(n), e(n-1)
579 : real(dp), intent(out) :: lambda
580 : real(dp), intent(out) :: v(n)
581 :
582 : ! Local copies (DSTEVX overwrites input)
583 36 : real(dp) :: dloc(n), eloc(n-1)
584 18 : real(dp), allocatable :: z(:,:), work(:)
585 18 : integer, allocatable :: iwork(:), ifail(:)
586 : integer :: info, m
587 :
588 : ! *********************************************************************
589 :
590 558 : dloc = d
591 540 : eloc = e
592 :
593 54 : ABI_MALLOC(z, (n,1))
594 54 : ABI_MALLOC(work, (5*n))
595 54 : ABI_MALLOC(iwork, (5*n))
596 54 : ABI_MALLOC(ifail, (n))
597 :
598 : ! DSTEVX computes selected eigenpairs (here smallest: index 1)
599 : call dstevx('V', 'I', n, dloc, eloc, 0.0d0, 0.0d0, 1, 1, 1.0d-12, m, dloc, z, &
600 18 : n, work, iwork, ifail, info)
601 :
602 18 : if (info /= 0) then
603 0 : ABI_ERROR('DSTEVX failed')
604 : end if
605 :
606 18 : lambda = dloc(1)
607 558 : v = z(:,1)
608 :
609 18 : ABI_FREE(z)
610 18 : ABI_FREE(work)
611 18 : ABI_FREE(iwork)
612 18 : ABI_FREE(ifail)
613 :
614 18 : end subroutine smallestTridiagEigenpair
615 : !!***
616 :
617 : end module m_trace_estimation
618 : !!***
|