26#include "./base/base_uses.f90"
31 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'hairy_probes'
33 INTEGER,
PARAMETER,
PRIVATE :: BISECT_MAX_ITER = 400
54 REAL(kind=
dp),
INTENT(out) :: occ(:), fermi, kts
55 REAL(kind=
dp),
INTENT(IN) :: energies(:)
57 REAL(kind=
dp),
INTENT(IN) :: maxocc
59 REAL(kind=
dp),
INTENT(IN) :: n
61 REAL(kind=
dp),
PARAMETER :: epsocc = 1.0e-12_dp
63 INTEGER :: iter, ncol_global, nrow_global
64 REAL(kind=
dp) :: de, delta_fermi, fermi_fit, fermi_half, &
65 fermi_max, fermi_min, h, n_fit, &
66 n_half, n_max, n_min, n_now, y0, y1, y2
67 REAL(kind=
dp),
ALLOCATABLE :: smatrix_squared(:, :)
68 REAL(kind=
dp),
POINTER :: smatrix(:, :)
75 nrow_global=nrow_global, &
76 ncol_global=ncol_global)
77 ALLOCATE (smatrix(nrow_global, ncol_global))
80 ALLOCATE (smatrix_squared(nrow_global, ncol_global))
81 smatrix_squared(:, :) = smatrix(:, :)**2.0d0
86 de = probe(1)%T*log((1.0_dp - epsocc)/epsocc)
88 fermi_max = maxval(probe%mu) + de
89 fermi_min = minval(probe%mu) - de
91 CALL hp_occupancy(probe=probe, matrix=smatrix_squared, energies=energies, &
92 maxocc=maxocc, fermi=fermi_max, occupancy=occ, kts=kts)
95 CALL hp_occupancy(probe=probe, matrix=smatrix_squared, energies=energies, &
96 maxocc=maxocc, fermi=fermi_min, occupancy=occ, kts=kts)
100 DO WHILE (abs(n_max - n_min) > n*epsocc)
103 fermi_half = (fermi_max + fermi_min)/2.0_dp
104 CALL hp_occupancy(probe=probe, matrix=smatrix_squared, energies=energies, &
105 maxocc=maxocc, fermi=fermi_half, occupancy=occ, kts=kts)
108 h = fermi_half - fermi_min
109 IF (h .GT. n*epsocc*100)
THEN
114 CALL three_point_zero(y0, y1, y2, h, delta_fermi)
115 fermi_fit = fermi_min + delta_fermi
117 CALL hp_occupancy(probe=probe, matrix=smatrix_squared, energies=energies, &
118 maxocc=maxocc, fermi=fermi_fit, occupancy=occ, kts=kts)
124 fermi_min = fermi_half
126 ELSE IF (n_half > n)
THEN
127 fermi_max = fermi_half
130 fermi_min = fermi_half
132 fermi_max = fermi_half
138 IF (h .GT. n*epsocc*100)
THEN
139 IF (fermi_fit .GE. fermi_min .AND. fermi_fit .LE. fermi_max)
THEN
141 fermi_min = fermi_fit
143 ELSE IF (n_fit > n)
THEN
144 fermi_max = fermi_fit
150 IF (abs(n_max - n) < n*epsocc)
THEN
153 ELSE IF (abs(n_min - n) < n*epsocc)
THEN
158 IF (iter > bisect_max_iter)
THEN
159 cpwarn(
"Maximum number of iterations reached while finding the Fermi energy")
169 CALL hp_occupancy(probe=probe, matrix=smatrix_squared, energies=energies, &
170 maxocc=maxocc, fermi=fermi, occupancy=occ, kts=kts)
173 IF (abs(n_now - n) > n*epsocc) cpwarn(
"Total number of electrons is not accurate - HP")
175 DEALLOCATE (smatrix, smatrix_squared)
195 REAL(kind=
dp),
INTENT(OUT) :: occ(:, :, :), fermi, kts
196 REAL(kind=
dp),
INTENT(IN) :: energies(:, :, :), rcoeff(:, :, :, :), &
197 icoeff(:, :, :, :), maxocc
199 REAL(kind=
dp),
INTENT(IN) :: n, wk(:)
201 CHARACTER(LEN=*),
PARAMETER :: routinen =
'probe_occupancy_kp'
202 REAL(kind=
dp),
PARAMETER :: epsocc = 1.0e-12_dp
204 INTEGER :: handle, ikp, ispin, iter, nao, nkp, nmo, &
206 REAL(kind=
dp) :: de, delta_fermi, fermi_fit, fermi_half, &
207 fermi_max, fermi_min, h, kts_kp, &
208 n_fit, n_half, n_max, n_min, n_now, &
210 REAL(kind=
dp),
ALLOCATABLE :: coeff_squared(:, :, :, :)
212 CALL timeset(routinen, handle)
217 nao =
SIZE(rcoeff, 1)
218 nmo =
SIZE(rcoeff, 2)
219 nkp =
SIZE(rcoeff, 3)
220 nspin =
SIZE(rcoeff, 4)
222 ALLOCATE (coeff_squared(nao, nmo, nkp, nspin))
223 coeff_squared(:, :, :, :) = rcoeff(:, :, :, :)**2.0d0 + icoeff(:, :, :, :)**2.0d0
225 occ(:, :, :) = 0.0_dp
228 de = probe(1)%T*log((1.0_dp - epsocc)/epsocc)
230 fermi_max = maxval(probe%mu) + de
231 fermi_min = minval(probe%mu) - de
238 CALL hp_occupancy(probe, coeff_squared(:, :, ikp, ispin), energies(:, ikp, ispin), &
239 maxocc, fermi_max, occ(:, ikp, ispin), kts_kp)
241 kts = kts + kts_kp*wk(ikp)
242 n_max = n_max +
accurate_sum(occ(1:nmo, ikp, ispin))*wk(ikp)
252 CALL hp_occupancy(probe, coeff_squared(:, :, ikp, ispin), energies(:, ikp, ispin), &
253 maxocc, fermi_min, occ(:, ikp, ispin), kts_kp)
255 kts = kts + kts_kp*wk(ikp)
256 n_min = n_min +
accurate_sum(occ(1:nmo, ikp, ispin))*wk(ikp)
262 DO WHILE (abs(n_max - n_min) > n*epsocc)
264 fermi_half = (fermi_max + fermi_min)/2.0_dp
270 CALL hp_occupancy(probe, coeff_squared(:, :, ikp, ispin), energies(:, ikp, ispin), &
271 maxocc, fermi_half, occ(:, ikp, ispin), kts_kp)
273 kts = kts + kts_kp*wk(ikp)
274 n_half = n_half +
accurate_sum(occ(1:nmo, ikp, ispin))*wk(ikp)
279 h = fermi_half - fermi_min
280 IF (h .GT. n*epsocc*100)
THEN
285 CALL three_point_zero(y0, y1, y2, h, delta_fermi)
286 fermi_fit = fermi_min + delta_fermi
293 CALL hp_occupancy(probe, coeff_squared(:, :, ikp, ispin), energies(:, ikp, ispin), &
294 maxocc, fermi_fit, occ(:, ikp, ispin), kts_kp)
296 kts = kts + kts_kp*wk(ikp)
297 n_fit = n_fit +
accurate_sum(occ(1:nmo, ikp, ispin))*wk(ikp)
306 fermi_min = fermi_half
308 ELSE IF (n_half > n)
THEN
309 fermi_max = fermi_half
312 fermi_min = fermi_half
314 fermi_max = fermi_half
320 IF (h .GT. n*epsocc*100)
THEN
321 IF (fermi_fit .GE. fermi_min .AND. fermi_fit .LE. fermi_max)
THEN
323 fermi_min = fermi_fit
325 ELSE IF (n_fit > n)
THEN
326 fermi_max = fermi_fit
332 IF (abs(n_max - n) < n*epsocc)
THEN
335 ELSE IF (abs(n_min - n) < n*epsocc)
THEN
340 IF (iter > bisect_max_iter)
THEN
341 cpwarn(
"Maximum number of iterations reached while finding the Fermi energy")
355 CALL hp_occupancy(probe, coeff_squared(:, :, ikp, ispin), energies(:, ikp, ispin), &
356 maxocc, fermi, occ(:, ikp, ispin), kts_kp)
358 kts = kts + kts_kp*wk(ikp)
359 n_now = n_now +
accurate_sum(occ(1:nmo, ikp, ispin))*wk(ikp)
364 DEALLOCATE (coeff_squared)
366 CALL timestop(handle)
384 SUBROUTINE hp_occupancy(probe, matrix, energies, maxocc, fermi, occupancy, kTS)
387 REAL(kind=
dp),
INTENT(IN) :: matrix(:, :), energies(:), maxocc, fermi
388 REAL(kind=
dp),
INTENT(OUT) :: occupancy(:), kts
390 INTEGER :: imo, ip, nmo, np
391 REAL(kind=
dp) :: alpha, c, f, fermi_fun, fermi_fun_sol, &
392 mu, s, sum_coeff, sum_coeff_sol, &
393 sum_fermi_fun, sum_fermi_fun_sol
397 nmo =
SIZE(matrix, 2)
403 mos2:
DO imo = 1, nmo
405 sum_fermi_fun = 0.0_dp
408 sum_fermi_fun_sol = 0.0_dp
409 sum_coeff_sol = 0.0_dp
410 fermi_fun_sol = 0.0_dp
412 probes2:
DO ip = 1, np
413 IF (probe(ip)%alpha .LT. 1.0_dp)
THEN
414 alpha = probe(ip)%alpha
416 CALL fermi_distribution(energies(imo), fermi, probe(ip)%T, fermi_fun_sol)
418 sum_coeff_sol = sum_coeff_sol + sum(matrix(probe(ip)%first_ao:probe(ip)%last_ao, imo))
420 c = sum(matrix(probe(ip)%first_ao:probe(ip)%last_ao, imo))
422 mu = fermi - probe(ip)%mu
424 CALL fermi_distribution(energies(imo), mu, probe(ip)%T, fermi_fun)
426 sum_fermi_fun = sum_fermi_fun + (fermi_fun*c)
428 sum_coeff = sum_coeff + c
432 sum_fermi_fun_sol = alpha*fermi_fun_sol*sum_coeff_sol
433 sum_coeff_sol = alpha*sum_coeff_sol
434 f = (sum_fermi_fun_sol + sum_fermi_fun)/(sum_coeff_sol + sum_coeff)
435 occupancy(imo) = f*maxocc
438 IF (f .EQ. 0.0d0 .OR. f .EQ. 1.0d0)
THEN
441 s = f*log(f) + (1.0d0 - f)*log(1.0d0 - f)
443 kts = kts + probe(np)%T*maxocc*s
446 END SUBROUTINE hp_occupancy
461 SUBROUTINE ao_boundaries(probe, atomic_kind_set, qs_kind_set, particle_set, nAO)
465 TYPE(
qs_kind_type),
INTENT(IN),
POINTER :: qs_kind_set(:)
467 INTEGER,
INTENT(IN) :: nao
469 INTEGER :: iatom, ii, ikind, iset, isgf, ishell, &
470 lshell, natom, nset, nsgf, p_atom
471 INTEGER,
DIMENSION(:),
POINTER :: nshell
472 INTEGER,
DIMENSION(:, :),
POINTER :: l
489 p_atom =
SIZE(probe%atom_ids)
490 probe%first_ao = nsgf
494 atoms:
DO iatom = 1, natom
495 NULLIFY (orb_basis_set)
497 CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
500 CALL get_qs_kind(qs_kind_set(ikind), basis_set=orb_basis_set)
503 IF (
ASSOCIATED(orb_basis_set))
THEN
505 nset=nset, nshell=nshell, l=l)
509 sets:
DO iset = 1, nset
511 shells:
DO ishell = 1, nshell(iset)
512 lshell = l(ishell, iset)
514 isgf = isgf +
nso(lshell)
516 boundaries:
DO ii = 1, p_atom
517 IF (iatom .NE. probe%atom_ids(ii))
THEN
521 probe%first_ao = min(probe%first_ao, isgf)
522 probe%last_ao = max(probe%last_ao, isgf)
530 IF (isgf .NE. nao) cpwarn(
"row count does not correspond to nAO, number of rows in mo_coeff")
544 SUBROUTINE fermi_distribution(E, pot, temp, f_p)
546 REAL(kind=
dp),
INTENT(IN) :: e, pot, temp
547 REAL(kind=
dp),
INTENT(OUT) :: f_p
549 REAL(kind=
dp) :: arg, exponential, exponential_plus_1, f, &
554 arg = -(e - pot)/temp
556 exponential = exp(arg)
557 exponential_plus_1 = exponential + 1.0_dp
559 one_minus_f = exponential/exponential_plus_1
560 f = 1.0_dp/exponential_plus_1
565 exponential = exp(arg)
566 exponential_plus_1 = exponential + 1.0_dp
568 f = 1.0_dp/exponential_plus_1
569 one_minus_f = exponential/exponential_plus_1
573 END SUBROUTINE fermi_distribution
585 SUBROUTINE three_point_zero(y0, y1, y2, h, delta)
587 REAL(kind=
dp),
INTENT(IN) :: y0, y1, y2, h
588 REAL(kind=
dp),
INTENT(OUT) :: delta
590 REAL(kind=
dp) :: a, b, c, d, u0
592 a = (y2 - 2.0_dp*y1 + y0)/(2.0_dp*h*h)
593 b = (4.0_dp*y1 - 3.0_dp*y0 - y2)/(2.0_dp*h)
596 IF (abs(a) .LT. 1.0e-15_dp)
THEN
601 d = sqrt(b*b - 4.0_dp*a*c)
603 u0 = (-b + d)/(2.0_dp*a)
605 IF (u0 .GE. 0.0_dp .AND. u0 .LE. 2.0_dp*h)
THEN
609 u0 = (-b - d)/(2.0_dp*a)
610 IF (u0 .GE. 0.0_dp .AND. u0 .LE. 2.0_dp*h)
THEN
614 IF (y1 .LT. 0.0_dp) delta = 2.0_dp*h
615 IF (y1 .GE. 0.0_dp) delta = 0.0_dp
619 END SUBROUTINE three_point_zero
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind_set(atomic_kind_set, atom_of_kind, kind_of, natom_of_kind, maxatom, natom, nshell, fist_potential_present, shell_present, shell_adiabatic, shell_check_distance, damping_present)
Get attributes of an atomic kind set.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
subroutine, public get_gto_basis_set(gto_basis_set, name, aliases, norm_type, kind_radius, ncgf, nset, nsgf, cgf_symbol, sgf_symbol, norm_cgf, set_radius, lmax, lmin, lx, ly, lz, m, ncgf_set, npgf, nsgf_set, nshell, cphi, pgf_radius, sphi, scon, zet, first_cgf, first_sgf, l, last_cgf, last_sgf, n, gcc, maxco, maxl, maxpgf, maxsgf_set, maxshell, maxso, nco_sum, npgf_sum, nshell_sum, maxder, short_kind_radius, npgf_seg_sum)
...
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
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_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
subroutine, public ao_boundaries(probe, atomic_kind_set, qs_kind_set, particle_set, nao)
...
subroutine, public probe_occupancy_kp(occ, fermi, kts, energies, rcoeff, icoeff, maxocc, probe, n, wk)
subroutine to calculate occupation number and 'Fermi' level using the
subroutine, public probe_occupancy(occ, fermi, kts, energies, coeff, maxocc, probe, n)
subroutine to calculate occupation number and 'Fermi' level using the
sums arrays of real/complex numbers with much reduced round-off as compared to a naive implementation...
Defines the basic variable types.
integer, parameter, public dp
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public nso
Define the data structure for the particle information.
Define the quickstep kind type and their sub types.
subroutine, public get_qs_kind(qs_kind, basis_set, basis_type, ncgf, nsgf, all_potential, tnadd_potential, gth_potential, sgp_potential, upf_potential, se_parameter, dftb_parameter, xtb_parameter, dftb3_param, zatom, zeff, elec_conf, mao, lmax_dftb, alpha_core_charge, ccore_charge, core_charge, core_charge_radius, paw_proj_set, paw_atom, hard_radius, hard0_radius, max_rad_local, covalent_radius, vdw_radius, gpw_type_forced, harmonics, max_iso_not0, max_s_harm, grid_atom, ngrid_ang, ngrid_rad, lmax_rho0, dft_plus_u_atom, l_of_dft_plus_u, n_of_dft_plus_u, u_minus_j, u_of_dft_plus_u, j_of_dft_plus_u, alpha_of_dft_plus_u, beta_of_dft_plus_u, j0_of_dft_plus_u, occupation_of_dft_plus_u, dispersion, bs_occupation, magnetization, no_optimize, addel, laddel, naddel, orbitals, max_scf, eps_scf, smear, u_ramping, u_minus_j_target, eps_u_ramping, init_u_ramping_each_scf, reltmat, ghost, floating, name, element_symbol, pao_basis_size, pao_model_file, pao_potentials, pao_descriptors, nelec)
Get attributes of an atomic kind.
subroutine, public get_qs_kind_set(qs_kind_set, all_potential_present, tnadd_potential_present, gth_potential_present, sgp_potential_present, paw_atom_present, dft_plus_u_atom_present, maxcgf, maxsgf, maxco, maxco_proj, maxgtops, maxlgto, maxlprj, maxnset, maxsgf_set, ncgf, npgf, nset, nsgf, nshell, maxpol, maxlppl, maxlppnl, maxppnl, nelectron, maxder, max_ngrid_rad, max_sph_harm, maxg_iso_not0, lmax_rho0, basis_rcut, basis_type, total_zeff_corr, npgf_seg)
Get attributes of an atomic kind set.
Provides all information about an atomic kind.
Provides all information about a quickstep kind.