PROGRESS  master
prg_sp2_fermi_mod.F90
Go to the documentation of this file.
1 
8 
9  use bml
11  use prg_timer_mod
13 
14  implicit none
15 
16  private !Everything is private by default
17 
18  integer, parameter :: dp = kind(1.0d0)
19 
20  public :: prg_sp2_fermi_init
22  public :: prg_sp2_fermi
23  public :: prg_sp2_entropy_function
24  public :: sp2_entropy_ts
25  public :: sp2_inverse
26 
27 contains
28 
43  subroutine prg_sp2_fermi_init(h_bml, nsteps, nocc, tscale, threshold, &
44  occErrLimit, traceLimit, x_bml, mu, beta, h1, hN, sgnlist)
45 
46  implicit none
47 
48  type(bml_matrix_t), intent(in) :: h_bml
49  type(bml_matrix_t), intent(inout) :: x_bml
50  integer, intent(in) :: nsteps
51  integer, intent(inout) :: sgnlist(:)
52  real(dp), intent(in) :: nocc, tscale, threshold
53  real(dp), intent(in) :: occerrlimit, tracelimit
54  real(dp), intent(inout) :: mu, beta, h1, hn
55 
56  type(bml_matrix_t) :: x1_bml, x2_bml, tmp_bml, i_bml
57  real(dp) :: lambda, occerr, sfactor
58  real(dp) :: tracex0, tracex1, tracex2, tracex
59  real(dp), allocatable :: gbnd(:), trace(:)
60  logical :: firsttime
61  character(20) :: bml_type
62  integer :: n, m, i
63 
64  bml_type = bml_get_type(h_bml)
65  n = bml_get_n(h_bml)
66  m = bml_get_m(h_bml)
67 
68  allocate(gbnd(2))
69 
71  call bml_gershgorin(h_bml, gbnd)
72  mu = 0.5 * (gbnd(2) + gbnd(1))
73  h1 = tscale * gbnd(1)
74  hn = tscale * gbnd(2)
75 
76  deallocate(gbnd)
77 
78  lambda = 0.0_dp
79  occerr = 1.0_dp
80  firsttime = .true.
81 
82  allocate(trace(2))
83 
84  call bml_identity_matrix(bml_type, bml_element_real, dp, n, m, i_bml)
85  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, x1_bml)
86  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, x2_bml)
87  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, tmp_bml)
88 
89  do while (occerr .gt. occerrlimit)
90 
91  call bml_copy(h_bml, x_bml)
92  call prg_normalize_fermi(x_bml, h1, hn, mu)
93 
94  ! X1 = -I/(hN-h1)
95  call bml_copy(i_bml, x1_bml)
96  sfactor = -1.0_dp / (hn - h1)
97  call bml_scale(sfactor, x1_bml)
98 
99  do i = 1, nsteps
100  call bml_multiply_x2(x_bml, x2_bml, threshold, trace)
101  tracex0 = trace(1)
102  tracex2 = trace(2)
103 
105  if (firsttime .eqv. .true.) then
106  if (abs(tracex2-nocc) .lt. abs(2.0_dp*tracex0-tracex2-nocc)) then
107  sgnlist(i) = -1
108  else
109  sgnlist(i) = 1
110  end if
111  end if
112 
113  ! X1 = X1 + sgnlist(i)*(X1 - X0*X1 - X1*X0)
114  ! if sgnlist == 1, X1 = 2 * X1 - (X0*X1 + X1*X0)
115  ! if sgnlist == -1, X1 = X0*X1 + X1*X0
116  !
117  ! tmp = X0*X1 + X1*X0
118  call bml_multiply(x_bml, x1_bml, tmp_bml, 1.0_dp, 0.0_dp, threshold)
119  call bml_multiply(x1_bml, x_bml, tmp_bml, 1.0_dp, 1.0_dp, threshold)
120 
121  if (sgnlist(i) .eq. 1) then
122  ! X1 = 2 * X1 - tmp
123  call bml_add_deprecated(2.0_dp, x1_bml, -1.0_dp, tmp_bml, threshold)
124  else
125  call bml_copy(tmp_bml, x1_bml)
126  endif
127 
128  ! X0 = X0 + sgnlist(i)*(X0 - X0_2)
129  ! if sgnlist == 1, X0 = 2.0*X0 - X0_2
130  ! if sgnlist == -1, X0 = X0_2
131  !
132  if (sgnlist(i) .eq. 1) then
133  ! X0 = 2 * X0 - X2
134  call bml_add_deprecated(2.0_dp, x_bml, -1.0_dp, x2_bml, threshold)
135  else
136  call bml_copy(x2_bml, x_bml)
137  endif
138 
139  end do
140 
141  firsttime = .false.
142  tracex0 = bml_trace(x_bml)
143  tracex1 = bml_trace(x1_bml)
144  occerr = abs(nocc - tracex0)
145  ! Newton=Rhapson step to correct for occupation
146  if (abs(tracex1) .gt. tracelimit) then
147  lambda = (nocc - tracex0) / tracex1
148  else
149  lambda = 0.0_dp
150  end if
151  mu = mu + lambda
152  end do
153 
154  deallocate(trace)
155  call bml_deallocate(x2_bml)
156 
157  ! X0*(I-X0)
158  ! I = I - X0
159  call bml_add_deprecated(1.0_dp, i_bml, -1.0_dp, x_bml, threshold)
160  ! tmp = X0*I
161  call bml_multiply(x_bml, i_bml, tmp_bml, 1.0_dp, 0.0_dp, threshold)
162  tracex = bml_trace(tmp_bml)
163  tracex1 = bml_trace(x1_bml)
164  if (abs(tracex) .gt. tracelimit) then
165  beta = -tracex1 / tracex
166  else
167  beta = -1000.0_dp
168  end if
169 
170  ! X = 2 * X
171  !call bml_scale(2.0_dp, x_bml)
172 
173  call bml_deallocate(tmp_bml)
174  call bml_deallocate(i_bml)
175  call bml_deallocate(x1_bml)
176 
177  end subroutine prg_sp2_fermi_init
178 
179 
198  subroutine prg_sp2_fermi_init_norecs(h_bml, nsteps, nocc, tscale, threshold, &
199  occErrLimit, traceLimit, x_bml, mu, beta, h1, hN, sgnlist, verbose)
200 
201  implicit none
202 
203  type(bml_matrix_t), intent(in) :: h_bml
204  type(bml_matrix_t), intent(inout) :: x_bml
205  integer, intent(inout) :: nsteps
206  integer, intent(inout) :: sgnlist(:)
207  real(dp), intent(in) :: nocc, tscale, threshold
208  real(dp), intent(in) :: occerrlimit, tracelimit
209  real(dp), intent(inout) :: mu, beta, h1, hn
210 
211  type(bml_matrix_t) :: x1_bml, x2_bml, tmp_bml, i_bml
212  real(dp) :: lambda, occerr, sfactor, maxder
213  real(dp) :: tracex0, tracex1, tracex2, tracex, beta0
214  real(dp), allocatable :: gbnd(:), trace(:), probe(:), probe_2(:)
215  logical :: firsttime
216  character(20) :: bml_type
217  integer :: n, m, i
218  integer, optional :: verbose
219 
220  if(present(verbose))then
221  if(verbose >= 1) write(*,*)"Inside prg_sp2_fermi_init_norecs ..."
222  endif
223 
224  bml_type = bml_get_type(h_bml)
225  n = bml_get_n(h_bml)
226  m = bml_get_m(h_bml)
227  beta0 = beta
228 
229  allocate(gbnd(2))
230 
232  call bml_gershgorin(h_bml, gbnd)
233  mu = 0.5 * (gbnd(2) + gbnd(1))
234  h1 = tscale * gbnd(1)
235  hn = tscale * gbnd(2)
236 
237  lambda = 0.0_dp
238  occerr = 1.0_dp
239  firsttime = .true.
240 
241  allocate(trace(2))
242 
243  call bml_identity_matrix(bml_type, bml_element_real, dp, n, m, i_bml)
244  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, x1_bml)
245  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, x2_bml)
246  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, tmp_bml)
247 
248  allocate(probe(1000),probe_2(1000))
249 
250  do while (occerr .gt. occerrlimit)
251 
252  call bml_copy(h_bml, x_bml)
253  call prg_normalize_fermi(x_bml, h1, hn, mu)
254 
255  ! Probe function to compute the derivative at mu.
256  do i = 1,1000
257  probe(i) = 1.0_dp - i*0.001_dp
258  enddo
259 
260  ! X1 = -I/(hN-h1)
261  call bml_copy(i_bml, x1_bml)
262  sfactor = -1.0_dp / (hn - h1)
263  call bml_scale(sfactor, x1_bml)
264 
265  do i = 1, nsteps
266  call bml_multiply_x2(x_bml, x2_bml, threshold, trace)
267 
268  probe_2(:) = probe(:)*probe(:)
269 
270  tracex0 = trace(1)
271  tracex2 = trace(2)
272 
274  if (firsttime .eqv. .true.) then
275  if (abs(tracex2-nocc) .lt. abs(2.0_dp*tracex0-tracex2-nocc)) then
276  sgnlist(i) = -1
277  else
278  sgnlist(i) = 1
279  end if
280  end if
281 
282  ! X1 = X1 + sgnlist(i)*(X1 - X0*X1 - X1*X0)
283  ! if sgnlist == 1, X1 = 2 * X1 - (X0*X1 + X1*X0)
284  ! if sgnlist == -1, X1 = X0*X1 + X1*X0
285  !
286  ! tmp = X0*X1 + X1*X0
287  call bml_multiply(x_bml, x1_bml, tmp_bml, 1.0_dp, 0.0_dp, threshold)
288  call bml_multiply(x1_bml, x_bml, tmp_bml, 1.0_dp, 1.0_dp, threshold)
289 
290  if (sgnlist(i) .eq. 1) then
291  ! X1 = 2 * X1 - tmp
292  call bml_add_deprecated(2.0_dp, x1_bml, -1.0_dp, tmp_bml, threshold)
293  else
294  call bml_copy(tmp_bml, x1_bml)
295  endif
296 
297  ! X0 = X0 + sgnlist(i)*(X0 - X0_2)
298  ! if sgnlist == 1, X0 = 2.0*X0 - X0_2
299  ! if sgnlist == -1, X0 = X0_2
300  !
301  if (sgnlist(i) .eq. 1) then
302  ! X0 = 2 * X0 - X2
303  call bml_add_deprecated(2.0_dp, x_bml, -1.0_dp, x2_bml, threshold)
304  probe = 2.0_dp*probe - probe_2
305  else
306  call bml_copy(x2_bml, x_bml)
307  probe = probe_2
308  endif
309 
310  maxder = absmaxderivative(probe,0.001_dp)
311  beta = (4.0_dp*maxder)/(gbnd(2)-gbnd(1))
312  if(beta > beta0) then
313  nsteps = i
314  exit
315  endif
316 
317  end do
318 
319  ! Write probe function into a file (only for debugging purposes)
320  ! do i = 1,1000
321  ! write(1000,*)gbnd(1) + ((gbnd(2)-gbnd(1))/1000.0_dp)*i,probe(i)
322  ! enddo
323 
324  if(present(verbose))then
325  if(verbose >= 1) then
326  write(*,*)"beta = ",beta
327  write(*,*)"kbT = ",1.0_dp/beta
328  endif
329  endif
330 
331  firsttime = .false.
332  tracex0 = bml_trace(x_bml)
333  tracex1 = bml_trace(x1_bml)
334  occerr = abs(nocc - tracex0)
335  ! Newton=Rhapson step to correct for occupation
336  if (abs(tracex1) .gt. tracelimit) then
337  lambda = (nocc - tracex0) / tracex1
338  else
339  lambda = 0.0_dp
340  end if
341  mu = mu + lambda
342  end do
343 
344  deallocate(trace)
345  call bml_deallocate(x2_bml)
346 
347  ! X0*(I-X0)
348  ! I = I - X0
349  call bml_add_deprecated(1.0_dp, i_bml, -1.0_dp, x_bml, threshold)
350  ! tmp = X0*I
351  call bml_print_matrix("x_bml",x_bml,1,4,1,4)
352  call bml_print_matrix("i_bml",i_bml,1,4,1,4)
353  call bml_multiply(x_bml, i_bml, tmp_bml, 1.0_dp, 0.0_dp, threshold)
354 
355  call bml_print_matrix("tmp_bml",tmp_bml,1,4,1,4)
356 
357  tracex = bml_trace(tmp_bml)
358  tracex1 = bml_trace(x1_bml)
359  if (abs(tracex) .gt. tracelimit) then
360  beta = -tracex1 / tracex
361  else
362  beta = -1000.0_dp
363  end if
364 
365  ! X = 2 * X
366  !call bml_scale(2.0_dp, x_bml)
367  deallocate(gbnd)
368  call bml_deallocate(tmp_bml)
369  call bml_deallocate(i_bml)
370  call bml_deallocate(x1_bml)
371 
372  end subroutine prg_sp2_fermi_init_norecs
373 
388  subroutine prg_sp2_fermi(h_bml, osteps, nsteps, nocc, mu, beta, h1, hN, sgnlist, &
389  threshold, eps, traceLimit, x_bml)
390 
391  implicit none
392 
393  type(bml_matrix_t), intent(in) :: h_bml
394  type(bml_matrix_t), intent(inout) :: x_bml
395  integer, intent(in) :: osteps, nsteps
396  integer, intent(in) :: sgnlist(:)
397  real(dp), intent(in) :: nocc, threshold, eps, tracelimit
398  real(dp), intent(inout) :: beta, h1, hn
399  real(dp), intent(inout) :: mu
400 
401  type(bml_matrix_t) :: x2_bml, dx_bml, i_bml
402  real(dp), allocatable :: trace(:), gbnd(:)
403  real(dp) :: sfactor, occerr, tracex0, tracex2, tracedx, lambda
404  real(dp) :: a, b
405  integer :: iter, i, n, m
406  character(20) :: bml_type
407 
408  bml_type = bml_get_type(h_bml)
409  n = bml_get_n(h_bml)
410  m = bml_get_m(h_bml)
411 
412  allocate(trace(2))
413 
414  call bml_identity_matrix(bml_type, bml_element_real, dp, n, m, i_bml)
415  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, dx_bml)
416  call bml_zero_matrix(bml_type, bml_element_real, dp, n, m, x2_bml)
417 
418  occerr = 1.0_dp + eps
419  iter = 0
420  do while ((osteps .eq. 0 .and. occerr .gt. eps) .or. &
421  (osteps .gt. 0 .and. iter .lt. osteps))
422  iter = iter + 1
423  call bml_copy(h_bml, x_bml)
424  call prg_normalize_fermi(x_bml, h1, hn, mu)
425 
426  do i = 1, nsteps
427  call bml_multiply_x2(x_bml, x2_bml, threshold, trace)
428  tracex0 = trace(1)
429  tracex2 = trace(2)
430 
431  ! X0 = X0 + sgnlist(i)*(X0 - X0_2)
432  if (sgnlist(i) .eq. 1) then
433  call bml_add_deprecated(2.0_dp, x_bml, -1.0_dp, x2_bml, threshold)
434  else
435  call bml_copy(x2_bml, x_bml)
436  endif
437 
438  end do
439 
440  tracex0 = bml_trace(x_bml)
441  occerr = abs(nocc - tracex0)
442 
443  ! DX = -beta*X0*(I-X0)
444  call bml_copy(i_bml, x2_bml)
445  call bml_add_deprecated(1.0_dp, x2_bml, -1.0_dp, x_bml, threshold)
446  call bml_multiply(x_bml, x2_bml, dx_bml, -beta, 0.0_dp, threshold)
447  tracedx = bml_trace(dx_bml)
448 
449  ! Newton-Rhapson step to correct for occupation
450  if (abs(tracedx) .gt. tracelimit) then
451  lambda = (nocc - tracex0) / tracedx
452  else
453  lambda = 0.0_dp
454  end if
455  mu = mu + lambda
456 
457  end do
458 
459  ! Correction for occupation
460  call bml_add_deprecated(1.0_dp, x_bml, lambda, dx_bml, threshold)
461 
462  ! X = 2*X
463  !call bml_scale(2.0_dp, x_bml)
464 
465  deallocate(trace)
466  call bml_deallocate(i_bml)
467  call bml_deallocate(x2_bml)
468  call bml_deallocate(dx_bml)
469 
470  end subroutine prg_sp2_fermi
471 
482  subroutine prg_sp2_entropy_function(mu, h1, hN, nsteps, sgnlist, GG, ee)
483 
484  implicit none
485 
486  real(dp), intent(in) :: mu, h1, hn
487  integer, intent(in) :: nsteps, sgnlist(:)
488  real(dp), intent(inout), allocatable :: gg(:), ee(:)
489 
490  real(dp) :: dh, c1, c2, x1, x2, iint
491  real(dp) :: a, b, c_1, c_2, x_1, x_2
492  integer :: i, k, n
493 
494  dh = 0.0001_dp
495  c1 = 1.0_dp
496  c2 = 1.0_dp
497  x1 = 0.5773502691896257_dp
498  x2 = -x1
499  n = 10001 ! number of elements in ee
500 
501  if (allocated(gg)) then
502  deallocate(gg)
503  end if
504  if (allocated(ee)) then
505  deallocate(ee)
506  end if
507 
508  allocate(gg(n))
509  allocate(ee(n))
510 
511  ! Set ee = 0.0 to 1.0 by 0.0001
512  do i = 0, n-1
513  ee(i+1) = i * dh
514  end do
515 
516  gg(1) = 0.0_dp
517  iint = 0.0_dp
518  do i = 1, n-1
519  a = ee(i)
520  b = ee(i+1)
521  c_1 = c1*(b-a)/2.0_dp
522  c_2 = c2*(b-a)/2.0_dp;
523  x_1 = ((b-a)*x1+(b+a))/2.0_dp
524  x_2 = ((b-a)*x2+(b+a))/2.0_dp
525  iint = iint + c_1*sp2_inverse(x_1,mu,h1,hn,nsteps,sgnlist)
526  iint = iint + c_2*sp2_inverse(x_2,mu,h1,hn,nsteps,sgnlist)
527  gg(i+1) = iint
528  end do
529 
530  gg = gg-gg(n)*ee
531 
532  end subroutine prg_sp2_entropy_function
533 
540  function sp2_entropy_ts(D0_bml, GG, ee) result(TS)
541 
542  implicit none
543 
544  type(bml_matrix_t), intent(in) :: d0_bml
545  real(dp), intent(in) :: gg(*), ee(*)
546  real(dp) :: ts
547 
548  type(bml_matrix_t) :: aux_bml
549  real(dp), allocatable :: hh(:)
550  real(dp) :: hs, threshold
551  integer :: s, j, n
552  character(20) :: bml_type, bml_dmode
553 
554  n = bml_get_n(d0_bml)
555  bml_type = bml_get_type(d0_bml)
556  bml_dmode = bml_get_distribution_mode(d0_bml)
557 
558  allocate(hh(n))
559 
560  ! Diagonalize D0
561  call bml_zero_matrix(bml_type, bml_element_real, &
562  dp, n, n, aux_bml)
563 
564  call bml_diagonalize(d0_bml, hh, aux_bml)
565 
566  call bml_deallocate(aux_bml)
567 
568  ts = 0.0_dp
569 
570  do s = 1,n
571  hs = abs(hh(s))
572  j = floor(hs/0.0001_dp + 0.00000_dp) + 1
573 
574  if (j .gt. 0 .and. j .le. 10001) then
575  ts = ts + ((hs-ee(j))*gg(j+1) + &
576  (ee(j+1)-hs)*gg(j))/(ee(j+1)-ee(j))
577  end if
578  end do
579 
580  deallocate(hh)
581 
582  end function sp2_entropy_ts
583 
592  function sp2_inverse(f, mu, h1, hN, nsteps, sgnlist) result(ee)
593 
594  implicit none
595 
596  real(dp), intent(in) :: f, mu, h1, hn
597  integer, intent(in) :: nsteps, sgnlist(:)
598 
599  real(dp) :: sgn, c, ee
600  integer :: i
601 
602  ee = f
603  do i = nsteps, 1, -1
604  sgn = float(sgnlist(i))
605  c = (1.0_dp+sgn)/2.0_dp
606  ee = c - sgn*sqrt(abs(c - sgn*ee))
607  end do
608 
609  ee = hn-mu-ee*(hn-h1)
610 
611  end function sp2_inverse
612 
617  real(dp) function absmaxderivative(func,de)
618 
619  implicit none
620  real(dp), intent(in) :: func(:), de
621  integer :: j
622 
623  absmaxderivative = -10000.0d0
624 
625  do j=1,size(func, dim=1)-1
626  if(abs(func(j+1) - func(j))/de > absmaxderivative) &
627  absmaxderivative = abs(func(j+1) - func(j))/de
628  enddo
629 
630  end function absmaxderivative
631 
632 
633 end module prg_sp2_fermi_mod
The prg_normalize module.
integer, parameter dp
subroutine, public prg_normalize_fermi(h_bml, h1, hN, mu)
Normalize a Hamiltonian matrix prior to running the truncated SP2 algorithm.
The parallel module.
The SP2 Fermi module.
real(dp) function, public sp2_entropy_ts(D0_bml, GG, ee)
Test SP2 entropy. Get the entropy contribution TS to the total free energy.
subroutine, public prg_sp2_fermi(h_bml, osteps, nsteps, nocc, mu, beta, h1, hN, sgnlist, threshold, eps, traceLimit, x_bml)
Calculate Truncated SP2.
real(dp) function absmaxderivative(func, de)
Gets the absolute maximum of the derivative of a function.
real(dp) function, public sp2_inverse(f, mu, h1, hN, nsteps, sgnlist)
Calculate the SP2 inverse.
subroutine, public prg_sp2_fermi_init_norecs(h_bml, nsteps, nocc, tscale, threshold, occErrLimit, traceLimit, x_bml, mu, beta, h1, hN, sgnlist, verbose)
Truncated SP2 prg_initialization. This routine also gives back the Number of SP2 recursive steps that...
subroutine, public prg_sp2_fermi_init(h_bml, nsteps, nocc, tscale, threshold, occErrLimit, traceLimit, x_bml, mu, beta, h1, hN, sgnlist)
Truncated SP2 prg_initialization.
subroutine, public prg_sp2_entropy_function(mu, h1, hN, nsteps, sgnlist, GG, ee)
Calculate SP2 entropy function using gaussian quadrature. Note that GG and ee are allocated and retur...
The timer module.