Line data Source code
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 Exchange and Correlation functional calculations
10 : !> \par History
11 : !> (13-Feb-2001) JGH, based on earlier version of apsi
12 : !> 02.2003 Many many changes [fawzi]
13 : !> 03.2004 new xc interface [fawzi]
14 : !> 04.2004 kinetic functionals [fawzi]
15 : !> \author fawzi
16 : ! **************************************************************************************************
17 : MODULE xc
18 : #:include 'xc.fypp'
19 : USE cp_array_utils, ONLY: cp_3d_r_cp_type
20 : USE cp_linked_list_xc_deriv, ONLY: cp_sll_xc_deriv_next, &
21 : cp_sll_xc_deriv_type
22 : USE cp_log_handling, ONLY: cp_get_default_logger, &
23 : cp_logger_get_default_unit_nr, &
24 : cp_logger_type, &
25 : cp_to_string
26 : USE input_section_types, ONLY: section_get_ival, &
27 : section_get_lval, &
28 : section_get_rval, &
29 : section_vals_get_subs_vals, &
30 : section_vals_type, &
31 : section_vals_val_get
32 : USE kahan_sum, ONLY: accurate_dot_product, &
33 : accurate_sum
34 : USE kinds, ONLY: default_path_length, &
35 : dp
36 : USE pw_grid_types, ONLY: PW_MODE_DISTRIBUTED, &
37 : pw_grid_type
38 : USE pw_methods, ONLY: pw_axpy, &
39 : pw_copy, &
40 : pw_copy_to_array, &
41 : pw_derive, &
42 : pw_multiply_with, &
43 : pw_scale, &
44 : pw_transfer, &
45 : pw_zero, pw_integrate_function, pw_integral_ab
46 : USE pw_pool_types, ONLY: &
47 : pw_pool_type
48 : USE pw_types, ONLY: &
49 : pw_c1d_gs_type, pw_r3d_rs_type
50 : USE xc_derivative_desc, ONLY: &
51 : deriv_rho, deriv_rhoa, deriv_rhob, &
52 : deriv_norm_drhoa, deriv_norm_drhob, deriv_norm_drho, deriv_tau_a, deriv_tau_b, deriv_tau, &
53 : deriv_laplace_rho, deriv_laplace_rhoa, deriv_laplace_rhob, id_to_desc
54 : USE xc_derivative_set_types, ONLY: xc_derivative_set_type, &
55 : xc_dset_create, &
56 : xc_dset_get_derivative, &
57 : xc_dset_release, &
58 : xc_dset_zero_all, xc_dset_recover_pw
59 : USE xc_derivative_types, ONLY: xc_derivative_get, &
60 : xc_derivative_type
61 : USE xc_derivatives, ONLY: xc_functionals_eval, &
62 : xc_functionals_get_needs
63 : USE xc_gauxc_functional, ONLY: xc_section_uses_gauxc
64 : USE xc_rho_cflags_types, ONLY: xc_rho_cflags_type
65 : USE xc_rho_set_types, ONLY: xc_rho_set_create, &
66 : xc_rho_set_get, &
67 : xc_rho_set_release, &
68 : xc_rho_set_type, &
69 : xc_rho_set_update, xc_rho_set_recover_pw
70 : USE xc_util, ONLY: xc_pw_smooth, xc_pw_laplace, xc_pw_divergence, xc_requires_tmp_g
71 : #include "../base/base_uses.f90"
72 :
73 : IMPLICIT NONE
74 : PRIVATE
75 : PUBLIC :: xc_vxc_pw_create, xc_exc_pw_create, &
76 : xc_exc_calc, xc_calc_2nd_deriv_analytical, xc_calc_2nd_deriv_numerical, xc_calc_3rd_deriv_analytical, &
77 : xc_calc_2nd_deriv, xc_prep_2nd_deriv, xc_prep_3rd_deriv, divide_by_norm_drho, smooth_cutoff, &
78 : xc_uses_kinetic_energy_density, xc_uses_norm_drho
79 : PUBLIC :: calc_xc_density
80 :
81 : LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
82 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xc'
83 : CHARACTER(len=*), PARAMETER, PRIVATE :: gauxc_high_deriv_message = &
84 : "Response and kernel properties with GauXC/Skala require higher XC derivatives, "// &
85 : "which are not implemented. Use a native CP2K XC functional or disable the coupled XC kernel."
86 :
87 : CONTAINS
88 :
89 : ! **************************************************************************************************
90 : !> \brief ...
91 : !> \param xc_fun_section ...
92 : !> \param lsd ...
93 : !> \return ...
94 : ! **************************************************************************************************
95 9134 : FUNCTION xc_uses_kinetic_energy_density(xc_fun_section, lsd) RESULT(res)
96 : TYPE(section_vals_type), POINTER, INTENT(IN) :: xc_fun_section
97 : LOGICAL, INTENT(IN) :: lsd
98 : LOGICAL :: res
99 :
100 : TYPE(xc_rho_cflags_type) :: needs
101 :
102 : needs = xc_functionals_get_needs(xc_fun_section, &
103 : lsd=lsd, &
104 18268 : calc_potential=.FALSE.)
105 9134 : res = (needs%tau_spin .OR. needs%tau)
106 :
107 9134 : END FUNCTION xc_uses_kinetic_energy_density
108 :
109 : ! **************************************************************************************************
110 : !> \brief ...
111 : !> \param xc_fun_section ...
112 : !> \param lsd ...
113 : !> \return ...
114 : ! **************************************************************************************************
115 8962 : FUNCTION xc_uses_norm_drho(xc_fun_section, lsd) RESULT(res)
116 : TYPE(section_vals_type), POINTER, INTENT(IN) :: xc_fun_section
117 : LOGICAL, INTENT(IN) :: lsd
118 : LOGICAL :: res
119 :
120 : TYPE(xc_rho_cflags_type) :: needs
121 :
122 : needs = xc_functionals_get_needs(xc_fun_section, &
123 : lsd=lsd, &
124 17924 : calc_potential=.FALSE.)
125 8962 : res = (needs%norm_drho .OR. needs%norm_drho_spin)
126 :
127 8962 : END FUNCTION xc_uses_norm_drho
128 :
129 : ! **************************************************************************************************
130 : !> \brief creates a xc_rho_set and a derivative set containing the derivatives
131 : !> of the functionals with the given deriv_order.
132 : !> \param rho_set will contain the rho set
133 : !> \param deriv_set will contain the derivatives
134 : !> \param deriv_order the order of the requested derivatives. If positive
135 : !> 0:deriv_order are calculated, if negative only -deriv_order is
136 : !> guaranteed to be valid. Orders not requested might be present,
137 : !> but might contain garbage.
138 : !> \param rho_r the value of the density in the real space
139 : !> \param rho_g value of the density in the g space (can be null, used only
140 : !> without smoothing of rho or deriv)
141 : !> \param tau value of the kinetic density tau on the grid (can be null,
142 : !> used only with meta functionals)
143 : !> \param xc_section the section describing the functional to use
144 : !> \param pw_pool the pool for the grids
145 : !> \param weights integration weights
146 : !> \param calc_potential if the basic components of the arguments
147 : !> should be kept in rho set (a basic component is for example drho
148 : !> when with lda a functional needs norm_drho)
149 : !> \author fawzi
150 : !> \note
151 : !> if any of the functionals is gradient corrected the full gradient is
152 : !> added to the rho set
153 : ! **************************************************************************************************
154 317114 : SUBROUTINE xc_rho_set_and_dset_create(rho_set, deriv_set, deriv_order, &
155 : rho_r, rho_g, tau, xc_section, pw_pool, &
156 : weights, calc_potential)
157 :
158 : TYPE(xc_rho_set_type) :: rho_set
159 : TYPE(xc_derivative_set_type) :: deriv_set
160 : INTEGER, INTENT(in) :: deriv_order
161 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau
162 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
163 : TYPE(section_vals_type), POINTER :: xc_section
164 : TYPE(pw_pool_type), POINTER :: pw_pool
165 : TYPE(pw_r3d_rs_type), POINTER :: weights
166 : LOGICAL, INTENT(in) :: calc_potential
167 :
168 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_rho_set_and_dset_create'
169 :
170 : INTEGER :: handle, nspins
171 : LOGICAL :: lsd
172 : TYPE(xc_derivative_type), POINTER :: deriv_att
173 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
174 : TYPE(section_vals_type), POINTER :: xc_fun_sections
175 :
176 158557 : CALL timeset(routineN, handle)
177 :
178 : MARK_USED(weights)
179 :
180 158557 : CPASSERT(ASSOCIATED(pw_pool))
181 :
182 158557 : nspins = SIZE(rho_r)
183 158557 : lsd = (nspins /= 1)
184 :
185 158557 : xc_fun_sections => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
186 :
187 : ! Create deriv_set object
188 158557 : CALL xc_dset_create(deriv_set, pw_pool)
189 :
190 : ! Create objects for density related stuff
191 : CALL xc_rho_set_create(rho_set, &
192 : rho_r(1)%pw_grid%bounds_local, &
193 : rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
194 : drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
195 158557 : tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
196 :
197 : ! Calculate density stuff, for example the gradient of rho, according to the functional needs
198 : CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, &
199 : xc_functionals_get_needs(xc_fun_sections, lsd, calc_potential), &
200 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
201 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
202 158557 : pw_pool)
203 :
204 : ! Calculate values of the functional on the grid
205 : CALL xc_functionals_eval(xc_fun_sections, &
206 : lsd=lsd, &
207 : rho_set=rho_set, &
208 : deriv_set=deriv_set, &
209 158557 : deriv_order=deriv_order)
210 :
211 : ! apply weights
212 158557 : IF (ASSOCIATED(weights)) THEN
213 11758 : pos => deriv_set%derivs
214 48582 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
215 4181674792 : deriv_att%deriv_data(:, :, :) = weights%array(:, :, :)*deriv_att%deriv_data(:, :, :)
216 : END DO
217 : END IF
218 :
219 158557 : CALL divide_by_norm_drho(deriv_set, rho_set, lsd)
220 :
221 158557 : CALL timestop(handle)
222 :
223 158557 : END SUBROUTINE xc_rho_set_and_dset_create
224 :
225 : ! **************************************************************************************************
226 : !> \brief smooths the cutoff on rho with a function smoothderiv_rho that is 0
227 : !> for rho<rho_cutoff and 1 for rho>rho_cutoff*rho_smooth_cutoff_range:
228 : !> E= integral e_0*smoothderiv_rho => dE/d...= de/d... * smooth,
229 : !> dE/drho = de/drho * smooth + e_0 * dsmooth/drho
230 : !> \param pot the potential to smooth
231 : !> \param rho , rhoa,rhob: the value of the density (used to apply the cutoff)
232 : !> \param rhoa ...
233 : !> \param rhob ...
234 : !> \param rho_cutoff the value at whch the cutoff function must go to 0
235 : !> \param rho_smooth_cutoff_range range of the smoothing
236 : !> \param e_0 value of e_0, if given it is assumed that pot is the derivative
237 : !> wrt. to rho, and needs the dsmooth*e_0 contribution
238 : !> \param e_0_scale_factor ...
239 : !> \author Fawzi Mohamed
240 : ! **************************************************************************************************
241 301913 : SUBROUTINE smooth_cutoff(pot, rho, rhoa, rhob, rho_cutoff, &
242 : rho_smooth_cutoff_range, e_0, e_0_scale_factor)
243 : REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN), &
244 : POINTER :: pot, rho, rhoa, rhob
245 : REAL(kind=dp), INTENT(in) :: rho_cutoff, rho_smooth_cutoff_range
246 : REAL(kind=dp), DIMENSION(:, :, :), OPTIONAL, &
247 : POINTER :: e_0
248 : REAL(kind=dp), INTENT(in), OPTIONAL :: e_0_scale_factor
249 :
250 : INTEGER :: i, j, k
251 : INTEGER, DIMENSION(2, 3) :: bo
252 : REAL(kind=dp) :: my_e_0_scale_factor, my_rho, my_rho_n, my_rho_n2, rho_smooth_cutoff, &
253 : rho_smooth_cutoff_2, rho_smooth_cutoff_range_2
254 :
255 301913 : CPASSERT(ASSOCIATED(pot))
256 1207652 : bo(1, :) = LBOUND(pot)
257 1207652 : bo(2, :) = UBOUND(pot)
258 301913 : my_e_0_scale_factor = 1.0_dp
259 301913 : IF (PRESENT(e_0_scale_factor)) my_e_0_scale_factor = e_0_scale_factor
260 301913 : rho_smooth_cutoff = rho_cutoff*rho_smooth_cutoff_range
261 301913 : rho_smooth_cutoff_2 = (rho_cutoff + rho_smooth_cutoff)/2
262 301913 : rho_smooth_cutoff_range_2 = rho_smooth_cutoff_2 - rho_cutoff
263 :
264 301913 : IF (rho_smooth_cutoff_range > 0.0_dp) THEN
265 2 : IF (PRESENT(e_0)) THEN
266 0 : CPASSERT(ASSOCIATED(e_0))
267 0 : IF (ASSOCIATED(rho)) THEN
268 : !$OMP PARALLEL DO DEFAULT(NONE) &
269 : !$OMP SHARED(bo,e_0,pot,rho,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
270 : !$OMP rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
271 : !$OMP PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
272 0 : !$OMP COLLAPSE(3)
273 : DO k = bo(1, 3), bo(2, 3)
274 : DO j = bo(1, 2), bo(2, 2)
275 : DO i = bo(1, 1), bo(2, 1)
276 : my_rho = rho(i, j, k)
277 : IF (my_rho < rho_smooth_cutoff) THEN
278 : IF (my_rho < rho_cutoff) THEN
279 : pot(i, j, k) = 0.0_dp
280 : ELSE IF (my_rho < rho_smooth_cutoff_2) THEN
281 : my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
282 : my_rho_n2 = my_rho_n*my_rho_n
283 : pot(i, j, k) = pot(i, j, k)* &
284 : my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
285 : my_e_0_scale_factor*e_0(i, j, k)* &
286 : my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
287 : /rho_smooth_cutoff_range_2
288 : ELSE
289 : my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
290 : my_rho_n2 = my_rho_n*my_rho_n
291 : pot(i, j, k) = pot(i, j, k)* &
292 : (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
293 : + my_e_0_scale_factor*e_0(i, j, k)* &
294 : my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
295 : /rho_smooth_cutoff_range_2
296 : END IF
297 : END IF
298 : END DO
299 : END DO
300 : END DO
301 : !$OMP END PARALLEL DO
302 : ELSE
303 : !$OMP PARALLEL DO DEFAULT(NONE) &
304 : !$OMP SHARED(bo,pot,e_0,rhoa,rhob,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
305 : !$OMP rho_smooth_cutoff_range_2,my_e_0_scale_factor) &
306 : !$OMP PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
307 0 : !$OMP COLLAPSE(3)
308 : DO k = bo(1, 3), bo(2, 3)
309 : DO j = bo(1, 2), bo(2, 2)
310 : DO i = bo(1, 1), bo(2, 1)
311 : my_rho = rhoa(i, j, k) + rhob(i, j, k)
312 : IF (my_rho < rho_smooth_cutoff) THEN
313 : IF (my_rho < rho_cutoff) THEN
314 : pot(i, j, k) = 0.0_dp
315 : ELSE IF (my_rho < rho_smooth_cutoff_2) THEN
316 : my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
317 : my_rho_n2 = my_rho_n*my_rho_n
318 : pot(i, j, k) = pot(i, j, k)* &
319 : my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2) + &
320 : my_e_0_scale_factor*e_0(i, j, k)* &
321 : my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
322 : /rho_smooth_cutoff_range_2
323 : ELSE
324 : my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
325 : my_rho_n2 = my_rho_n*my_rho_n
326 : pot(i, j, k) = pot(i, j, k)* &
327 : (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)) &
328 : + my_e_0_scale_factor*e_0(i, j, k)* &
329 : my_rho_n2*(3.0_dp - 2.0_dp*my_rho_n) &
330 : /rho_smooth_cutoff_range_2
331 : END IF
332 : END IF
333 : END DO
334 : END DO
335 : END DO
336 : !$OMP END PARALLEL DO
337 : END IF
338 : ELSE
339 2 : IF (ASSOCIATED(rho)) THEN
340 : !$OMP PARALLEL DO DEFAULT(NONE) &
341 : !$OMP SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
342 : !$OMP rho_smooth_cutoff_range_2,rho) &
343 : !$OMP PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
344 2 : !$OMP COLLAPSE(3)
345 : DO k = bo(1, 3), bo(2, 3)
346 : DO j = bo(1, 2), bo(2, 2)
347 : DO i = bo(1, 1), bo(2, 1)
348 : my_rho = rho(i, j, k)
349 : IF (my_rho < rho_smooth_cutoff) THEN
350 : IF (my_rho < rho_cutoff) THEN
351 : pot(i, j, k) = 0.0_dp
352 : ELSE IF (my_rho < rho_smooth_cutoff_2) THEN
353 : my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
354 : my_rho_n2 = my_rho_n*my_rho_n
355 : pot(i, j, k) = pot(i, j, k)* &
356 : my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
357 : ELSE
358 : my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
359 : my_rho_n2 = my_rho_n*my_rho_n
360 : pot(i, j, k) = pot(i, j, k)* &
361 : (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
362 : END IF
363 : END IF
364 : END DO
365 : END DO
366 : END DO
367 : !$OMP END PARALLEL DO
368 : ELSE
369 : !$OMP PARALLEL DO DEFAULT(NONE) &
370 : !$OMP SHARED(bo,pot,rho_cutoff,rho_smooth_cutoff,rho_smooth_cutoff_2, &
371 : !$OMP rho_smooth_cutoff_range_2,rhoa,rhob) &
372 : !$OMP PRIVATE(k,j,i,my_rho,my_rho_n,my_rho_n2) &
373 0 : !$OMP COLLAPSE(3)
374 : DO k = bo(1, 3), bo(2, 3)
375 : DO j = bo(1, 2), bo(2, 2)
376 : DO i = bo(1, 1), bo(2, 1)
377 : my_rho = rhoa(i, j, k) + rhob(i, j, k)
378 : IF (my_rho < rho_smooth_cutoff) THEN
379 : IF (my_rho < rho_cutoff) THEN
380 : pot(i, j, k) = 0.0_dp
381 : ELSE IF (my_rho < rho_smooth_cutoff_2) THEN
382 : my_rho_n = (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
383 : my_rho_n2 = my_rho_n*my_rho_n
384 : pot(i, j, k) = pot(i, j, k)* &
385 : my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2)
386 : ELSE
387 : my_rho_n = 2.0_dp - (my_rho - rho_cutoff)/rho_smooth_cutoff_range_2
388 : my_rho_n2 = my_rho_n*my_rho_n
389 : pot(i, j, k) = pot(i, j, k)* &
390 : (1.0_dp - my_rho_n2*(my_rho_n - 0.5_dp*my_rho_n2))
391 : END IF
392 : END IF
393 : END DO
394 : END DO
395 : END DO
396 : !$OMP END PARALLEL DO
397 : END IF
398 : END IF
399 : END IF
400 301913 : END SUBROUTINE smooth_cutoff
401 :
402 64 : SUBROUTINE calc_xc_density(pot, rho, rho_cutoff)
403 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: pot
404 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(INOUT) :: rho
405 : REAL(kind=dp), INTENT(in) :: rho_cutoff
406 :
407 : INTEGER :: i, j, k, nspins
408 : INTEGER, DIMENSION(2, 3) :: bo
409 : REAL(kind=dp) :: eps1, eps2, my_rho, my_pot
410 :
411 256 : bo(1, :) = LBOUND(pot%array)
412 256 : bo(2, :) = UBOUND(pot%array)
413 64 : nspins = SIZE(rho)
414 :
415 64 : eps1 = rho_cutoff*1.E-4_dp
416 64 : eps2 = rho_cutoff
417 :
418 3160 : DO k = bo(1, 3), bo(2, 3)
419 161272 : DO j = bo(1, 2), bo(2, 2)
420 4529376 : DO i = bo(1, 1), bo(2, 1)
421 4368168 : my_pot = pot%array(i, j, k)
422 4368168 : IF (nspins == 2) THEN
423 339714 : my_rho = rho(1)%array(i, j, k) + rho(2)%array(i, j, k)
424 : ELSE
425 4028454 : my_rho = rho(1)%array(i, j, k)
426 : END IF
427 4526280 : IF (my_rho > eps1) THEN
428 4139408 : pot%array(i, j, k) = my_pot/my_rho
429 228760 : ELSE IF (my_rho < eps2) THEN
430 228760 : pot%array(i, j, k) = 0.0_dp
431 : ELSE
432 0 : pot%array(i, j, k) = MIN(my_pot/my_rho, my_rho**(1._dp/3._dp))
433 : END IF
434 : END DO
435 : END DO
436 : END DO
437 :
438 64 : END SUBROUTINE calc_xc_density
439 :
440 : ! **************************************************************************************************
441 : !> \brief Exchange and Correlation functional calculations
442 : !> \param vxc_rho will contain the v_xc part that depend on rho
443 : !> (if one of the chosen xc functionals has it it is allocated and you
444 : !> are responsible for it)
445 : !> \param vxc_tau will contain the kinetic tau part of v_xc
446 : !> (if one of the chosen xc functionals has it it is allocated and you
447 : !> are responsible for it)
448 : !> \param exc the xc energy
449 : !> \param rho_r the value of the density in the real space
450 : !> \param rho_g value of the density in the g space (needs to be associated
451 : !> only for gradient corrections)
452 : !> \param tau value of the kinetic density tau on the grid (can be null,
453 : !> used only with meta functionals)
454 : !> \param xc_section which functional to calculate, and how to do it
455 : !> \param weights integration weights
456 : !> \param pw_pool the pool for the grids
457 : !> \param compute_virial ...
458 : !> \param virial_xc ...
459 : !> \param exc_r the value of the xc functional in the real space
460 : !> \par History
461 : !> JGH (13-Jun-2002): adaptation to new functionals
462 : !> Fawzi (11.2002): drho_g(1:3)->drho_g
463 : !> Fawzi (1.2003). lsd version
464 : !> Fawzi (11.2003): version using the new xc interface
465 : !> Fawzi (03.2004): fft free for smoothed density and derivs, gga lsd
466 : !> Fawzi (04.2004): metafunctionals
467 : !> mguidon (12.2008) : laplace functionals
468 : !> \author fawzi; based LDA version of JGH, based on earlier version of apsi
469 : !> \note
470 : !> Beware: some really dirty pointer handling!
471 : !> energy should be kept consistent with xc_exc_calc
472 : ! **************************************************************************************************
473 133261 : SUBROUTINE xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau, xc_section, weights, &
474 : pw_pool, compute_virial, virial_xc, exc_r)
475 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: vxc_rho, vxc_tau
476 : REAL(KIND=dp), INTENT(out) :: exc
477 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau
478 : TYPE(pw_r3d_rs_type), POINTER :: weights
479 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
480 : TYPE(section_vals_type), POINTER :: xc_section
481 : TYPE(pw_pool_type), POINTER :: pw_pool
482 : LOGICAL :: compute_virial
483 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT) :: virial_xc
484 : TYPE(pw_r3d_rs_type), INTENT(INOUT), OPTIONAL :: exc_r
485 :
486 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_vxc_pw_create'
487 : INTEGER, DIMENSION(2), PARAMETER :: norm_drho_spin_name = [deriv_norm_drhoa, deriv_norm_drhob]
488 :
489 : INTEGER :: handle, idir, ispin, jdir, &
490 : npoints, nspins, &
491 : xc_deriv_method_id, xc_rho_smooth_id, deriv_id
492 : INTEGER, DIMENSION(2, 3) :: bo
493 : LOGICAL :: dealloc_pw_to_deriv, has_laplace, &
494 : has_tau, lsd, use_virial, has_gradient, &
495 : has_derivs, has_rho, dealloc_pw_to_deriv_rho
496 : REAL(KIND=dp) :: density_smooth_cut_range, drho_cutoff, &
497 : rho_cutoff
498 133261 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, norm_drho, norm_drho_spin, &
499 266522 : rho, rhoa, rhob
500 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
501 : TYPE(pw_grid_type), POINTER :: pw_grid
502 932827 : TYPE(pw_r3d_rs_type), DIMENSION(3) :: pw_to_deriv, pw_to_deriv_rho
503 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
504 : TYPE(pw_r3d_rs_type) :: v_drho_r, virial_pw
505 : TYPE(xc_derivative_set_type) :: deriv_set
506 : TYPE(xc_derivative_type), POINTER :: deriv_att
507 : TYPE(xc_rho_set_type) :: rho_set
508 :
509 133261 : CALL timeset(routineN, handle)
510 133261 : NULLIFY (norm_drho_spin, norm_drho, pos)
511 :
512 133261 : pw_grid => rho_r(1)%pw_grid
513 :
514 133261 : CPASSERT(ASSOCIATED(xc_section))
515 133261 : CPASSERT(ASSOCIATED(pw_pool))
516 133261 : CPASSERT(.NOT. ASSOCIATED(vxc_rho))
517 133261 : CPASSERT(.NOT. ASSOCIATED(vxc_tau))
518 133261 : nspins = SIZE(rho_r)
519 133261 : lsd = (nspins /= 1)
520 133261 : IF (lsd) THEN
521 24757 : CPASSERT(nspins == 2)
522 : END IF
523 :
524 133261 : use_virial = compute_virial
525 133261 : virial_xc = 0.0_dp
526 :
527 1332610 : bo = rho_r(1)%pw_grid%bounds_local
528 133261 : npoints = (bo(2, 1) - bo(1, 1) + 1)*(bo(2, 2) - bo(1, 2) + 1)*(bo(2, 3) - bo(1, 3) + 1)
529 :
530 : ! calculate the potential derivatives
531 : CALL xc_rho_set_and_dset_create(rho_set=rho_set, deriv_set=deriv_set, &
532 : deriv_order=1, rho_r=rho_r, rho_g=rho_g, tau=tau, &
533 : xc_section=xc_section, &
534 : pw_pool=pw_pool, weights=weights, &
535 133261 : calc_potential=.TRUE.)
536 :
537 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
538 133261 : i_val=xc_deriv_method_id)
539 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", &
540 133261 : i_val=xc_rho_smooth_id)
541 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
542 133261 : r_val=density_smooth_cut_range)
543 :
544 : CALL xc_rho_set_get(rho_set, rho_cutoff=rho_cutoff, &
545 133261 : drho_cutoff=drho_cutoff)
546 :
547 133261 : CALL check_for_derivatives(deriv_set, lsd, has_rho, has_gradient, has_tau, has_laplace)
548 : ! check for unknown derivatives
549 133261 : has_derivs = has_rho .OR. has_gradient .OR. has_tau .OR. has_laplace
550 :
551 557801 : ALLOCATE (vxc_rho(nspins))
552 :
553 : CALL xc_rho_set_get(rho_set, rho=rho, rhoa=rhoa, rhob=rhob, &
554 133261 : can_return_null=.TRUE.)
555 :
556 : ! recover the vxc arrays
557 133261 : IF (lsd) THEN
558 24757 : CALL xc_dset_recover_pw(deriv_set, [deriv_rhoa], vxc_rho(1), pw_grid, pw_pool)
559 24757 : CALL xc_dset_recover_pw(deriv_set, [deriv_rhob], vxc_rho(2), pw_grid, pw_pool)
560 : ELSE
561 108504 : CALL xc_dset_recover_pw(deriv_set, [deriv_rho], vxc_rho(1), pw_grid, pw_pool)
562 : END IF
563 :
564 133261 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho])
565 133261 : IF (ASSOCIATED(deriv_att)) THEN
566 75363 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
567 :
568 : CALL xc_rho_set_get(rho_set, norm_drho=norm_drho, &
569 : rho_cutoff=rho_cutoff, &
570 : drho_cutoff=drho_cutoff, &
571 75363 : can_return_null=.TRUE.)
572 75363 : CALL xc_rho_set_recover_pw(rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv_rho, drho=pw_to_deriv_rho)
573 :
574 75363 : CPASSERT(ASSOCIATED(deriv_data))
575 75363 : IF (use_virial) THEN
576 1616 : CALL pw_pool%create_pw(virial_pw)
577 1616 : CALL pw_zero(virial_pw)
578 6464 : DO idir = 1, 3
579 4848 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(virial_pw,pw_to_deriv_rho,deriv_data,idir)
580 : virial_pw%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
581 : !$OMP END PARALLEL WORKSHARE
582 16160 : DO jdir = 1, idir
583 : virial_xc(idir, jdir) = -pw_grid%dvol* &
584 : accurate_dot_product(virial_pw%array(:, :, :), &
585 9696 : pw_to_deriv_rho(jdir)%array(:, :, :))
586 14544 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
587 : END DO
588 : END DO
589 1616 : CALL pw_pool%give_back_pw(virial_pw)
590 : END IF ! use_virial
591 301452 : DO idir = 1, 3
592 226089 : CPASSERT(ASSOCIATED(pw_to_deriv_rho(idir)%array))
593 301452 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv_rho,idir)
594 : pw_to_deriv_rho(idir)%array(:, :, :) = pw_to_deriv_rho(idir)%array(:, :, :)*deriv_data(:, :, :)
595 : !$OMP END PARALLEL WORKSHARE
596 : END DO
597 :
598 : ! Deallocate pw to save memory
599 75363 : CALL pw_pool%give_back_cr3d(deriv_att%deriv_data)
600 :
601 : END IF
602 :
603 133261 : IF ((has_gradient .AND. xc_requires_tmp_g(xc_deriv_method_id)) .OR. pw_grid%spherical) THEN
604 75167 : CALL pw_pool%create_pw(vxc_g)
605 75167 : IF (.NOT. pw_grid%spherical) THEN
606 75167 : CALL pw_pool%create_pw(tmp_g)
607 : END IF
608 : END IF
609 :
610 291279 : DO ispin = 1, nspins
611 :
612 158018 : IF (lsd) THEN
613 49514 : IF (ispin == 1) THEN
614 : CALL xc_rho_set_get(rho_set, norm_drhoa=norm_drho_spin, &
615 24757 : can_return_null=.TRUE.)
616 24757 : IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
617 15872 : rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhoa=pw_to_deriv)
618 : ELSE
619 : CALL xc_rho_set_get(rho_set, norm_drhob=norm_drho_spin, &
620 24757 : can_return_null=.TRUE.)
621 24757 : IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
622 15872 : rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhob=pw_to_deriv)
623 : END IF
624 :
625 99028 : deriv_att => xc_dset_get_derivative(deriv_set, [norm_drho_spin_name(ispin)])
626 49514 : IF (ASSOCIATED(deriv_att)) THEN
627 : CPASSERT(lsd)
628 31744 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
629 :
630 31744 : IF (use_virial) THEN
631 120 : CALL pw_pool%create_pw(virial_pw)
632 120 : CALL pw_zero(virial_pw)
633 480 : DO idir = 1, 3
634 360 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,pw_to_deriv,virial_pw,idir)
635 : virial_pw%array(:, :, :) = pw_to_deriv(idir)%array(:, :, :)*deriv_data(:, :, :)
636 : !$OMP END PARALLEL WORKSHARE
637 1200 : DO jdir = 1, idir
638 : virial_xc(idir, jdir) = virial_xc(idir, jdir) - pw_grid%dvol* &
639 : accurate_dot_product(virial_pw%array(:, :, :), &
640 720 : pw_to_deriv(jdir)%array(:, :, :))
641 1080 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
642 : END DO
643 : END DO
644 120 : CALL pw_pool%give_back_pw(virial_pw)
645 : END IF ! use_virial
646 :
647 126976 : DO idir = 1, 3
648 126976 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_data,idir,pw_to_deriv)
649 : pw_to_deriv(idir)%array(:, :, :) = deriv_data(:, :, :)*pw_to_deriv(idir)%array(:, :, :)
650 : !$OMP END PARALLEL WORKSHARE
651 : END DO
652 : END IF ! deriv_att
653 :
654 : END IF ! LSD
655 :
656 158018 : IF (ASSOCIATED(pw_to_deriv_rho(1)%array)) THEN
657 90357 : IF (.NOT. ASSOCIATED(pw_to_deriv(1)%array)) THEN
658 60369 : pw_to_deriv = pw_to_deriv_rho
659 60369 : dealloc_pw_to_deriv = ((.NOT. lsd) .OR. (ispin == 2))
660 60369 : dealloc_pw_to_deriv = dealloc_pw_to_deriv .AND. dealloc_pw_to_deriv_rho
661 : ELSE
662 : ! This branch is called in case of open-shell systems
663 : ! Add the contributions from norm_drho and norm_drho_spin
664 119952 : DO idir = 1, 3
665 89964 : CALL pw_axpy(pw_to_deriv_rho(idir), pw_to_deriv(idir))
666 119952 : IF (ispin == 2) THEN
667 44982 : IF (dealloc_pw_to_deriv_rho) THEN
668 44982 : CALL pw_pool%give_back_pw(pw_to_deriv_rho(idir))
669 : END IF
670 : END IF
671 : END DO
672 : END IF
673 : END IF
674 :
675 158018 : IF (ASSOCIATED(pw_to_deriv(1)%array)) THEN
676 368452 : DO idir = 1, 3
677 368452 : CALL pw_scale(pw_to_deriv(idir), -1.0_dp)
678 : END DO
679 :
680 92113 : CALL xc_pw_divergence(xc_deriv_method_id, pw_to_deriv, tmp_g, vxc_g, vxc_rho(ispin))
681 :
682 92113 : IF (dealloc_pw_to_deriv) THEN
683 368452 : DO idir = 1, 3
684 368452 : CALL pw_pool%give_back_pw(pw_to_deriv(idir))
685 : END DO
686 : END IF
687 : END IF
688 :
689 : ! Add laplace part to vxc_rho
690 158018 : IF (has_laplace) THEN
691 1092 : IF (lsd) THEN
692 472 : IF (ispin == 1) THEN
693 : deriv_id = deriv_laplace_rhoa
694 : ELSE
695 236 : deriv_id = deriv_laplace_rhob
696 : END IF
697 : ELSE
698 : deriv_id = deriv_laplace_rho
699 : END IF
700 :
701 2184 : CALL xc_dset_recover_pw(deriv_set, [deriv_id], pw_to_deriv(1), pw_grid)
702 :
703 1092 : IF (use_virial) CALL virial_laplace(rho_r(ispin), pw_pool, virial_xc, &
704 102 : pw_to_deriv(1)%array)
705 :
706 1092 : CALL xc_pw_laplace(pw_to_deriv(1), pw_pool, xc_deriv_method_id)
707 :
708 1092 : CALL pw_axpy(pw_to_deriv(1), vxc_rho(ispin))
709 :
710 1092 : CALL pw_pool%give_back_pw(pw_to_deriv(1))
711 : END IF
712 :
713 158018 : IF (pw_grid%spherical) THEN
714 : ! filter vxc
715 0 : CALL pw_transfer(vxc_rho(ispin), vxc_g)
716 0 : CALL pw_transfer(vxc_g, vxc_rho(ispin))
717 : END IF
718 : CALL smooth_cutoff(pot=vxc_rho(ispin)%array, rho=rho, rhoa=rhoa, rhob=rhob, &
719 : rho_cutoff=rho_cutoff*density_smooth_cut_range, &
720 158018 : rho_smooth_cutoff_range=density_smooth_cut_range)
721 :
722 158018 : v_drho_r = vxc_rho(ispin)
723 158018 : CALL pw_pool%create_pw(vxc_rho(ispin))
724 158018 : CALL xc_pw_smooth(v_drho_r, vxc_rho(ispin), xc_rho_smooth_id)
725 291279 : CALL pw_pool%give_back_pw(v_drho_r)
726 : END DO
727 :
728 133261 : CALL pw_pool%give_back_pw(vxc_g)
729 133261 : CALL pw_pool%give_back_pw(tmp_g)
730 :
731 : ! 0-deriv -> value of exc
732 : ! this has to be kept consistent with xc_exc_calc
733 133261 : IF (has_derivs) THEN
734 132941 : CALL xc_dset_recover_pw(deriv_set, [INTEGER::], v_drho_r, pw_grid)
735 :
736 : CALL smooth_cutoff(pot=v_drho_r%array, rho=rho, rhoa=rhoa, rhob=rhob, &
737 : rho_cutoff=rho_cutoff, &
738 132941 : rho_smooth_cutoff_range=density_smooth_cut_range)
739 :
740 132941 : exc = pw_integrate_function(v_drho_r)
741 : !
742 : ! return the xc functional value at the grid points
743 : !
744 132941 : IF (PRESENT(exc_r)) THEN
745 98 : exc_r = v_drho_r
746 : ELSE
747 132843 : CALL v_drho_r%release()
748 : END IF
749 : ELSE
750 320 : exc = 0.0_dp
751 : END IF
752 :
753 133261 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
754 :
755 : ! tau part
756 133261 : IF (has_tau) THEN
757 10620 : ALLOCATE (vxc_tau(nspins))
758 3326 : IF (lsd) THEN
759 642 : CALL xc_dset_recover_pw(deriv_set, [deriv_tau_a], vxc_tau(1), pw_grid)
760 642 : CALL xc_dset_recover_pw(deriv_set, [deriv_tau_b], vxc_tau(2), pw_grid)
761 : ELSE
762 2684 : CALL xc_dset_recover_pw(deriv_set, [deriv_tau], vxc_tau(1), pw_grid)
763 : END IF
764 7294 : DO ispin = 1, nspins
765 7294 : CPASSERT(ASSOCIATED(vxc_tau(ispin)%array))
766 : END DO
767 : END IF
768 133261 : CALL xc_dset_release(deriv_set)
769 :
770 133261 : CALL timestop(handle)
771 :
772 2798481 : END SUBROUTINE xc_vxc_pw_create
773 :
774 : ! **************************************************************************************************
775 : !> \brief calculates just the exchange and correlation energy
776 : !> (no vxc)
777 : !> \param rho_r realspace density on the grid
778 : !> \param rho_g g-space density on the grid
779 : !> \param tau kinetic energy density on the grid
780 : !> \param xc_section XC parameters
781 : !> \param weights Integration weights
782 : !> \param pw_pool pool of plain-wave grids
783 : !> \return the XC energy
784 : !> \par History
785 : !> 11.2003 created [fawzi]
786 : !> \author fawzi
787 : !> \note
788 : !> has to be kept consistent with xc_vxc_pw_create
789 : ! **************************************************************************************************
790 21444 : FUNCTION xc_exc_calc(rho_r, rho_g, tau, xc_section, weights, pw_pool) &
791 : RESULT(exc)
792 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau
793 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
794 : TYPE(section_vals_type), POINTER :: xc_section
795 : TYPE(pw_r3d_rs_type), POINTER :: weights
796 : TYPE(pw_pool_type), POINTER :: pw_pool
797 : REAL(kind=dp) :: exc
798 :
799 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_exc_calc'
800 :
801 : INTEGER :: handle
802 : REAL(dp) :: density_smooth_cut_range, rho_cutoff
803 10722 : REAL(dp), DIMENSION(:, :, :), POINTER :: e_0
804 : TYPE(xc_derivative_set_type) :: deriv_set
805 : TYPE(xc_derivative_type), POINTER :: deriv
806 : TYPE(xc_rho_set_type) :: rho_set
807 :
808 10722 : CALL timeset(routineN, handle)
809 :
810 10722 : NULLIFY (deriv, e_0)
811 10722 : exc = 0.0_dp
812 :
813 : ! this has to be consistent with what is done in xc_vxc_pw_create
814 : CALL xc_rho_set_and_dset_create(rho_set=rho_set, &
815 : deriv_set=deriv_set, deriv_order=0, &
816 : rho_r=rho_r, rho_g=rho_g, tau=tau, xc_section=xc_section, &
817 : pw_pool=pw_pool, weights=weights, &
818 10722 : calc_potential=.FALSE.)
819 10722 : deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
820 :
821 10722 : IF (ASSOCIATED(deriv)) THEN
822 10722 : CALL xc_derivative_get(deriv, deriv_data=e_0)
823 :
824 : CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
825 10722 : r_val=rho_cutoff)
826 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
827 10722 : r_val=density_smooth_cut_range)
828 : CALL smooth_cutoff(pot=e_0, rho=rho_set%rho, &
829 : rhoa=rho_set%rhoa, rhob=rho_set%rhob, &
830 : rho_cutoff=rho_cutoff, &
831 10722 : rho_smooth_cutoff_range=density_smooth_cut_range)
832 :
833 10722 : exc = accurate_sum(e_0)*rho_r(1)%pw_grid%dvol
834 10722 : IF (rho_r(1)%pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
835 10584 : CALL rho_r(1)%pw_grid%para%group%sum(exc)
836 : END IF
837 :
838 10722 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
839 10722 : CALL xc_dset_release(deriv_set)
840 : END IF
841 :
842 10722 : CALL timestop(handle)
843 :
844 203718 : END FUNCTION xc_exc_calc
845 :
846 : ! **************************************************************************************************
847 : !> \brief calculates just the exchange and correlation energy density
848 : !> \param rho_r realspace density on the grid
849 : !> \param rho_g g-space density on the grid
850 : !> \param tau kinetic energy density on the grid
851 : !> \param xc_section XC parameters
852 : !> \param weights Integration weights
853 : !> \param pw_pool pool of plain-wave grids
854 : !> \param exc xc energy density
855 : !> \author JGH
856 : ! **************************************************************************************************
857 460 : SUBROUTINE xc_exc_pw_create(rho_r, rho_g, tau, xc_section, weights, pw_pool, exc)
858 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau
859 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
860 : TYPE(section_vals_type), POINTER :: xc_section
861 : TYPE(pw_r3d_rs_type), POINTER :: weights
862 : TYPE(pw_pool_type), POINTER :: pw_pool
863 : TYPE(pw_r3d_rs_type) :: exc
864 :
865 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_exc_pw_create'
866 :
867 : INTEGER :: handle
868 : REAL(dp) :: density_smooth_cut_range, rho_cutoff
869 230 : REAL(dp), DIMENSION(:, :, :), POINTER :: e_0
870 : TYPE(xc_derivative_set_type) :: deriv_set
871 : TYPE(xc_derivative_type), POINTER :: deriv
872 : TYPE(xc_rho_set_type) :: rho_set
873 :
874 230 : CALL timeset(routineN, handle)
875 :
876 230 : NULLIFY (deriv, e_0)
877 :
878 : CALL xc_rho_set_and_dset_create(rho_set=rho_set, &
879 : deriv_set=deriv_set, deriv_order=0, &
880 : rho_r=rho_r, rho_g=rho_g, tau=tau, xc_section=xc_section, &
881 : pw_pool=pw_pool, weights=weights, &
882 230 : calc_potential=.FALSE.)
883 230 : deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
884 :
885 230 : IF (ASSOCIATED(deriv)) THEN
886 230 : CALL xc_derivative_get(deriv, deriv_data=e_0)
887 :
888 : CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
889 230 : r_val=rho_cutoff)
890 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
891 230 : r_val=density_smooth_cut_range)
892 : CALL smooth_cutoff(pot=e_0, rho=rho_set%rho, &
893 : rhoa=rho_set%rhoa, rhob=rho_set%rhob, &
894 : rho_cutoff=rho_cutoff, &
895 230 : rho_smooth_cutoff_range=density_smooth_cut_range)
896 :
897 16776469 : exc%array = e_0
898 :
899 230 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
900 230 : CALL xc_dset_release(deriv_set)
901 : END IF
902 :
903 230 : CALL timestop(handle)
904 :
905 5060 : END SUBROUTINE xc_exc_pw_create
906 :
907 : ! **************************************************************************************************
908 : !> \brief Caller routine to calculate the second order potential in the direction of rho1_r
909 : !> \param v_xc XC potential, will be allocated, to be integrated with the KS density
910 : !> \param v_xc_tau ...
911 : !> \param deriv_set XC derivatives from xc_prep_2nd_deriv
912 : !> \param rho_set XC rho set from KS rho from xc_prep_2nd_deriv
913 : !> \param rho1_r first-order density in r space
914 : !> \param rho1_g first-order density in g space
915 : !> \param tau1_r ...
916 : !> \param pw_pool pw pool to create new grids
917 : !> \param xc_section XC section to calculate the derivatives from
918 : !> \param gapw whether to carry out GAPW (not possible with numerical derivatives)
919 : !> \param vxg GAPW potential
920 : !> \param do_excitations ...
921 : !> \param do_triplet ...
922 : !> \param compute_virial ...
923 : !> \param virial_xc virial terms will be collected here
924 : ! **************************************************************************************************
925 16012 : SUBROUTINE xc_calc_2nd_deriv(v_xc, v_xc_tau, deriv_set, rho_set, rho1_r, rho1_g, tau1_r, &
926 : pw_pool, weights, xc_section, gapw, vxg, &
927 : do_excitations, do_sf, do_triplet, &
928 : compute_virial, virial_xc)
929 :
930 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_xc, v_xc_tau
931 : TYPE(xc_derivative_set_type) :: deriv_set
932 : TYPE(xc_rho_set_type) :: rho_set
933 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho1_r, tau1_r
934 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho1_g
935 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
936 : TYPE(pw_r3d_rs_type), POINTER :: weights
937 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
938 : LOGICAL, INTENT(IN) :: gapw
939 : REAL(KIND=dp), DIMENSION(:, :, :, :), OPTIONAL, &
940 : POINTER :: vxg
941 : LOGICAL, INTENT(IN), OPTIONAL :: do_excitations, do_sf, &
942 : do_triplet, compute_virial
943 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
944 : OPTIONAL :: virial_xc
945 :
946 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv'
947 :
948 : INTEGER :: handle, ispin, nspins
949 : INTEGER, DIMENSION(2, 3) :: bo
950 : LOGICAL :: lsd, my_compute_virial, &
951 : my_do_excitations, my_do_sf, &
952 : my_do_triplet
953 : REAL(KIND=dp) :: fac
954 : TYPE(section_vals_type), POINTER :: xc_fun_section
955 : TYPE(xc_rho_cflags_type) :: needs
956 : TYPE(xc_rho_set_type) :: rho1_set
957 :
958 16012 : CALL timeset(routineN, handle)
959 :
960 16012 : my_compute_virial = .FALSE.
961 16012 : IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
962 :
963 16012 : my_do_sf = .FALSE.
964 16012 : IF (PRESENT(do_sf)) my_do_sf = do_sf
965 :
966 16012 : my_do_excitations = .FALSE.
967 16012 : IF (PRESENT(do_excitations)) my_do_excitations = do_excitations
968 :
969 16012 : my_do_triplet = .FALSE.
970 16012 : IF (PRESENT(do_triplet)) my_do_triplet = do_triplet
971 :
972 16012 : nspins = SIZE(rho1_r)
973 16012 : lsd = (nspins == 2)
974 16012 : IF (nspins == 1 .AND. my_do_excitations .AND. my_do_triplet) THEN
975 0 : nspins = 2
976 0 : lsd = .TRUE.
977 16012 : ELSE IF (my_do_sf) THEN
978 104 : nspins = 1
979 104 : lsd = .TRUE.
980 : END IF
981 :
982 16012 : NULLIFY (v_xc, v_xc_tau)
983 66116 : ALLOCATE (v_xc(nspins))
984 34092 : DO ispin = 1, nspins
985 18080 : CALL pw_pool%create_pw(v_xc(ispin))
986 34092 : CALL pw_zero(v_xc(ispin))
987 : END DO
988 :
989 16012 : xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
990 16012 : needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
991 :
992 16012 : IF (needs%tau .OR. needs%tau_spin) THEN
993 536 : IF (.NOT. ASSOCIATED(tau1_r)) THEN
994 0 : CPABORT("Tau-dependent functionals requires allocated kinetic energy density grid")
995 : END IF
996 1736 : ALLOCATE (v_xc_tau(nspins))
997 1200 : DO ispin = 1, nspins
998 664 : CALL pw_pool%create_pw(v_xc_tau(ispin))
999 16676 : CALL pw_zero(v_xc_tau(ispin))
1000 : END DO
1001 : END IF
1002 :
1003 16012 : IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
1004 : !------!
1005 : ! rho1 !
1006 : !------!
1007 157120 : bo = rho1_r(1)%pw_grid%bounds_local
1008 : ! create the place where to store the argument for the functionals
1009 : CALL xc_rho_set_create(rho1_set, bo, &
1010 : rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
1011 : drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
1012 15712 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1013 :
1014 : ! calculate the arguments needed by the functionals
1015 : CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
1016 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1017 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1018 15712 : pw_pool, spinflip=my_do_sf)
1019 :
1020 15712 : fac = 0._dp
1021 15712 : IF (nspins == 1 .AND. my_do_excitations) THEN
1022 1124 : IF (my_do_triplet) fac = -1.0_dp
1023 : END IF
1024 :
1025 : CALL xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, &
1026 : rho1_set, pw_pool, xc_section, &
1027 : gapw, vxg=vxg, spinflip=my_do_sf, tddfpt_fac=fac, &
1028 15712 : compute_virial=compute_virial, virial_xc=virial_xc)
1029 :
1030 15712 : CALL xc_rho_set_release(rho1_set)
1031 :
1032 : ELSE
1033 300 : IF (gapw) CPABORT("Numerical 2nd derivatives not implemented with GAPW")
1034 :
1035 : CALL xc_calc_2nd_deriv_numerical(v_xc, v_xc_tau, rho_set, rho1_r, rho1_g, tau1_r, &
1036 : pw_pool, weights, xc_section, &
1037 : my_do_excitations .AND. my_do_triplet, &
1038 300 : compute_virial, virial_xc, deriv_set)
1039 : END IF
1040 :
1041 16012 : CALL timestop(handle)
1042 :
1043 352264 : END SUBROUTINE xc_calc_2nd_deriv
1044 :
1045 : ! **************************************************************************************************
1046 : !> \brief calculates 2nd derivative numerically
1047 : !> \param v_xc potential to be calculated (has to be allocated already)
1048 : !> \param v_tau tau-part of the potential to be calculated (has to be allocated already)
1049 : !> \param rho_set KS density from xc_prep_2nd_deriv
1050 : !> \param rho1_r first-order density in r-space
1051 : !> \param rho1_g first-order density in g-space
1052 : !> \param tau1_r first-order kinetic-energy density in r-space
1053 : !> \param pw_pool pw pool for new grids
1054 : !> \param xc_section XC section to calculate the derivatives from
1055 : !> \param do_triplet ...
1056 : !> \param calc_virial whether to calculate virial terms
1057 : !> \param virial_xc collects stress tensor components (no metaGGAs!)
1058 : !> \param deriv_set deriv set from xc_prep_2nd_deriv (only for virials)
1059 : ! **************************************************************************************************
1060 340 : SUBROUTINE xc_calc_2nd_deriv_numerical(v_xc, v_tau, rho_set, rho1_r, rho1_g, tau1_r, &
1061 : pw_pool, weights, xc_section, &
1062 : do_triplet, calc_virial, virial_xc, deriv_set)
1063 :
1064 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: v_xc, v_tau
1065 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set
1066 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_r, tau1_r
1067 : TYPE(pw_c1d_gs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_g
1068 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
1069 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: weights
1070 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
1071 : LOGICAL, INTENT(IN) :: do_triplet
1072 : LOGICAL, INTENT(IN), OPTIONAL :: calc_virial
1073 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
1074 : OPTIONAL :: virial_xc
1075 : TYPE(xc_derivative_set_type), OPTIONAL :: deriv_set
1076 :
1077 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_numerical'
1078 : REAL(KIND=dp), DIMENSION(-4:4, 4), PARAMETER :: &
1079 : rweights = RESHAPE([0.0_dp, 0.0_dp, 0.0_dp, -0.5_dp, 0.0_dp, 0.5_dp, 0.0_dp, 0.0_dp, 0.0_dp, &
1080 : 0.0_dp, 0.0_dp, 1.0_dp/12.0_dp, -2.0_dp/3.0_dp, 0.0_dp, 2.0_dp/3.0_dp, -1.0_dp/12.0_dp, 0.0_dp, 0.0_dp, &
1081 : 0.0_dp, -1.0_dp/60.0_dp, 0.15_dp, -0.75_dp, 0.0_dp, 0.75_dp, -0.15_dp, 1.0_dp/60.0_dp, 0.0_dp, &
1082 : 1.0_dp/280.0_dp, -4.0_dp/105.0_dp, 0.2_dp, -0.8_dp, 0.0_dp, 0.8_dp, -0.2_dp, 4.0_dp/105.0_dp, -1.0_dp/280.0_dp], [9, 4])
1083 :
1084 : INTEGER :: handle, idir, ispin, nspins, istep, nsteps
1085 : INTEGER, DIMENSION(2, 3) :: bo
1086 : LOGICAL :: gradient_f, lsd, my_calc_virial, tau_f, laplace_f, rho_f
1087 : REAL(KIND=dp) :: exc, gradient_cut, h, rweight, step, rho_cutoff
1088 340 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
1089 : REAL(KIND=dp), DIMENSION(3, 3) :: virial_dummy
1090 340 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: norm_drho, norm_drho2, norm_drho2a, &
1091 340 : norm_drho2b, norm_drhoa, norm_drhob, &
1092 1020 : rho, rho1, rho1a, rho1b, rhoa, rhob, &
1093 680 : tau_a, tau_b, tau, tau1, tau1a, tau1b, laplace, laplace1, &
1094 340 : laplacea, laplaceb, laplace1a, laplace1b, &
1095 680 : laplace2, laplace2a, laplace2b, deriv_data
1096 8160 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
1097 : TYPE(pw_r3d_rs_type) :: v_drho, v_drhoa, v_drhob
1098 340 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: vxc_rho, vxc_tau
1099 340 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
1100 340 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau_r
1101 : TYPE(pw_r3d_rs_type) :: virial_pw, v_laplace, v_laplacea, v_laplaceb
1102 : TYPE(section_vals_type), POINTER :: xc_fun_section
1103 : TYPE(xc_derivative_set_type) :: deriv_set1
1104 : TYPE(xc_rho_cflags_type) :: needs
1105 : TYPE(xc_rho_set_type) :: rho1_set, rho2_set
1106 :
1107 340 : CALL timeset(routineN, handle)
1108 :
1109 340 : my_calc_virial = .FALSE.
1110 340 : IF (PRESENT(calc_virial) .AND. PRESENT(virial_xc)) my_calc_virial = calc_virial
1111 :
1112 340 : nspins = SIZE(v_xc)
1113 :
1114 340 : NULLIFY (tau, tau_r, tau_a, tau_b)
1115 :
1116 340 : h = section_get_rval(xc_section, "STEP_SIZE")
1117 340 : nsteps = section_get_ival(xc_section, "NSTEPS")
1118 340 : IF (nsteps < LBOUND(rweights, 2) .OR. nspins > UBOUND(rweights, 2)) THEN
1119 0 : CPABORT("The number of steps must be a value from 1 to 4.")
1120 : END IF
1121 :
1122 340 : IF (nspins == 2) THEN
1123 148 : NULLIFY (vxc_rho, rho_g, vxc_tau)
1124 444 : ALLOCATE (rho_r(2))
1125 444 : DO ispin = 1, nspins
1126 444 : CALL pw_pool%create_pw(rho_r(ispin))
1127 : END DO
1128 148 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1129 162 : ALLOCATE (tau_r(2))
1130 162 : DO ispin = 1, nspins
1131 162 : CALL pw_pool%create_pw(tau_r(ispin))
1132 : END DO
1133 : END IF
1134 148 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
1135 1088 : DO istep = -nsteps, nsteps
1136 940 : IF (istep == 0) CYCLE
1137 792 : rweight = rweights(istep, nsteps)/h
1138 792 : step = REAL(istep, dp)*h
1139 : CALL calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
1140 : tau_r, tau1_r, tau_a, tau_b, vxc_tau, xc_section, &
1141 792 : weights, pw_pool, step)
1142 2376 : DO ispin = 1, nspins
1143 1584 : CALL pw_axpy(vxc_rho(ispin), v_xc(ispin), rweight)
1144 2376 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1145 456 : CALL pw_axpy(vxc_tau(ispin), v_tau(ispin), rweight)
1146 : END IF
1147 : END DO
1148 2376 : DO ispin = 1, nspins
1149 2376 : CALL vxc_rho(ispin)%release()
1150 : END DO
1151 792 : DEALLOCATE (vxc_rho)
1152 940 : IF (ASSOCIATED(vxc_tau)) THEN
1153 684 : DO ispin = 1, nspins
1154 684 : CALL vxc_tau(ispin)%release()
1155 : END DO
1156 228 : DEALLOCATE (vxc_tau)
1157 : END IF
1158 : END DO
1159 192 : ELSE IF (nspins == 1 .AND. do_triplet) THEN
1160 20 : NULLIFY (vxc_rho, vxc_tau, rho_g)
1161 60 : ALLOCATE (rho_r(2))
1162 60 : DO ispin = 1, 2
1163 60 : CALL pw_pool%create_pw(rho_r(ispin))
1164 : END DO
1165 20 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1166 0 : ALLOCATE (tau_r(2))
1167 0 : DO ispin = 1, nspins
1168 0 : CALL pw_pool%create_pw(tau_r(ispin))
1169 : END DO
1170 : END IF
1171 20 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
1172 160 : DO istep = -nsteps, nsteps
1173 140 : IF (istep == 0) CYCLE
1174 120 : rweight = rweights(istep, nsteps)/h
1175 120 : step = REAL(istep, dp)*h
1176 : ! K(alpha,alpha)
1177 120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1178 : !$OMP WORKSHARE
1179 : rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
1180 : !$OMP END WORKSHARE NOWAIT
1181 : !$OMP WORKSHARE
1182 : rho_r(2)%array(:, :, :) = rhob(:, :, :)
1183 : !$OMP END WORKSHARE NOWAIT
1184 : IF (ASSOCIATED(tau1_r)) THEN
1185 : !$OMP WORKSHARE
1186 : tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
1187 : !$OMP END WORKSHARE NOWAIT
1188 : !$OMP WORKSHARE
1189 : tau_r(2)%array(:, :, :) = tau_b(:, :, :)
1190 : !$OMP END WORKSHARE NOWAIT
1191 : END IF
1192 : !$OMP END PARALLEL
1193 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1194 120 : weights, pw_pool, .FALSE., virial_dummy)
1195 120 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1196 120 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1197 0 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1198 : END IF
1199 360 : DO ispin = 1, 2
1200 360 : CALL vxc_rho(ispin)%release()
1201 : END DO
1202 120 : DEALLOCATE (vxc_rho)
1203 120 : IF (ASSOCIATED(vxc_tau)) THEN
1204 0 : DO ispin = 1, 2
1205 0 : CALL vxc_tau(ispin)%release()
1206 : END DO
1207 0 : DEALLOCATE (vxc_tau)
1208 : END IF
1209 120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1210 : !$OMP WORKSHARE
1211 : ! K(alpha,beta)
1212 : rho_r(1)%array(:, :, :) = rhoa(:, :, :)
1213 : !$OMP END WORKSHARE NOWAIT
1214 : !$OMP WORKSHARE
1215 : rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(1)%array(:, :, :)
1216 : !$OMP END WORKSHARE NOWAIT
1217 : IF (ASSOCIATED(tau1_r)) THEN
1218 : !$OMP WORKSHARE
1219 : tau_r(1)%array(:, :, :) = tau_a(:, :, :)
1220 : !$OMP END WORKSHARE NOWAIT
1221 : !$OMP WORKSHARE
1222 : tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(1)%array(:, :, :)
1223 : !$OMP END WORKSHARE NOWAIT
1224 : END IF
1225 : !$OMP END PARALLEL
1226 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1227 120 : weights, pw_pool, .FALSE., virial_dummy)
1228 120 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1229 120 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1230 0 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1231 : END IF
1232 360 : DO ispin = 1, 2
1233 360 : CALL vxc_rho(ispin)%release()
1234 : END DO
1235 120 : DEALLOCATE (vxc_rho)
1236 140 : IF (ASSOCIATED(vxc_tau)) THEN
1237 0 : DO ispin = 1, 2
1238 0 : CALL vxc_tau(ispin)%release()
1239 : END DO
1240 0 : DEALLOCATE (vxc_tau)
1241 : END IF
1242 : END DO
1243 : ELSE
1244 172 : NULLIFY (vxc_rho, rho_r, rho_g, vxc_tau, tau_r, tau)
1245 344 : ALLOCATE (rho_r(1))
1246 172 : CALL pw_pool%create_pw(rho_r(1))
1247 172 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1248 92 : ALLOCATE (tau_r(1))
1249 46 : CALL pw_pool%create_pw(tau_r(1))
1250 : END IF
1251 172 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rho=rho, tau=tau)
1252 1280 : DO istep = -nsteps, nsteps
1253 1108 : IF (istep == 0) CYCLE
1254 936 : rweight = rweights(istep, nsteps)/h
1255 936 : step = REAL(istep, dp)*h
1256 936 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rho,step,rho1_r,tau1_r,tau,tau_r)
1257 : !$OMP WORKSHARE
1258 : rho_r(1)%array(:, :, :) = rho(:, :, :) + step*rho1_r(1)%array(:, :, :)
1259 : !$OMP END WORKSHARE NOWAIT
1260 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau) .AND. ASSOCIATED(tau1_r)) THEN
1261 : !$OMP WORKSHARE
1262 : tau_r(1)%array(:, :, :) = tau(:, :, :) + step*tau1_r(1)%array(:, :, :)
1263 : !$OMP END WORKSHARE NOWAIT
1264 : END IF
1265 : !$OMP END PARALLEL
1266 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1267 936 : weights, pw_pool, .FALSE., virial_dummy)
1268 936 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1269 936 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1270 276 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1271 : END IF
1272 936 : CALL vxc_rho(1)%release()
1273 936 : DEALLOCATE (vxc_rho)
1274 1108 : IF (ASSOCIATED(vxc_tau)) THEN
1275 276 : CALL vxc_tau(1)%release()
1276 276 : DEALLOCATE (vxc_tau)
1277 : END IF
1278 : END DO
1279 : END IF
1280 :
1281 340 : IF (my_calc_virial) THEN
1282 36 : lsd = (nspins == 2)
1283 36 : IF (nspins == 1 .AND. do_triplet) THEN
1284 0 : lsd = .TRUE.
1285 : END IF
1286 :
1287 36 : CALL check_for_derivatives(deriv_set, (nspins == 2), rho_f, gradient_f, tau_f, laplace_f)
1288 :
1289 : ! Calculate the virial terms
1290 : ! Those arising from the first derivatives are treated like in xc_calc_2nd_deriv_analytical
1291 : ! Those arising from the second derivatives are calculated numerically
1292 : ! We assume that all metaGGA functionals require the gradient
1293 36 : IF (gradient_f) THEN
1294 360 : bo = rho_set%local_bounds
1295 :
1296 : ! Create the work grid for the virial terms
1297 36 : CALL allocate_pw(virial_pw, pw_pool, bo)
1298 :
1299 36 : gradient_cut = section_get_rval(xc_section, "GRADIENT_CUTOFF")
1300 :
1301 : ! create the container to store the argument of the functionals
1302 : CALL xc_rho_set_create(rho1_set, bo, &
1303 : rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
1304 : drho_cutoff=gradient_cut, &
1305 36 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1306 :
1307 36 : xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
1308 36 : needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
1309 :
1310 : ! calculate the arguments needed by the functionals
1311 : CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
1312 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1313 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1314 36 : pw_pool)
1315 :
1316 36 : IF (lsd) THEN
1317 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, norm_drho=norm_drho, &
1318 : norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, tau_a=tau_a, tau_b=tau_b, &
1319 10 : laplace_rhoa=laplacea, laplace_rhob=laplaceb, can_return_null=.TRUE.)
1320 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, drhoa=drho1a, drhob=drho1b, laplace_rhoa=laplace1a, &
1321 10 : laplace_rhob=laplace1b, can_return_null=.TRUE.)
1322 :
1323 10 : CALL calc_drho_from_ab(drho, drhoa, drhob)
1324 10 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
1325 : ELSE
1326 26 : CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho, tau=tau, laplace_rho=laplace, can_return_null=.TRUE.)
1327 26 : CALL xc_rho_set_get(rho1_set, rho=rho1, drho=drho1, laplace_rho=laplace1, can_return_null=.TRUE.)
1328 : END IF
1329 :
1330 36 : CALL prepare_dr1dr(dr1dr, drho, drho1)
1331 :
1332 36 : IF (lsd) THEN
1333 10 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
1334 10 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
1335 :
1336 10 : CALL allocate_pw(v_drho, pw_pool, bo)
1337 10 : CALL allocate_pw(v_drhoa, pw_pool, bo)
1338 10 : CALL allocate_pw(v_drhob, pw_pool, bo)
1339 :
1340 10 : IF (ASSOCIATED(norm_drhoa)) CALL apply_drho(deriv_set, [deriv_norm_drhoa], virial_pw, &
1341 : drhoa, drho1a, virial_xc, &
1342 10 : norm_drhoa, gradient_cut, dra1dra, v_drhoa%array)
1343 10 : IF (ASSOCIATED(norm_drhob)) CALL apply_drho(deriv_set, [deriv_norm_drhob], virial_pw, &
1344 : drhob, drho1b, virial_xc, &
1345 10 : norm_drhob, gradient_cut, drb1drb, v_drhob%array)
1346 10 : IF (ASSOCIATED(norm_drho)) CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, &
1347 : drho, drho1, virial_xc, &
1348 6 : norm_drho, gradient_cut, dr1dr, v_drho%array)
1349 10 : IF (laplace_f) THEN
1350 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhoa]), deriv_data=deriv_data)
1351 2 : CPASSERT(ASSOCIATED(deriv_data))
1352 15026 : virial_pw%array(:, :, :) = -rho1a(:, :, :)
1353 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1354 :
1355 2 : CALL allocate_pw(v_laplacea, pw_pool, bo)
1356 :
1357 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhob]), deriv_data=deriv_data)
1358 2 : CPASSERT(ASSOCIATED(deriv_data))
1359 15026 : virial_pw%array(:, :, :) = -rho1b(:, :, :)
1360 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1361 :
1362 2 : CALL allocate_pw(v_laplaceb, pw_pool, bo)
1363 : END IF
1364 :
1365 : ELSE
1366 :
1367 : ! Create the work grid for the potential of the gradient part
1368 26 : CALL allocate_pw(v_drho, pw_pool, bo)
1369 :
1370 : CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
1371 26 : norm_drho, gradient_cut, dr1dr, v_drho%array)
1372 26 : IF (laplace_f) THEN
1373 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rho]), deriv_data=deriv_data)
1374 2 : CPASSERT(ASSOCIATED(deriv_data))
1375 28862 : virial_pw%array(:, :, :) = -rho1(:, :, :)
1376 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1377 :
1378 2 : CALL allocate_pw(v_laplace, pw_pool, bo)
1379 : END IF
1380 :
1381 : END IF
1382 :
1383 36 : IF (lsd) THEN
1384 150260 : rho_r(1)%array = rhoa
1385 150260 : rho_r(2)%array = rhob
1386 : ELSE
1387 701552 : rho_r(1)%array = rho
1388 : END IF
1389 36 : IF (ASSOCIATED(tau1_r)) THEN
1390 8 : IF (lsd) THEN
1391 60104 : tau_r(1)%array = tau_a
1392 60104 : tau_r(2)%array = tau_b
1393 : ELSE
1394 115448 : tau_r(1)%array = tau
1395 : END IF
1396 : END IF
1397 :
1398 : ! Create deriv sets with same densities but different gradients
1399 36 : CALL xc_dset_create(deriv_set1, pw_pool)
1400 :
1401 36 : rho_cutoff = section_get_rval(xc_section, "DENSITY_CUTOFF")
1402 :
1403 : ! create the place where to store the argument for the functionals
1404 : CALL xc_rho_set_create(rho2_set, bo, &
1405 : rho_cutoff=rho_cutoff, &
1406 : drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
1407 36 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1408 :
1409 : ! calculate the arguments needed by the functionals
1410 : CALL xc_rho_set_update(rho2_set, rho_r, rho_g, tau_r, needs, &
1411 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1412 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1413 36 : pw_pool)
1414 :
1415 36 : IF (lsd) THEN
1416 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, tau_a=tau1a, tau_b=tau1b, &
1417 10 : laplace_rhoa=laplace1a, laplace_rhob=laplace1b, can_return_null=.TRUE.)
1418 : CALL xc_rho_set_get(rho2_set, norm_drhoa=norm_drho2a, norm_drhob=norm_drho2b, &
1419 10 : norm_drho=norm_drho2, laplace_rhoa=laplace2a, laplace_rhob=laplace2b, can_return_null=.TRUE.)
1420 :
1421 64 : DO istep = -nsteps, nsteps
1422 54 : IF (istep == 0) CYCLE
1423 44 : rweight = rweights(istep, nsteps)/h
1424 44 : step = REAL(istep, dp)*h
1425 44 : IF (ASSOCIATED(norm_drhoa)) THEN
1426 44 : CALL get_derivs_rho(norm_drho2a, norm_drhoa, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1427 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1428 44 : norm_drhoa, gradient_cut, rweight, rho1a, v_drhoa%array)
1429 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1430 44 : norm_drhoa, gradient_cut, rweight, rho1b, v_drhoa%array)
1431 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drhoa], bo, &
1432 44 : norm_drhoa, gradient_cut, rweight, dra1dra, v_drhoa%array)
1433 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
1434 44 : norm_drhoa, gradient_cut, rweight, dra1dra, drb1drb, v_drhoa%array, v_drhob%array)
1435 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
1436 44 : norm_drhoa, gradient_cut, rweight, dra1dra, dr1dr, v_drhoa%array, v_drho%array)
1437 44 : IF (tau_f) THEN
1438 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1439 8 : norm_drhoa, gradient_cut, rweight, tau1a, v_drhoa%array)
1440 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1441 8 : norm_drhoa, gradient_cut, rweight, tau1b, v_drhoa%array)
1442 : END IF
1443 44 : IF (laplace_f) THEN
1444 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1445 4 : norm_drhoa, gradient_cut, rweight, laplace1a, v_drhoa%array)
1446 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1447 4 : norm_drhoa, gradient_cut, rweight, laplace1b, v_drhoa%array)
1448 : END IF
1449 : END IF
1450 :
1451 44 : IF (ASSOCIATED(norm_drhob)) THEN
1452 44 : CALL get_derivs_rho(norm_drho2b, norm_drhob, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1453 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1454 44 : norm_drhob, gradient_cut, rweight, rho1a, v_drhob%array)
1455 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1456 44 : norm_drhob, gradient_cut, rweight, rho1b, v_drhob%array)
1457 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drhob], bo, &
1458 44 : norm_drhob, gradient_cut, rweight, drb1drb, v_drhob%array)
1459 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
1460 44 : norm_drhob, gradient_cut, rweight, drb1drb, dra1dra, v_drhob%array, v_drhoa%array)
1461 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
1462 44 : norm_drhob, gradient_cut, rweight, drb1drb, dr1dr, v_drhob%array, v_drho%array)
1463 44 : IF (tau_f) THEN
1464 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1465 8 : norm_drhob, gradient_cut, rweight, tau1a, v_drhob%array)
1466 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1467 8 : norm_drhob, gradient_cut, rweight, tau1b, v_drhob%array)
1468 : END IF
1469 44 : IF (laplace_f) THEN
1470 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1471 4 : norm_drhob, gradient_cut, rweight, laplace1a, v_drhob%array)
1472 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1473 4 : norm_drhob, gradient_cut, rweight, laplace1b, v_drhob%array)
1474 : END IF
1475 : END IF
1476 :
1477 44 : IF (ASSOCIATED(norm_drho)) THEN
1478 20 : CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1479 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1480 20 : norm_drho, gradient_cut, rweight, rho1a, v_drho%array)
1481 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1482 20 : norm_drho, gradient_cut, rweight, rho1b, v_drho%array)
1483 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
1484 20 : norm_drho, gradient_cut, rweight, dr1dr, v_drho%array)
1485 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
1486 20 : norm_drho, gradient_cut, rweight, dr1dr, dra1dra, v_drho%array, v_drhoa%array)
1487 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
1488 20 : norm_drho, gradient_cut, rweight, dr1dr, drb1drb, v_drho%array, v_drhob%array)
1489 20 : IF (tau_f) THEN
1490 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1491 8 : norm_drho, gradient_cut, rweight, tau1a, v_drho%array)
1492 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1493 8 : norm_drho, gradient_cut, rweight, tau1b, v_drho%array)
1494 : END IF
1495 20 : IF (laplace_f) THEN
1496 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1497 4 : norm_drho, gradient_cut, rweight, laplace1a, v_drho%array)
1498 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1499 4 : norm_drho, gradient_cut, rweight, laplace1b, v_drho%array)
1500 : END IF
1501 : END IF
1502 :
1503 54 : IF (laplace_f) THEN
1504 :
1505 4 : CALL get_derivs_rho(laplace2a, laplacea, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1506 :
1507 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1508 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhoa], bo, &
1509 4 : rweight, rho1a, v_laplacea%array)
1510 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhob], bo, &
1511 4 : rweight, rho1b, v_laplacea%array)
1512 4 : IF (ASSOCIATED(norm_drho)) THEN
1513 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drho], bo, &
1514 4 : rweight, dr1dr, v_laplacea%array)
1515 : END IF
1516 4 : IF (ASSOCIATED(norm_drhoa)) THEN
1517 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhoa], bo, &
1518 4 : rweight, dra1dra, v_laplacea%array)
1519 : END IF
1520 4 : IF (ASSOCIATED(norm_drhob)) THEN
1521 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhob], bo, &
1522 4 : rweight, drb1drb, v_laplacea%array)
1523 : END IF
1524 :
1525 4 : IF (ASSOCIATED(tau1a)) THEN
1526 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_a], bo, &
1527 4 : rweight, tau1a, v_laplacea%array)
1528 : END IF
1529 4 : IF (ASSOCIATED(tau1b)) THEN
1530 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_b], bo, &
1531 4 : rweight, tau1b, v_laplacea%array)
1532 : END IF
1533 :
1534 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhoa], bo, &
1535 4 : rweight, laplace1a, v_laplacea%array)
1536 :
1537 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhob], bo, &
1538 4 : rweight, laplace1b, v_laplacea%array)
1539 :
1540 : ! The same for the beta spin
1541 4 : CALL get_derivs_rho(laplace2b, laplaceb, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1542 :
1543 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1544 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhoa], bo, &
1545 4 : rweight, rho1a, v_laplaceb%array)
1546 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhob], bo, &
1547 4 : rweight, rho1b, v_laplaceb%array)
1548 4 : IF (ASSOCIATED(norm_drho)) THEN
1549 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drho], bo, &
1550 4 : rweight, dr1dr, v_laplaceb%array)
1551 : END IF
1552 4 : IF (ASSOCIATED(norm_drhoa)) THEN
1553 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhoa], bo, &
1554 4 : rweight, dra1dra, v_laplaceb%array)
1555 : END IF
1556 4 : IF (ASSOCIATED(norm_drhob)) THEN
1557 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhob], bo, &
1558 4 : rweight, drb1drb, v_laplaceb%array)
1559 : END IF
1560 :
1561 4 : IF (tau_f) THEN
1562 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_a], bo, &
1563 4 : rweight, tau1a, v_laplaceb%array)
1564 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_b], bo, &
1565 4 : rweight, tau1b, v_laplaceb%array)
1566 : END IF
1567 :
1568 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhoa], bo, &
1569 4 : rweight, laplace1a, v_laplaceb%array)
1570 :
1571 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhob], bo, &
1572 4 : rweight, laplace1b, v_laplaceb%array)
1573 : END IF
1574 : END DO
1575 :
1576 10 : CALL virial_drho_drho(virial_pw, drhoa, v_drhoa, virial_xc)
1577 10 : CALL virial_drho_drho(virial_pw, drhob, v_drhob, virial_xc)
1578 10 : CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
1579 :
1580 10 : CALL deallocate_pw(v_drho, pw_pool)
1581 10 : CALL deallocate_pw(v_drhoa, pw_pool)
1582 10 : CALL deallocate_pw(v_drhob, pw_pool)
1583 :
1584 10 : IF (laplace_f) THEN
1585 15026 : virial_pw%array(:, :, :) = -rhoa(:, :, :)
1586 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplacea%array)
1587 2 : CALL deallocate_pw(v_laplacea, pw_pool)
1588 :
1589 15026 : virial_pw%array(:, :, :) = -rhob(:, :, :)
1590 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplaceb%array)
1591 2 : CALL deallocate_pw(v_laplaceb, pw_pool)
1592 : END IF
1593 :
1594 10 : CALL deallocate_pw(virial_pw, pw_pool)
1595 :
1596 40 : DO idir = 1, 3
1597 30 : DEALLOCATE (drho(idir)%array)
1598 40 : DEALLOCATE (drho1(idir)%array)
1599 : END DO
1600 10 : DEALLOCATE (dra1dra, drb1drb)
1601 :
1602 : ELSE
1603 26 : CALL xc_rho_set_get(rho1_set, rho=rho1, tau=tau1, laplace_rho=laplace1, can_return_null=.TRUE.)
1604 26 : CALL xc_rho_set_get(rho2_set, norm_drho=norm_drho2, laplace_rho=laplace2, can_return_null=.TRUE.)
1605 :
1606 200 : DO istep = -nsteps, nsteps
1607 174 : IF (istep == 0) CYCLE
1608 148 : rweight = rweights(istep, nsteps)/h
1609 148 : step = REAL(istep, dp)*h
1610 148 : CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1611 :
1612 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1613 : CALL update_deriv_rho(deriv_set1, [deriv_rho], bo, &
1614 148 : norm_drho, gradient_cut, rweight, rho1, v_drho%array)
1615 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
1616 148 : norm_drho, gradient_cut, rweight, dr1dr, v_drho%array)
1617 :
1618 148 : IF (tau_f) THEN
1619 : CALL update_deriv_rho(deriv_set1, [deriv_tau], bo, &
1620 24 : norm_drho, gradient_cut, rweight, tau1, v_drho%array)
1621 : END IF
1622 174 : IF (laplace_f) THEN
1623 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rho], bo, &
1624 12 : norm_drho, gradient_cut, rweight, laplace1, v_drho%array)
1625 :
1626 12 : CALL get_derivs_rho(laplace2, laplace, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1627 :
1628 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1629 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_rho], bo, &
1630 12 : rweight, rho1, v_laplace%array)
1631 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_norm_drho], bo, &
1632 12 : rweight, dr1dr, v_laplace%array)
1633 :
1634 12 : IF (tau_f) THEN
1635 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_tau], bo, &
1636 12 : rweight, tau1, v_laplace%array)
1637 : END IF
1638 :
1639 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_laplace_rho], bo, &
1640 12 : rweight, laplace1, v_laplace%array)
1641 : END IF
1642 : END DO
1643 :
1644 : ! Calculate the virial contribution from the potential
1645 26 : CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
1646 :
1647 26 : CALL deallocate_pw(v_drho, pw_pool)
1648 :
1649 26 : IF (laplace_f) THEN
1650 28862 : virial_pw%array(:, :, :) = -rho(:, :, :)
1651 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace%array)
1652 2 : CALL deallocate_pw(v_laplace, pw_pool)
1653 : END IF
1654 :
1655 26 : CALL deallocate_pw(virial_pw, pw_pool)
1656 : END IF
1657 :
1658 : END IF
1659 :
1660 36 : CALL xc_dset_release(deriv_set1)
1661 :
1662 36 : DEALLOCATE (dr1dr)
1663 :
1664 36 : CALL xc_rho_set_release(rho1_set)
1665 36 : CALL xc_rho_set_release(rho2_set)
1666 : END IF
1667 :
1668 848 : DO ispin = 1, SIZE(rho_r)
1669 848 : CALL pw_pool%give_back_pw(rho_r(ispin))
1670 : END DO
1671 340 : DEALLOCATE (rho_r)
1672 :
1673 340 : IF (ASSOCIATED(tau_r)) THEN
1674 254 : DO ispin = 1, SIZE(tau_r)
1675 254 : CALL pw_pool%give_back_pw(tau_r(ispin))
1676 : END DO
1677 100 : DEALLOCATE (tau_r)
1678 : END IF
1679 :
1680 340 : CALL timestop(handle)
1681 :
1682 15300 : END SUBROUTINE xc_calc_2nd_deriv_numerical
1683 :
1684 : ! **************************************************************************************************
1685 : !> \brief ...
1686 : !> \param rho_r ...
1687 : !> \param rho_g ...
1688 : !> \param rho1_r ...
1689 : !> \param rhoa ...
1690 : !> \param rhob ...
1691 : !> \param vxc_rho ...
1692 : !> \param tau_r ...
1693 : !> \param tau1_r ...
1694 : !> \param tau_a ...
1695 : !> \param tau_b ...
1696 : !> \param vxc_tau ...
1697 : !> \param xc_section ...
1698 : !> \param pw_pool ...
1699 : !> \param step ...
1700 : ! **************************************************************************************************
1701 792 : SUBROUTINE calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
1702 : tau_r, tau1_r, tau_a, tau_b, vxc_tau, &
1703 : xc_section, weights, pw_pool, step)
1704 :
1705 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: vxc_rho, vxc_tau
1706 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN) :: rho1_r
1707 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: tau1_r
1708 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: weights
1709 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
1710 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
1711 : REAL(KIND=dp), INTENT(IN) :: step
1712 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER, INTENT(IN) :: rhoa, rhob, tau_a, tau_b
1713 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: rho_r
1714 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
1715 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau_r
1716 :
1717 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_potential_numer_ab'
1718 :
1719 : INTEGER :: handle
1720 : REAL(KIND=dp) :: exc
1721 : REAL(KIND=dp), DIMENSION(3, 3) :: virial_dummy
1722 :
1723 792 : CALL timeset(routineN, handle)
1724 :
1725 792 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1726 : !$OMP WORKSHARE
1727 : rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
1728 : !$OMP END WORKSHARE NOWAIT
1729 : !$OMP WORKSHARE
1730 : rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(2)%array(:, :, :)
1731 : !$OMP END WORKSHARE NOWAIT
1732 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau_r) .AND. ASSOCIATED(tau_a) .AND. ASSOCIATED(tau_b)) THEN
1733 : !$OMP WORKSHARE
1734 : tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
1735 : !$OMP END WORKSHARE NOWAIT
1736 : !$OMP WORKSHARE
1737 : tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(2)%array(:, :, :)
1738 : !$OMP END WORKSHARE NOWAIT
1739 : END IF
1740 : !$OMP END PARALLEL
1741 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1742 792 : weights, pw_pool, .FALSE., virial_dummy)
1743 :
1744 792 : CALL timestop(handle)
1745 :
1746 792 : END SUBROUTINE calc_resp_potential_numer_ab
1747 :
1748 : ! **************************************************************************************************
1749 : !> \brief calculates stress tensor and potential contributions from the first derivative
1750 : !> \param deriv_set ...
1751 : !> \param description ...
1752 : !> \param virial_pw ...
1753 : !> \param drho ...
1754 : !> \param drho1 ...
1755 : !> \param virial_xc ...
1756 : !> \param norm_drho ...
1757 : !> \param gradient_cut ...
1758 : !> \param dr1dr ...
1759 : !> \param v_drho ...
1760 : ! **************************************************************************************************
1761 52 : SUBROUTINE apply_drho(deriv_set, description, virial_pw, drho, drho1, &
1762 52 : virial_xc, norm_drho, gradient_cut, dr1dr, v_drho)
1763 :
1764 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set
1765 : INTEGER, DIMENSION(:), INTENT(in) :: description
1766 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
1767 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
1768 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
1769 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: norm_drho
1770 : REAL(KIND=dp), INTENT(IN) :: gradient_cut
1771 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: dr1dr
1772 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT) :: v_drho
1773 :
1774 : CHARACTER(len=*), PARAMETER :: routineN = 'apply_drho'
1775 :
1776 : INTEGER :: handle
1777 52 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data
1778 : TYPE(xc_derivative_type), POINTER :: deriv_att
1779 :
1780 52 : CALL timeset(routineN, handle)
1781 :
1782 52 : deriv_att => xc_dset_get_derivative(deriv_set, description)
1783 52 : IF (ASSOCIATED(deriv_att)) THEN
1784 52 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
1785 52 : CALL virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
1786 :
1787 52 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,gradient_cut,norm_drho,v_drho,deriv_data)
1788 : v_drho(:, :, :) = v_drho(:, :, :) + &
1789 : deriv_data(:, :, :)*dr1dr(:, :, :)/MAX(gradient_cut, norm_drho(:, :, :))**2
1790 : !$OMP END PARALLEL WORKSHARE
1791 : END IF
1792 :
1793 52 : CALL timestop(handle)
1794 :
1795 52 : END SUBROUTINE apply_drho
1796 :
1797 : ! **************************************************************************************************
1798 : !> \brief adds potential contributions from derivatives of rho or diagonal terms of norm_drho
1799 : !> \param deriv_set1 ...
1800 : !> \param description ...
1801 : !> \param bo ...
1802 : !> \param norm_drho norm_drho of which derivative is calculated
1803 : !> \param gradient_cut ...
1804 : !> \param h ...
1805 : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
1806 : !> \param v_drho ...
1807 : ! **************************************************************************************************
1808 728 : SUBROUTINE update_deriv_rho(deriv_set1, description, bo, norm_drho, gradient_cut, weight, rho1, v_drho)
1809 :
1810 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1811 : INTEGER, DIMENSION(:), INTENT(in) :: description
1812 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1813 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1814 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: norm_drho
1815 : REAL(KIND=dp), INTENT(IN) :: gradient_cut, weight
1816 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1817 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: rho1
1818 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1819 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v_drho
1820 :
1821 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_rho'
1822 :
1823 : INTEGER :: handle, i, j, k
1824 : REAL(KIND=dp) :: de
1825 728 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1826 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1827 :
1828 728 : CALL timeset(routineN, handle)
1829 :
1830 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1831 728 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1832 728 : IF (ASSOCIATED(deriv_att1)) THEN
1833 728 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1834 : !$OMP PARALLEL DO DEFAULT(NONE) &
1835 : !$OMP SHARED(bo,deriv_data1,weight,norm_drho,v_drho,rho1,gradient_cut) &
1836 : !$OMP PRIVATE(i,j,k,de) &
1837 728 : !$OMP COLLAPSE(3)
1838 : DO k = bo(1, 3), bo(2, 3)
1839 : DO j = bo(1, 2), bo(2, 2)
1840 : DO i = bo(1, 1), bo(2, 1)
1841 : de = weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drho(i, j, k))**2
1842 : v_drho(i, j, k) = v_drho(i, j, k) - de*rho1(i, j, k)
1843 : END DO
1844 : END DO
1845 : END DO
1846 : !$OMP END PARALLEL DO
1847 : END IF
1848 :
1849 728 : CALL timestop(handle)
1850 :
1851 728 : END SUBROUTINE update_deriv_rho
1852 :
1853 : ! **************************************************************************************************
1854 : !> \brief adds potential contributions from derivatives of a component with positive and negative values
1855 : !> \param deriv_set1 ...
1856 : !> \param description ...
1857 : !> \param bo ...
1858 : !> \param h ...
1859 : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
1860 : !> \param v ...
1861 : ! **************************************************************************************************
1862 120 : SUBROUTINE update_deriv(deriv_set1, rho, rho_cutoff, description, bo, weight, rho1, v)
1863 :
1864 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1865 : INTEGER, DIMENSION(:), INTENT(in) :: description
1866 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1867 : REAL(KIND=dp), INTENT(IN) :: weight, rho_cutoff
1868 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1869 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: rho, rho1
1870 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1871 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v
1872 :
1873 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv'
1874 :
1875 : INTEGER :: handle, i, j, k
1876 : REAL(KIND=dp) :: de
1877 120 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1878 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1879 :
1880 120 : CALL timeset(routineN, handle)
1881 :
1882 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1883 120 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1884 120 : IF (ASSOCIATED(deriv_att1)) THEN
1885 120 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1886 : !$OMP PARALLEL DO DEFAULT(NONE) &
1887 : !$OMP SHARED(bo,deriv_data1,weight,v,rho1,rho, rho_cutoff) &
1888 : !$OMP PRIVATE(i,j,k,de) &
1889 120 : !$OMP COLLAPSE(3)
1890 : DO k = bo(1, 3), bo(2, 3)
1891 : DO j = bo(1, 2), bo(2, 2)
1892 : DO i = bo(1, 1), bo(2, 1)
1893 : ! We have to consider that the given density (mostly the Laplacian) may have positive and negative values
1894 : de = weight*deriv_data1(i, j, k)/SIGN(MAX(ABS(rho(i, j, k)), rho_cutoff), rho(i, j, k))
1895 : v(i, j, k) = v(i, j, k) + de*rho1(i, j, k)
1896 : END DO
1897 : END DO
1898 : END DO
1899 : !$OMP END PARALLEL DO
1900 : END IF
1901 :
1902 120 : CALL timestop(handle)
1903 :
1904 120 : END SUBROUTINE update_deriv
1905 :
1906 : ! **************************************************************************************************
1907 : !> \brief adds mixed derivatives of norm_drho
1908 : !> \param deriv_set1 ...
1909 : !> \param description ...
1910 : !> \param bo ...
1911 : !> \param norm_drhoa norm_drho of which derivatives is calculated
1912 : !> \param gradient_cut ...
1913 : !> \param h ...
1914 : !> \param dra1dra dr1dr corresponding to norm_drho
1915 : !> \param drb1drb ...
1916 : !> \param v_drhoa potential corresponding to norm_drho
1917 : !> \param v_drhob ...
1918 : ! **************************************************************************************************
1919 216 : SUBROUTINE update_deriv_drho_ab(deriv_set1, description, bo, &
1920 216 : norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa, v_drhob)
1921 :
1922 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1923 : INTEGER, DIMENSION(:), INTENT(in) :: description
1924 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1925 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1926 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: norm_drhoa
1927 : REAL(KIND=dp), INTENT(IN) :: gradient_cut, weight
1928 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1929 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: dra1dra, drb1drb
1930 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1931 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v_drhoa, v_drhob
1932 :
1933 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_drho_ab'
1934 :
1935 : INTEGER :: handle, i, j, k
1936 : REAL(KIND=dp) :: de
1937 216 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1938 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1939 :
1940 216 : CALL timeset(routineN, handle)
1941 :
1942 216 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1943 216 : IF (ASSOCIATED(deriv_att1)) THEN
1944 168 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1945 : !$OMP PARALLEL DO DEFAULT(NONE) &
1946 : !$OMP PRIVATE(k,j,i,de) &
1947 : !$OMP SHARED(bo,drb1drb,dra1dra,deriv_data1,weight,gradient_cut,norm_drhoa,v_drhoa,v_drhob) &
1948 168 : !$OMP COLLAPSE(3)
1949 : DO k = bo(1, 3), bo(2, 3)
1950 : DO j = bo(1, 2), bo(2, 2)
1951 : DO i = bo(1, 1), bo(2, 1)
1952 : ! We introduce a factor of two because we will average between both numerical derivatives
1953 : de = 0.5_dp*weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drhoa(i, j, k))**2
1954 : v_drhoa(i, j, k) = v_drhoa(i, j, k) - de*drb1drb(i, j, k)
1955 : v_drhob(i, j, k) = v_drhob(i, j, k) - de*dra1dra(i, j, k)
1956 : END DO
1957 : END DO
1958 : END DO
1959 : !$OMP END PARALLEL DO
1960 : END IF
1961 :
1962 216 : CALL timestop(handle)
1963 :
1964 216 : END SUBROUTINE update_deriv_drho_ab
1965 :
1966 : ! **************************************************************************************************
1967 : !> \brief calculate derivative sets for helper points
1968 : !> \param norm_drho2 norm_drho of new points
1969 : !> \param norm_drho norm_drho of KS density
1970 : !> \param h ...
1971 : !> \param xc_fun_section ...
1972 : !> \param lsd ...
1973 : !> \param rho2_set rho_set for new points
1974 : !> \param deriv_set1 will contain derivatives of the perturbed density
1975 : ! **************************************************************************************************
1976 276 : SUBROUTINE get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1977 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT) :: norm_drho2
1978 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: norm_drho
1979 : REAL(KIND=dp), INTENT(IN) :: step
1980 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_fun_section
1981 : LOGICAL, INTENT(IN) :: lsd
1982 : TYPE(xc_rho_set_type), INTENT(INOUT) :: rho2_set
1983 : TYPE(xc_derivative_set_type) :: deriv_set1
1984 :
1985 : CHARACTER(len=*), PARAMETER :: routineN = 'get_derivs_rho'
1986 :
1987 : INTEGER :: handle
1988 :
1989 276 : CALL timeset(routineN, handle)
1990 :
1991 : ! Copy the densities, do one step into the direction of drho
1992 276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2,step)
1993 : norm_drho2 = norm_drho*(1.0_dp + step)
1994 : !$OMP END PARALLEL WORKSHARE
1995 :
1996 276 : CALL xc_dset_zero_all(deriv_set1)
1997 :
1998 : ! Calculate the derivatives of the functional
1999 : CALL xc_functionals_eval(xc_fun_section, &
2000 : lsd=lsd, &
2001 : rho_set=rho2_set, &
2002 : deriv_set=deriv_set1, &
2003 276 : deriv_order=1)
2004 :
2005 : ! Return to the original values
2006 276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2)
2007 : norm_drho2 = norm_drho
2008 : !$OMP END PARALLEL WORKSHARE
2009 :
2010 276 : CALL divide_by_norm_drho(deriv_set1, rho2_set, lsd)
2011 :
2012 276 : CALL timestop(handle)
2013 :
2014 276 : END SUBROUTINE get_derivs_rho
2015 :
2016 : ! **************************************************************************************************
2017 : !> \brief Calculates the second derivative of E_xc at rho in the direction
2018 : !> rho1 (if you see the second derivative as bilinear form)
2019 : !> partial_rho|_(rho=rho) partial_rho|_(rho=rho) E_xc drho(rho1)drho
2020 : !> The other direction is still undetermined, thus it returns
2021 : !> a potential (partial integration is performed to reduce it to
2022 : !> function of rho, removing the dependence from its partial derivs)
2023 : !> Has to be called after the setup by xc_prep_2nd_deriv.
2024 : !> \param v_xc exchange-correlation potential
2025 : !> \param v_xc_tau ...
2026 : !> \param deriv_set derivatives of the exchange-correlation potential
2027 : !> \param rho_set object containing the density at which the derivatives were calculated
2028 : !> \param rho1_set object containing the density with which to fold
2029 : !> \param pw_pool the pool for the grids
2030 : !> \param xc_section XC parameters
2031 : !> \param gapw Gaussian and augmented plane waves calculation
2032 : !> \param vxg ...
2033 : !> \param tddfpt_fac factor that multiplies the crossterms (tddfpt triplets
2034 : !> on a closed shell system it should be -1, defaults to 1)
2035 : !> \param compute_virial ...
2036 : !> \param virial_xc ...
2037 : !> \note
2038 : !> The old version of this routine was smarter: it handled split_desc(1)
2039 : !> and split_desc(2) separately, thus the code automatically handled all
2040 : !> possible cross terms (you only had to check if it was diagonal to avoid
2041 : !> double counting). I think that is the way to go if you want to add more
2042 : !> terms (tau,rho in LSD,...). The problem with the old code was that it
2043 : !> because of the old functional structure it sometime guessed wrongly
2044 : !> which derivative was where. There were probably still bugs with gradient
2045 : !> corrected functionals (never tested), and it didn't contain first
2046 : !> derivatives with respect to drho (that contribute also to the second
2047 : !> derivative wrt. rho).
2048 : !> The code was a little complex because it really tried to handle any
2049 : !> functional derivative in the most efficient way with the given contents of
2050 : !> rho_set.
2051 : !> Anyway I strongly encourage whoever wants to modify this code to give a
2052 : !> look to the old version. [fawzi]
2053 : ! **************************************************************************************************
2054 45684 : SUBROUTINE xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
2055 : pw_pool, xc_section, gapw, vxg, tddfpt_fac, &
2056 : compute_virial, virial_xc, spinflip)
2057 :
2058 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_xc, v_xc_tau
2059 : TYPE(xc_derivative_set_type) :: deriv_set
2060 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set, rho1_set
2061 : TYPE(pw_pool_type), POINTER :: pw_pool
2062 : TYPE(section_vals_type), POINTER :: xc_section
2063 : LOGICAL, INTENT(IN), OPTIONAL :: gapw
2064 : REAL(kind=dp), DIMENSION(:, :, :, :), OPTIONAL, &
2065 : POINTER :: vxg
2066 : REAL(kind=dp), INTENT(in), OPTIONAL :: tddfpt_fac
2067 : LOGICAL, INTENT(IN), OPTIONAL :: compute_virial
2068 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
2069 : OPTIONAL :: virial_xc
2070 : LOGICAL, INTENT(in), OPTIONAL :: spinflip
2071 :
2072 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_analytical'
2073 :
2074 : INTEGER :: handle, i, ia, idir, ir, ispin, j, jdir, &
2075 : k, nspins, xc_deriv_method_id
2076 : INTEGER, DIMENSION(2, 3) :: bo
2077 : LOGICAL :: gradient_f, lsd, my_compute_virial, alda0, &
2078 : my_gapw, tau_f, laplace_f, rho_f, do_spinflip
2079 : REAL(KIND=dp) :: fac, gradient_cut, tmp, factor2, s, S_THRESH
2080 45684 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
2081 45684 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, deriv_data2, &
2082 45684 : e_drhoa, e_drhob, e_drho, norm_drho, norm_drhoa, &
2083 45684 : norm_drhob, rho1, rho1a, rho1b, &
2084 45684 : tau1, tau1a, tau1b, laplace1, laplace1a, laplace1b, &
2085 45684 : rho, rhoa, rhob
2086 867996 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
2087 45684 : TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE :: v_drhoa, v_drhob, v_drho, v_laplace
2088 45684 : TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE :: v_drho_r
2089 : TYPE(pw_r3d_rs_type) :: virial_pw
2090 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
2091 : TYPE(xc_derivative_type), POINTER :: deriv_att
2092 :
2093 45684 : CALL timeset(routineN, handle)
2094 :
2095 45684 : NULLIFY (e_drhoa, e_drhob, e_drho)
2096 :
2097 45684 : my_gapw = .FALSE.
2098 45684 : IF (PRESENT(gapw)) my_gapw = gapw
2099 :
2100 45684 : my_compute_virial = .FALSE.
2101 45684 : IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
2102 :
2103 45684 : CPASSERT(ASSOCIATED(v_xc))
2104 45684 : CPASSERT(ASSOCIATED(xc_section))
2105 45684 : IF (my_gapw) THEN
2106 20420 : CPASSERT(PRESENT(vxg))
2107 : END IF
2108 45684 : IF (my_compute_virial) THEN
2109 366 : CPASSERT(PRESENT(virial_xc))
2110 : END IF
2111 :
2112 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
2113 45684 : i_val=xc_deriv_method_id)
2114 45684 : CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
2115 45684 : nspins = SIZE(v_xc)
2116 45684 : lsd = ASSOCIATED(rho_set%rhoa)
2117 45684 : fac = 0.0_dp
2118 45684 : factor2 = 1.0_dp
2119 45684 : IF (PRESENT(tddfpt_fac)) fac = tddfpt_fac
2120 45684 : IF (PRESENT(tddfpt_fac)) factor2 = tddfpt_fac
2121 45684 : do_spinflip = .FALSE.
2122 45684 : IF (PRESENT(spinflip)) do_spinflip = spinflip
2123 :
2124 456840 : bo = rho_set%local_bounds
2125 :
2126 45684 : CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
2127 :
2128 45684 : alda0 = .false.
2129 45684 : IF (gradient_f) THEN
2130 : S_THRESH = 1.0E-04
2131 : ELSE
2132 15898 : S_THRESH = 1.0E-10
2133 : END IF
2134 :
2135 45684 : IF (tau_f) THEN
2136 656 : CPASSERT(ASSOCIATED(v_xc_tau))
2137 : END IF
2138 :
2139 45684 : IF (gradient_f) THEN
2140 310230 : ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
2141 62046 : DO ispin = 1, nspins
2142 129040 : DO idir = 1, 3
2143 129040 : CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
2144 : END DO
2145 62046 : CALL allocate_pw(v_drho(ispin), pw_pool, bo)
2146 : END DO
2147 :
2148 29786 : IF (xc_requires_tmp_g(xc_deriv_method_id) .AND. .NOT. my_gapw) THEN
2149 14546 : IF (ASSOCIATED(pw_pool)) THEN
2150 14546 : CALL pw_pool%create_pw(tmp_g)
2151 14546 : CALL pw_pool%create_pw(vxc_g)
2152 : ELSE
2153 : ! remember to refix for gapw
2154 0 : CPABORT("XC_DERIV method is not implemented in GAPW")
2155 : END IF
2156 : END IF
2157 : END IF
2158 :
2159 95920 : DO ispin = 1, nspins
2160 1190380532 : v_xc(ispin)%array = 0.0_dp
2161 : END DO
2162 :
2163 45684 : IF (tau_f) THEN
2164 1386 : DO ispin = 1, nspins
2165 14897758 : v_xc_tau(ispin)%array = 0.0_dp
2166 : END DO
2167 : END IF
2168 :
2169 45684 : IF (laplace_f .AND. my_gapw) THEN
2170 0 : CPABORT("Laplace-dependent functional not implemented with GAPW!")
2171 : END IF
2172 :
2173 45684 : IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) CALL allocate_pw(virial_pw, pw_pool, bo)
2174 :
2175 45684 : IF (lsd) THEN
2176 :
2177 : !-------------------!
2178 : ! UNrestricted case !
2179 : !-------------------!
2180 :
2181 6302 : IF (do_spinflip) THEN
2182 414 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
2183 414 : CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2184 : ELSE
2185 5888 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
2186 : END IF
2187 :
2188 6302 : IF (gradient_f) THEN
2189 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
2190 3676 : norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
2191 3676 : IF (do_spinflip) THEN
2192 262 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
2193 262 : CALL calc_drho_from_a(drho1, drho1a)
2194 : ELSE
2195 3414 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
2196 3414 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
2197 : END IF
2198 :
2199 3676 : CALL calc_drho_from_ab(drho, drhoa, drhob)
2200 :
2201 3676 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
2202 3676 : IF (do_spinflip) THEN
2203 262 : CALL prepare_dr1dr(drb1drb, drhob, drho1a)
2204 262 : CALL prepare_dr1dr(dr1dr, drho, drho1a)
2205 3414 : ELSE IF (nspins /= 1) THEN
2206 2264 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2207 2264 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2208 : ELSE
2209 1150 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2210 1150 : CALL prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
2211 : END IF
2212 :
2213 27004 : ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
2214 9826 : DO ispin = 1, nspins
2215 6150 : CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
2216 9826 : CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
2217 : END DO
2218 :
2219 : END IF
2220 :
2221 6302 : IF (laplace_f) THEN
2222 38 : CALL xc_rho_set_get(rho1_set, laplace_rhoa=laplace1a, laplace_rhob=laplace1b)
2223 :
2224 190 : ALLOCATE (v_laplace(nspins))
2225 114 : DO ispin = 1, nspins
2226 114 : CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
2227 : END DO
2228 :
2229 38 : IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2230 : END IF
2231 :
2232 6302 : IF (tau_f) THEN
2233 74 : CALL xc_rho_set_get(rho1_set, tau_a=tau1a, tau_b=tau1b)
2234 : END IF
2235 :
2236 6302 : IF (do_spinflip) THEN
2237 :
2238 : ! vxc contributions
2239 : ! vxc = (vxc^{\alpha}-vxc^{\beta})*rho1/(rhoa-rhob)
2240 : ! Alpha LDA contribution
2241 : ! | d e_xc d e_xc | rho1a
2242 : ! vxca = |-------- - --------|*-------------
2243 : ! | drhoa drhob | |rhoa - rhob|
2244 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
2245 414 : IF (ASSOCIATED(deriv_att)) THEN
2246 414 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2247 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
2248 414 : IF (ASSOCIATED(deriv_att)) THEN
2249 414 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2250 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2251 414 : !$OMP SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH) COLLAPSE(3)
2252 : DO k = bo(1, 3), bo(2, 3)
2253 : DO j = bo(1, 2), bo(2, 2)
2254 : DO i = bo(1, 1), bo(2, 1)
2255 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2256 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2257 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)/s
2258 : END DO
2259 : END DO
2260 : END DO
2261 : !$OMP END PARALLEL DO
2262 : END IF
2263 : END IF
2264 : ! GGA contributions to the spin-flip xcKernel
2265 : ! GGA contribution
2266 : ! | d e_xc d e_xc | 1
2267 : ! vxca += |----------* dra1dra - ----------*drb1drb|*-------------
2268 : ! | d|drhoa| d|drhob| | |rhoa - rhob|
2269 : IF (.NOT. alda0) THEN
2270 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
2271 414 : IF (ASSOCIATED(deriv_att)) THEN
2272 262 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2273 262 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
2274 262 : IF (ASSOCIATED(deriv_att)) THEN
2275 262 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2276 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2277 262 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2278 : DO k = bo(1, 3), bo(2, 3)
2279 : DO j = bo(1, 2), bo(2, 2)
2280 : DO i = bo(1, 1), bo(2, 1)
2281 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2282 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2283 : (deriv_data(i, j, k)*dra1dra(i, j, k) - &
2284 : deriv_data2(i, j, k)*drb1drb(i, j, k))/s
2285 : END DO
2286 : END DO
2287 : END DO
2288 : !$OMP END PARALLEL DO
2289 : END IF
2290 : END IF
2291 : END IF
2292 :
2293 5888 : ELSE IF (nspins /= 1) THEN
2294 :
2295 : ! Compute \sum_{\tau}fxc^{\sigma\tau}*\rho^{\tau}(1) over the grid points
2296 34290 : $:add_2nd_derivative_terms(arguments_openshell)
2297 :
2298 : ELSE
2299 :
2300 : ! Compute (fxc^{\alpha\alpha}+-fxc^{\beta\beta})*\rho(1) over the grid points
2301 1646 : $:add_2nd_derivative_terms(arguments_triplet_outer, arguments_triplet_inner)
2302 :
2303 : END IF
2304 :
2305 6302 : IF (gradient_f) THEN
2306 3676 : IF (.NOT. do_spinflip) THEN
2307 :
2308 3414 : IF (my_compute_virial) THEN
2309 10 : CALL virial_drho_drho(virial_pw, drhoa, v_drhoa(1), virial_xc)
2310 10 : CALL virial_drho_drho(virial_pw, drhob, v_drhob(2), virial_xc)
2311 40 : DO idir = 1, 3
2312 30 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
2313 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*(v_drho(1)%array(:, :, :) + v_drho(2)%array(:, :, :))
2314 : !$OMP END PARALLEL WORKSHARE
2315 100 : DO jdir = 1, idir
2316 : tmp = -0.5_dp*virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
2317 60 : drho(jdir)%array(:, :, :))
2318 60 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2319 90 : virial_xc(idir, jdir) = virial_xc(jdir, idir)
2320 : END DO
2321 : END DO
2322 : END IF ! my_compute_virial
2323 :
2324 3414 : IF (my_gapw) THEN
2325 : !$OMP PARALLEL DO DEFAULT(NONE) &
2326 : !$OMP PRIVATE(ia,idir,ispin,ir) &
2327 : !$OMP SHARED(bo,nspins,vxg,drhoa,drhob,v_drhoa,v_drhob,v_drho, &
2328 1218 : !$OMP e_drhoa,e_drhob,e_drho,drho1a,drho1b,fac,drho,drho1) COLLAPSE(3)
2329 : DO ir = bo(1, 2), bo(2, 2)
2330 : DO ia = bo(1, 1), bo(2, 1)
2331 : DO idir = 1, 3
2332 : DO ispin = 1, nspins
2333 : vxg(idir, ia, ir, ispin) = &
2334 : -(v_drhoa(ispin)%array(ia, ir, 1)*drhoa(idir)%array(ia, ir, 1) + &
2335 : v_drhob(ispin)%array(ia, ir, 1)*drhob(idir)%array(ia, ir, 1) + &
2336 : v_drho(ispin)%array(ia, ir, 1)*drho(idir)%array(ia, ir, 1))
2337 : END DO
2338 : IF (ASSOCIATED(e_drhoa)) THEN
2339 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2340 : e_drhoa(ia, ir, 1)*drho1a(idir)%array(ia, ir, 1)
2341 : END IF
2342 : IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
2343 : vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
2344 : e_drhob(ia, ir, 1)*drho1b(idir)%array(ia, ir, 1)
2345 : END IF
2346 : IF (ASSOCIATED(e_drho)) THEN
2347 : IF (nspins /= 1) THEN
2348 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2349 : e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
2350 : vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
2351 : e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
2352 : ELSE
2353 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2354 : e_drho(ia, ir, 1)*(drho1a(idir)%array(ia, ir, 1) + &
2355 : fac*drho1b(idir)%array(ia, ir, 1))
2356 : END IF
2357 : END IF
2358 : END DO
2359 : END DO
2360 : END DO
2361 : !$OMP END PARALLEL DO
2362 : ELSE
2363 :
2364 : ! partial integration
2365 8784 : DO idir = 1, 3
2366 :
2367 18528 : DO ispin = 1, nspins
2368 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
2369 18528 : !$OMP SHARED(v_drho_r,v_drhoa,v_drhob,v_drho,drhoa,drhob,drho,ispin,idir)
2370 : v_drho_r(idir, ispin)%array(:, :, :) = &
2371 : v_drhoa(ispin)%array(:, :, :)*drhoa(idir)%array(:, :, :) + &
2372 : v_drhob(ispin)%array(:, :, :)*drhob(idir)%array(:, :, :) + &
2373 : v_drho(ispin)%array(:, :, :)*drho(idir)%array(:, :, :)
2374 : !$OMP END PARALLEL WORKSHARE
2375 : END DO
2376 6588 : IF (ASSOCIATED(e_drhoa)) THEN
2377 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
2378 6588 : !$OMP SHARED(v_drho_r,e_drhoa,drho1a,idir)
2379 : v_drho_r(idir, 1)%array(:, :, :) = v_drho_r(idir, 1)%array(:, :, :) - &
2380 : e_drhoa(:, :, :)*drho1a(idir)%array(:, :, :)
2381 : !$OMP END PARALLEL WORKSHARE
2382 : END IF
2383 6588 : IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
2384 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE)&
2385 5352 : !$OMP SHARED(v_drho_r,e_drhob,drho1b,idir)
2386 : v_drho_r(idir, 2)%array(:, :, :) = v_drho_r(idir, 2)%array(:, :, :) - &
2387 : e_drhob(:, :, :)*drho1b(idir)%array(:, :, :)
2388 : !$OMP END PARALLEL WORKSHARE
2389 : END IF
2390 8784 : IF (ASSOCIATED(e_drho)) THEN
2391 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2392 6588 : !$OMP SHARED(bo,v_drho_r,e_drho,drho1a,drho1b,drho1,fac,idir,nspins) COLLAPSE(3)
2393 : DO k = bo(1, 3), bo(2, 3)
2394 : DO j = bo(1, 2), bo(2, 2)
2395 : DO i = bo(1, 1), bo(2, 1)
2396 : IF (nspins /= 1) THEN
2397 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
2398 : e_drho(i, j, k)*drho1(idir)%array(i, j, k)
2399 : v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) - &
2400 : e_drho(i, j, k)*drho1(idir)%array(i, j, k)
2401 : ELSE
2402 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
2403 : e_drho(i, j, k)*(drho1a(idir)%array(i, j, k) + &
2404 : fac*drho1b(idir)%array(i, j, k))
2405 : END IF
2406 : END DO
2407 : END DO
2408 : END DO
2409 : !$OMP END PARALLEL DO
2410 : END IF
2411 : END DO
2412 :
2413 : ! partial integration
2414 6176 : DO ispin = 1, nspins
2415 6176 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
2416 : END DO ! ispin
2417 :
2418 : END IF
2419 :
2420 : END IF ! .NOT.do_spinflip
2421 :
2422 14704 : DO idir = 1, 3
2423 11028 : DEALLOCATE (drho(idir)%array)
2424 14704 : DEALLOCATE (drho1(idir)%array)
2425 : END DO
2426 :
2427 9826 : DO ispin = 1, nspins
2428 6150 : CALL deallocate_pw(v_drhoa(ispin), pw_pool)
2429 9826 : CALL deallocate_pw(v_drhob(ispin), pw_pool)
2430 : END DO
2431 :
2432 3676 : DEALLOCATE (v_drhoa, v_drhob)
2433 :
2434 : END IF ! gradient_f
2435 :
2436 6302 : IF (laplace_f .AND. my_compute_virial) THEN
2437 15026 : virial_pw%array(:, :, :) = -rhoa(:, :, :)
2438 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
2439 15026 : virial_pw%array(:, :, :) = -rhob(:, :, :)
2440 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(2)%array)
2441 : END IF
2442 :
2443 : ELSE
2444 :
2445 : !-----------------!
2446 : ! restricted case !
2447 : !-----------------!
2448 :
2449 39382 : CALL xc_rho_set_get(rho1_set, rho=rho1)
2450 :
2451 39382 : IF (gradient_f) THEN
2452 26110 : CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho)
2453 26110 : CALL xc_rho_set_get(rho1_set, drho=drho1)
2454 26110 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2455 : END IF
2456 :
2457 39382 : IF (laplace_f) THEN
2458 136 : CALL xc_rho_set_get(rho1_set, laplace_rho=laplace1)
2459 :
2460 544 : ALLOCATE (v_laplace(nspins))
2461 272 : DO ispin = 1, nspins
2462 272 : CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
2463 : END DO
2464 :
2465 136 : IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rho=rho)
2466 : END IF
2467 :
2468 39382 : IF (tau_f) THEN
2469 582 : CALL xc_rho_set_get(rho1_set, tau=tau1)
2470 : END IF
2471 :
2472 333898 : $:add_2nd_derivative_terms(arguments_closedshell)
2473 :
2474 39382 : IF (gradient_f) THEN
2475 :
2476 26110 : IF (my_compute_virial) THEN
2477 222 : CALL virial_drho_drho(virial_pw, drho, v_drho(1), virial_xc)
2478 : END IF ! my_compute_virial
2479 :
2480 26110 : IF (my_gapw) THEN
2481 :
2482 54024 : DO idir = 1, 3
2483 : !$OMP PARALLEL DO DEFAULT(NONE) &
2484 : !$OMP PRIVATE(ia,ir) &
2485 : !$OMP SHARED(bo,vxg,drho,v_drho,e_drho,drho1,idir,factor2) &
2486 54024 : !$OMP COLLAPSE(2)
2487 : DO ia = bo(1, 1), bo(2, 1)
2488 : DO ir = bo(1, 2), bo(2, 2)
2489 : vxg(idir, ia, ir, 1) = -drho(idir)%array(ia, ir, 1)*v_drho(1)%array(ia, ir, 1)
2490 : IF (ASSOCIATED(e_drho)) THEN
2491 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + factor2*drho1(idir)%array(ia, ir, 1)*e_drho(ia, ir, 1)
2492 : END IF
2493 : END DO
2494 : END DO
2495 : !$OMP END PARALLEL DO
2496 : END DO
2497 :
2498 : ELSE
2499 : ! partial integration
2500 50416 : DO idir = 1, 3
2501 50416 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,drho,v_drho,drho1,e_drho,idir)
2502 : v_drho_r(idir, 1)%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho(1)%array(:, :, :) - &
2503 : drho1(idir)%array(:, :, :)*e_drho(:, :, :)
2504 : !$OMP END PARALLEL WORKSHARE
2505 : END DO
2506 :
2507 12604 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, 1), tmp_g, vxc_g, v_xc(1))
2508 : END IF
2509 :
2510 : END IF
2511 :
2512 39382 : IF (laplace_f .AND. my_compute_virial) THEN
2513 294530 : virial_pw%array(:, :, :) = -rho(:, :, :)
2514 14 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
2515 : END IF
2516 :
2517 : END IF
2518 :
2519 45684 : IF (laplace_f) THEN
2520 386 : DO ispin = 1, nspins
2521 212 : CALL xc_pw_laplace(v_laplace(ispin), pw_pool, xc_deriv_method_id)
2522 386 : CALL pw_axpy(v_laplace(ispin), v_xc(ispin))
2523 : END DO
2524 : END IF
2525 :
2526 45684 : IF (gradient_f) THEN
2527 :
2528 62046 : DO ispin = 1, nspins
2529 32260 : CALL deallocate_pw(v_drho(ispin), pw_pool)
2530 158826 : DO idir = 1, 3
2531 129040 : CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
2532 : END DO
2533 : END DO
2534 29786 : DEALLOCATE (v_drho, v_drho_r)
2535 :
2536 : END IF
2537 :
2538 45684 : IF (laplace_f) THEN
2539 386 : DO ispin = 1, nspins
2540 386 : CALL deallocate_pw(v_laplace(ispin), pw_pool)
2541 : END DO
2542 174 : DEALLOCATE (v_laplace)
2543 : END IF
2544 :
2545 45684 : IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
2546 14546 : CALL pw_pool%give_back_pw(tmp_g)
2547 : END IF
2548 :
2549 45684 : IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
2550 14546 : CALL pw_pool%give_back_pw(vxc_g)
2551 : END IF
2552 :
2553 45684 : IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) THEN
2554 232 : CALL deallocate_pw(virial_pw, pw_pool)
2555 : END IF
2556 :
2557 45684 : CALL timestop(handle)
2558 :
2559 137052 : END SUBROUTINE xc_calc_2nd_deriv_analytical
2560 :
2561 : ! **************************************************************************************************
2562 : !> \brief Calculates the third functional derivative of the exchange-correlation functional, E_xc.
2563 : !> Any GGA functional can be written as:
2564 : !>
2565 : !> E_xc[\rho] = \int e_xc(\rho,\nabla\rho)dr
2566 : !>
2567 : !> This routine gives you back the contraction of the derivatives of e_xc with respect to the
2568 : !> alpha or beta density or with respect to the norm of their gradients contracted with rho1.
2569 : !> For example, the alpha component would be (d stands for total derivative):
2570 : !>
2571 : !> d^3 e_xc
2572 : !> v_xc(1) = \sum_{s,s'}^{a,b} ---------------------\rhos1\rho1s'
2573 : !> d\rhoa d\rhos d\rhos'
2574 : !>
2575 : !> \param v_xc Third derivative of the exchange-correlation functional
2576 : !> \param v_xc_tau ...
2577 : !> \param deriv_set derivatives of the exchange-correlation potential, e_xc
2578 : !> \param rho_set object containing the density at which the derivatives were calculated, \rho
2579 : !> \param rho1_set object containing the density with which to fold, \rho1s
2580 : !> \param pw_pool the pool for the grids
2581 : !> \param xc_section XC parameters
2582 : !> \par History
2583 : !> * 07.2024 Created [LHS]
2584 : ! **************************************************************************************************
2585 0 : SUBROUTINE xc_calc_3rd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
2586 : pw_pool, xc_section, spinflip)
2587 :
2588 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_xc, v_xc_tau
2589 : TYPE(xc_derivative_set_type) :: deriv_set
2590 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set, rho1_set
2591 : TYPE(pw_pool_type), POINTER :: pw_pool
2592 : TYPE(section_vals_type), POINTER :: xc_section
2593 : LOGICAL, INTENT(in), OPTIONAL :: spinflip
2594 :
2595 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_3rd_deriv_analytical'
2596 :
2597 : INTEGER :: handle, i, idir, ispin, j, &
2598 : k, nspins, xc_deriv_method_id
2599 : INTEGER, DIMENSION(2, 3) :: bo
2600 : LOGICAL :: lsd, do_spinflip, alda0, &
2601 : rho_f, gradient_f, tau_f, laplace_f
2602 : REAL(KIND=dp) :: s, S_THRESH, S_THRESH2, gradient_cut
2603 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
2604 0 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, deriv_data2, e_drhoa, e_drhob, &
2605 0 : e_drho, norm_drho, norm_drhoa, &
2606 0 : norm_drhob, rho1a, rho1b, &
2607 0 : rhoa, rhob
2608 0 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
2609 0 : TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE :: v_drhoa, v_drhob, v_drho
2610 0 : TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE :: v_drho_r
2611 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
2612 : TYPE(xc_derivative_type), POINTER :: deriv_att
2613 :
2614 0 : CALL timeset(routineN, handle)
2615 :
2616 0 : NULLIFY (e_drhoa, e_drhob, e_drho)
2617 :
2618 0 : CPASSERT(ASSOCIATED(v_xc))
2619 0 : CPASSERT(ASSOCIATED(xc_section))
2620 :
2621 : ! Initialize parameters
2622 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
2623 0 : i_val=xc_deriv_method_id)
2624 : !
2625 0 : nspins = SIZE(v_xc)
2626 0 : lsd = ASSOCIATED(rho_set%rhoa)
2627 : !
2628 0 : do_spinflip = .FALSE.
2629 0 : IF (PRESENT(spinflip)) do_spinflip = spinflip
2630 : !
2631 0 : bo = rho_set%local_bounds
2632 : !
2633 0 : CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
2634 : !
2635 0 : CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
2636 : !
2637 : !S_THRESH has to be the same as S_THRESH in xc_calc_2nd_deriv_analytical
2638 0 : alda0 = .false.
2639 0 : S_THRESH = 1.0E-04
2640 0 : S_THRESH2 = 1.0E-07
2641 :
2642 : ! Initialize potential
2643 0 : DO ispin = 1, nspins
2644 : !CALL pw_zero(v_xc(ispin))
2645 0 : v_xc(ispin)%array = 0.0_dp
2646 : END DO
2647 :
2648 : ! Create GGA fields
2649 0 : IF (gradient_f) THEN
2650 0 : ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
2651 0 : DO ispin = 1, nspins
2652 0 : DO idir = 1, 3
2653 0 : CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
2654 : END DO
2655 0 : CALL allocate_pw(v_drho(ispin), pw_pool, bo)
2656 : END DO
2657 :
2658 0 : IF (xc_requires_tmp_g(xc_deriv_method_id)) THEN
2659 0 : IF (ASSOCIATED(pw_pool)) THEN
2660 0 : CALL pw_pool%create_pw(tmp_g)
2661 0 : CALL pw_pool%create_pw(vxc_g)
2662 : ELSE
2663 : ! remember to refix for gapw
2664 0 : CPABORT("XC_DERIV method is not implemented in GAPW")
2665 : END IF
2666 : END IF
2667 :
2668 : END IF
2669 :
2670 : ! Initialize mGGA potential
2671 0 : IF (tau_f) THEN
2672 0 : CPASSERT(ASSOCIATED(v_xc_tau))
2673 0 : DO ispin = 1, nspins
2674 0 : v_xc_tau(ispin)%array = 0.0_dp
2675 : END DO
2676 : END IF
2677 :
2678 0 : IF (lsd) THEN
2679 :
2680 : !-------------------!
2681 : ! UNrestricted case !
2682 : !-------------------!
2683 :
2684 0 : IF (do_spinflip) THEN
2685 0 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
2686 0 : CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2687 : ELSE
2688 0 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
2689 : END IF
2690 :
2691 0 : IF (gradient_f) THEN
2692 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
2693 0 : norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
2694 0 : IF (do_spinflip) THEN
2695 0 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
2696 0 : CALL calc_drho_from_a(drho1, drho1a)
2697 : ELSE
2698 0 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
2699 0 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
2700 : END IF
2701 :
2702 0 : CALL calc_drho_from_ab(drho, drhoa, drhob)
2703 :
2704 0 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
2705 0 : IF (do_spinflip) THEN
2706 0 : CALL prepare_dr1dr(drb1drb, drhob, drho1a)
2707 0 : CALL prepare_dr1dr(dr1dr, drho, drho1a)
2708 0 : ELSE IF (nspins /= 1) THEN
2709 0 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2710 0 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2711 : ELSE
2712 0 : CPABORT("Exchange-correlation's third derivative for closed-shell not yet implemented")
2713 : END IF
2714 :
2715 : ! Create vectors for partial integration term
2716 0 : ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
2717 0 : DO ispin = 1, nspins
2718 0 : CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
2719 0 : CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
2720 : END DO
2721 :
2722 : END IF
2723 :
2724 0 : IF (laplace_f) THEN
2725 0 : CPABORT("Exchange-correlation's laplace analytic third derivative not implemented")
2726 : END IF
2727 :
2728 0 : IF (tau_f) THEN
2729 0 : CPABORT("Exchange-correlation's mGGA analytic third derivative not implemented")
2730 : END IF
2731 :
2732 0 : IF (nspins /= 1) THEN
2733 :
2734 0 : IF (.NOT. do_spinflip) THEN
2735 : ! Analytic third derivative of the excchange-correlation functional
2736 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
2737 :
2738 : ELSE
2739 :
2740 : ! vxc contributions
2741 : ! vxca = (vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
2742 : ! vxcb =-(vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
2743 : ! Alpha LDA contribution
2744 : ! | d e_xc d e_xc | rho1a
2745 : ! vxca = rho1a*|-------- - --------|*---------------
2746 : ! | drhoa drhob | |rhoa - rhob|^2
2747 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
2748 0 : IF (ASSOCIATED(deriv_att)) THEN
2749 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2750 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
2751 0 : IF (ASSOCIATED(deriv_att)) THEN
2752 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2753 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2754 0 : !$OMP SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
2755 : DO k = bo(1, 3), bo(2, 3)
2756 : DO j = bo(1, 2), bo(2, 2)
2757 : DO i = bo(1, 1), bo(2, 1)
2758 : s = rhoa(i, j, k) - rhob(i, j, k)
2759 : s = -SIGN(MAX(s**2, S_THRESH2), s)
2760 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2761 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)**2/s
2762 : END DO
2763 : END DO
2764 : END DO
2765 : !$OMP END PARALLEL DO
2766 : END IF
2767 : END IF
2768 : ! GGA contributions to the spin-flip xcKernel
2769 : ! Alpha GGA contributions
2770 : ! | d e_xc d e_xc | rho1a
2771 : ! vxca += + |----------*dra1dra - ----------*drb1drb|*---------------
2772 : ! | d|drhoa| d|drhob| | |rhoa - rhob|^2
2773 : IF (.NOT. alda0) THEN
2774 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
2775 0 : IF (ASSOCIATED(deriv_att)) THEN
2776 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2777 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
2778 0 : IF (ASSOCIATED(deriv_att)) THEN
2779 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2780 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2781 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
2782 : DO k = bo(1, 3), bo(2, 3)
2783 : DO j = bo(1, 2), bo(2, 2)
2784 : DO i = bo(1, 1), bo(2, 1)
2785 : s = rhoa(i, j, k) - rhob(i, j, k)
2786 : s = -SIGN(MAX(s**2, S_THRESH2), s)
2787 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2788 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k)) &
2789 : *rho1a(i, j, k)/s
2790 : END DO
2791 : END DO
2792 : END DO
2793 : !$OMP END PARALLEL DO
2794 : END IF
2795 : END IF
2796 : END IF
2797 : ! Beta contribution = - alpha
2798 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2799 0 : !$OMP SHARED(bo,v_xc) COLLAPSE(3)
2800 : DO k = bo(1, 3), bo(2, 3)
2801 : DO j = bo(1, 2), bo(2, 2)
2802 : DO i = bo(1, 1), bo(2, 1)
2803 : v_xc(2)%array(i, j, k) = -v_xc(1)%array(i, j, k)
2804 : END DO
2805 : END DO
2806 : END DO
2807 : !$OMP END PARALLEL DO
2808 : ! fxc contributions
2809 : ! vxca = rho1*(fxc^{\alpha\alpha}-fxc^{\alpha\beta})*rho1/|rhoa-rhob|
2810 : ! vxcb = rho1*(fxc^{\beta\alpha}-fxc^{\beta\beta})*rho1/|rhoa-rhob|
2811 : ! Alpha LDA contribution
2812 : ! | d^2 e_xc d^2 e_xc | rho1a
2813 : ! vxca += rho1a*|------------- - -------------|*-------------
2814 : ! | drhoa drhoa drhoa drhob | |rhoa - rhob|
2815 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob])
2816 0 : IF (ASSOCIATED(deriv_att)) THEN
2817 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2818 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa])
2819 0 : IF (ASSOCIATED(deriv_att)) THEN
2820 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2821 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2822 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2823 : DO k = bo(1, 3), bo(2, 3)
2824 : DO j = bo(1, 2), bo(2, 2)
2825 : DO i = bo(1, 1), bo(2, 1)
2826 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2827 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2828 : rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
2829 : END DO
2830 : END DO
2831 : END DO
2832 : !$OMP END PARALLEL DO
2833 : END IF
2834 : END IF
2835 : ! Beta LDA contribution
2836 : ! | d^2 e_xc d^2 e_xc | rho1a
2837 : ! vxcb += rho1a*|------------- - -------------|*-------------
2838 : ! | drhob drhoa drhob drhob | |rhoa - rhob|
2839 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob])
2840 0 : IF (ASSOCIATED(deriv_att)) THEN
2841 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2842 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhoa])
2843 0 : IF (ASSOCIATED(deriv_att)) THEN
2844 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2845 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2846 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2847 : DO k = bo(1, 3), bo(2, 3)
2848 : DO j = bo(1, 2), bo(2, 2)
2849 : DO i = bo(1, 1), bo(2, 1)
2850 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2851 : v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
2852 : rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
2853 : END DO
2854 : END DO
2855 : END DO
2856 : !$OMP END PARALLEL DO
2857 : END IF
2858 : END IF
2859 : ! Alpha GGA contribution
2860 : IF (.NOT. alda0) THEN
2861 : ! rho1a | d^2 e_xc d^2 e_xc |
2862 : ! vxca += + -------------*|----------------*dra1dra - ----------------*drb1drb|
2863 : ! |rhoa - rhob| | drhoa d|drhoa| drhoa d|drhob| |
2864 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhob])
2865 0 : IF (ASSOCIATED(deriv_att)) THEN
2866 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2867 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhoa])
2868 0 : IF (ASSOCIATED(deriv_att)) THEN
2869 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2870 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2871 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2872 : DO k = bo(1, 3), bo(2, 3)
2873 : DO j = bo(1, 2), bo(2, 2)
2874 : DO i = bo(1, 1), bo(2, 1)
2875 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2876 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2877 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
2878 : rho1a(i, j, k)/s
2879 : END DO
2880 : END DO
2881 : END DO
2882 : !$OMP END PARALLEL DO
2883 : END IF
2884 : END IF
2885 : ! Beta GGA contribution
2886 : ! rho1a | d^2 e_xc d^2 e_xc |
2887 : ! vxcb += + -------------*|----------------*dra1dra - ----------------*drb1drb|
2888 : ! |rhoa - rhob| | drhob d|drhoa| drhob d|drhob| |
2889 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhob])
2890 0 : IF (ASSOCIATED(deriv_att)) THEN
2891 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2892 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhoa])
2893 0 : IF (ASSOCIATED(deriv_att)) THEN
2894 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2895 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2896 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2897 : DO k = bo(1, 3), bo(2, 3)
2898 : DO j = bo(1, 2), bo(2, 2)
2899 : DO i = bo(1, 1), bo(2, 1)
2900 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2901 : v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
2902 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
2903 : rho1a(i, j, k)/s
2904 : END DO
2905 : END DO
2906 : END DO
2907 : !$OMP END PARALLEL DO
2908 : END IF
2909 : END IF
2910 : !
2911 : !
2912 : ! Calculate the vector for the partial integration term of GGA functionals
2913 : ! First contribution alpha
2914 : ! | d^2 e_xc d^2 e_xc |
2915 : ! v_drhoa(1) += -|---------------- - ----------------|*rho1a
2916 : ! | d|drhoa| drhoa d|drhoa| drhob |
2917 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhob])
2918 0 : IF (ASSOCIATED(deriv_att)) THEN
2919 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2920 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhoa])
2921 0 : IF (ASSOCIATED(deriv_att)) THEN
2922 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2923 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2924 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhoa) COLLAPSE(3)
2925 : DO k = bo(1, 3), bo(2, 3)
2926 : DO j = bo(1, 2), bo(2, 2)
2927 : DO i = bo(1, 1), bo(2, 1)
2928 : v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
2929 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2930 : END DO
2931 : END DO
2932 : END DO
2933 : !$OMP END PARALLEL DO
2934 : END IF
2935 : END IF
2936 : ! First contribution beta
2937 : ! | d^2 e_xc d^2 e_xc |
2938 : ! v_drhob(2) += +|---------------- - ----------------|*rho1a
2939 : ! | d|drhob| drhob d|drhob| drhoa |
2940 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhoa])
2941 0 : IF (ASSOCIATED(deriv_att)) THEN
2942 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2943 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhob])
2944 0 : IF (ASSOCIATED(deriv_att)) THEN
2945 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2946 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2947 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhob) COLLAPSE(3)
2948 : DO k = bo(1, 3), bo(2, 3)
2949 : DO j = bo(1, 2), bo(2, 2)
2950 : DO i = bo(1, 1), bo(2, 1)
2951 : v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) + &
2952 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2953 : END DO
2954 : END DO
2955 : END DO
2956 : !$OMP END PARALLEL DO
2957 : END IF
2958 : END IF
2959 : ! First contribution spinless
2960 : ! | d^2 e_xc d^2 e_xc |
2961 : ! v_drho(1) += -|--------------- - ---------------|*rho1a
2962 : ! | d|drho| drhoa d|drho| drhob |
2963 : !
2964 : ! | d^2 e_xc d^2 e_xc |
2965 : ! v_drho(2) += -|--------------- - ---------------|*rho1a
2966 : ! | d|drho| drhoa d|drho| drhob |
2967 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhoa])
2968 0 : IF (ASSOCIATED(deriv_att)) THEN
2969 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2970 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhob])
2971 0 : IF (ASSOCIATED(deriv_att)) THEN
2972 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2973 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2974 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drho) COLLAPSE(3)
2975 : DO k = bo(1, 3), bo(2, 3)
2976 : DO j = bo(1, 2), bo(2, 2)
2977 : DO i = bo(1, 1), bo(2, 1)
2978 : v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
2979 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2980 : v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
2981 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2982 : END DO
2983 : END DO
2984 : END DO
2985 : !$OMP END PARALLEL DO
2986 : END IF
2987 : END IF
2988 : ! Second contribution
2989 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhob])
2990 0 : IF (ASSOCIATED(deriv_att)) THEN
2991 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2992 : ! d^2 e_xc d^2 e_xc
2993 : ! v_drhoa(1) += - -------------------*dra1dra + ------------------*drb1drb
2994 : ! d|drhoa| d|drhoa| d|drhoa| d|drhob|
2995 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhoa])
2996 0 : IF (ASSOCIATED(deriv_att)) THEN
2997 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2998 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2999 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhoa) COLLAPSE(3)
3000 : DO k = bo(1, 3), bo(2, 3)
3001 : DO j = bo(1, 2), bo(2, 2)
3002 : DO i = bo(1, 1), bo(2, 1)
3003 : v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
3004 : deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
3005 : END DO
3006 : END DO
3007 : END DO
3008 : !$OMP END PARALLEL DO
3009 : END IF
3010 : ! d^2 e_xc d^2 e_xc
3011 : ! v_drhob(2) += - -------------------*dra1dra + -------------------*drb1drb
3012 : ! d|drhoa| d|drhob| d|drhob| d|drhob|
3013 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drhob])
3014 0 : IF (ASSOCIATED(deriv_att)) THEN
3015 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3016 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
3017 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhob) COLLAPSE(3)
3018 : DO k = bo(1, 3), bo(2, 3)
3019 : DO j = bo(1, 2), bo(2, 2)
3020 : DO i = bo(1, 1), bo(2, 1)
3021 : v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) - &
3022 : deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
3023 : END DO
3024 : END DO
3025 : END DO
3026 : !$OMP END PARALLEL DO
3027 : END IF
3028 : END IF
3029 : ! d^2 e_xc d^2 e_xc
3030 : ! v_drho(1) += - ------------------*dra1dra + ------------------*drb1drb
3031 : ! d|drho| d|drhoa| d|drho| d|drhob|
3032 : !
3033 : ! d^2 e_xc d^2 e_xc
3034 : ! v_drho(2) += - ------------------*dra1dra + ------------------*drb1drb
3035 : ! d|drho| d|drhoa| d|drho| d|drhob|
3036 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhob])
3037 0 : IF (ASSOCIATED(deriv_att)) THEN
3038 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
3039 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhoa])
3040 0 : IF (ASSOCIATED(deriv_att)) THEN
3041 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3042 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
3043 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drho) COLLAPSE(3)
3044 : DO k = bo(1, 3), bo(2, 3)
3045 : DO j = bo(1, 2), bo(2, 2)
3046 : DO i = bo(1, 1), bo(2, 1)
3047 : v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
3048 : deriv_data(i, j, k)*dra1dra(i, j, k) + &
3049 : deriv_data2(i, j, k)*drb1drb(i, j, k)
3050 : v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
3051 : deriv_data(i, j, k)*dra1dra(i, j, k) + &
3052 : deriv_data2(i, j, k)*drb1drb(i, j, k)
3053 : END DO
3054 : END DO
3055 : END DO
3056 : !$OMP END PARALLEL DO
3057 : END IF
3058 : END IF
3059 : !
3060 :
3061 : ! Last GGA contribution
3062 : ! Alpha contribution
3063 : ! d e_xc
3064 : ! v_drhoa(1) += + ----------*dra1dra
3065 : ! d|drhoa|
3066 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
3067 0 : IF (ASSOCIATED(deriv_att)) THEN
3068 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3069 0 : CALL xc_derivative_get(deriv_att, deriv_data=e_drhoa)
3070 :
3071 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dra1dra,gradient_cut,norm_drhoa,v_drhoa,deriv_data)
3072 : v_drhoa(1)%array(:, :, :) = v_drhoa(1)%array(:, :, :) + &
3073 : deriv_data(:, :, :)*dra1dra(:, :, :)/MAX(gradient_cut, norm_drhoa(:, :, :))**2
3074 : !$OMP END PARALLEL WORKSHARE
3075 : END IF
3076 : ! Beta contribution
3077 : ! d e_xc
3078 : ! v_drhob(2) += - ----------*drb1drb
3079 : ! d|drhob|
3080 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
3081 0 : IF (ASSOCIATED(deriv_att)) THEN
3082 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3083 0 : CALL xc_derivative_get(deriv_att, deriv_data=e_drhob)
3084 :
3085 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drb1drb,gradient_cut,norm_drhob,v_drhob,deriv_data)
3086 : v_drhob(2)%array(:, :, :) = v_drhob(2)%array(:, :, :) - &
3087 : deriv_data(:, :, :)*drb1drb(:, :, :)/MAX(gradient_cut, norm_drhob(:, :, :))**2
3088 : !$OMP END PARALLEL WORKSHARE
3089 : END IF
3090 : END IF ! If ALDA0
3091 : END IF
3092 :
3093 : ELSE
3094 :
3095 : ! Analytic third derivative for closed-shell
3096 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
3097 :
3098 : END IF
3099 :
3100 0 : IF (gradient_f) THEN
3101 : IF (.NOT. alda0) THEN
3102 :
3103 : ! partial integration
3104 0 : DO idir = 1, 3
3105 :
3106 : ! GGA contributions to the spin-flip xc-Kernel
3107 : !
3108 : ! v_drhoa(1)*drhoa(:)*rhoa1 v_drhob(1)*drhob(:)*rhoa1 v_drho(1)*drho(:)*rhoa1
3109 : ! v_drho_r(:,1) = --------------------------- + --------------------------- + -------------------------
3110 : ! |rhoa - rhob| |rhoa - rhob| |rhoa - rhob|
3111 : !
3112 : ! v_drhoa(2)*drhoa(:)*rhoa1 v_drhob(2)*drhob(:)*rhoa1 v_drho(2)*drho(:)*rhoa1
3113 : ! v_drho_r(:,2) = --------------------------- + --------------------------- + -------------------------
3114 : ! |rhoa - rhob| |rhoa - rhob| |rhoa - rhob|
3115 0 : IF (do_spinflip) THEN
3116 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3117 0 : !$OMP SHARED(bo,v_drho_r,v_drho,v_drhoa,v_drhob,rhoa,rhob,drho,drhoa,drhob,rho1a,idir,S_THRESH) COLLAPSE(3)
3118 : DO k = bo(1, 3), bo(2, 3)
3119 : DO j = bo(1, 2), bo(2, 2)
3120 : DO i = bo(1, 1), bo(2, 1)
3121 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3122 : DO ispin = 1, 2
3123 : v_drho_r(idir, ispin)%array(i, j, k) = v_drho_r(idir, ispin)%array(i, j, k) + &
3124 : v_drhoa(ispin)%array(i, j, k)*drhoa(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
3125 : v_drhob(ispin)%array(i, j, k)*drhob(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
3126 : v_drho(ispin)%array(i, j, k)*drho(idir)%array(i, j, k)*rho1a(i, j, k)/s
3127 : END DO
3128 : END DO
3129 : END DO
3130 : END DO
3131 : !$OMP END PARALLEL DO
3132 : END IF
3133 : ! Last GGA contribution
3134 : ! Alpha contribution
3135 : ! rho1a d e_xc
3136 : ! v_drho_r(:,1) += - -------------*----------*drho1a(:)
3137 : ! |rhoa - rhob| d|drhoa|
3138 0 : IF (ASSOCIATED(e_drhoa)) THEN
3139 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3140 0 : !$OMP SHARED(bo,e_drhoa,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
3141 : DO k = bo(1, 3), bo(2, 3)
3142 : DO j = bo(1, 2), bo(2, 2)
3143 : DO i = bo(1, 1), bo(2, 1)
3144 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3145 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
3146 : e_drhoa(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
3147 : END DO
3148 : END DO
3149 : END DO
3150 : !$OMP END PARALLEL DO
3151 : END IF
3152 : ! Beta contribution
3153 : ! rho1a d e_xc
3154 : ! v_drho_r(:,2) += + -------------*----------*drho1a(:)
3155 : ! |rhoa - rhob| d|drhob|
3156 0 : IF (ASSOCIATED(e_drhob)) THEN
3157 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3158 0 : !$OMP SHARED(bo,e_drhob,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
3159 : DO k = bo(1, 3), bo(2, 3)
3160 : DO j = bo(1, 2), bo(2, 2)
3161 : DO i = bo(1, 1), bo(2, 1)
3162 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3163 : v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) + &
3164 : e_drhob(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
3165 : END DO
3166 : END DO
3167 : END DO
3168 : !$OMP END PARALLEL DO
3169 : END IF
3170 : END DO
3171 :
3172 : ! partial integration: v_xc = v_xc - \nabla \cdot vdrho_r
3173 0 : DO ispin = 1, nspins
3174 0 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
3175 : END DO ! ispin
3176 : END IF ! ALDA0
3177 :
3178 0 : DO idir = 1, 3
3179 0 : DEALLOCATE (drho(idir)%array)
3180 0 : DEALLOCATE (drho1(idir)%array)
3181 : END DO
3182 :
3183 0 : DO ispin = 1, nspins
3184 0 : CALL deallocate_pw(v_drhoa(ispin), pw_pool)
3185 0 : CALL deallocate_pw(v_drhob(ispin), pw_pool)
3186 : END DO
3187 :
3188 0 : DEALLOCATE (v_drhoa, v_drhob)
3189 :
3190 : END IF ! gradient_f
3191 :
3192 : ELSE
3193 :
3194 : !-----------------!
3195 : ! restricted case !
3196 : !-----------------!
3197 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
3198 :
3199 : END IF
3200 :
3201 0 : IF (gradient_f) THEN
3202 :
3203 0 : DO ispin = 1, nspins
3204 0 : CALL deallocate_pw(v_drho(ispin), pw_pool)
3205 0 : DO idir = 1, 3
3206 0 : CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
3207 : END DO
3208 : END DO
3209 0 : DEALLOCATE (v_drho, v_drho_r)
3210 :
3211 : END IF
3212 :
3213 0 : IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
3214 0 : CALL pw_pool%give_back_pw(tmp_g)
3215 : END IF
3216 :
3217 0 : IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
3218 0 : CALL pw_pool%give_back_pw(vxc_g)
3219 : END IF
3220 :
3221 0 : CALL timestop(handle)
3222 0 : END SUBROUTINE xc_calc_3rd_deriv_analytical
3223 :
3224 : ! **************************************************************************************************
3225 : !> \brief allocates grids using pw_pool (if associated) or with bounds
3226 : !> \param pw ...
3227 : !> \param pw_pool ...
3228 : !> \param bo ...
3229 : ! **************************************************************************************************
3230 141882 : SUBROUTINE allocate_pw(pw, pw_pool, bo)
3231 : TYPE(pw_r3d_rs_type), INTENT(OUT) :: pw
3232 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
3233 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
3234 :
3235 141882 : IF (ASSOCIATED(pw_pool)) THEN
3236 77670 : CALL pw_pool%create_pw(pw)
3237 77670 : CALL pw_zero(pw)
3238 : ELSE
3239 321060 : ALLOCATE (pw%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)))
3240 163869024 : pw%array = 0.0_dp
3241 : END IF
3242 :
3243 141882 : END SUBROUTINE allocate_pw
3244 :
3245 : ! **************************************************************************************************
3246 : !> \brief deallocates grid allocated with allocate_pw
3247 : !> \param pw ...
3248 : !> \param pw_pool ...
3249 : ! **************************************************************************************************
3250 141882 : SUBROUTINE deallocate_pw(pw, pw_pool)
3251 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: pw
3252 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
3253 :
3254 141882 : IF (ASSOCIATED(pw_pool)) THEN
3255 77670 : CALL pw_pool%give_back_pw(pw)
3256 : ELSE
3257 64212 : CALL pw%release()
3258 : END IF
3259 :
3260 141882 : END SUBROUTINE deallocate_pw
3261 :
3262 : ! **************************************************************************************************
3263 : !> \brief updates virial from first derivative w.r.t. norm_drho
3264 : !> \param virial_pw ...
3265 : !> \param drho ...
3266 : !> \param drho1 ...
3267 : !> \param deriv_data ...
3268 : !> \param virial_xc ...
3269 : ! **************************************************************************************************
3270 304 : SUBROUTINE virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
3271 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
3272 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
3273 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
3274 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3275 :
3276 : INTEGER :: idir, jdir
3277 : REAL(KIND=dp) :: tmp
3278 :
3279 1216 : DO idir = 1, 3
3280 912 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,virial_pw,deriv_data)
3281 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*deriv_data(:, :, :)
3282 : !$OMP END PARALLEL WORKSHARE
3283 3952 : DO jdir = 1, 3
3284 : tmp = virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
3285 2736 : drho1(jdir)%array(:, :, :))
3286 2736 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
3287 3648 : virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
3288 : END DO
3289 : END DO
3290 :
3291 304 : END SUBROUTINE virial_drho_drho1
3292 :
3293 : ! **************************************************************************************************
3294 : !> \brief Adds virial contribution from second order potential parts
3295 : !> \param virial_pw ...
3296 : !> \param drho ...
3297 : !> \param v_drho ...
3298 : !> \param virial_xc ...
3299 : ! **************************************************************************************************
3300 298 : SUBROUTINE virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
3301 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
3302 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho
3303 : TYPE(pw_r3d_rs_type), INTENT(IN) :: v_drho
3304 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3305 :
3306 : INTEGER :: idir, jdir
3307 : REAL(KIND=dp) :: tmp
3308 :
3309 1192 : DO idir = 1, 3
3310 894 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
3311 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho%array(:, :, :)
3312 : !$OMP END PARALLEL WORKSHARE
3313 2980 : DO jdir = 1, idir
3314 : tmp = -virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
3315 1788 : drho(jdir)%array(:, :, :))
3316 1788 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
3317 2682 : virial_xc(idir, jdir) = virial_xc(jdir, idir)
3318 : END DO
3319 : END DO
3320 :
3321 298 : END SUBROUTINE virial_drho_drho
3322 :
3323 : ! **************************************************************************************************
3324 : !> \brief ...
3325 : !> \param rho_r ...
3326 : !> \param pw_pool ...
3327 : !> \param virial_xc ...
3328 : !> \param deriv_data ...
3329 : ! **************************************************************************************************
3330 150 : SUBROUTINE virial_laplace(rho_r, pw_pool, virial_xc, deriv_data)
3331 : TYPE(pw_r3d_rs_type), TARGET :: rho_r
3332 : TYPE(pw_pool_type), POINTER, INTENT(IN) :: pw_pool
3333 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3334 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
3335 :
3336 : CHARACTER(len=*), PARAMETER :: routineN = 'virial_laplace'
3337 :
3338 : INTEGER :: handle, idir, jdir
3339 : TYPE(pw_r3d_rs_type), POINTER :: virial_pw
3340 : TYPE(pw_c1d_gs_type), POINTER :: tmp_g, rho_g
3341 : INTEGER, DIMENSION(3) :: my_deriv
3342 :
3343 150 : CALL timeset(routineN, handle)
3344 :
3345 150 : NULLIFY (virial_pw, tmp_g, rho_g)
3346 150 : ALLOCATE (virial_pw, tmp_g, rho_g)
3347 150 : CALL pw_pool%create_pw(virial_pw)
3348 150 : CALL pw_pool%create_pw(tmp_g)
3349 150 : CALL pw_pool%create_pw(rho_g)
3350 150 : CALL pw_zero(virial_pw)
3351 150 : CALL pw_transfer(rho_r, rho_g)
3352 600 : DO idir = 1, 3
3353 1500 : DO jdir = idir, 3
3354 900 : CALL pw_copy(rho_g, tmp_g)
3355 :
3356 900 : my_deriv = 0
3357 900 : my_deriv(idir) = 1
3358 900 : my_deriv(jdir) = my_deriv(jdir) + 1
3359 :
3360 900 : CALL pw_derive(tmp_g, my_deriv)
3361 900 : CALL pw_transfer(tmp_g, virial_pw)
3362 : virial_xc(idir, jdir) = virial_xc(idir, jdir) - 2.0_dp*virial_pw%pw_grid%dvol* &
3363 : accurate_dot_product(virial_pw%array(:, :, :), &
3364 900 : deriv_data(:, :, :))
3365 1350 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
3366 : END DO
3367 : END DO
3368 150 : CALL pw_pool%give_back_pw(virial_pw)
3369 150 : CALL pw_pool%give_back_pw(tmp_g)
3370 150 : CALL pw_pool%give_back_pw(rho_g)
3371 150 : DEALLOCATE (virial_pw, tmp_g, rho_g)
3372 :
3373 150 : CALL timestop(handle)
3374 :
3375 150 : END SUBROUTINE virial_laplace
3376 :
3377 : ! **************************************************************************************************
3378 : !> \brief Prepare objects for the calculation of the 2nd derivatives of the density functional.
3379 : !> The calculation must then be performed with xc_calc_2nd_deriv.
3380 : !> \param deriv_set object containing the XC derivatives (out)
3381 : !> \param rho_set object that will contain the density at which the
3382 : !> derivatives were calculated
3383 : !> \param rho_r the place where you evaluate the derivative
3384 : !> \param pw_pool the pool for the grids
3385 : !> \param weights integration weights
3386 : !> \param xc_section which functional should be used and how to calculate it
3387 : !> \param tau_r kinetic energy density in real space
3388 : ! **************************************************************************************************
3389 14344 : SUBROUTINE xc_prep_2nd_deriv(deriv_set, &
3390 : rho_set, rho_r, pw_pool, weights, xc_section, tau_r)
3391 :
3392 : TYPE(xc_derivative_set_type) :: deriv_set
3393 : TYPE(xc_rho_set_type) :: rho_set
3394 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3395 : TYPE(pw_pool_type), POINTER :: pw_pool
3396 : TYPE(pw_r3d_rs_type), POINTER :: weights
3397 : TYPE(section_vals_type), POINTER :: xc_section
3398 : TYPE(pw_r3d_rs_type), DIMENSION(:), &
3399 : OPTIONAL, POINTER :: tau_r
3400 :
3401 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_prep_2nd_deriv'
3402 :
3403 : INTEGER :: handle, nspins
3404 : LOGICAL :: lsd
3405 14344 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
3406 14344 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
3407 :
3408 14344 : CALL timeset(routineN, handle)
3409 :
3410 14344 : CPASSERT(ASSOCIATED(xc_section))
3411 14344 : CPASSERT(ASSOCIATED(pw_pool))
3412 :
3413 14344 : IF (xc_section_uses_gauxc(xc_section)) THEN
3414 0 : CALL cp_abort(__LOCATION__, gauxc_high_deriv_message)
3415 : END IF
3416 :
3417 14344 : nspins = SIZE(rho_r)
3418 14344 : lsd = (nspins /= 1)
3419 :
3420 14344 : NULLIFY (rho_g, tau)
3421 14344 : IF (PRESENT(tau_r)) tau => tau_r
3422 :
3423 14344 : IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
3424 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
3425 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3426 14260 : calc_potential=.TRUE.)
3427 : ELSE
3428 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 1, &
3429 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3430 84 : calc_potential=.TRUE.)
3431 : END IF
3432 :
3433 14344 : CALL timestop(handle)
3434 :
3435 14344 : END SUBROUTINE xc_prep_2nd_deriv
3436 :
3437 : ! **************************************************************************************************
3438 : !> \brief Prepare deriv_set for the calculation of the 3rd derivatives of the density functional.
3439 : !> The calculation must then be performed with xc_calc_3rd_deriv.
3440 : !> \param deriv_set object containing the XC derivatives (out)
3441 : !> \param rho_set object that will contain the density at which the
3442 : !> derivatives were calculated
3443 : !> \param rho_r the place where you evaluate the derivative
3444 : !> \param pw_pool the pool for the grids
3445 : !> \param weights integration weights
3446 : !> \param xc_section which functional should be used and how to calculate it
3447 : !> \param tau_r kinetic energy density in real space
3448 : !> \param do_sf Flag to activate the noncollinear kernel for spin flip calculations
3449 : !> \par History
3450 : !> * 07.2024 Created [LHS]
3451 : ! **************************************************************************************************
3452 0 : SUBROUTINE xc_prep_3rd_deriv(deriv_set, rho_set, rho_r, pw_pool, weights, &
3453 : xc_section, tau_r, do_sf)
3454 :
3455 : TYPE(xc_derivative_set_type) :: deriv_set
3456 : TYPE(xc_rho_set_type) :: rho_set
3457 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3458 : TYPE(pw_pool_type), POINTER :: pw_pool
3459 : TYPE(pw_r3d_rs_type), POINTER :: weights
3460 : TYPE(section_vals_type), POINTER :: xc_section
3461 : TYPE(pw_r3d_rs_type), DIMENSION(:), &
3462 : OPTIONAL, POINTER :: tau_r
3463 : LOGICAL, OPTIONAL :: do_sf
3464 :
3465 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_prep_3rd_deriv'
3466 :
3467 : INTEGER :: handle, nspins
3468 : LOGICAL :: lsd, my_do_sf
3469 0 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
3470 0 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
3471 :
3472 0 : CALL timeset(routineN, handle)
3473 :
3474 0 : CPASSERT(ASSOCIATED(xc_section))
3475 0 : CPASSERT(ASSOCIATED(pw_pool))
3476 :
3477 0 : IF (xc_section_uses_gauxc(xc_section)) THEN
3478 0 : CALL cp_abort(__LOCATION__, gauxc_high_deriv_message)
3479 : END IF
3480 :
3481 0 : nspins = SIZE(rho_r)
3482 0 : lsd = (nspins /= 1)
3483 :
3484 0 : NULLIFY (rho_g, tau)
3485 0 : IF (PRESENT(tau_r)) tau => tau_r
3486 :
3487 0 : my_do_sf = .FALSE.
3488 0 : IF (PRESENT(do_sf)) my_do_sf = do_sf
3489 :
3490 0 : IF (do_sf) THEN
3491 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
3492 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3493 0 : calc_potential=.TRUE.)
3494 : ELSE
3495 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 3, &
3496 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3497 0 : calc_potential=.TRUE.)
3498 : END IF
3499 :
3500 0 : CALL timestop(handle)
3501 :
3502 0 : END SUBROUTINE xc_prep_3rd_deriv
3503 :
3504 : ! **************************************************************************************************
3505 : !> \brief divides derivatives from deriv_set by norm_drho
3506 : !> \param deriv_set ...
3507 : !> \param rho_set ...
3508 : !> \param lsd ...
3509 : ! **************************************************************************************************
3510 179285 : SUBROUTINE divide_by_norm_drho(deriv_set, rho_set, lsd)
3511 :
3512 : TYPE(xc_derivative_set_type), INTENT(INOUT) :: deriv_set
3513 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set
3514 : LOGICAL, INTENT(IN) :: lsd
3515 :
3516 179285 : INTEGER, DIMENSION(:), POINTER :: split_desc
3517 : INTEGER :: idesc
3518 : INTEGER, DIMENSION(2, 3) :: bo
3519 : REAL(KIND=dp) :: drho_cutoff
3520 179285 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: norm_drho, norm_drhoa, norm_drhob
3521 2151420 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drhoa, drhob
3522 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
3523 : TYPE(xc_derivative_type), POINTER :: deriv_att
3524 :
3525 : ! check for unknown derivatives and divide by norm_drho where necessary
3526 :
3527 1792850 : bo = rho_set%local_bounds
3528 : CALL xc_rho_set_get(rho_set, drho_cutoff=drho_cutoff, norm_drho=norm_drho, &
3529 : norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, &
3530 179285 : drho=drho, drhoa=drhoa, drhob=drhob, can_return_null=.TRUE.)
3531 :
3532 179285 : pos => deriv_set%derivs
3533 785885 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
3534 606600 : CALL xc_derivative_get(deriv_att, split_desc=split_desc)
3535 1311716 : DO idesc = 1, SIZE(split_desc)
3536 606600 : SELECT CASE (split_desc(idesc))
3537 : CASE (deriv_norm_drho)
3538 168331 : IF (ASSOCIATED(norm_drho)) THEN
3539 168331 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drho,drho_cutoff)
3540 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3541 : MAX(norm_drho(:, :, :), drho_cutoff)
3542 : !$OMP END PARALLEL WORKSHARE
3543 0 : ELSE IF (ASSOCIATED(drho(1)%array)) THEN
3544 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drho,drho_cutoff)
3545 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3546 : MAX(SQRT(drho(1)%array(:, :, :)**2 + &
3547 : drho(2)%array(:, :, :)**2 + &
3548 : drho(3)%array(:, :, :)**2), drho_cutoff)
3549 : !$OMP END PARALLEL WORKSHARE
3550 0 : ELSE IF (ASSOCIATED(drhoa(1)%array) .AND. ASSOCIATED(drhob(1)%array)) THEN
3551 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drhob,drho_cutoff)
3552 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3553 : MAX(SQRT((drhoa(1)%array(:, :, :) + drhob(1)%array(:, :, :))**2 + &
3554 : (drhoa(2)%array(:, :, :) + drhob(2)%array(:, :, :))**2 + &
3555 : (drhoa(3)%array(:, :, :) + drhob(3)%array(:, :, :))**2), drho_cutoff)
3556 : !$OMP END PARALLEL WORKSHARE
3557 : ELSE
3558 0 : CPABORT("Normalization of derivative requires any of norm_drho, drho or drhoa+drhob!")
3559 : END IF
3560 : CASE (deriv_norm_drhoa)
3561 24806 : IF (ASSOCIATED(norm_drhoa)) THEN
3562 24806 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhoa,drho_cutoff)
3563 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3564 : MAX(norm_drhoa(:, :, :), drho_cutoff)
3565 : !$OMP END PARALLEL WORKSHARE
3566 0 : ELSE IF (ASSOCIATED(drhoa(1)%array)) THEN
3567 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhoa,drho_cutoff)
3568 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3569 : MAX(SQRT(drhoa(1)%array(:, :, :)**2 + &
3570 : drhoa(2)%array(:, :, :)**2 + &
3571 : drhoa(3)%array(:, :, :)**2), drho_cutoff)
3572 : !$OMP END PARALLEL WORKSHARE
3573 : ELSE
3574 0 : CPABORT("Normalization of derivative requires any of norm_drhoa or drhoa!")
3575 : END IF
3576 : CASE (deriv_norm_drhob)
3577 24802 : IF (ASSOCIATED(norm_drhob)) THEN
3578 24802 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,norm_drhob,drho_cutoff)
3579 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3580 : MAX(norm_drhob(:, :, :), drho_cutoff)
3581 : !$OMP END PARALLEL WORKSHARE
3582 0 : ELSE IF (ASSOCIATED(drhob(1)%array)) THEN
3583 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(deriv_att,drhob,drho_cutoff)
3584 : deriv_att%deriv_data(:, :, :) = deriv_att%deriv_data(:, :, :)/ &
3585 : MAX(SQRT(drhob(1)%array(:, :, :)**2 + &
3586 : drhob(2)%array(:, :, :)**2 + &
3587 : drhob(3)%array(:, :, :)**2), drho_cutoff)
3588 : !$OMP END PARALLEL WORKSHARE
3589 : ELSE
3590 0 : CPABORT("Normalization of derivative requires any of norm_drhob or drhob!")
3591 : END IF
3592 : CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
3593 222608 : IF (lsd) THEN
3594 0 : CPABORT(TRIM(id_to_desc(split_desc(idesc)))//" not handled in lsd!'")
3595 : END IF
3596 : CASE (deriv_rhoa, deriv_rhob, deriv_tau_a, deriv_tau_b, deriv_laplace_rhoa, deriv_laplace_rhob)
3597 : CASE default
3598 525831 : CPABORT("Unknown derivative id")
3599 : END SELECT
3600 : END DO
3601 : END DO
3602 :
3603 179285 : END SUBROUTINE divide_by_norm_drho
3604 :
3605 : ! **************************************************************************************************
3606 : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
3607 : !> \param drho ...
3608 : !> \param drhoa ...
3609 : !> \param drhob ...
3610 : ! **************************************************************************************************
3611 28440 : SUBROUTINE calc_drho_from_ab(drho, drhoa, drhob)
3612 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT) :: drho
3613 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa, drhob
3614 :
3615 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_drho_from_ab'
3616 :
3617 : INTEGER :: handle, idir
3618 :
3619 7110 : CALL timeset(routineN, handle)
3620 :
3621 28440 : DO idir = 1, 3
3622 21330 : NULLIFY (drho(idir)%array)
3623 : ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3624 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3625 106650 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3626 28440 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,drhob,idir)
3627 : drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :) + drhob(idir)%array(:, :, :)
3628 : !$OMP END PARALLEL WORKSHARE
3629 : END DO
3630 :
3631 7110 : CALL timestop(handle)
3632 :
3633 7110 : END SUBROUTINE calc_drho_from_ab
3634 :
3635 : ! **************************************************************************************************
3636 : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
3637 : !> \param drho ...
3638 : !> \param drhoa ...
3639 : !> \param drhob ...
3640 : ! **************************************************************************************************
3641 1048 : SUBROUTINE calc_drho_from_a(drho, drhoa)
3642 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT) :: drho
3643 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa
3644 :
3645 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_drho_from_a'
3646 :
3647 : INTEGER :: handle, idir
3648 :
3649 262 : CALL timeset(routineN, handle)
3650 :
3651 1048 : DO idir = 1, 3
3652 786 : NULLIFY (drho(idir)%array)
3653 : ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3654 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3655 3930 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3656 1048 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,idir)
3657 : drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :)
3658 : !$OMP END PARALLEL WORKSHARE
3659 : END DO
3660 :
3661 262 : CALL timestop(handle)
3662 :
3663 262 : END SUBROUTINE calc_drho_from_a
3664 :
3665 : ! **************************************************************************************************
3666 : !> \brief allocates and calculates dot products of two density gradients
3667 : !> \param dr1dr ...
3668 : !> \param drho ...
3669 : !> \param drho1 ...
3670 : ! **************************************************************************************************
3671 36044 : SUBROUTINE prepare_dr1dr(dr1dr, drho, drho1)
3672 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
3673 : INTENT(OUT) :: dr1dr
3674 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
3675 :
3676 : CHARACTER(len=*), PARAMETER :: routineN = 'prepare_dr1dr'
3677 :
3678 : INTEGER :: handle, idir
3679 :
3680 36044 : CALL timeset(routineN, handle)
3681 :
3682 0 : ALLOCATE (dr1dr(LBOUND(drho(1)%array, 1):UBOUND(drho(1)%array, 1), &
3683 : LBOUND(drho(1)%array, 2):UBOUND(drho(1)%array, 2), &
3684 180220 : LBOUND(drho(1)%array, 3):UBOUND(drho(1)%array, 3)))
3685 :
3686 36044 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1)
3687 : dr1dr(:, :, :) = drho(1)%array(:, :, :)*drho1(1)%array(:, :, :)
3688 : !$OMP END PARALLEL WORKSHARE
3689 108132 : DO idir = 2, 3
3690 108132 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1,idir)
3691 : dr1dr(:, :, :) = dr1dr(:, :, :) + drho(idir)%array(:, :, :)*drho1(idir)%array(:, :, :)
3692 : !$OMP END PARALLEL WORKSHARE
3693 : END DO
3694 :
3695 36044 : CALL timestop(handle)
3696 :
3697 36044 : END SUBROUTINE prepare_dr1dr
3698 :
3699 : ! **************************************************************************************************
3700 : !> \brief allocates and calculates dot product of two densities for triplets
3701 : !> \param dr1dr ...
3702 : !> \param drhoa ...
3703 : !> \param drhob ...
3704 : !> \param drho1a ...
3705 : !> \param drho1b ...
3706 : !> \param fac ...
3707 : ! **************************************************************************************************
3708 1150 : SUBROUTINE prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
3709 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
3710 : INTENT(OUT) :: dr1dr
3711 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa, drhob, drho1a, drho1b
3712 : REAL(KIND=dp), INTENT(IN) :: fac
3713 :
3714 : CHARACTER(len=*), PARAMETER :: routineN = 'prepare_dr1dr_ab'
3715 :
3716 : INTEGER :: handle, idir
3717 :
3718 1150 : CALL timeset(routineN, handle)
3719 :
3720 0 : ALLOCATE (dr1dr(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3721 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3722 5750 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3723 :
3724 1150 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob)
3725 : dr1dr(:, :, :) = drhoa(1)%array(:, :, :)*(drho1a(1)%array(:, :, :) + &
3726 : fac*drho1b(1)%array(:, :, :)) + &
3727 : drhob(1)%array(:, :, :)*(fac*drho1a(1)%array(:, :, :) + &
3728 : drho1b(1)%array(:, :, :))
3729 : !$OMP END PARALLEL WORKSHARE
3730 3450 : DO idir = 2, 3
3731 3450 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob,idir)
3732 : dr1dr(:, :, :) = dr1dr(:, :, :) + &
3733 : drhoa(idir)%array(:, :, :)*(drho1a(idir)%array(:, :, :) + &
3734 : fac*drho1b(idir)%array(:, :, :)) + &
3735 : drhob(idir)%array(:, :, :)*(fac*drho1a(idir)%array(:, :, :) + &
3736 : drho1b(idir)%array(:, :, :))
3737 : !$OMP END PARALLEL WORKSHARE
3738 : END DO
3739 :
3740 1150 : CALL timestop(handle)
3741 :
3742 1150 : END SUBROUTINE prepare_dr1dr_ab
3743 :
3744 : ! **************************************************************************************************
3745 : !> \brief checks for gradients
3746 : !> \param deriv_set ...
3747 : !> \param lsd ...
3748 : !> \param gradient_f ...
3749 : !> \param tau_f ...
3750 : !> \param laplace_f ...
3751 : ! **************************************************************************************************
3752 178981 : SUBROUTINE check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
3753 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set
3754 : LOGICAL, INTENT(IN) :: lsd
3755 : LOGICAL, INTENT(OUT) :: rho_f, gradient_f, tau_f, laplace_f
3756 :
3757 : CHARACTER(len=*), PARAMETER :: routineN = 'check_for_derivatives'
3758 :
3759 : INTEGER :: handle, iorder, order
3760 178981 : INTEGER, DIMENSION(:), POINTER :: split_desc
3761 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
3762 : TYPE(xc_derivative_type), POINTER :: deriv_att
3763 :
3764 178981 : CALL timeset(routineN, handle)
3765 :
3766 178981 : rho_f = .FALSE.
3767 178981 : gradient_f = .FALSE.
3768 178981 : tau_f = .FALSE.
3769 178981 : laplace_f = .FALSE.
3770 : ! check for unknown derivatives
3771 178981 : pos => deriv_set%derivs
3772 840285 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
3773 : CALL xc_derivative_get(deriv_att, order=order, &
3774 661304 : split_desc=split_desc)
3775 840285 : IF (lsd) THEN
3776 398661 : DO iorder = 1, size(split_desc)
3777 192449 : SELECT CASE (split_desc(iorder))
3778 : CASE (deriv_rhoa, deriv_rhob)
3779 106248 : rho_f = .TRUE.
3780 : CASE (deriv_norm_drho, deriv_norm_drhoa, deriv_norm_drhob)
3781 95876 : gradient_f = .TRUE.
3782 : CASE (deriv_tau_a, deriv_tau_b)
3783 2776 : tau_f = .TRUE.
3784 : CASE (deriv_laplace_rhoa, deriv_laplace_rhob)
3785 1312 : laplace_f = .TRUE.
3786 : CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
3787 0 : CPABORT("Derivative not handled in lsd!")
3788 : CASE default
3789 206212 : CPABORT("Unknown derivative id")
3790 : END SELECT
3791 : END DO
3792 : ELSE
3793 883714 : DO iorder = 1, size(split_desc)
3794 468855 : SELECT CASE (split_desc(iorder))
3795 : CASE (deriv_rho)
3796 242134 : rho_f = .TRUE.
3797 : CASE (deriv_tau)
3798 5734 : tau_f = .TRUE.
3799 : CASE (deriv_norm_drho)
3800 165553 : gradient_f = .TRUE.
3801 : CASE (deriv_laplace_rho)
3802 1438 : laplace_f = .TRUE.
3803 : CASE default
3804 414859 : CPABORT("Unknown derivative id")
3805 : END SELECT
3806 : END DO
3807 : END IF
3808 : END DO
3809 :
3810 178981 : CALL timestop(handle)
3811 :
3812 178981 : END SUBROUTINE check_for_derivatives
3813 :
3814 : END MODULE xc
|