45#include "./base/base_uses.f90"
51 REAL(KIND=
dp),
PARAMETER :: epsr = 1.e-12_dp
53 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'qs_dispersion_nonloc'
70 CHARACTER(len=*),
PARAMETER :: routinen =
'qs_dispersion_nonloc_init'
72 CHARACTER(LEN=default_path_length) :: filename
73 INTEGER :: funit, handle, ipair, itable, nqs, &
76 CALL timeset(routinen, handle)
78 SELECT CASE (dispersion_env%nl_type)
80 cpabort(
"Unknown vdW-DF functional")
88 vdw_type = dispersion_env%type
89 SELECT CASE (vdw_type)
94 filename = dispersion_env%kernel_file_name
95 IF (para_env%is_source())
THEN
97 CALL open_file(file_name=filename, unit_number=funit, file_form=
"FORMATTED")
98 READ (funit, *) nqs, nr_points
99 READ (funit, *) dispersion_env%r_max
101 CALL para_env%bcast(nqs)
102 CALL para_env%bcast(nr_points)
103 CALL para_env%bcast(dispersion_env%r_max)
104 ALLOCATE (dispersion_env%q_mesh(nqs), dispersion_env%kernel_table(nqs*(nqs + 1)/2, 0:nr_points, 2))
105 dispersion_env%nqs = nqs
106 dispersion_env%nr_points = nr_points
107 IF (para_env%is_source())
THEN
109 READ (funit,
"(1p, 4e23.14)") dispersion_env%q_mesh
113 DO ipair = 1, nqs*(nqs + 1)/2
114 READ (funit,
"(1p, 4e23.14)") dispersion_env%kernel_table(ipair, 0:nr_points, itable)
119 CALL para_env%bcast(dispersion_env%q_mesh)
120 CALL para_env%bcast(dispersion_env%kernel_table)
122 ALLOCATE (dispersion_env%d2y_dx2(nqs, nqs))
123 CALL initialize_spline_interpolation(dispersion_env%q_mesh, dispersion_env%d2y_dx2)
125 dispersion_env%q_cut = dispersion_env%q_mesh(nqs)
126 dispersion_env%q_min = dispersion_env%q_mesh(1)
127 dispersion_env%dk = 2.0_dp*
pi/dispersion_env%r_max
131 CALL timestop(handle)
150 dispersion_env, energy_only, pw_pool, xc_pw_pool, para_env, virial)
153 REAL(kind=
dp),
INTENT(OUT) :: edispersion
155 LOGICAL,
INTENT(IN) :: energy_only
160 CHARACTER(LEN=*),
PARAMETER :: routinen =
'calculate_dispersion_nonloc'
161 INTEGER,
DIMENSION(3, 3),
PARAMETER :: nd = reshape([1, 0, 0, 0, 1, 0, 0, 0, 1], [3, 3])
163 INTEGER :: handle, handle_fft, i, i_grid, idir, &
164 ispin, nl_type, np, nspin, p, q, r, s
165 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: q_low
166 INTEGER,
DIMENSION(1:3) :: hi, lo, n
167 LOGICAL :: use_virial
168 REAL(kind=
dp) :: b_value, beta, ec_nl, sumnp
169 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: dq0_dgradrho, dq0_drho, hpot, q0, rho, &
171 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: drho, spline_coeff, u_contract
172 REAL(kind=
dp),
CONTIGUOUS,
POINTER :: tmp_1d(:), vxc_1d(:)
178 CALL timeset(routinen, handle)
180 cpassert(
ASSOCIATED(rho_r))
181 cpassert(
ASSOCIATED(rho_g))
182 cpassert(
ASSOCIATED(pw_pool))
184 IF (
PRESENT(virial))
THEN
185 use_virial = virial%pv_calculate .AND. (.NOT. virial%pv_numer)
190 cpassert(.NOT. energy_only)
192 IF (.NOT. energy_only)
THEN
193 cpassert(
ASSOCIATED(vxc_rho))
196 nl_type = dispersion_env%nl_type
198 b_value = dispersion_env%b_value
199 beta = 0.03125_dp*(3.0_dp/(b_value**2.0_dp))**0.75_dp
203 CALL pw_pool%create_pw(tmp_g)
204 CALL pw_pool%create_pw(tmp_r)
207 CALL pw_pool%create_pw(rho_tot_g)
211 CALL pw_axpy(tmp_g, rho_tot_g, 1._dp)
215 np =
SIZE(tmp_r%array)
216 tmp_1d(1:np) => tmp_r%array
217 ALLOCATE (rho(np), drho(np, 3))
219 lo(i) = lbound(tmp_r%array, i)
220 hi(i) = ubound(tmp_r%array, i)
221 n(i) = hi(i) - lo(i) + 1
228 s = r*n(2)*n(1) + q*n(1) + p + 1
229 rho(s) = tmp_r%array(p + lo(1), q + lo(2), r + lo(3))
243 s = r*n(2)*n(1) + q*n(1) + p + 1
244 drho(s, idir) = tmp_r%array(p + lo(1), q + lo(2), r + lo(3))
250 CALL pw_pool%give_back_pw(rho_tot_g)
260 IF (energy_only)
THEN
262 SELECT CASE (nl_type)
264 cpabort(
"Unknown vdW-DF functional")
266 CALL get_q0_on_grid_eo_vdw(rho, drho, q0, dispersion_env)
268 CALL get_q0_on_grid_eo_rvv10(rho, drho, q0, dispersion_env)
271 ALLOCATE (q0(np), dq0_drho(np), dq0_dgradrho(np))
272 SELECT CASE (nl_type)
274 cpabort(
"Unknown vdW-DF functional")
276 CALL get_q0_on_grid_vdw(rho, drho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
278 CALL get_q0_on_grid_rvv10(rho, drho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
284 ALLOCATE (q_low(np), spline_coeff(np, 4), theta_scale(np))
285 CALL prepare_splines(q0, rho, dispersion_env, q_low, spline_coeff, theta_scale)
286 ALLOCATE (thetas_g(dispersion_env%nqs))
287 CALL timeset(
"vdW_theta_forward", handle_fft)
288 DO i = 1, dispersion_env%nqs
289 CALL build_theta(i, q_low, spline_coeff, theta_scale, dispersion_env, tmp_1d)
290 CALL pw_pool%create_pw(thetas_g(i))
293 CALL timestop(handle_fft)
294 DEALLOCATE (spline_coeff, theta_scale)
295 grid => thetas_g(1)%pw_grid
302 CALL para_env%sum(sumnp)
305 CALL vdw_energy(thetas_g, dispersion_env, ec_nl, energy_only, virial)
306 SELECT CASE (nl_type)
308 ec_nl = 0.5_dp*ec_nl + beta*sum(rho(:))*grid%vol/sumnp
313 virial%pv_xc(idir, idir) = virial%pv_xc(idir, idir) + ec_nl
316 CALL vdw_energy(thetas_g, dispersion_env, ec_nl, energy_only)
317 SELECT CASE (nl_type)
319 ec_nl = 0.5_dp*ec_nl + beta*sum(rho(:))*grid%vol/sumnp
322 CALL para_env%sum(ec_nl)
323 IF (nl_type ==
vdw_nl_rvv10) ec_nl = ec_nl*dispersion_env%scale_rvv10
326 IF (energy_only)
THEN
327 DEALLOCATE (q0, q_low)
331 ALLOCATE (u_contract(np, 4), hpot(np))
335 IF (s > 0 .AND. s < dispersion_env%nqs - 1)
THEN
336 IF (q0(i_grid) == dispersion_env%q_mesh(s + 1)) q_low(i_grid) = s + 1
338 u_contract(i_grid, :) = 0.0_dp
341 CALL timeset(
"vdW_theta_inverse", handle_fft)
342 DO i = 1, dispersion_env%nqs
344 CALL accumulate_potential(i, q_low, dispersion_env, tmp_1d, u_contract)
346 CALL timestop(handle_fft)
349 CALL pw_pool%create_pw(vxc_r)
350 vxc_1d(1:np) => vxc_r%array
352 grid => tmp_g%pw_grid
353 CALL get_potential(q0, dq0_drho, dq0_dgradrho, rho, q_low, u_contract, vxc_1d, hpot, &
354 dispersion_env, drho, grid%dvol, virial)
356 CALL get_potential(q0, dq0_drho, dq0_dgradrho, rho, q_low, u_contract, vxc_1d, hpot, &
359 DEALLOCATE (u_contract, q_low, q0, dq0_drho, dq0_dgradrho)
360 SELECT CASE (nl_type)
364 vxc_1d(i_grid) = (0.5_dp*vxc_1d(i_grid) + beta)*dispersion_env%scale_rvv10
365 hpot(i_grid) = 0.5_dp*dispersion_env%scale_rvv10*hpot(i_grid)
372 CALL pw_pool%create_pw(div_g)
379 s = r*n(2)*n(1) + q*n(1) + p + 1
380 tmp_r%array(p + lo(1), q + lo(2), r + lo(3)) = hpot(s)*drho(s, idir)
390 CALL pw_axpy(tmp_g, div_g, 1._dp)
394 CALL pw_pool%give_back_pw(div_g)
395 CALL pw_axpy(tmp_r, vxc_r, -1._dp)
397 CALL pw_pool%give_back_pw(vxc_r)
398 CALL xc_pw_pool%create_pw(vxc_r)
399 CALL xc_pw_pool%create_pw(vxc_g)
403 CALL pw_axpy(vxc_r, vxc_rho(ispin), 1._dp)
405 CALL xc_pw_pool%give_back_pw(vxc_r)
406 CALL xc_pw_pool%give_back_pw(vxc_g)
411 DO i = 1, dispersion_env%nqs
412 CALL pw_pool%give_back_pw(thetas_g(i))
414 CALL pw_pool%give_back_pw(tmp_r)
415 CALL pw_pool%give_back_pw(tmp_g)
417 DEALLOCATE (rho, drho, thetas_g)
419 CALL timestop(handle)
436 SUBROUTINE vdw_energy(thetas_g, dispersion_env, vdW_xc_energy, energy_only, virial)
439 REAL(kind=
dp),
INTENT(OUT) :: vdw_xc_energy
440 LOGICAL,
INTENT(IN) :: energy_only
443 CHARACTER(LEN=*),
PARAMETER :: routinen =
'vdW_energy'
445 INTEGER :: handle, ig, iq, l, m, nl_type, nqs, &
447 LOGICAL :: use_virial
448 REAL(kind=
dp) :: g, g2, g2_last, g_multiplier, gm
449 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: theta_im, theta_re, u_im, u_re
450 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: dkernel_of_dk, kernel_of_k
451 REAL(kind=
dp),
DIMENSION(3, 3) :: virial_thread
454 CALL timeset(routinen, handle)
455 nqs = dispersion_env%nqs
457 use_virial =
PRESENT(virial)
458 virial_thread(:, :) = 0.0_dp
460 vdw_xc_energy = 0._dp
461 grid => thetas_g(1)%pw_grid
469 nl_type = dispersion_env%nl_type
478 g2_last = huge(0._dp)
480 ALLOCATE (kernel_of_k(nqs, nqs))
481 IF (use_virial)
ALLOCATE (dkernel_of_dk(nqs, nqs))
482 ALLOCATE (theta_re(nqs), theta_im(nqs), u_re(nqs), u_im(nqs))
485 DO ig = 1, grid%ngpts_cut_local
487 IF (abs(g2 - g2_last) > 1.e-10)
THEN
491 CALL interpolate_kernel(g, kernel_of_k, dispersion_env, dispersion_env%kernel_table, dkernel_of_dk)
493 CALL interpolate_kernel(g, kernel_of_k, dispersion_env, dispersion_env%kernel_table)
499 theta_re(iq) = real(thetas_g(iq)%array(ig), kind=
dp)
500 theta_im(iq) = aimag(thetas_g(iq)%array(ig))
507 u_re(q2_i) = u_re(q2_i) + kernel_of_k(q2_i, q1_i)*theta_re(q1_i)
508 u_im(q2_i) = u_im(q2_i) + kernel_of_k(q2_i, q1_i)*theta_im(q1_i)
513 IF (ig < grid%first_gne0)
THEN
514 vdw_xc_energy = vdw_xc_energy + (u_re(q2_i)*theta_re(q2_i) + u_im(q2_i)*theta_im(q2_i))
516 vdw_xc_energy = vdw_xc_energy &
517 + g_multiplier*(u_re(q2_i)*theta_re(q2_i) + u_im(q2_i)*theta_im(q2_i))
519 IF (.NOT. energy_only) thetas_g(q2_i)%array(ig) = cmplx(u_re(q2_i), u_im(q2_i), kind=
dp)
522 IF (use_virial .AND. ig >= grid%first_gne0)
THEN
528 gm = gm + dkernel_of_dk(q1_i, q2_i) &
529 *(theta_re(q1_i)*theta_re(q2_i) + theta_im(q1_i)*theta_im(q2_i))
533 gm = 0.5_dp*g_multiplier*grid%vol*gm
537 virial_thread(l, m) = virial_thread(l, m) - gm*(grid%g(l, ig)*grid%g(m, ig))/g
544 DEALLOCATE (theta_re, theta_im, u_re, u_im, kernel_of_k)
545 IF (use_virial)
DEALLOCATE (dkernel_of_dk)
549 vdw_xc_energy = vdw_xc_energy*grid%vol*0.5_dp
554 virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
555 virial%pv_xc(m, l) = virial%pv_xc(l, m)
558 virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
562 CALL timestop(handle)
564 END SUBROUTINE vdw_energy
590 SUBROUTINE get_potential(q0, dq0_drho, dq0_dgradrho, total_rho, q_low_grid, u_contract, potential, h_prefactor, &
591 dispersion_env, drho, dvol, virial)
593 REAL(
dp),
DIMENSION(:),
INTENT(in) :: q0, dq0_drho, dq0_dgradrho, total_rho
594 INTEGER,
DIMENSION(:),
INTENT(IN) :: q_low_grid
595 REAL(
dp),
DIMENSION(:, :),
INTENT(in) :: u_contract
596 REAL(
dp),
DIMENSION(:),
INTENT(out) :: potential, h_prefactor
598 REAL(
dp),
DIMENSION(:, :),
INTENT(in),
OPTIONAL :: drho
599 REAL(
dp),
INTENT(IN),
OPTIONAL :: dvol
602 CHARACTER(len=*),
PARAMETER :: routinen =
'get_potential'
604 INTEGER :: handle, i_grid, l, m, nl_type, nqs, &
606 LOGICAL :: use_virial
607 REAL(
dp) :: a, b, b_value, c, const, d, dq, dq_6, e, &
608 f, prefactor, tmp_1_2, tmp_1_4, &
609 tmp_3_4, u_dp_dq0, u_p
610 REAL(
dp),
DIMENSION(3, 3) :: virial_thread
611 REAL(
dp),
DIMENSION(:),
POINTER :: q_mesh
613 CALL timeset(routinen, handle)
615 use_virial =
PRESENT(virial)
616 cpassert(.NOT. use_virial .OR.
PRESENT(drho))
617 cpassert(.NOT. use_virial .OR.
PRESENT(dvol))
619 virial_thread(:, :) = 0.0_dp
620 b_value = dispersion_env%b_value
621 const = 1.0_dp/(3.0_dp*b_value**(3.0_dp/2.0_dp)*
pi**(5.0_dp/4.0_dp))
623 q_mesh => dispersion_env%q_mesh
624 nqs = dispersion_env%nqs
625 nl_type = dispersion_env%nl_type
635 DO i_grid = 1,
SIZE(q0)
636 potential(i_grid) = 0.0_dp
637 h_prefactor(i_grid) = 0.0_dp
638 IF (nl_type ==
vdw_nl_rvv10 .AND. total_rho(i_grid) <= epsr) cycle
639 q_low = q_low_grid(i_grid)
642 dq = q_mesh(q_hi) - q_mesh(q_low)
645 a = (q_mesh(q_hi) - q0(i_grid))/dq
646 b = (q0(i_grid) - q_mesh(q_low))/dq
647 c = (a**3 - a)*dq*dq_6
648 d = (b**3 - b)*dq*dq_6
649 e = (3.0_dp*a**2 - 1.0_dp)*dq_6
650 f = (3.0_dp*b**2 - 1.0_dp)*dq_6
652 u_p = a*u_contract(i_grid, 3) + b*u_contract(i_grid, 4) &
653 + c*u_contract(i_grid, 1) + d*u_contract(i_grid, 2)
654 u_dp_dq0 = (u_contract(i_grid, 4) - u_contract(i_grid, 3))/dq &
655 - e*u_contract(i_grid, 1) + f*u_contract(i_grid, 2)
658 SELECT CASE (nl_type)
660 cpabort(
"Unknown vdW-DF functional")
662 potential(i_grid) = u_p + u_dp_dq0*dq0_drho(i_grid)
663 prefactor = u_dp_dq0*dq0_dgradrho(i_grid)
665 tmp_1_2 = sqrt(total_rho(i_grid))
666 tmp_1_4 = sqrt(tmp_1_2)
667 tmp_3_4 = tmp_1_4*tmp_1_4*tmp_1_4
668 potential(i_grid) = const*0.75_dp/tmp_1_4*u_p + const*tmp_3_4*u_dp_dq0*dq0_drho(i_grid)
669 prefactor = const*tmp_3_4*u_dp_dq0*dq0_dgradrho(i_grid)
671 IF (q0(i_grid) /= q_mesh(nqs))
THEN
672 h_prefactor(i_grid) = prefactor
676 IF (use_virial .AND. abs(prefactor) > 0.0_dp)
THEN
677 IF (nl_type ==
vdw_nl_rvv10) prefactor = 0.5_dp*prefactor
678 prefactor = prefactor*dvol
681 virial_thread(l, m) = virial_thread(l, m) - prefactor*drho(i_grid, l)*drho(i_grid, m)
693 virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
694 virial%pv_xc(m, l) = virial%pv_xc(l, m)
697 virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
701 CALL timestop(handle)
702 END SUBROUTINE get_potential
712 ELEMENTAL SUBROUTINE calculate_exponent(hi, alpha, exponent)
713 INTEGER,
INTENT(in) :: hi
714 REAL(
dp),
INTENT(in) :: alpha
715 REAL(
dp),
INTENT(out) :: exponent
718 REAL(
dp) :: multiplier
724 multiplier = multiplier*alpha
725 exponent = exponent + (multiplier/i)
727 END SUBROUTINE calculate_exponent
739 ELEMENTAL SUBROUTINE calculate_exponent_derivative(hi, alpha, exponent, derivative)
740 INTEGER,
INTENT(in) :: hi
741 REAL(
dp),
INTENT(in) :: alpha
742 REAL(
dp),
INTENT(out) :: exponent, derivative
745 REAL(
dp) :: multiplier
752 derivative = derivative + multiplier
753 multiplier = multiplier*alpha
754 exponent = exponent + (multiplier/i)
756 END SUBROUTINE calculate_exponent_derivative
770 SUBROUTINE get_q0_on_grid_vdw(total_rho, gradient_rho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
778 REAL(
dp),
INTENT(IN) :: total_rho(:), gradient_rho(:, :)
779 REAL(
dp),
INTENT(OUT) :: q0(:), dq0_drho(:), dq0_dgradrho(:)
782 INTEGER,
PARAMETER :: m_cut = 12
783 REAL(
dp),
PARAMETER :: lda_a = 0.031091_dp, lda_a1 = 0.2137_dp, lda_b1 = 7.5957_dp, &
784 lda_b2 = 3.5876_dp, lda_b3 = 1.6382_dp, lda_b4 = 0.49294_dp
787 REAL(
dp) :: dq0_dq, exponent, gradient_correction, &
788 kf, lda_1, lda_2, q, q__q_cut, q_cut, &
789 q_min, r_s, sqrt_r_s, z_ab
791 q_cut = dispersion_env%q_cut
792 q_min = dispersion_env%q_min
793 SELECT CASE (dispersion_env%nl_type)
795 cpabort(
"Unknown vdW-DF functional")
806 DO i_grid = 1,
SIZE(total_rho)
808 dq0_drho(i_grid) = 0.0_dp
809 dq0_dgradrho(i_grid) = 0.0_dp
817 IF (total_rho(i_grid) < epsr) cycle
821 kf = (3.0_dp*
pi*
pi*total_rho(i_grid))**(1.0_dp/3.0_dp)
822 r_s = (3.0_dp/(4.0_dp*
pi*total_rho(i_grid)))**(1.0_dp/3.0_dp)
825 gradient_correction = -z_ab/(36.0_dp*kf*total_rho(i_grid)**2) &
826 *(gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2)
828 lda_1 = 8.0_dp*
pi/3.0_dp*(lda_a*(1.0_dp + lda_a1*r_s))
829 lda_2 = 2.0_dp*lda_a*(lda_b1*sqrt_r_s + lda_b2*r_s + lda_b3*r_s*sqrt_r_s + lda_b4*r_s*r_s)
833 q = kf + lda_1*log(1.0_dp + 1.0_dp/lda_2) + gradient_correction
839 CALL calculate_exponent_derivative(m_cut, q__q_cut, exponent, dq0_dq)
840 q0(i_grid) = q_cut*(1.0_dp - exp(-exponent))
841 dq0_dq = dq0_dq*exp(-exponent)
846 IF (q0(i_grid) < q_min)
THEN
861 dq0_drho(i_grid) = dq0_dq*(kf/3.0_dp - 7.0_dp/3.0_dp*gradient_correction &
862 - 8.0_dp*
pi/9.0_dp*lda_a*lda_a1*r_s*log(1.0_dp + 1.0_dp/lda_2) &
863 + lda_1/(lda_2*(1.0_dp + lda_2)) &
864 *(2.0_dp*lda_a*(lda_b1/6.0_dp*sqrt_r_s + lda_b2/3.0_dp*r_s + lda_b3/2.0_dp*r_s*sqrt_r_s &
865 + 2.0_dp*lda_b4/3.0_dp*r_s**2)))
867 dq0_dgradrho(i_grid) = total_rho(i_grid)*dq0_dq*2.0_dp*(-z_ab)/(36.0_dp*kf*total_rho(i_grid)**2)
872 END SUBROUTINE get_q0_on_grid_vdw
883 SUBROUTINE get_q0_on_grid_rvv10(total_rho, gradient_rho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
891 REAL(
dp),
INTENT(IN) :: total_rho(:), gradient_rho(:, :)
892 REAL(
dp),
INTENT(OUT) :: q0(:), dq0_drho(:), dq0_dgradrho(:)
895 INTEGER,
PARAMETER :: m_cut = 12
898 REAL(
dp) :: b_value, c_value, dk_dn, dq0_dq, dw0_dn, &
899 exponent, gmod2, k, mod_grad, q, &
900 q__q_cut, q_cut, q_min, w0, wg2, wp2
902 q_cut = dispersion_env%q_cut
903 q_min = dispersion_env%q_min
904 b_value = dispersion_env%b_value
905 c_value = dispersion_env%c_value
911 DO i_grid = 1,
SIZE(total_rho)
913 dq0_drho(i_grid) = 0.0_dp
914 dq0_dgradrho(i_grid) = 0.0_dp
916 gmod2 = gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2
919 IF (total_rho(i_grid) > epsr)
THEN
923 mod_grad = sqrt(gmod2)
925 wp2 = 16.0_dp*
pi*total_rho(i_grid)
926 wg2 = 4_dp*c_value*(mod_grad/total_rho(i_grid))**4
928 k = b_value*3.0_dp*
pi*((total_rho(i_grid)/(9.0_dp*
pi))**(1.0_dp/6.0_dp))
929 w0 = sqrt(wg2 + wp2/3.0_dp)
936 CALL calculate_exponent_derivative(m_cut, q__q_cut, exponent, dq0_dq)
937 q0(i_grid) = q_cut*(1.0_dp - exp(-exponent))
938 dq0_dq = dq0_dq*exp(-exponent)
941 IF (q0(i_grid) < q_min)
THEN
946 dw0_dn = 1.0_dp/(2.0_dp*w0)*(16.0_dp/3.0_dp*
pi - 4.0_dp*wg2/total_rho(i_grid))
947 dk_dn = k/(6.0_dp*total_rho(i_grid))
949 dq0_drho(i_grid) = dq0_dq*1.0_dp/(k**2.0)*(dw0_dn*k - dk_dn*w0)
951 IF (gmod2 > 0.0_dp)
THEN
952 dq0_dgradrho(i_grid) = dq0_dq*1.0_dp/(2.0_dp*k*w0)*4.0_dp*wg2/gmod2
959 END SUBROUTINE get_q0_on_grid_rvv10
968 SUBROUTINE get_q0_on_grid_eo_vdw(total_rho, gradient_rho, q0, dispersion_env)
970 REAL(
dp),
INTENT(IN) :: total_rho(:), gradient_rho(:, :)
971 REAL(
dp),
INTENT(OUT) :: q0(:)
974 INTEGER,
PARAMETER :: m_cut = 12
975 REAL(
dp),
PARAMETER :: lda_a = 0.031091_dp, lda_a1 = 0.2137_dp, lda_b1 = 7.5957_dp, &
976 lda_b2 = 3.5876_dp, lda_b3 = 1.6382_dp, lda_b4 = 0.49294_dp
979 REAL(
dp) :: exponent, gradient_correction, kf, &
980 lda_1, lda_2, q, q__q_cut, q_cut, &
981 q_min, r_s, sqrt_r_s, z_ab
983 q_cut = dispersion_env%q_cut
984 q_min = dispersion_env%q_min
985 SELECT CASE (dispersion_env%nl_type)
987 cpabort(
"Unknown vdW-DF functional")
998 DO i_grid = 1,
SIZE(total_rho)
1006 IF (total_rho(i_grid) < epsr) cycle
1010 kf = (3.0_dp*
pi*
pi*total_rho(i_grid))**(1.0_dp/3.0_dp)
1011 r_s = (3.0_dp/(4.0_dp*
pi*total_rho(i_grid)))**(1.0_dp/3.0_dp)
1012 sqrt_r_s = sqrt(r_s)
1014 gradient_correction = -z_ab/(36.0_dp*kf*total_rho(i_grid)**2) &
1015 *(gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2)
1017 lda_1 = 8.0_dp*
pi/3.0_dp*(lda_a*(1.0_dp + lda_a1*r_s))
1018 lda_2 = 2.0_dp*lda_a*(lda_b1*sqrt_r_s + lda_b2*r_s + lda_b3*r_s*sqrt_r_s + lda_b4*r_s*r_s)
1022 q = kf + lda_1*log(1.0_dp + 1.0_dp/lda_2) + gradient_correction
1029 CALL calculate_exponent(m_cut, q__q_cut, exponent)
1030 q0(i_grid) = q_cut*(1.0_dp - exp(-exponent))
1036 IF (q0(i_grid) < q_min)
THEN
1042 END SUBROUTINE get_q0_on_grid_eo_vdw
1051 SUBROUTINE get_q0_on_grid_eo_rvv10(total_rho, gradient_rho, q0, dispersion_env)
1053 REAL(
dp),
INTENT(IN) :: total_rho(:), gradient_rho(:, :)
1054 REAL(
dp),
INTENT(OUT) :: q0(:)
1057 INTEGER,
PARAMETER :: m_cut = 12
1060 REAL(
dp) :: b_value, c_value, exponent, gmod2, k, q, &
1061 q__q_cut, q_cut, q_min, w0, wg2, wp2
1063 q_cut = dispersion_env%q_cut
1064 q_min = dispersion_env%q_min
1065 b_value = dispersion_env%b_value
1066 c_value = dispersion_env%c_value
1072 DO i_grid = 1,
SIZE(total_rho)
1075 gmod2 = gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2
1078 IF (total_rho(i_grid) > epsr)
THEN
1082 wp2 = 16.0_dp*
pi*total_rho(i_grid)
1083 wg2 = 4_dp*c_value*(gmod2*gmod2)/(total_rho(i_grid)**4)
1085 k = b_value*3.0_dp*
pi*((total_rho(i_grid)/(9.0_dp*
pi))**(1.0_dp/6.0_dp))
1086 w0 = sqrt(wg2 + wp2/3.0_dp)
1093 CALL calculate_exponent(m_cut, q__q_cut, exponent)
1094 q0(i_grid) = q_cut*(1.0_dp - exp(-exponent))
1096 IF (q0(i_grid) < q_min)
THEN
1105 END SUBROUTINE get_q0_on_grid_eo_rvv10
1116 SUBROUTINE prepare_splines(q0, rho, dispersion_env, q_low, coeff, theta_scale)
1117 REAL(
dp),
INTENT(IN) :: q0(:), rho(:)
1119 INTEGER,
INTENT(OUT) :: q_low(:)
1120 REAL(
dp),
INTENT(OUT) :: coeff(:, :), theta_scale(:)
1122 INTEGER :: i, j, lower, nqs, upper
1124 REAL(
dp) :: a, b, const, dx, dx2_6
1125 REAL(
dp),
POINTER :: q_mesh(:)
1127 q_mesh => dispersion_env%q_mesh
1128 nqs = dispersion_env%nqs
1131 const = 1.0_dp/(3.0_dp*
rootpi*dispersion_env%b_value**1.5_dp)/(
pi**0.75_dp)
1136 IF (rvv10 .AND. rho(i) <= epsr)
THEN
1138 coeff(i, :) = 0.0_dp
1139 theta_scale(i) = 0.0_dp
1144 DO WHILE (upper - lower > 1)
1145 j = (upper + lower)/2
1146 IF (q0(i) > q_mesh(j))
THEN
1153 dx = q_mesh(upper) - q_mesh(lower)
1154 dx2_6 = dx*dx/6.0_dp
1155 a = (q_mesh(upper) - q0(i))/dx
1156 b = (q0(i) - q_mesh(lower))/dx
1159 coeff(i, 3) = (a**3 - a)*dx2_6
1160 coeff(i, 4) = (b**3 - b)*dx2_6
1162 theta_scale(i) = const*rho(i)**0.75_dp
1164 theta_scale(i) = rho(i)
1168 END SUBROUTINE prepare_splines
1179 SUBROUTINE build_theta(iq, q_low, coeff, theta_scale, dispersion_env, theta)
1180 INTEGER,
INTENT(IN) :: iq, q_low(:)
1181 REAL(
dp),
INTENT(IN) :: coeff(:, :), theta_scale(:)
1183 REAL(
dp),
INTENT(OUT) :: theta(:)
1187 REAL(
dp),
POINTER :: d2y(:, :)
1189 d2y => dispersion_env%d2y_dx2
1192 DO i = 1,
SIZE(theta)
1195 IF (lower == 0) cycle
1196 p = coeff(i, 1)*merge(1.0_dp, 0.0_dp, iq == lower) &
1197 + coeff(i, 2)*merge(1.0_dp, 0.0_dp, iq == lower + 1) &
1198 + (coeff(i, 3)*d2y(iq, lower) + coeff(i, 4)*d2y(iq, lower + 1))
1199 theta(i) = p*theta_scale(i)
1202 END SUBROUTINE build_theta
1212 SUBROUTINE accumulate_potential(iq, q_low, dispersion_env, u, u_contract)
1213 INTEGER,
INTENT(IN) :: iq, q_low(:)
1215 REAL(
dp),
INTENT(IN) :: u(:)
1216 REAL(
dp),
INTENT(INOUT) :: u_contract(:, :)
1219 REAL(
dp),
POINTER :: d2y(:, :)
1221 d2y => dispersion_env%d2y_dx2
1226 IF (lower == 0) cycle
1227 u_contract(i, 1) = u_contract(i, 1) + u(i)*d2y(iq, lower)
1228 u_contract(i, 2) = u_contract(i, 2) + u(i)*d2y(iq, lower + 1)
1229 IF (iq == lower) u_contract(i, 3) = u(i)
1230 IF (iq == lower + 1) u_contract(i, 4) = u(i)
1233 END SUBROUTINE accumulate_potential
1243 SUBROUTINE initialize_spline_interpolation(x, d2y_dx2)
1245 REAL(
dp),
INTENT(in) :: x(:)
1246 REAL(
dp),
INTENT(inout) :: d2y_dx2(:, :)
1248 INTEGER :: index, nx, p_i
1249 REAL(
dp) :: temp1, temp2
1250 REAL(
dp),
ALLOCATABLE :: temp_array(:), y(:)
1260 ALLOCATE (temp_array(nx), y(nx))
1272 d2y_dx2(p_i, 1) = 0.0_dp
1273 temp_array(1) = 0.0_dp
1274 DO index = 2, nx - 1
1275 temp1 = (x(index) - x(index - 1))/(x(index + 1) - x(index - 1))
1276 temp2 = temp1*d2y_dx2(p_i, index - 1) + 2.0_dp
1277 d2y_dx2(p_i, index) = (temp1 - 1.0_dp)/temp2
1278 temp_array(index) = (y(index + 1) - y(index))/(x(index + 1) - x(index)) &
1279 - (y(index) - y(index - 1))/(x(index) - x(index - 1))
1280 temp_array(index) = (6.0_dp*temp_array(index)/(x(index + 1) - x(index - 1)) &
1281 - temp1*temp_array(index - 1))/temp2
1283 d2y_dx2(p_i, nx) = 0.0_dp
1284 DO index = nx - 1, 1, -1
1285 d2y_dx2(p_i, index) = d2y_dx2(p_i, index)*d2y_dx2(p_i, index + 1) + temp_array(index)
1290 DEALLOCATE (temp_array, y)
1293 END SUBROUTINE initialize_spline_interpolation
1303 SUBROUTINE interpolate_kernel(k, kernel_of_k, dispersion_env, kernel_table, dkernel_of_dk)
1304 REAL(
dp),
INTENT(IN) :: k
1305 REAL(
dp),
INTENT(OUT) :: kernel_of_k(:, :)
1307 REAL(
dp),
INTENT(IN) :: kernel_table(:, 0:, :)
1308 REAL(
dp),
INTENT(OUT),
OPTIONAL :: dkernel_of_dk(:, :)
1310 INTEGER :: ipair, k_i, q1_i, q2_i
1312 REAL(
dp) :: a, b, c, d, da, db, dc, dd, dk, dk_6, &
1315 dk = dispersion_env%dk
1316 cpassert(k < dispersion_env%nr_points*dk)
1318 on_mesh = mod(k, dk) == 0.0_dp
1319 a = (dk*(k_i + 1.0_dp) - k)/dk
1321 c = (a**3 - a)*(dk*dk/6.0_dp)
1322 d = (b**3 - b)*(dk*dk/6.0_dp)
1323 DO q1_i = 1, dispersion_env%nqs
1326 ipair = q1_i*(q1_i - 1)/2 + q2_i
1328 value = kernel_table(ipair, k_i, 1)
1330 value = a*kernel_table(ipair, k_i, 1) + b*kernel_table(ipair, k_i + 1, 1) &
1331 + (c*kernel_table(ipair, k_i, 2) + d*kernel_table(ipair, k_i + 1, 2))
1333 kernel_of_k(q2_i, q1_i) =
value
1334 kernel_of_k(q1_i, q2_i) =
value
1338 IF (
PRESENT(dkernel_of_dk))
THEN
1342 dc = -(3*a**2 - 1.0_dp)*dk_6
1343 dd = (3*b**2 - 1.0_dp)*dk_6
1344 DO q1_i = 1, dispersion_env%nqs
1347 ipair = q1_i*(q1_i - 1)/2 + q2_i
1348 value = da*kernel_table(ipair, k_i, 1) + db*kernel_table(ipair, k_i + 1, 1) &
1349 + dc*kernel_table(ipair, k_i, 2) + dd*kernel_table(ipair, k_i + 1, 2)
1350 dkernel_of_dk(q2_i, q1_i) =
value
1351 dkernel_of_dk(q1_i, q2_i) =
value
1356 END SUBROUTINE interpolate_kernel
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public dion2004
integer, save, public romanperez2009
integer, save, public sabatini2013
Utility routines to open and close files. Tracking of preconnections.
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_path_length
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
real(kind=dp), parameter, public rootpi
Interface to the message passing library MPI.
integer, parameter, public halfspace
subroutine, public pw_derive(pw, n)
Calculate the derivative of a plane wave vector.
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Calculation of non local dispersion functionals Some routines adapted from: Copyright (C) 2001-2009 Q...
subroutine, public qs_dispersion_nonloc_init(dispersion_env, para_env)
...
subroutine, public calculate_dispersion_nonloc(vxc_rho, rho_r, rho_g, edispersion, dispersion_env, energy_only, pw_pool, xc_pw_pool, para_env, virial)
Calculates the non-local vdW functional using the method of Soler For spin polarized cases we use E(a...
Definition of disperson types for DFT calculations.
stores all the informations relevant to an mpi environment
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...