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/OneDFT/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 8758 : 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 17516 : calc_potential=.FALSE.)
105 8758 : res = (needs%tau_spin .OR. needs%tau)
106 :
107 8758 : END FUNCTION xc_uses_kinetic_energy_density
108 :
109 : ! **************************************************************************************************
110 : !> \brief ...
111 : !> \param xc_fun_section ...
112 : !> \param lsd ...
113 : !> \return ...
114 : ! **************************************************************************************************
115 8582 : 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 17164 : calc_potential=.FALSE.)
125 8582 : res = (needs%norm_drho .OR. needs%norm_drho_spin)
126 :
127 8582 : 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 307182 : 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 153591 : CALL timeset(routineN, handle)
177 :
178 : MARK_USED(weights)
179 :
180 153591 : CPASSERT(ASSOCIATED(pw_pool))
181 :
182 153591 : nspins = SIZE(rho_r)
183 153591 : lsd = (nspins /= 1)
184 :
185 153591 : xc_fun_sections => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
186 :
187 : ! Create deriv_set object
188 153591 : 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 153591 : 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 153591 : 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 153591 : deriv_order=deriv_order)
210 :
211 : ! apply weights
212 153591 : IF (ASSOCIATED(weights)) THEN
213 11380 : pos => deriv_set%derivs
214 47066 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
215 4053660258 : deriv_att%deriv_data(:, :, :) = weights%array(:, :, :)*deriv_att%deriv_data(:, :, :)
216 : END DO
217 : END IF
218 :
219 153591 : CALL divide_by_norm_drho(deriv_set, rho_set, lsd)
220 :
221 153591 : CALL timestop(handle)
222 :
223 153591 : 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 291617 : 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 291617 : CPASSERT(ASSOCIATED(pot))
256 1166468 : bo(1, :) = LBOUND(pot)
257 1166468 : bo(2, :) = UBOUND(pot)
258 291617 : my_e_0_scale_factor = 1.0_dp
259 291617 : IF (PRESENT(e_0_scale_factor)) my_e_0_scale_factor = e_0_scale_factor
260 291617 : rho_smooth_cutoff = rho_cutoff*rho_smooth_cutoff_range
261 291617 : rho_smooth_cutoff_2 = (rho_cutoff + rho_smooth_cutoff)/2
262 291617 : rho_smooth_cutoff_range_2 = rho_smooth_cutoff_2 - rho_cutoff
263 :
264 291617 : 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 : ELSEIF (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 : ELSEIF (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 : ELSEIF (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 : ELSEIF (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 291617 : 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 4139220 : pot%array(i, j, k) = my_pot/my_rho
429 228948 : ELSE IF (my_rho < eps2) THEN
430 228948 : 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 128559 : 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 128559 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, norm_drho, norm_drho_spin, &
499 257118 : rho, rhoa, rhob
500 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
501 : TYPE(pw_grid_type), POINTER :: pw_grid
502 899913 : 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 128559 : CALL timeset(routineN, handle)
510 128559 : NULLIFY (norm_drho_spin, norm_drho, pos)
511 :
512 128559 : pw_grid => rho_r(1)%pw_grid
513 :
514 128559 : CPASSERT(ASSOCIATED(xc_section))
515 128559 : CPASSERT(ASSOCIATED(pw_pool))
516 128559 : CPASSERT(.NOT. ASSOCIATED(vxc_rho))
517 128559 : CPASSERT(.NOT. ASSOCIATED(vxc_tau))
518 128559 : nspins = SIZE(rho_r)
519 128559 : lsd = (nspins /= 1)
520 128559 : IF (lsd) THEN
521 23913 : CPASSERT(nspins == 2)
522 : END IF
523 :
524 128559 : use_virial = compute_virial
525 128559 : virial_xc = 0.0_dp
526 :
527 1285590 : bo = rho_r(1)%pw_grid%bounds_local
528 128559 : 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 128559 : calc_potential=.TRUE.)
536 :
537 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
538 128559 : i_val=xc_deriv_method_id)
539 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_SMOOTH_RHO", &
540 128559 : i_val=xc_rho_smooth_id)
541 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
542 128559 : r_val=density_smooth_cut_range)
543 :
544 : CALL xc_rho_set_get(rho_set, rho_cutoff=rho_cutoff, &
545 128559 : drho_cutoff=drho_cutoff)
546 :
547 128559 : CALL check_for_derivatives(deriv_set, lsd, has_rho, has_gradient, has_tau, has_laplace)
548 : ! check for unknown derivatives
549 128559 : has_derivs = has_rho .OR. has_gradient .OR. has_tau .OR. has_laplace
550 :
551 538149 : ALLOCATE (vxc_rho(nspins))
552 :
553 : CALL xc_rho_set_get(rho_set, rho=rho, rhoa=rhoa, rhob=rhob, &
554 128559 : can_return_null=.TRUE.)
555 :
556 : ! recover the vxc arrays
557 128559 : IF (lsd) THEN
558 23913 : CALL xc_dset_recover_pw(deriv_set, [deriv_rhoa], vxc_rho(1), pw_grid, pw_pool)
559 23913 : CALL xc_dset_recover_pw(deriv_set, [deriv_rhob], vxc_rho(2), pw_grid, pw_pool)
560 : ELSE
561 104646 : CALL xc_dset_recover_pw(deriv_set, [deriv_rho], vxc_rho(1), pw_grid, pw_pool)
562 : END IF
563 :
564 128559 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho])
565 128559 : IF (ASSOCIATED(deriv_att)) THEN
566 71549 : 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 71549 : can_return_null=.TRUE.)
572 71549 : CALL xc_rho_set_recover_pw(rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv_rho, drho=pw_to_deriv_rho)
573 :
574 71549 : CPASSERT(ASSOCIATED(deriv_data))
575 71549 : IF (use_virial) THEN
576 1582 : CALL pw_pool%create_pw(virial_pw)
577 1582 : CALL pw_zero(virial_pw)
578 6328 : DO idir = 1, 3
579 4746 : !$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 15820 : DO jdir = 1, idir
583 : virial_xc(idir, jdir) = -pw_grid%dvol* &
584 : accurate_dot_product(virial_pw%array(:, :, :), &
585 9492 : pw_to_deriv_rho(jdir)%array(:, :, :))
586 14238 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
587 : END DO
588 : END DO
589 1582 : CALL pw_pool%give_back_pw(virial_pw)
590 : END IF ! use_virial
591 286196 : DO idir = 1, 3
592 214647 : CPASSERT(ASSOCIATED(pw_to_deriv_rho(idir)%array))
593 286196 : !$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 71549 : CALL pw_pool%give_back_cr3d(deriv_att%deriv_data)
600 :
601 : END IF
602 :
603 128559 : IF ((has_gradient .AND. xc_requires_tmp_g(xc_deriv_method_id)) .OR. pw_grid%spherical) THEN
604 71389 : CALL pw_pool%create_pw(vxc_g)
605 71389 : IF (.NOT. pw_grid%spherical) THEN
606 71389 : CALL pw_pool%create_pw(tmp_g)
607 : END IF
608 : END IF
609 :
610 281031 : DO ispin = 1, nspins
611 :
612 152472 : IF (lsd) THEN
613 47826 : IF (ispin == 1) THEN
614 : CALL xc_rho_set_get(rho_set, norm_drhoa=norm_drho_spin, &
615 23913 : can_return_null=.TRUE.)
616 23913 : IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
617 15278 : 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 23913 : can_return_null=.TRUE.)
621 23913 : IF (ASSOCIATED(norm_drho_spin)) CALL xc_rho_set_recover_pw( &
622 15278 : rho_set, pw_grid, pw_pool, dealloc_pw_to_deriv, drhob=pw_to_deriv)
623 : END IF
624 :
625 95652 : deriv_att => xc_dset_get_derivative(deriv_set, [norm_drho_spin_name(ispin)])
626 47826 : IF (ASSOCIATED(deriv_att)) THEN
627 : CPASSERT(lsd)
628 30556 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
629 :
630 30556 : IF (use_virial) THEN
631 112 : CALL pw_pool%create_pw(virial_pw)
632 112 : CALL pw_zero(virial_pw)
633 448 : DO idir = 1, 3
634 336 : !$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 1120 : DO jdir = 1, idir
638 : virial_xc(idir, jdir) = virial_xc(idir, jdir) - pw_grid%dvol* &
639 : accurate_dot_product(virial_pw%array(:, :, :), &
640 672 : pw_to_deriv(jdir)%array(:, :, :))
641 1008 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
642 : END DO
643 : END DO
644 112 : CALL pw_pool%give_back_pw(virial_pw)
645 : END IF ! use_virial
646 :
647 122224 : DO idir = 1, 3
648 122224 : !$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 152472 : IF (ASSOCIATED(pw_to_deriv_rho(1)%array)) THEN
657 85949 : IF (.NOT. ASSOCIATED(pw_to_deriv(1)%array)) THEN
658 57149 : pw_to_deriv = pw_to_deriv_rho
659 57149 : dealloc_pw_to_deriv = ((.NOT. lsd) .OR. (ispin == 2))
660 57149 : 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 115200 : DO idir = 1, 3
665 86400 : CALL pw_axpy(pw_to_deriv_rho(idir), pw_to_deriv(idir))
666 115200 : IF (ispin == 2) THEN
667 43200 : IF (dealloc_pw_to_deriv_rho) THEN
668 43200 : 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 152472 : IF (ASSOCIATED(pw_to_deriv(1)%array)) THEN
676 350820 : DO idir = 1, 3
677 350820 : CALL pw_scale(pw_to_deriv(idir), -1.0_dp)
678 : END DO
679 :
680 87705 : CALL xc_pw_divergence(xc_deriv_method_id, pw_to_deriv, tmp_g, vxc_g, vxc_rho(ispin))
681 :
682 87705 : IF (dealloc_pw_to_deriv) THEN
683 350820 : DO idir = 1, 3
684 350820 : 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 152472 : 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 152472 : 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 152472 : rho_smooth_cutoff_range=density_smooth_cut_range)
721 :
722 152472 : v_drho_r = vxc_rho(ispin)
723 152472 : CALL pw_pool%create_pw(vxc_rho(ispin))
724 152472 : CALL xc_pw_smooth(v_drho_r, vxc_rho(ispin), xc_rho_smooth_id)
725 281031 : CALL pw_pool%give_back_pw(v_drho_r)
726 : END DO
727 :
728 128559 : CALL pw_pool%give_back_pw(vxc_g)
729 128559 : 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 128559 : IF (has_derivs) THEN
734 128239 : 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 128239 : rho_smooth_cutoff_range=density_smooth_cut_range)
739 :
740 128239 : exc = pw_integrate_function(v_drho_r)
741 : !
742 : ! return the xc functional value at the grid points
743 : !
744 128239 : IF (PRESENT(exc_r)) THEN
745 98 : exc_r = v_drho_r
746 : ELSE
747 128141 : CALL v_drho_r%release()
748 : END IF
749 : ELSE
750 320 : exc = 0.0_dp
751 : END IF
752 :
753 128559 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
754 :
755 : ! tau part
756 128559 : IF (has_tau) THEN
757 9924 : ALLOCATE (vxc_tau(nspins))
758 3094 : 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 2452 : CALL xc_dset_recover_pw(deriv_set, [deriv_tau], vxc_tau(1), pw_grid)
763 : END IF
764 6830 : DO ispin = 1, nspins
765 6830 : CPASSERT(ASSOCIATED(vxc_tau(ispin)%array))
766 : END DO
767 : END IF
768 128559 : CALL xc_dset_release(deriv_set)
769 :
770 128559 : CALL timestop(handle)
771 :
772 2699739 : 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 21388 : 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 10694 : 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 10694 : CALL timeset(routineN, handle)
809 :
810 10694 : NULLIFY (deriv, e_0)
811 10694 : 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 10694 : calc_potential=.FALSE.)
819 10694 : deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
820 :
821 10694 : IF (ASSOCIATED(deriv)) THEN
822 10694 : CALL xc_derivative_get(deriv, deriv_data=e_0)
823 :
824 : CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
825 10694 : r_val=rho_cutoff)
826 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
827 10694 : 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 10694 : rho_smooth_cutoff_range=density_smooth_cut_range)
832 :
833 10694 : exc = accurate_sum(e_0)*rho_r(1)%pw_grid%dvol
834 10694 : IF (rho_r(1)%pw_grid%para%mode == PW_MODE_DISTRIBUTED) THEN
835 10558 : CALL rho_r(1)%pw_grid%para%group%sum(exc)
836 : END IF
837 :
838 10694 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
839 10694 : CALL xc_dset_release(deriv_set)
840 : END IF
841 :
842 10694 : CALL timestop(handle)
843 :
844 203186 : 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 420 : 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 210 : 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 210 : CALL timeset(routineN, handle)
875 :
876 210 : 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 210 : calc_potential=.FALSE.)
883 210 : deriv => xc_dset_get_derivative(deriv_set, [INTEGER::])
884 :
885 210 : IF (ASSOCIATED(deriv)) THEN
886 210 : CALL xc_derivative_get(deriv, deriv_data=e_0)
887 :
888 : CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
889 210 : r_val=rho_cutoff)
890 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
891 210 : 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 210 : rho_smooth_cutoff_range=density_smooth_cut_range)
896 :
897 15646873 : exc%array = e_0
898 :
899 210 : CALL xc_rho_set_release(rho_set, pw_pool=pw_pool)
900 210 : CALL xc_dset_release(deriv_set)
901 : END IF
902 :
903 210 : CALL timestop(handle)
904 :
905 4620 : 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 15684 : 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 15684 : CALL timeset(routineN, handle)
959 :
960 15684 : my_compute_virial = .FALSE.
961 15684 : IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
962 :
963 15684 : my_do_sf = .FALSE.
964 15684 : IF (PRESENT(do_sf)) my_do_sf = do_sf
965 :
966 15684 : my_do_excitations = .FALSE.
967 15684 : IF (PRESENT(do_excitations)) my_do_excitations = do_excitations
968 :
969 15684 : my_do_triplet = .FALSE.
970 15684 : IF (PRESENT(do_triplet)) my_do_triplet = do_triplet
971 :
972 15684 : nspins = SIZE(rho1_r)
973 15684 : lsd = (nspins == 2)
974 15684 : IF (nspins == 1 .AND. my_do_excitations .AND. my_do_triplet) THEN
975 0 : nspins = 2
976 0 : lsd = .TRUE.
977 15684 : ELSE IF (my_do_sf) THEN
978 104 : nspins = 1
979 104 : lsd = .TRUE.
980 : END IF
981 :
982 15684 : NULLIFY (v_xc, v_xc_tau)
983 64748 : ALLOCATE (v_xc(nspins))
984 33380 : DO ispin = 1, nspins
985 17696 : CALL pw_pool%create_pw(v_xc(ispin))
986 33380 : CALL pw_zero(v_xc(ispin))
987 : END DO
988 :
989 15684 : xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
990 15684 : needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
991 :
992 15684 : IF (needs%tau .OR. needs%tau_spin) THEN
993 536 : IF (.NOT. ASSOCIATED(tau1_r)) &
994 0 : CPABORT("Tau-dependent functionals requires allocated kinetic energy density grid")
995 1736 : ALLOCATE (v_xc_tau(nspins))
996 1200 : DO ispin = 1, nspins
997 664 : CALL pw_pool%create_pw(v_xc_tau(ispin))
998 16348 : CALL pw_zero(v_xc_tau(ispin))
999 : END DO
1000 : END IF
1001 :
1002 15684 : IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
1003 : !------!
1004 : ! rho1 !
1005 : !------!
1006 153840 : bo = rho1_r(1)%pw_grid%bounds_local
1007 : ! create the place where to store the argument for the functionals
1008 : CALL xc_rho_set_create(rho1_set, bo, &
1009 : rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
1010 : drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
1011 15384 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1012 :
1013 : ! calculate the arguments needed by the functionals
1014 : CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
1015 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1016 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1017 15384 : pw_pool, spinflip=my_do_sf)
1018 :
1019 15384 : fac = 0._dp
1020 15384 : IF (nspins == 1 .AND. my_do_excitations) THEN
1021 1124 : IF (my_do_triplet) fac = -1.0_dp
1022 : END IF
1023 :
1024 : CALL xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, &
1025 : rho1_set, pw_pool, xc_section, &
1026 : gapw, vxg=vxg, spinflip=my_do_sf, tddfpt_fac=fac, &
1027 15384 : compute_virial=compute_virial, virial_xc=virial_xc)
1028 :
1029 15384 : CALL xc_rho_set_release(rho1_set)
1030 :
1031 : ELSE
1032 300 : IF (gapw) CPABORT("Numerical 2nd derivatives not implemented with GAPW")
1033 :
1034 : CALL xc_calc_2nd_deriv_numerical(v_xc, v_xc_tau, rho_set, rho1_r, rho1_g, tau1_r, &
1035 : pw_pool, weights, xc_section, &
1036 : my_do_excitations .AND. my_do_triplet, &
1037 300 : compute_virial, virial_xc, deriv_set)
1038 : END IF
1039 :
1040 15684 : CALL timestop(handle)
1041 :
1042 345048 : END SUBROUTINE xc_calc_2nd_deriv
1043 :
1044 : ! **************************************************************************************************
1045 : !> \brief calculates 2nd derivative numerically
1046 : !> \param v_xc potential to be calculated (has to be allocated already)
1047 : !> \param v_tau tau-part of the potential to be calculated (has to be allocated already)
1048 : !> \param rho_set KS density from xc_prep_2nd_deriv
1049 : !> \param rho1_r first-order density in r-space
1050 : !> \param rho1_g first-order density in g-space
1051 : !> \param tau1_r first-order kinetic-energy density in r-space
1052 : !> \param pw_pool pw pool for new grids
1053 : !> \param xc_section XC section to calculate the derivatives from
1054 : !> \param do_triplet ...
1055 : !> \param calc_virial whether to calculate virial terms
1056 : !> \param virial_xc collects stress tensor components (no metaGGAs!)
1057 : !> \param deriv_set deriv set from xc_prep_2nd_deriv (only for virials)
1058 : ! **************************************************************************************************
1059 340 : SUBROUTINE xc_calc_2nd_deriv_numerical(v_xc, v_tau, rho_set, rho1_r, rho1_g, tau1_r, &
1060 : pw_pool, weights, xc_section, &
1061 : do_triplet, calc_virial, virial_xc, deriv_set)
1062 :
1063 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: v_xc, v_tau
1064 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set
1065 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_r, tau1_r
1066 : TYPE(pw_c1d_gs_type), DIMENSION(:), INTENT(IN), POINTER :: rho1_g
1067 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
1068 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: weights
1069 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
1070 : LOGICAL, INTENT(IN) :: do_triplet
1071 : LOGICAL, INTENT(IN), OPTIONAL :: calc_virial
1072 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
1073 : OPTIONAL :: virial_xc
1074 : TYPE(xc_derivative_set_type), OPTIONAL :: deriv_set
1075 :
1076 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_numerical'
1077 : REAL(KIND=dp), DIMENSION(-4:4, 4), PARAMETER :: &
1078 : 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, &
1079 : 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, &
1080 : 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, &
1081 : 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])
1082 :
1083 : INTEGER :: handle, idir, ispin, nspins, istep, nsteps
1084 : INTEGER, DIMENSION(2, 3) :: bo
1085 : LOGICAL :: gradient_f, lsd, my_calc_virial, tau_f, laplace_f, rho_f
1086 : REAL(KIND=dp) :: exc, gradient_cut, h, rweight, step, rho_cutoff
1087 340 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
1088 : REAL(KIND=dp), DIMENSION(3, 3) :: virial_dummy
1089 340 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: norm_drho, norm_drho2, norm_drho2a, &
1090 340 : norm_drho2b, norm_drhoa, norm_drhob, &
1091 1020 : rho, rho1, rho1a, rho1b, rhoa, rhob, &
1092 680 : tau_a, tau_b, tau, tau1, tau1a, tau1b, laplace, laplace1, &
1093 340 : laplacea, laplaceb, laplace1a, laplace1b, &
1094 680 : laplace2, laplace2a, laplace2b, deriv_data
1095 8160 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
1096 : TYPE(pw_r3d_rs_type) :: v_drho, v_drhoa, v_drhob
1097 340 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: vxc_rho, vxc_tau
1098 340 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
1099 340 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r, tau_r
1100 : TYPE(pw_r3d_rs_type) :: virial_pw, v_laplace, v_laplacea, v_laplaceb
1101 : TYPE(section_vals_type), POINTER :: xc_fun_section
1102 : TYPE(xc_derivative_set_type) :: deriv_set1
1103 : TYPE(xc_rho_cflags_type) :: needs
1104 : TYPE(xc_rho_set_type) :: rho1_set, rho2_set
1105 :
1106 340 : CALL timeset(routineN, handle)
1107 :
1108 340 : my_calc_virial = .FALSE.
1109 340 : IF (PRESENT(calc_virial) .AND. PRESENT(virial_xc)) my_calc_virial = calc_virial
1110 :
1111 340 : nspins = SIZE(v_xc)
1112 :
1113 340 : NULLIFY (tau, tau_r, tau_a, tau_b)
1114 :
1115 340 : h = section_get_rval(xc_section, "STEP_SIZE")
1116 340 : nsteps = section_get_ival(xc_section, "NSTEPS")
1117 340 : IF (nsteps < LBOUND(rweights, 2) .OR. nspins > UBOUND(rweights, 2)) THEN
1118 0 : CPABORT("The number of steps must be a value from 1 to 4.")
1119 : END IF
1120 :
1121 340 : IF (nspins == 2) THEN
1122 148 : NULLIFY (vxc_rho, rho_g, vxc_tau)
1123 444 : ALLOCATE (rho_r(2))
1124 444 : DO ispin = 1, nspins
1125 444 : CALL pw_pool%create_pw(rho_r(ispin))
1126 : END DO
1127 148 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1128 162 : ALLOCATE (tau_r(2))
1129 162 : DO ispin = 1, nspins
1130 162 : CALL pw_pool%create_pw(tau_r(ispin))
1131 : END DO
1132 : END IF
1133 148 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
1134 1088 : DO istep = -nsteps, nsteps
1135 940 : IF (istep == 0) CYCLE
1136 792 : rweight = rweights(istep, nsteps)/h
1137 792 : step = REAL(istep, dp)*h
1138 : CALL calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
1139 : tau_r, tau1_r, tau_a, tau_b, vxc_tau, xc_section, &
1140 792 : weights, pw_pool, step)
1141 2376 : DO ispin = 1, nspins
1142 1584 : CALL pw_axpy(vxc_rho(ispin), v_xc(ispin), rweight)
1143 2376 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1144 456 : CALL pw_axpy(vxc_tau(ispin), v_tau(ispin), rweight)
1145 : END IF
1146 : END DO
1147 2376 : DO ispin = 1, nspins
1148 2376 : CALL vxc_rho(ispin)%release()
1149 : END DO
1150 792 : DEALLOCATE (vxc_rho)
1151 940 : IF (ASSOCIATED(vxc_tau)) THEN
1152 684 : DO ispin = 1, nspins
1153 684 : CALL vxc_tau(ispin)%release()
1154 : END DO
1155 228 : DEALLOCATE (vxc_tau)
1156 : END IF
1157 : END DO
1158 192 : ELSE IF (nspins == 1 .AND. do_triplet) THEN
1159 20 : NULLIFY (vxc_rho, vxc_tau, rho_g)
1160 60 : ALLOCATE (rho_r(2))
1161 60 : DO ispin = 1, 2
1162 60 : CALL pw_pool%create_pw(rho_r(ispin))
1163 : END DO
1164 20 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1165 0 : ALLOCATE (tau_r(2))
1166 0 : DO ispin = 1, nspins
1167 0 : CALL pw_pool%create_pw(tau_r(ispin))
1168 : END DO
1169 : END IF
1170 20 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rhoa=rhoa, rhob=rhob, tau_a=tau_a, tau_b=tau_b)
1171 160 : DO istep = -nsteps, nsteps
1172 140 : IF (istep == 0) CYCLE
1173 120 : rweight = rweights(istep, nsteps)/h
1174 120 : step = REAL(istep, dp)*h
1175 : ! K(alpha,alpha)
1176 120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1177 : !$OMP WORKSHARE
1178 : rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
1179 : !$OMP END WORKSHARE NOWAIT
1180 : !$OMP WORKSHARE
1181 : rho_r(2)%array(:, :, :) = rhob(:, :, :)
1182 : !$OMP END WORKSHARE NOWAIT
1183 : IF (ASSOCIATED(tau1_r)) THEN
1184 : !$OMP WORKSHARE
1185 : tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
1186 : !$OMP END WORKSHARE NOWAIT
1187 : !$OMP WORKSHARE
1188 : tau_r(2)%array(:, :, :) = tau_b(:, :, :)
1189 : !$OMP END WORKSHARE NOWAIT
1190 : END IF
1191 : !$OMP END PARALLEL
1192 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1193 120 : weights, pw_pool, .FALSE., virial_dummy)
1194 120 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1195 120 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1196 0 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1197 : END IF
1198 360 : DO ispin = 1, 2
1199 360 : CALL vxc_rho(ispin)%release()
1200 : END DO
1201 120 : DEALLOCATE (vxc_rho)
1202 120 : IF (ASSOCIATED(vxc_tau)) THEN
1203 0 : DO ispin = 1, 2
1204 0 : CALL vxc_tau(ispin)%release()
1205 : END DO
1206 0 : DEALLOCATE (vxc_tau)
1207 : END IF
1208 120 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1209 : !$OMP WORKSHARE
1210 : ! K(alpha,beta)
1211 : rho_r(1)%array(:, :, :) = rhoa(:, :, :)
1212 : !$OMP END WORKSHARE NOWAIT
1213 : !$OMP WORKSHARE
1214 : rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(1)%array(:, :, :)
1215 : !$OMP END WORKSHARE NOWAIT
1216 : IF (ASSOCIATED(tau1_r)) THEN
1217 : !$OMP WORKSHARE
1218 : tau_r(1)%array(:, :, :) = tau_a(:, :, :)
1219 : !$OMP END WORKSHARE NOWAIT
1220 : !$OMP WORKSHARE
1221 : tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(1)%array(:, :, :)
1222 : !$OMP END WORKSHARE NOWAIT
1223 : END IF
1224 : !$OMP END PARALLEL
1225 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1226 120 : weights, pw_pool, .FALSE., virial_dummy)
1227 120 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1228 120 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1229 0 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1230 : END IF
1231 360 : DO ispin = 1, 2
1232 360 : CALL vxc_rho(ispin)%release()
1233 : END DO
1234 120 : DEALLOCATE (vxc_rho)
1235 140 : IF (ASSOCIATED(vxc_tau)) THEN
1236 0 : DO ispin = 1, 2
1237 0 : CALL vxc_tau(ispin)%release()
1238 : END DO
1239 0 : DEALLOCATE (vxc_tau)
1240 : END IF
1241 : END DO
1242 : ELSE
1243 172 : NULLIFY (vxc_rho, rho_r, rho_g, vxc_tau, tau_r, tau)
1244 344 : ALLOCATE (rho_r(1))
1245 172 : CALL pw_pool%create_pw(rho_r(1))
1246 172 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(v_tau)) THEN
1247 92 : ALLOCATE (tau_r(1))
1248 46 : CALL pw_pool%create_pw(tau_r(1))
1249 : END IF
1250 172 : CALL xc_rho_set_get(rho_set, can_return_null=.TRUE., rho=rho, tau=tau)
1251 1280 : DO istep = -nsteps, nsteps
1252 1108 : IF (istep == 0) CYCLE
1253 936 : rweight = rweights(istep, nsteps)/h
1254 936 : step = REAL(istep, dp)*h
1255 936 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rho,step,rho1_r,tau1_r,tau,tau_r)
1256 : !$OMP WORKSHARE
1257 : rho_r(1)%array(:, :, :) = rho(:, :, :) + step*rho1_r(1)%array(:, :, :)
1258 : !$OMP END WORKSHARE NOWAIT
1259 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau) .AND. ASSOCIATED(tau1_r)) THEN
1260 : !$OMP WORKSHARE
1261 : tau_r(1)%array(:, :, :) = tau(:, :, :) + step*tau1_r(1)%array(:, :, :)
1262 : !$OMP END WORKSHARE NOWAIT
1263 : END IF
1264 : !$OMP END PARALLEL
1265 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1266 936 : weights, pw_pool, .FALSE., virial_dummy)
1267 936 : CALL pw_axpy(vxc_rho(1), v_xc(1), rweight)
1268 936 : IF (ASSOCIATED(vxc_tau) .AND. ASSOCIATED(v_tau)) THEN
1269 276 : CALL pw_axpy(vxc_tau(1), v_tau(1), rweight)
1270 : END IF
1271 936 : CALL vxc_rho(1)%release()
1272 936 : DEALLOCATE (vxc_rho)
1273 1108 : IF (ASSOCIATED(vxc_tau)) THEN
1274 276 : CALL vxc_tau(1)%release()
1275 276 : DEALLOCATE (vxc_tau)
1276 : END IF
1277 : END DO
1278 : END IF
1279 :
1280 340 : IF (my_calc_virial) THEN
1281 36 : lsd = (nspins == 2)
1282 36 : IF (nspins == 1 .AND. do_triplet) THEN
1283 0 : lsd = .TRUE.
1284 : END IF
1285 :
1286 36 : CALL check_for_derivatives(deriv_set, (nspins == 2), rho_f, gradient_f, tau_f, laplace_f)
1287 :
1288 : ! Calculate the virial terms
1289 : ! Those arising from the first derivatives are treated like in xc_calc_2nd_deriv_analytical
1290 : ! Those arising from the second derivatives are calculated numerically
1291 : ! We assume that all metaGGA functionals require the gradient
1292 36 : IF (gradient_f) THEN
1293 360 : bo = rho_set%local_bounds
1294 :
1295 : ! Create the work grid for the virial terms
1296 36 : CALL allocate_pw(virial_pw, pw_pool, bo)
1297 :
1298 36 : gradient_cut = section_get_rval(xc_section, "GRADIENT_CUTOFF")
1299 :
1300 : ! create the container to store the argument of the functionals
1301 : CALL xc_rho_set_create(rho1_set, bo, &
1302 : rho_cutoff=section_get_rval(xc_section, "DENSITY_CUTOFF"), &
1303 : drho_cutoff=gradient_cut, &
1304 36 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1305 :
1306 36 : xc_fun_section => section_vals_get_subs_vals(xc_section, "XC_FUNCTIONAL")
1307 36 : needs = xc_functionals_get_needs(xc_fun_section, lsd, .TRUE.)
1308 :
1309 : ! calculate the arguments needed by the functionals
1310 : CALL xc_rho_set_update(rho1_set, rho1_r, rho1_g, tau1_r, needs, &
1311 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1312 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1313 36 : pw_pool)
1314 :
1315 36 : IF (lsd) THEN
1316 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, norm_drho=norm_drho, &
1317 : norm_drhoa=norm_drhoa, norm_drhob=norm_drhob, tau_a=tau_a, tau_b=tau_b, &
1318 10 : laplace_rhoa=laplacea, laplace_rhob=laplaceb, can_return_null=.TRUE.)
1319 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, drhoa=drho1a, drhob=drho1b, laplace_rhoa=laplace1a, &
1320 10 : laplace_rhob=laplace1b, can_return_null=.TRUE.)
1321 :
1322 10 : CALL calc_drho_from_ab(drho, drhoa, drhob)
1323 10 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
1324 : ELSE
1325 26 : CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho, tau=tau, laplace_rho=laplace, can_return_null=.TRUE.)
1326 26 : CALL xc_rho_set_get(rho1_set, rho=rho1, drho=drho1, laplace_rho=laplace1, can_return_null=.TRUE.)
1327 : END IF
1328 :
1329 36 : CALL prepare_dr1dr(dr1dr, drho, drho1)
1330 :
1331 36 : IF (lsd) THEN
1332 10 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
1333 10 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
1334 :
1335 10 : CALL allocate_pw(v_drho, pw_pool, bo)
1336 10 : CALL allocate_pw(v_drhoa, pw_pool, bo)
1337 10 : CALL allocate_pw(v_drhob, pw_pool, bo)
1338 :
1339 10 : IF (ASSOCIATED(norm_drhoa)) CALL apply_drho(deriv_set, [deriv_norm_drhoa], virial_pw, &
1340 : drhoa, drho1a, virial_xc, &
1341 10 : norm_drhoa, gradient_cut, dra1dra, v_drhoa%array)
1342 10 : IF (ASSOCIATED(norm_drhob)) CALL apply_drho(deriv_set, [deriv_norm_drhob], virial_pw, &
1343 : drhob, drho1b, virial_xc, &
1344 10 : norm_drhob, gradient_cut, drb1drb, v_drhob%array)
1345 10 : IF (ASSOCIATED(norm_drho)) CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, &
1346 : drho, drho1, virial_xc, &
1347 6 : norm_drho, gradient_cut, dr1dr, v_drho%array)
1348 10 : IF (laplace_f) THEN
1349 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhoa]), deriv_data=deriv_data)
1350 2 : CPASSERT(ASSOCIATED(deriv_data))
1351 15026 : virial_pw%array(:, :, :) = -rho1a(:, :, :)
1352 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1353 :
1354 2 : CALL allocate_pw(v_laplacea, pw_pool, bo)
1355 :
1356 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rhob]), deriv_data=deriv_data)
1357 2 : CPASSERT(ASSOCIATED(deriv_data))
1358 15026 : virial_pw%array(:, :, :) = -rho1b(:, :, :)
1359 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1360 :
1361 2 : CALL allocate_pw(v_laplaceb, pw_pool, bo)
1362 : END IF
1363 :
1364 : ELSE
1365 :
1366 : ! Create the work grid for the potential of the gradient part
1367 26 : CALL allocate_pw(v_drho, pw_pool, bo)
1368 :
1369 : CALL apply_drho(deriv_set, [deriv_norm_drho], virial_pw, drho, drho1, virial_xc, &
1370 26 : norm_drho, gradient_cut, dr1dr, v_drho%array)
1371 26 : IF (laplace_f) THEN
1372 2 : CALL xc_derivative_get(xc_dset_get_derivative(deriv_set, [deriv_laplace_rho]), deriv_data=deriv_data)
1373 2 : CPASSERT(ASSOCIATED(deriv_data))
1374 28862 : virial_pw%array(:, :, :) = -rho1(:, :, :)
1375 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, deriv_data)
1376 :
1377 2 : CALL allocate_pw(v_laplace, pw_pool, bo)
1378 : END IF
1379 :
1380 : END IF
1381 :
1382 36 : IF (lsd) THEN
1383 150260 : rho_r(1)%array = rhoa
1384 150260 : rho_r(2)%array = rhob
1385 : ELSE
1386 701552 : rho_r(1)%array = rho
1387 : END IF
1388 36 : IF (ASSOCIATED(tau1_r)) THEN
1389 8 : IF (lsd) THEN
1390 60104 : tau_r(1)%array = tau_a
1391 60104 : tau_r(2)%array = tau_b
1392 : ELSE
1393 115448 : tau_r(1)%array = tau
1394 : END IF
1395 : END IF
1396 :
1397 : ! Create deriv sets with same densities but different gradients
1398 36 : CALL xc_dset_create(deriv_set1, pw_pool)
1399 :
1400 36 : rho_cutoff = section_get_rval(xc_section, "DENSITY_CUTOFF")
1401 :
1402 : ! create the place where to store the argument for the functionals
1403 : CALL xc_rho_set_create(rho2_set, bo, &
1404 : rho_cutoff=rho_cutoff, &
1405 : drho_cutoff=section_get_rval(xc_section, "GRADIENT_CUTOFF"), &
1406 36 : tau_cutoff=section_get_rval(xc_section, "TAU_CUTOFF"))
1407 :
1408 : ! calculate the arguments needed by the functionals
1409 : CALL xc_rho_set_update(rho2_set, rho_r, rho_g, tau_r, needs, &
1410 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
1411 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
1412 36 : pw_pool)
1413 :
1414 36 : IF (lsd) THEN
1415 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b, tau_a=tau1a, tau_b=tau1b, &
1416 10 : laplace_rhoa=laplace1a, laplace_rhob=laplace1b, can_return_null=.TRUE.)
1417 : CALL xc_rho_set_get(rho2_set, norm_drhoa=norm_drho2a, norm_drhob=norm_drho2b, &
1418 10 : norm_drho=norm_drho2, laplace_rhoa=laplace2a, laplace_rhob=laplace2b, can_return_null=.TRUE.)
1419 :
1420 64 : DO istep = -nsteps, nsteps
1421 54 : IF (istep == 0) CYCLE
1422 44 : rweight = rweights(istep, nsteps)/h
1423 44 : step = REAL(istep, dp)*h
1424 44 : IF (ASSOCIATED(norm_drhoa)) THEN
1425 44 : CALL get_derivs_rho(norm_drho2a, norm_drhoa, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1426 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1427 44 : norm_drhoa, gradient_cut, rweight, rho1a, v_drhoa%array)
1428 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1429 44 : norm_drhoa, gradient_cut, rweight, rho1b, v_drhoa%array)
1430 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drhoa], bo, &
1431 44 : norm_drhoa, gradient_cut, rweight, dra1dra, v_drhoa%array)
1432 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
1433 44 : norm_drhoa, gradient_cut, rweight, dra1dra, drb1drb, v_drhoa%array, v_drhob%array)
1434 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
1435 44 : norm_drhoa, gradient_cut, rweight, dra1dra, dr1dr, v_drhoa%array, v_drho%array)
1436 44 : IF (tau_f) THEN
1437 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1438 8 : norm_drhoa, gradient_cut, rweight, tau1a, v_drhoa%array)
1439 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1440 8 : norm_drhoa, gradient_cut, rweight, tau1b, v_drhoa%array)
1441 : END IF
1442 44 : IF (laplace_f) THEN
1443 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1444 4 : norm_drhoa, gradient_cut, rweight, laplace1a, v_drhoa%array)
1445 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1446 4 : norm_drhoa, gradient_cut, rweight, laplace1b, v_drhoa%array)
1447 : END IF
1448 : END IF
1449 :
1450 44 : IF (ASSOCIATED(norm_drhob)) THEN
1451 44 : CALL get_derivs_rho(norm_drho2b, norm_drhob, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1452 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1453 44 : norm_drhob, gradient_cut, rweight, rho1a, v_drhob%array)
1454 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1455 44 : norm_drhob, gradient_cut, rweight, rho1b, v_drhob%array)
1456 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drhob], bo, &
1457 44 : norm_drhob, gradient_cut, rweight, drb1drb, v_drhob%array)
1458 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
1459 44 : norm_drhob, gradient_cut, rweight, drb1drb, dra1dra, v_drhob%array, v_drhoa%array)
1460 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drho], bo, &
1461 44 : norm_drhob, gradient_cut, rweight, drb1drb, dr1dr, v_drhob%array, v_drho%array)
1462 44 : IF (tau_f) THEN
1463 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1464 8 : norm_drhob, gradient_cut, rweight, tau1a, v_drhob%array)
1465 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1466 8 : norm_drhob, gradient_cut, rweight, tau1b, v_drhob%array)
1467 : END IF
1468 44 : IF (laplace_f) THEN
1469 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1470 4 : norm_drhob, gradient_cut, rweight, laplace1a, v_drhob%array)
1471 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1472 4 : norm_drhob, gradient_cut, rweight, laplace1b, v_drhob%array)
1473 : END IF
1474 : END IF
1475 :
1476 44 : IF (ASSOCIATED(norm_drho)) THEN
1477 20 : CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1478 : CALL update_deriv_rho(deriv_set1, [deriv_rhoa], bo, &
1479 20 : norm_drho, gradient_cut, rweight, rho1a, v_drho%array)
1480 : CALL update_deriv_rho(deriv_set1, [deriv_rhob], bo, &
1481 20 : norm_drho, gradient_cut, rweight, rho1b, v_drho%array)
1482 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
1483 20 : norm_drho, gradient_cut, rweight, dr1dr, v_drho%array)
1484 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhoa], bo, &
1485 20 : norm_drho, gradient_cut, rweight, dr1dr, dra1dra, v_drho%array, v_drhoa%array)
1486 : CALL update_deriv_drho_ab(deriv_set1, [deriv_norm_drhob], bo, &
1487 20 : norm_drho, gradient_cut, rweight, dr1dr, drb1drb, v_drho%array, v_drhob%array)
1488 20 : IF (tau_f) THEN
1489 : CALL update_deriv_rho(deriv_set1, [deriv_tau_a], bo, &
1490 8 : norm_drho, gradient_cut, rweight, tau1a, v_drho%array)
1491 : CALL update_deriv_rho(deriv_set1, [deriv_tau_b], bo, &
1492 8 : norm_drho, gradient_cut, rweight, tau1b, v_drho%array)
1493 : END IF
1494 20 : IF (laplace_f) THEN
1495 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhoa], bo, &
1496 4 : norm_drho, gradient_cut, rweight, laplace1a, v_drho%array)
1497 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rhob], bo, &
1498 4 : norm_drho, gradient_cut, rweight, laplace1b, v_drho%array)
1499 : END IF
1500 : END IF
1501 :
1502 54 : IF (laplace_f) THEN
1503 :
1504 4 : CALL get_derivs_rho(laplace2a, laplacea, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1505 :
1506 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1507 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhoa], bo, &
1508 4 : rweight, rho1a, v_laplacea%array)
1509 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_rhob], bo, &
1510 4 : rweight, rho1b, v_laplacea%array)
1511 4 : IF (ASSOCIATED(norm_drho)) THEN
1512 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drho], bo, &
1513 4 : rweight, dr1dr, v_laplacea%array)
1514 : END IF
1515 4 : IF (ASSOCIATED(norm_drhoa)) THEN
1516 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhoa], bo, &
1517 4 : rweight, dra1dra, v_laplacea%array)
1518 : END IF
1519 4 : IF (ASSOCIATED(norm_drhob)) THEN
1520 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_norm_drhob], bo, &
1521 4 : rweight, drb1drb, v_laplacea%array)
1522 : END IF
1523 :
1524 4 : IF (ASSOCIATED(tau1a)) THEN
1525 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_a], bo, &
1526 4 : rweight, tau1a, v_laplacea%array)
1527 : END IF
1528 4 : IF (ASSOCIATED(tau1b)) THEN
1529 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_tau_b], bo, &
1530 4 : rweight, tau1b, v_laplacea%array)
1531 : END IF
1532 :
1533 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhoa], bo, &
1534 4 : rweight, laplace1a, v_laplacea%array)
1535 :
1536 : CALL update_deriv(deriv_set1, laplacea, rho_cutoff, [deriv_laplace_rhob], bo, &
1537 4 : rweight, laplace1b, v_laplacea%array)
1538 :
1539 : ! The same for the beta spin
1540 4 : CALL get_derivs_rho(laplace2b, laplaceb, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1541 :
1542 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1543 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhoa], bo, &
1544 4 : rweight, rho1a, v_laplaceb%array)
1545 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_rhob], bo, &
1546 4 : rweight, rho1b, v_laplaceb%array)
1547 4 : IF (ASSOCIATED(norm_drho)) THEN
1548 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drho], bo, &
1549 4 : rweight, dr1dr, v_laplaceb%array)
1550 : END IF
1551 4 : IF (ASSOCIATED(norm_drhoa)) THEN
1552 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhoa], bo, &
1553 4 : rweight, dra1dra, v_laplaceb%array)
1554 : END IF
1555 4 : IF (ASSOCIATED(norm_drhob)) THEN
1556 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_norm_drhob], bo, &
1557 4 : rweight, drb1drb, v_laplaceb%array)
1558 : END IF
1559 :
1560 4 : IF (tau_f) THEN
1561 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_a], bo, &
1562 4 : rweight, tau1a, v_laplaceb%array)
1563 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_tau_b], bo, &
1564 4 : rweight, tau1b, v_laplaceb%array)
1565 : END IF
1566 :
1567 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhoa], bo, &
1568 4 : rweight, laplace1a, v_laplaceb%array)
1569 :
1570 : CALL update_deriv(deriv_set1, laplaceb, rho_cutoff, [deriv_laplace_rhob], bo, &
1571 4 : rweight, laplace1b, v_laplaceb%array)
1572 : END IF
1573 : END DO
1574 :
1575 10 : CALL virial_drho_drho(virial_pw, drhoa, v_drhoa, virial_xc)
1576 10 : CALL virial_drho_drho(virial_pw, drhob, v_drhob, virial_xc)
1577 10 : CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
1578 :
1579 10 : CALL deallocate_pw(v_drho, pw_pool)
1580 10 : CALL deallocate_pw(v_drhoa, pw_pool)
1581 10 : CALL deallocate_pw(v_drhob, pw_pool)
1582 :
1583 10 : IF (laplace_f) THEN
1584 15026 : virial_pw%array(:, :, :) = -rhoa(:, :, :)
1585 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplacea%array)
1586 2 : CALL deallocate_pw(v_laplacea, pw_pool)
1587 :
1588 15026 : virial_pw%array(:, :, :) = -rhob(:, :, :)
1589 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplaceb%array)
1590 2 : CALL deallocate_pw(v_laplaceb, pw_pool)
1591 : END IF
1592 :
1593 10 : CALL deallocate_pw(virial_pw, pw_pool)
1594 :
1595 40 : DO idir = 1, 3
1596 30 : DEALLOCATE (drho(idir)%array)
1597 40 : DEALLOCATE (drho1(idir)%array)
1598 : END DO
1599 10 : DEALLOCATE (dra1dra, drb1drb)
1600 :
1601 : ELSE
1602 26 : CALL xc_rho_set_get(rho1_set, rho=rho1, tau=tau1, laplace_rho=laplace1, can_return_null=.TRUE.)
1603 26 : CALL xc_rho_set_get(rho2_set, norm_drho=norm_drho2, laplace_rho=laplace2, can_return_null=.TRUE.)
1604 :
1605 200 : DO istep = -nsteps, nsteps
1606 174 : IF (istep == 0) CYCLE
1607 148 : rweight = rweights(istep, nsteps)/h
1608 148 : step = REAL(istep, dp)*h
1609 148 : CALL get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1610 :
1611 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1612 : CALL update_deriv_rho(deriv_set1, [deriv_rho], bo, &
1613 148 : norm_drho, gradient_cut, rweight, rho1, v_drho%array)
1614 : CALL update_deriv_rho(deriv_set1, [deriv_norm_drho], bo, &
1615 148 : norm_drho, gradient_cut, rweight, dr1dr, v_drho%array)
1616 :
1617 148 : IF (tau_f) THEN
1618 : CALL update_deriv_rho(deriv_set1, [deriv_tau], bo, &
1619 24 : norm_drho, gradient_cut, rweight, tau1, v_drho%array)
1620 : END IF
1621 174 : IF (laplace_f) THEN
1622 : CALL update_deriv_rho(deriv_set1, [deriv_laplace_rho], bo, &
1623 12 : norm_drho, gradient_cut, rweight, laplace1, v_drho%array)
1624 :
1625 12 : CALL get_derivs_rho(laplace2, laplace, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1626 :
1627 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1628 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_rho], bo, &
1629 12 : rweight, rho1, v_laplace%array)
1630 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_norm_drho], bo, &
1631 12 : rweight, dr1dr, v_laplace%array)
1632 :
1633 12 : IF (tau_f) THEN
1634 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_tau], bo, &
1635 12 : rweight, tau1, v_laplace%array)
1636 : END IF
1637 :
1638 : CALL update_deriv(deriv_set1, laplace, rho_cutoff, [deriv_laplace_rho], bo, &
1639 12 : rweight, laplace1, v_laplace%array)
1640 : END IF
1641 : END DO
1642 :
1643 : ! Calculate the virial contribution from the potential
1644 26 : CALL virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
1645 :
1646 26 : CALL deallocate_pw(v_drho, pw_pool)
1647 :
1648 26 : IF (laplace_f) THEN
1649 28862 : virial_pw%array(:, :, :) = -rho(:, :, :)
1650 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace%array)
1651 2 : CALL deallocate_pw(v_laplace, pw_pool)
1652 : END IF
1653 :
1654 26 : CALL deallocate_pw(virial_pw, pw_pool)
1655 : END IF
1656 :
1657 : END IF
1658 :
1659 36 : CALL xc_dset_release(deriv_set1)
1660 :
1661 36 : DEALLOCATE (dr1dr)
1662 :
1663 36 : CALL xc_rho_set_release(rho1_set)
1664 36 : CALL xc_rho_set_release(rho2_set)
1665 : END IF
1666 :
1667 848 : DO ispin = 1, SIZE(rho_r)
1668 848 : CALL pw_pool%give_back_pw(rho_r(ispin))
1669 : END DO
1670 340 : DEALLOCATE (rho_r)
1671 :
1672 340 : IF (ASSOCIATED(tau_r)) THEN
1673 254 : DO ispin = 1, SIZE(tau_r)
1674 254 : CALL pw_pool%give_back_pw(tau_r(ispin))
1675 : END DO
1676 100 : DEALLOCATE (tau_r)
1677 : END IF
1678 :
1679 340 : CALL timestop(handle)
1680 :
1681 15300 : END SUBROUTINE xc_calc_2nd_deriv_numerical
1682 :
1683 : ! **************************************************************************************************
1684 : !> \brief ...
1685 : !> \param rho_r ...
1686 : !> \param rho_g ...
1687 : !> \param rho1_r ...
1688 : !> \param rhoa ...
1689 : !> \param rhob ...
1690 : !> \param vxc_rho ...
1691 : !> \param tau_r ...
1692 : !> \param tau1_r ...
1693 : !> \param tau_a ...
1694 : !> \param tau_b ...
1695 : !> \param vxc_tau ...
1696 : !> \param xc_section ...
1697 : !> \param pw_pool ...
1698 : !> \param step ...
1699 : ! **************************************************************************************************
1700 792 : SUBROUTINE calc_resp_potential_numer_ab(rho_r, rho_g, rho1_r, rhoa, rhob, vxc_rho, &
1701 : tau_r, tau1_r, tau_a, tau_b, vxc_tau, &
1702 : xc_section, weights, pw_pool, step)
1703 :
1704 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: vxc_rho, vxc_tau
1705 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN) :: rho1_r
1706 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN), POINTER :: tau1_r
1707 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: weights
1708 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
1709 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_section
1710 : REAL(KIND=dp), INTENT(IN) :: step
1711 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER, INTENT(IN) :: rhoa, rhob, tau_a, tau_b
1712 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER, INTENT(IN) :: rho_r
1713 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
1714 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau_r
1715 :
1716 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_resp_potential_numer_ab'
1717 :
1718 : INTEGER :: handle
1719 : REAL(KIND=dp) :: exc
1720 : REAL(KIND=dp), DIMENSION(3, 3) :: virial_dummy
1721 :
1722 792 : CALL timeset(routineN, handle)
1723 :
1724 792 : !$OMP PARALLEL DEFAULT(NONE) SHARED(rho_r,rhoa,rhob,step,rho1_r,tau_r,tau_a,tau_b,tau1_r)
1725 : !$OMP WORKSHARE
1726 : rho_r(1)%array(:, :, :) = rhoa(:, :, :) + step*rho1_r(1)%array(:, :, :)
1727 : !$OMP END WORKSHARE NOWAIT
1728 : !$OMP WORKSHARE
1729 : rho_r(2)%array(:, :, :) = rhob(:, :, :) + step*rho1_r(2)%array(:, :, :)
1730 : !$OMP END WORKSHARE NOWAIT
1731 : IF (ASSOCIATED(tau1_r) .AND. ASSOCIATED(tau_r) .AND. ASSOCIATED(tau_a) .AND. ASSOCIATED(tau_b)) THEN
1732 : !$OMP WORKSHARE
1733 : tau_r(1)%array(:, :, :) = tau_a(:, :, :) + step*tau1_r(1)%array(:, :, :)
1734 : !$OMP END WORKSHARE NOWAIT
1735 : !$OMP WORKSHARE
1736 : tau_r(2)%array(:, :, :) = tau_b(:, :, :) + step*tau1_r(2)%array(:, :, :)
1737 : !$OMP END WORKSHARE NOWAIT
1738 : END IF
1739 : !$OMP END PARALLEL
1740 : CALL xc_vxc_pw_create(vxc_rho, vxc_tau, exc, rho_r, rho_g, tau_r, xc_section, &
1741 792 : weights, pw_pool, .FALSE., virial_dummy)
1742 :
1743 792 : CALL timestop(handle)
1744 :
1745 792 : END SUBROUTINE calc_resp_potential_numer_ab
1746 :
1747 : ! **************************************************************************************************
1748 : !> \brief calculates stress tensor and potential contributions from the first derivative
1749 : !> \param deriv_set ...
1750 : !> \param description ...
1751 : !> \param virial_pw ...
1752 : !> \param drho ...
1753 : !> \param drho1 ...
1754 : !> \param virial_xc ...
1755 : !> \param norm_drho ...
1756 : !> \param gradient_cut ...
1757 : !> \param dr1dr ...
1758 : !> \param v_drho ...
1759 : ! **************************************************************************************************
1760 52 : SUBROUTINE apply_drho(deriv_set, description, virial_pw, drho, drho1, &
1761 52 : virial_xc, norm_drho, gradient_cut, dr1dr, v_drho)
1762 :
1763 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set
1764 : INTEGER, DIMENSION(:), INTENT(in) :: description
1765 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
1766 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
1767 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
1768 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: norm_drho
1769 : REAL(KIND=dp), INTENT(IN) :: gradient_cut
1770 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: dr1dr
1771 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT) :: v_drho
1772 :
1773 : CHARACTER(len=*), PARAMETER :: routineN = 'apply_drho'
1774 :
1775 : INTEGER :: handle
1776 52 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data
1777 : TYPE(xc_derivative_type), POINTER :: deriv_att
1778 :
1779 52 : CALL timeset(routineN, handle)
1780 :
1781 52 : deriv_att => xc_dset_get_derivative(deriv_set, description)
1782 52 : IF (ASSOCIATED(deriv_att)) THEN
1783 52 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
1784 52 : CALL virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
1785 :
1786 52 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,gradient_cut,norm_drho,v_drho,deriv_data)
1787 : v_drho(:, :, :) = v_drho(:, :, :) + &
1788 : deriv_data(:, :, :)*dr1dr(:, :, :)/MAX(gradient_cut, norm_drho(:, :, :))**2
1789 : !$OMP END PARALLEL WORKSHARE
1790 : END IF
1791 :
1792 52 : CALL timestop(handle)
1793 :
1794 52 : END SUBROUTINE apply_drho
1795 :
1796 : ! **************************************************************************************************
1797 : !> \brief adds potential contributions from derivatives of rho or diagonal terms of norm_drho
1798 : !> \param deriv_set1 ...
1799 : !> \param description ...
1800 : !> \param bo ...
1801 : !> \param norm_drho norm_drho of which derivative is calculated
1802 : !> \param gradient_cut ...
1803 : !> \param h ...
1804 : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
1805 : !> \param v_drho ...
1806 : ! **************************************************************************************************
1807 728 : SUBROUTINE update_deriv_rho(deriv_set1, description, bo, norm_drho, gradient_cut, weight, rho1, v_drho)
1808 :
1809 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1810 : INTEGER, DIMENSION(:), INTENT(in) :: description
1811 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1812 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1813 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: norm_drho
1814 : REAL(KIND=dp), INTENT(IN) :: gradient_cut, weight
1815 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1816 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: rho1
1817 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1818 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v_drho
1819 :
1820 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_rho'
1821 :
1822 : INTEGER :: handle, i, j, k
1823 : REAL(KIND=dp) :: de
1824 728 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1825 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1826 :
1827 728 : CALL timeset(routineN, handle)
1828 :
1829 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1830 728 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1831 728 : IF (ASSOCIATED(deriv_att1)) THEN
1832 728 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1833 : !$OMP PARALLEL DO DEFAULT(NONE) &
1834 : !$OMP SHARED(bo,deriv_data1,weight,norm_drho,v_drho,rho1,gradient_cut) &
1835 : !$OMP PRIVATE(i,j,k,de) &
1836 728 : !$OMP COLLAPSE(3)
1837 : DO k = bo(1, 3), bo(2, 3)
1838 : DO j = bo(1, 2), bo(2, 2)
1839 : DO i = bo(1, 1), bo(2, 1)
1840 : de = weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drho(i, j, k))**2
1841 : v_drho(i, j, k) = v_drho(i, j, k) - de*rho1(i, j, k)
1842 : END DO
1843 : END DO
1844 : END DO
1845 : !$OMP END PARALLEL DO
1846 : END IF
1847 :
1848 728 : CALL timestop(handle)
1849 :
1850 728 : END SUBROUTINE update_deriv_rho
1851 :
1852 : ! **************************************************************************************************
1853 : !> \brief adds potential contributions from derivatives of a component with positive and negative values
1854 : !> \param deriv_set1 ...
1855 : !> \param description ...
1856 : !> \param bo ...
1857 : !> \param h ...
1858 : !> \param rho1 function to contract the derivative with (rho1 for rho, dr1dr for norm_drho)
1859 : !> \param v ...
1860 : ! **************************************************************************************************
1861 120 : SUBROUTINE update_deriv(deriv_set1, rho, rho_cutoff, description, bo, weight, rho1, v)
1862 :
1863 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1864 : INTEGER, DIMENSION(:), INTENT(in) :: description
1865 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1866 : REAL(KIND=dp), INTENT(IN) :: weight, rho_cutoff
1867 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1868 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: rho, rho1
1869 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1870 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v
1871 :
1872 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv'
1873 :
1874 : INTEGER :: handle, i, j, k
1875 : REAL(KIND=dp) :: de
1876 120 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1877 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1878 :
1879 120 : CALL timeset(routineN, handle)
1880 :
1881 : ! Obtain the numerical 2nd derivatives w.r.t. to drho and collect the potential
1882 120 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1883 120 : IF (ASSOCIATED(deriv_att1)) THEN
1884 120 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1885 : !$OMP PARALLEL DO DEFAULT(NONE) &
1886 : !$OMP SHARED(bo,deriv_data1,weight,v,rho1,rho, rho_cutoff) &
1887 : !$OMP PRIVATE(i,j,k,de) &
1888 120 : !$OMP COLLAPSE(3)
1889 : DO k = bo(1, 3), bo(2, 3)
1890 : DO j = bo(1, 2), bo(2, 2)
1891 : DO i = bo(1, 1), bo(2, 1)
1892 : ! We have to consider that the given density (mostly the Laplacian) may have positive and negative values
1893 : de = weight*deriv_data1(i, j, k)/SIGN(MAX(ABS(rho(i, j, k)), rho_cutoff), rho(i, j, k))
1894 : v(i, j, k) = v(i, j, k) + de*rho1(i, j, k)
1895 : END DO
1896 : END DO
1897 : END DO
1898 : !$OMP END PARALLEL DO
1899 : END IF
1900 :
1901 120 : CALL timestop(handle)
1902 :
1903 120 : END SUBROUTINE update_deriv
1904 :
1905 : ! **************************************************************************************************
1906 : !> \brief adds mixed derivatives of norm_drho
1907 : !> \param deriv_set1 ...
1908 : !> \param description ...
1909 : !> \param bo ...
1910 : !> \param norm_drhoa norm_drho of which derivatives is calculated
1911 : !> \param gradient_cut ...
1912 : !> \param h ...
1913 : !> \param dra1dra dr1dr corresponding to norm_drho
1914 : !> \param drb1drb ...
1915 : !> \param v_drhoa potential corresponding to norm_drho
1916 : !> \param v_drhob ...
1917 : ! **************************************************************************************************
1918 216 : SUBROUTINE update_deriv_drho_ab(deriv_set1, description, bo, &
1919 216 : norm_drhoa, gradient_cut, weight, dra1dra, drb1drb, v_drhoa, v_drhob)
1920 :
1921 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set1
1922 : INTEGER, DIMENSION(:), INTENT(in) :: description
1923 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
1924 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1925 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: norm_drhoa
1926 : REAL(KIND=dp), INTENT(IN) :: gradient_cut, weight
1927 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1928 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(IN) :: dra1dra, drb1drb
1929 : REAL(KIND=dp), DIMENSION(bo(1, 1):bo(2, 1), bo(1, &
1930 : 2):bo(2, 2), bo(1, 3):bo(2, 3)), INTENT(INOUT) :: v_drhoa, v_drhob
1931 :
1932 : CHARACTER(len=*), PARAMETER :: routineN = 'update_deriv_drho_ab'
1933 :
1934 : INTEGER :: handle, i, j, k
1935 : REAL(KIND=dp) :: de
1936 216 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: deriv_data1
1937 : TYPE(xc_derivative_type), POINTER :: deriv_att1
1938 :
1939 216 : CALL timeset(routineN, handle)
1940 :
1941 216 : deriv_att1 => xc_dset_get_derivative(deriv_set1, description)
1942 216 : IF (ASSOCIATED(deriv_att1)) THEN
1943 168 : CALL xc_derivative_get(deriv_att1, deriv_data=deriv_data1)
1944 : !$OMP PARALLEL DO DEFAULT(NONE) &
1945 : !$OMP PRIVATE(k,j,i,de) &
1946 : !$OMP SHARED(bo,drb1drb,dra1dra,deriv_data1,weight,gradient_cut,norm_drhoa,v_drhoa,v_drhob) &
1947 168 : !$OMP COLLAPSE(3)
1948 : DO k = bo(1, 3), bo(2, 3)
1949 : DO j = bo(1, 2), bo(2, 2)
1950 : DO i = bo(1, 1), bo(2, 1)
1951 : ! We introduce a factor of two because we will average between both numerical derivatives
1952 : de = 0.5_dp*weight*deriv_data1(i, j, k)/MAX(gradient_cut, norm_drhoa(i, j, k))**2
1953 : v_drhoa(i, j, k) = v_drhoa(i, j, k) - de*drb1drb(i, j, k)
1954 : v_drhob(i, j, k) = v_drhob(i, j, k) - de*dra1dra(i, j, k)
1955 : END DO
1956 : END DO
1957 : END DO
1958 : !$OMP END PARALLEL DO
1959 : END IF
1960 :
1961 216 : CALL timestop(handle)
1962 :
1963 216 : END SUBROUTINE update_deriv_drho_ab
1964 :
1965 : ! **************************************************************************************************
1966 : !> \brief calculate derivative sets for helper points
1967 : !> \param norm_drho2 norm_drho of new points
1968 : !> \param norm_drho norm_drho of KS density
1969 : !> \param h ...
1970 : !> \param xc_fun_section ...
1971 : !> \param lsd ...
1972 : !> \param rho2_set rho_set for new points
1973 : !> \param deriv_set1 will contain derivatives of the perturbed density
1974 : ! **************************************************************************************************
1975 276 : SUBROUTINE get_derivs_rho(norm_drho2, norm_drho, step, xc_fun_section, lsd, rho2_set, deriv_set1)
1976 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT) :: norm_drho2
1977 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: norm_drho
1978 : REAL(KIND=dp), INTENT(IN) :: step
1979 : TYPE(section_vals_type), INTENT(IN), POINTER :: xc_fun_section
1980 : LOGICAL, INTENT(IN) :: lsd
1981 : TYPE(xc_rho_set_type), INTENT(INOUT) :: rho2_set
1982 : TYPE(xc_derivative_set_type) :: deriv_set1
1983 :
1984 : CHARACTER(len=*), PARAMETER :: routineN = 'get_derivs_rho'
1985 :
1986 : INTEGER :: handle
1987 :
1988 276 : CALL timeset(routineN, handle)
1989 :
1990 : ! Copy the densities, do one step into the direction of drho
1991 276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2,step)
1992 : norm_drho2 = norm_drho*(1.0_dp + step)
1993 : !$OMP END PARALLEL WORKSHARE
1994 :
1995 276 : CALL xc_dset_zero_all(deriv_set1)
1996 :
1997 : ! Calculate the derivatives of the functional
1998 : CALL xc_functionals_eval(xc_fun_section, &
1999 : lsd=lsd, &
2000 : rho_set=rho2_set, &
2001 : deriv_set=deriv_set1, &
2002 276 : deriv_order=1)
2003 :
2004 : ! Return to the original values
2005 276 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(norm_drho,norm_drho2)
2006 : norm_drho2 = norm_drho
2007 : !$OMP END PARALLEL WORKSHARE
2008 :
2009 276 : CALL divide_by_norm_drho(deriv_set1, rho2_set, lsd)
2010 :
2011 276 : CALL timestop(handle)
2012 :
2013 276 : END SUBROUTINE get_derivs_rho
2014 :
2015 : ! **************************************************************************************************
2016 : !> \brief Calculates the second derivative of E_xc at rho in the direction
2017 : !> rho1 (if you see the second derivative as bilinear form)
2018 : !> partial_rho|_(rho=rho) partial_rho|_(rho=rho) E_xc drho(rho1)drho
2019 : !> The other direction is still undetermined, thus it returns
2020 : !> a potential (partial integration is performed to reduce it to
2021 : !> function of rho, removing the dependence from its partial derivs)
2022 : !> Has to be called after the setup by xc_prep_2nd_deriv.
2023 : !> \param v_xc exchange-correlation potential
2024 : !> \param v_xc_tau ...
2025 : !> \param deriv_set derivatives of the exchange-correlation potential
2026 : !> \param rho_set object containing the density at which the derivatives were calculated
2027 : !> \param rho1_set object containing the density with which to fold
2028 : !> \param pw_pool the pool for the grids
2029 : !> \param xc_section XC parameters
2030 : !> \param gapw Gaussian and augmented plane waves calculation
2031 : !> \param vxg ...
2032 : !> \param tddfpt_fac factor that multiplies the crossterms (tddfpt triplets
2033 : !> on a closed shell system it should be -1, defaults to 1)
2034 : !> \param compute_virial ...
2035 : !> \param virial_xc ...
2036 : !> \note
2037 : !> The old version of this routine was smarter: it handled split_desc(1)
2038 : !> and split_desc(2) separately, thus the code automatically handled all
2039 : !> possible cross terms (you only had to check if it was diagonal to avoid
2040 : !> double counting). I think that is the way to go if you want to add more
2041 : !> terms (tau,rho in LSD,...). The problem with the old code was that it
2042 : !> because of the old functional structure it sometime guessed wrongly
2043 : !> which derivative was where. There were probably still bugs with gradient
2044 : !> corrected functionals (never tested), and it didn't contain first
2045 : !> derivatives with respect to drho (that contribute also to the second
2046 : !> derivative wrt. rho).
2047 : !> The code was a little complex because it really tried to handle any
2048 : !> functional derivative in the most efficient way with the given contents of
2049 : !> rho_set.
2050 : !> Anyway I strongly encourage whoever wants to modify this code to give a
2051 : !> look to the old version. [fawzi]
2052 : ! **************************************************************************************************
2053 44640 : SUBROUTINE xc_calc_2nd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
2054 : pw_pool, xc_section, gapw, vxg, tddfpt_fac, &
2055 : compute_virial, virial_xc, spinflip)
2056 :
2057 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_xc, v_xc_tau
2058 : TYPE(xc_derivative_set_type) :: deriv_set
2059 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set, rho1_set
2060 : TYPE(pw_pool_type), POINTER :: pw_pool
2061 : TYPE(section_vals_type), POINTER :: xc_section
2062 : LOGICAL, INTENT(IN), OPTIONAL :: gapw
2063 : REAL(kind=dp), DIMENSION(:, :, :, :), OPTIONAL, &
2064 : POINTER :: vxg
2065 : REAL(kind=dp), INTENT(in), OPTIONAL :: tddfpt_fac
2066 : LOGICAL, INTENT(IN), OPTIONAL :: compute_virial
2067 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT), &
2068 : OPTIONAL :: virial_xc
2069 : LOGICAL, INTENT(in), OPTIONAL :: spinflip
2070 :
2071 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_2nd_deriv_analytical'
2072 :
2073 : INTEGER :: handle, i, ia, idir, ir, ispin, j, jdir, &
2074 : k, nspins, xc_deriv_method_id
2075 : INTEGER, DIMENSION(2, 3) :: bo
2076 : LOGICAL :: gradient_f, lsd, my_compute_virial, alda0, &
2077 : my_gapw, tau_f, laplace_f, rho_f, do_spinflip
2078 : REAL(KIND=dp) :: fac, gradient_cut, tmp, factor2, s, S_THRESH
2079 44640 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
2080 44640 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, deriv_data2, &
2081 44640 : e_drhoa, e_drhob, e_drho, norm_drho, norm_drhoa, &
2082 44640 : norm_drhob, rho1, rho1a, rho1b, &
2083 44640 : tau1, tau1a, tau1b, laplace1, laplace1a, laplace1b, &
2084 44640 : rho, rhoa, rhob
2085 848160 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
2086 44640 : TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE :: v_drhoa, v_drhob, v_drho, v_laplace
2087 44640 : TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE :: v_drho_r
2088 : TYPE(pw_r3d_rs_type) :: virial_pw
2089 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
2090 : TYPE(xc_derivative_type), POINTER :: deriv_att
2091 :
2092 44640 : CALL timeset(routineN, handle)
2093 :
2094 44640 : NULLIFY (e_drhoa, e_drhob, e_drho)
2095 :
2096 44640 : my_gapw = .FALSE.
2097 44640 : IF (PRESENT(gapw)) my_gapw = gapw
2098 :
2099 44640 : my_compute_virial = .FALSE.
2100 44640 : IF (PRESENT(compute_virial)) my_compute_virial = compute_virial
2101 :
2102 44640 : CPASSERT(ASSOCIATED(v_xc))
2103 44640 : CPASSERT(ASSOCIATED(xc_section))
2104 44640 : IF (my_gapw) THEN
2105 19724 : CPASSERT(PRESENT(vxg))
2106 : END IF
2107 44640 : IF (my_compute_virial) THEN
2108 366 : CPASSERT(PRESENT(virial_xc))
2109 : END IF
2110 :
2111 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
2112 44640 : i_val=xc_deriv_method_id)
2113 44640 : CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
2114 44640 : nspins = SIZE(v_xc)
2115 44640 : lsd = ASSOCIATED(rho_set%rhoa)
2116 44640 : fac = 0.0_dp
2117 44640 : factor2 = 1.0_dp
2118 44640 : IF (PRESENT(tddfpt_fac)) fac = tddfpt_fac
2119 44640 : IF (PRESENT(tddfpt_fac)) factor2 = tddfpt_fac
2120 44640 : do_spinflip = .FALSE.
2121 44640 : IF (PRESENT(spinflip)) do_spinflip = spinflip
2122 :
2123 446400 : bo = rho_set%local_bounds
2124 :
2125 44640 : CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
2126 :
2127 44640 : alda0 = .false.
2128 44640 : IF (gradient_f) THEN
2129 : S_THRESH = 1.0E-04
2130 : ELSE
2131 15756 : S_THRESH = 1.0E-10
2132 : END IF
2133 :
2134 44640 : IF (tau_f) THEN
2135 646 : CPASSERT(ASSOCIATED(v_xc_tau))
2136 : END IF
2137 :
2138 44640 : IF (gradient_f) THEN
2139 300370 : ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
2140 60074 : DO ispin = 1, nspins
2141 124760 : DO idir = 1, 3
2142 124760 : CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
2143 : END DO
2144 60074 : CALL allocate_pw(v_drho(ispin), pw_pool, bo)
2145 : END DO
2146 :
2147 28884 : IF (xc_requires_tmp_g(xc_deriv_method_id) .AND. .NOT. my_gapw) THEN
2148 14266 : IF (ASSOCIATED(pw_pool)) THEN
2149 14266 : CALL pw_pool%create_pw(tmp_g)
2150 14266 : CALL pw_pool%create_pw(vxc_g)
2151 : ELSE
2152 : ! remember to refix for gapw
2153 0 : CPABORT("XC_DERIV method is not implemented in GAPW")
2154 : END IF
2155 : END IF
2156 : END IF
2157 :
2158 93664 : DO ispin = 1, nspins
2159 1195054189 : v_xc(ispin)%array = 0.0_dp
2160 : END DO
2161 :
2162 44640 : IF (tau_f) THEN
2163 1366 : DO ispin = 1, nspins
2164 14651138 : v_xc_tau(ispin)%array = 0.0_dp
2165 : END DO
2166 : END IF
2167 :
2168 44640 : IF (laplace_f .AND. my_gapw) &
2169 0 : CPABORT("Laplace-dependent functional not implemented with GAPW!")
2170 :
2171 44640 : IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) CALL allocate_pw(virial_pw, pw_pool, bo)
2172 :
2173 44640 : IF (lsd) THEN
2174 :
2175 : !-------------------!
2176 : ! UNrestricted case !
2177 : !-------------------!
2178 :
2179 6134 : IF (do_spinflip) THEN
2180 414 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
2181 414 : CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2182 : ELSE
2183 5720 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
2184 : END IF
2185 :
2186 6134 : IF (gradient_f) THEN
2187 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
2188 3508 : norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
2189 3508 : IF (do_spinflip) THEN
2190 262 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
2191 262 : CALL calc_drho_from_a(drho1, drho1a)
2192 : ELSE
2193 3246 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
2194 3246 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
2195 : END IF
2196 :
2197 3508 : CALL calc_drho_from_ab(drho, drhoa, drhob)
2198 :
2199 3508 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
2200 3508 : IF (do_spinflip) THEN
2201 262 : CALL prepare_dr1dr(drb1drb, drhob, drho1a)
2202 262 : CALL prepare_dr1dr(dr1dr, drho, drho1a)
2203 3246 : ELSE IF (nspins /= 1) THEN
2204 2096 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2205 2096 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2206 : ELSE
2207 1150 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2208 1150 : CALL prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
2209 : END IF
2210 :
2211 25660 : ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
2212 9322 : DO ispin = 1, nspins
2213 5814 : CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
2214 9322 : CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
2215 : END DO
2216 :
2217 : END IF
2218 :
2219 6134 : IF (laplace_f) THEN
2220 38 : CALL xc_rho_set_get(rho1_set, laplace_rhoa=laplace1a, laplace_rhob=laplace1b)
2221 :
2222 190 : ALLOCATE (v_laplace(nspins))
2223 114 : DO ispin = 1, nspins
2224 114 : CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
2225 : END DO
2226 :
2227 38 : IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2228 : END IF
2229 :
2230 6134 : IF (tau_f) THEN
2231 74 : CALL xc_rho_set_get(rho1_set, tau_a=tau1a, tau_b=tau1b)
2232 : END IF
2233 :
2234 6134 : IF (do_spinflip) THEN
2235 :
2236 : ! vxc contributions
2237 : ! vxc = (vxc^{\alpha}-vxc^{\beta})*rho1/(rhoa-rhob)
2238 : ! Alpha LDA contribution
2239 : ! | d e_xc d e_xc | rho1a
2240 : ! vxca = |-------- - --------|*-------------
2241 : ! | drhoa drhob | |rhoa - rhob|
2242 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
2243 414 : IF (ASSOCIATED(deriv_att)) THEN
2244 414 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2245 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
2246 414 : IF (ASSOCIATED(deriv_att)) THEN
2247 414 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2248 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2249 414 : !$OMP SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH) COLLAPSE(3)
2250 : DO k = bo(1, 3), bo(2, 3)
2251 : DO j = bo(1, 2), bo(2, 2)
2252 : DO i = bo(1, 1), bo(2, 1)
2253 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2254 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2255 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)/s
2256 : END DO
2257 : END DO
2258 : END DO
2259 : !$OMP END PARALLEL DO
2260 : END IF
2261 : END IF
2262 : ! GGA contributions to the spin-flip xcKernel
2263 : ! GGA contribution
2264 : ! | d e_xc d e_xc | 1
2265 : ! vxca += |----------* dra1dra - ----------*drb1drb|*-------------
2266 : ! | d|drhoa| d|drhob| | |rhoa - rhob|
2267 : IF (.NOT. alda0) THEN
2268 414 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
2269 414 : IF (ASSOCIATED(deriv_att)) THEN
2270 262 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2271 262 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
2272 262 : IF (ASSOCIATED(deriv_att)) THEN
2273 262 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2274 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2275 262 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2276 : DO k = bo(1, 3), bo(2, 3)
2277 : DO j = bo(1, 2), bo(2, 2)
2278 : DO i = bo(1, 1), bo(2, 1)
2279 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2280 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2281 : (deriv_data(i, j, k)*dra1dra(i, j, k) - &
2282 : deriv_data2(i, j, k)*drb1drb(i, j, k))/s
2283 : END DO
2284 : END DO
2285 : END DO
2286 : !$OMP END PARALLEL DO
2287 : END IF
2288 : END IF
2289 : END IF
2290 :
2291 5720 : ELSE IF (nspins /= 1) THEN
2292 :
2293 : ! Compute \sum_{\tau}fxc^{\sigma\tau}*\rho^{\tau}(1) over the grid points
2294 34122 : $:add_2nd_derivative_terms(arguments_openshell)
2295 :
2296 : ELSE
2297 :
2298 : ! Compute (fxc^{\alpha\alpha}+-fxc^{\beta\beta})*\rho(1) over the grid points
2299 1646 : $:add_2nd_derivative_terms(arguments_triplet_outer, arguments_triplet_inner)
2300 :
2301 : END IF
2302 :
2303 6134 : IF (gradient_f) THEN
2304 3508 : IF (.NOT. do_spinflip) THEN
2305 :
2306 3246 : IF (my_compute_virial) THEN
2307 10 : CALL virial_drho_drho(virial_pw, drhoa, v_drhoa(1), virial_xc)
2308 10 : CALL virial_drho_drho(virial_pw, drhob, v_drhob(2), virial_xc)
2309 40 : DO idir = 1, 3
2310 30 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
2311 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*(v_drho(1)%array(:, :, :) + v_drho(2)%array(:, :, :))
2312 : !$OMP END PARALLEL WORKSHARE
2313 100 : DO jdir = 1, idir
2314 : tmp = -0.5_dp*virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
2315 60 : drho(jdir)%array(:, :, :))
2316 60 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
2317 90 : virial_xc(idir, jdir) = virial_xc(jdir, idir)
2318 : END DO
2319 : END DO
2320 : END IF ! my_compute_virial
2321 :
2322 3246 : IF (my_gapw) THEN
2323 : !$OMP PARALLEL DO DEFAULT(NONE) &
2324 : !$OMP PRIVATE(ia,idir,ispin,ir) &
2325 : !$OMP SHARED(bo,nspins,vxg,drhoa,drhob,v_drhoa,v_drhob,v_drho, &
2326 1106 : !$OMP e_drhoa,e_drhob,e_drho,drho1a,drho1b,fac,drho,drho1) COLLAPSE(3)
2327 : DO ir = bo(1, 2), bo(2, 2)
2328 : DO ia = bo(1, 1), bo(2, 1)
2329 : DO idir = 1, 3
2330 : DO ispin = 1, nspins
2331 : vxg(idir, ia, ir, ispin) = &
2332 : -(v_drhoa(ispin)%array(ia, ir, 1)*drhoa(idir)%array(ia, ir, 1) + &
2333 : v_drhob(ispin)%array(ia, ir, 1)*drhob(idir)%array(ia, ir, 1) + &
2334 : v_drho(ispin)%array(ia, ir, 1)*drho(idir)%array(ia, ir, 1))
2335 : END DO
2336 : IF (ASSOCIATED(e_drhoa)) THEN
2337 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2338 : e_drhoa(ia, ir, 1)*drho1a(idir)%array(ia, ir, 1)
2339 : END IF
2340 : IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
2341 : vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
2342 : e_drhob(ia, ir, 1)*drho1b(idir)%array(ia, ir, 1)
2343 : END IF
2344 : IF (ASSOCIATED(e_drho)) THEN
2345 : IF (nspins /= 1) THEN
2346 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2347 : e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
2348 : vxg(idir, ia, ir, 2) = vxg(idir, ia, ir, 2) + &
2349 : e_drho(ia, ir, 1)*drho1(idir)%array(ia, ir, 1)
2350 : ELSE
2351 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + &
2352 : e_drho(ia, ir, 1)*(drho1a(idir)%array(ia, ir, 1) + &
2353 : fac*drho1b(idir)%array(ia, ir, 1))
2354 : END IF
2355 : END IF
2356 : END DO
2357 : END DO
2358 : END DO
2359 : !$OMP END PARALLEL DO
2360 : ELSE
2361 :
2362 : ! partial integration
2363 8560 : DO idir = 1, 3
2364 :
2365 18024 : DO ispin = 1, nspins
2366 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
2367 18024 : !$OMP SHARED(v_drho_r,v_drhoa,v_drhob,v_drho,drhoa,drhob,drho,ispin,idir)
2368 : v_drho_r(idir, ispin)%array(:, :, :) = &
2369 : v_drhoa(ispin)%array(:, :, :)*drhoa(idir)%array(:, :, :) + &
2370 : v_drhob(ispin)%array(:, :, :)*drhob(idir)%array(:, :, :) + &
2371 : v_drho(ispin)%array(:, :, :)*drho(idir)%array(:, :, :)
2372 : !$OMP END PARALLEL WORKSHARE
2373 : END DO
2374 6420 : IF (ASSOCIATED(e_drhoa)) THEN
2375 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
2376 6420 : !$OMP SHARED(v_drho_r,e_drhoa,drho1a,idir)
2377 : v_drho_r(idir, 1)%array(:, :, :) = v_drho_r(idir, 1)%array(:, :, :) - &
2378 : e_drhoa(:, :, :)*drho1a(idir)%array(:, :, :)
2379 : !$OMP END PARALLEL WORKSHARE
2380 : END IF
2381 6420 : IF (nspins /= 1 .AND. ASSOCIATED(e_drhob)) THEN
2382 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE)&
2383 5184 : !$OMP SHARED(v_drho_r,e_drhob,drho1b,idir)
2384 : v_drho_r(idir, 2)%array(:, :, :) = v_drho_r(idir, 2)%array(:, :, :) - &
2385 : e_drhob(:, :, :)*drho1b(idir)%array(:, :, :)
2386 : !$OMP END PARALLEL WORKSHARE
2387 : END IF
2388 8560 : IF (ASSOCIATED(e_drho)) THEN
2389 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2390 6420 : !$OMP SHARED(bo,v_drho_r,e_drho,drho1a,drho1b,drho1,fac,idir,nspins) COLLAPSE(3)
2391 : DO k = bo(1, 3), bo(2, 3)
2392 : DO j = bo(1, 2), bo(2, 2)
2393 : DO i = bo(1, 1), bo(2, 1)
2394 : IF (nspins /= 1) THEN
2395 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
2396 : e_drho(i, j, k)*drho1(idir)%array(i, j, k)
2397 : v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) - &
2398 : e_drho(i, j, k)*drho1(idir)%array(i, j, k)
2399 : ELSE
2400 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
2401 : e_drho(i, j, k)*(drho1a(idir)%array(i, j, k) + &
2402 : fac*drho1b(idir)%array(i, j, k))
2403 : END IF
2404 : END DO
2405 : END DO
2406 : END DO
2407 : !$OMP END PARALLEL DO
2408 : END IF
2409 : END DO
2410 :
2411 : ! partial integration
2412 6008 : DO ispin = 1, nspins
2413 6008 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
2414 : END DO ! ispin
2415 :
2416 : END IF
2417 :
2418 : END IF ! .NOT.do_spinflip
2419 :
2420 14032 : DO idir = 1, 3
2421 10524 : DEALLOCATE (drho(idir)%array)
2422 14032 : DEALLOCATE (drho1(idir)%array)
2423 : END DO
2424 :
2425 9322 : DO ispin = 1, nspins
2426 5814 : CALL deallocate_pw(v_drhoa(ispin), pw_pool)
2427 9322 : CALL deallocate_pw(v_drhob(ispin), pw_pool)
2428 : END DO
2429 :
2430 3508 : DEALLOCATE (v_drhoa, v_drhob)
2431 :
2432 : END IF ! gradient_f
2433 :
2434 6134 : IF (laplace_f .AND. my_compute_virial) THEN
2435 15026 : virial_pw%array(:, :, :) = -rhoa(:, :, :)
2436 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
2437 15026 : virial_pw%array(:, :, :) = -rhob(:, :, :)
2438 2 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(2)%array)
2439 : END IF
2440 :
2441 : ELSE
2442 :
2443 : !-----------------!
2444 : ! restricted case !
2445 : !-----------------!
2446 :
2447 38506 : CALL xc_rho_set_get(rho1_set, rho=rho1)
2448 :
2449 38506 : IF (gradient_f) THEN
2450 25376 : CALL xc_rho_set_get(rho_set, drho=drho, norm_drho=norm_drho)
2451 25376 : CALL xc_rho_set_get(rho1_set, drho=drho1)
2452 25376 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2453 : END IF
2454 :
2455 38506 : IF (laplace_f) THEN
2456 136 : CALL xc_rho_set_get(rho1_set, laplace_rho=laplace1)
2457 :
2458 544 : ALLOCATE (v_laplace(nspins))
2459 272 : DO ispin = 1, nspins
2460 272 : CALL allocate_pw(v_laplace(ispin), pw_pool, bo)
2461 : END DO
2462 :
2463 136 : IF (my_compute_virial) CALL xc_rho_set_get(rho_set, rho=rho)
2464 : END IF
2465 :
2466 38506 : IF (tau_f) THEN
2467 572 : CALL xc_rho_set_get(rho1_set, tau=tau1)
2468 : END IF
2469 :
2470 333022 : $:add_2nd_derivative_terms(arguments_closedshell)
2471 :
2472 38506 : IF (gradient_f) THEN
2473 :
2474 25376 : IF (my_compute_virial) THEN
2475 222 : CALL virial_drho_drho(virial_pw, drho, v_drho(1), virial_xc)
2476 : END IF ! my_compute_virial
2477 :
2478 25376 : IF (my_gapw) THEN
2479 :
2480 51984 : DO idir = 1, 3
2481 : !$OMP PARALLEL DO DEFAULT(NONE) &
2482 : !$OMP PRIVATE(ia,ir) &
2483 : !$OMP SHARED(bo,vxg,drho,v_drho,e_drho,drho1,idir,factor2) &
2484 51984 : !$OMP COLLAPSE(2)
2485 : DO ia = bo(1, 1), bo(2, 1)
2486 : DO ir = bo(1, 2), bo(2, 2)
2487 : vxg(idir, ia, ir, 1) = -drho(idir)%array(ia, ir, 1)*v_drho(1)%array(ia, ir, 1)
2488 : IF (ASSOCIATED(e_drho)) THEN
2489 : vxg(idir, ia, ir, 1) = vxg(idir, ia, ir, 1) + factor2*drho1(idir)%array(ia, ir, 1)*e_drho(ia, ir, 1)
2490 : END IF
2491 : END DO
2492 : END DO
2493 : !$OMP END PARALLEL DO
2494 : END DO
2495 :
2496 : ELSE
2497 : ! partial integration
2498 49520 : DO idir = 1, 3
2499 49520 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(v_drho_r,drho,v_drho,drho1,e_drho,idir)
2500 : v_drho_r(idir, 1)%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho(1)%array(:, :, :) - &
2501 : drho1(idir)%array(:, :, :)*e_drho(:, :, :)
2502 : !$OMP END PARALLEL WORKSHARE
2503 : END DO
2504 :
2505 12380 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, 1), tmp_g, vxc_g, v_xc(1))
2506 : END IF
2507 :
2508 : END IF
2509 :
2510 38506 : IF (laplace_f .AND. my_compute_virial) THEN
2511 294530 : virial_pw%array(:, :, :) = -rho(:, :, :)
2512 14 : CALL virial_laplace(virial_pw, pw_pool, virial_xc, v_laplace(1)%array)
2513 : END IF
2514 :
2515 : END IF
2516 :
2517 44640 : IF (laplace_f) THEN
2518 386 : DO ispin = 1, nspins
2519 212 : CALL xc_pw_laplace(v_laplace(ispin), pw_pool, xc_deriv_method_id)
2520 386 : CALL pw_axpy(v_laplace(ispin), v_xc(ispin))
2521 : END DO
2522 : END IF
2523 :
2524 44640 : IF (gradient_f) THEN
2525 :
2526 60074 : DO ispin = 1, nspins
2527 31190 : CALL deallocate_pw(v_drho(ispin), pw_pool)
2528 153644 : DO idir = 1, 3
2529 124760 : CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
2530 : END DO
2531 : END DO
2532 28884 : DEALLOCATE (v_drho, v_drho_r)
2533 :
2534 : END IF
2535 :
2536 44640 : IF (laplace_f) THEN
2537 386 : DO ispin = 1, nspins
2538 386 : CALL deallocate_pw(v_laplace(ispin), pw_pool)
2539 : END DO
2540 174 : DEALLOCATE (v_laplace)
2541 : END IF
2542 :
2543 44640 : IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
2544 14266 : CALL pw_pool%give_back_pw(tmp_g)
2545 : END IF
2546 :
2547 44640 : IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
2548 14266 : CALL pw_pool%give_back_pw(vxc_g)
2549 : END IF
2550 :
2551 44640 : IF (my_compute_virial .AND. (gradient_f .OR. laplace_f)) THEN
2552 232 : CALL deallocate_pw(virial_pw, pw_pool)
2553 : END IF
2554 :
2555 44640 : CALL timestop(handle)
2556 :
2557 133920 : END SUBROUTINE xc_calc_2nd_deriv_analytical
2558 :
2559 : ! **************************************************************************************************
2560 : !> \brief Calculates the third functional derivative of the exchange-correlation functional, E_xc.
2561 : !> Any GGA functional can be written as:
2562 : !>
2563 : !> E_xc[\rho] = \int e_xc(\rho,\nabla\rho)dr
2564 : !>
2565 : !> This routine gives you back the contraction of the derivatives of e_xc with respect to the
2566 : !> alpha or beta density or with respect to the norm of their gradients contracted with rho1.
2567 : !> For example, the alpha component would be (d stands for total derivative):
2568 : !>
2569 : !> d^3 e_xc
2570 : !> v_xc(1) = \sum_{s,s'}^{a,b} ---------------------\rhos1\rho1s'
2571 : !> d\rhoa d\rhos d\rhos'
2572 : !>
2573 : !> \param v_xc Third derivative of the exchange-correlation functional
2574 : !> \param v_xc_tau ...
2575 : !> \param deriv_set derivatives of the exchange-correlation potential, e_xc
2576 : !> \param rho_set object containing the density at which the derivatives were calculated, \rho
2577 : !> \param rho1_set object containing the density with which to fold, \rho1s
2578 : !> \param pw_pool the pool for the grids
2579 : !> \param xc_section XC parameters
2580 : !> \par History
2581 : !> * 07.2024 Created [LHS]
2582 : ! **************************************************************************************************
2583 0 : SUBROUTINE xc_calc_3rd_deriv_analytical(v_xc, v_xc_tau, deriv_set, rho_set, rho1_set, &
2584 : pw_pool, xc_section, spinflip)
2585 :
2586 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_xc, v_xc_tau
2587 : TYPE(xc_derivative_set_type) :: deriv_set
2588 : TYPE(xc_rho_set_type), INTENT(IN) :: rho_set, rho1_set
2589 : TYPE(pw_pool_type), POINTER :: pw_pool
2590 : TYPE(section_vals_type), POINTER :: xc_section
2591 : LOGICAL, INTENT(in), OPTIONAL :: spinflip
2592 :
2593 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_calc_3rd_deriv_analytical'
2594 :
2595 : INTEGER :: handle, i, idir, ispin, j, &
2596 : k, nspins, xc_deriv_method_id
2597 : INTEGER, DIMENSION(2, 3) :: bo
2598 : LOGICAL :: lsd, do_spinflip, alda0, &
2599 : rho_f, gradient_f, tau_f, laplace_f
2600 : REAL(KIND=dp) :: s, S_THRESH, S_THRESH2, gradient_cut
2601 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dr1dr, dra1dra, drb1drb
2602 0 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: deriv_data, deriv_data2, e_drhoa, e_drhob, &
2603 0 : e_drho, norm_drho, norm_drhoa, &
2604 0 : norm_drhob, rho1a, rho1b, &
2605 0 : rhoa, rhob
2606 0 : TYPE(cp_3d_r_cp_type), DIMENSION(3) :: drho, drho1, drho1a, drho1b, drhoa, drhob
2607 0 : TYPE(pw_r3d_rs_type), DIMENSION(:), ALLOCATABLE :: v_drhoa, v_drhob, v_drho
2608 0 : TYPE(pw_r3d_rs_type), DIMENSION(:, :), ALLOCATABLE :: v_drho_r
2609 : TYPE(pw_c1d_gs_type) :: tmp_g, vxc_g
2610 : TYPE(xc_derivative_type), POINTER :: deriv_att
2611 :
2612 0 : CALL timeset(routineN, handle)
2613 :
2614 0 : NULLIFY (e_drhoa, e_drhob, e_drho)
2615 :
2616 0 : CPASSERT(ASSOCIATED(v_xc))
2617 0 : CPASSERT(ASSOCIATED(xc_section))
2618 :
2619 : ! Initialize parameters
2620 : CALL section_vals_val_get(xc_section, "XC_GRID%XC_DERIV", &
2621 0 : i_val=xc_deriv_method_id)
2622 : !
2623 0 : nspins = SIZE(v_xc)
2624 0 : lsd = ASSOCIATED(rho_set%rhoa)
2625 : !
2626 0 : do_spinflip = .FALSE.
2627 0 : IF (PRESENT(spinflip)) do_spinflip = spinflip
2628 : !
2629 0 : bo = rho_set%local_bounds
2630 : !
2631 0 : CALL check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
2632 : !
2633 0 : CALL xc_rho_set_get(rho_set, drho_cutoff=gradient_cut)
2634 : !
2635 : !S_THRESH has to be the same as S_THRESH in xc_calc_2nd_deriv_analytical
2636 0 : alda0 = .false.
2637 0 : S_THRESH = 1.0E-04
2638 0 : S_THRESH2 = 1.0E-07
2639 :
2640 : ! Initialize potential
2641 0 : DO ispin = 1, nspins
2642 : !CALL pw_zero(v_xc(ispin))
2643 0 : v_xc(ispin)%array = 0.0_dp
2644 : END DO
2645 :
2646 : ! Create GGA fields
2647 0 : IF (gradient_f) THEN
2648 0 : ALLOCATE (v_drho_r(3, nspins), v_drho(nspins))
2649 0 : DO ispin = 1, nspins
2650 0 : DO idir = 1, 3
2651 0 : CALL allocate_pw(v_drho_r(idir, ispin), pw_pool, bo)
2652 : END DO
2653 0 : CALL allocate_pw(v_drho(ispin), pw_pool, bo)
2654 : END DO
2655 :
2656 0 : IF (xc_requires_tmp_g(xc_deriv_method_id)) THEN
2657 0 : IF (ASSOCIATED(pw_pool)) THEN
2658 0 : CALL pw_pool%create_pw(tmp_g)
2659 0 : CALL pw_pool%create_pw(vxc_g)
2660 : ELSE
2661 : ! remember to refix for gapw
2662 0 : CPABORT("XC_DERIV method is not implemented in GAPW")
2663 : END IF
2664 : END IF
2665 :
2666 : END IF
2667 :
2668 : ! Initialize mGGA potential
2669 0 : IF (tau_f) THEN
2670 0 : CPASSERT(ASSOCIATED(v_xc_tau))
2671 0 : DO ispin = 1, nspins
2672 0 : v_xc_tau(ispin)%array = 0.0_dp
2673 : END DO
2674 : END IF
2675 :
2676 0 : IF (lsd) THEN
2677 :
2678 : !-------------------!
2679 : ! UNrestricted case !
2680 : !-------------------!
2681 :
2682 0 : IF (do_spinflip) THEN
2683 0 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a)
2684 0 : CALL xc_rho_set_get(rho_set, rhoa=rhoa, rhob=rhob)
2685 : ELSE
2686 0 : CALL xc_rho_set_get(rho1_set, rhoa=rho1a, rhob=rho1b)
2687 : END IF
2688 :
2689 0 : IF (gradient_f) THEN
2690 : CALL xc_rho_set_get(rho_set, drhoa=drhoa, drhob=drhob, &
2691 0 : norm_drho=norm_drho, norm_drhoa=norm_drhoa, norm_drhob=norm_drhob)
2692 0 : IF (do_spinflip) THEN
2693 0 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a)
2694 0 : CALL calc_drho_from_a(drho1, drho1a)
2695 : ELSE
2696 0 : CALL xc_rho_set_get(rho1_set, drhoa=drho1a, drhob=drho1b)
2697 0 : CALL calc_drho_from_ab(drho1, drho1a, drho1b)
2698 : END IF
2699 :
2700 0 : CALL calc_drho_from_ab(drho, drhoa, drhob)
2701 :
2702 0 : CALL prepare_dr1dr(dra1dra, drhoa, drho1a)
2703 0 : IF (do_spinflip) THEN
2704 0 : CALL prepare_dr1dr(drb1drb, drhob, drho1a)
2705 0 : CALL prepare_dr1dr(dr1dr, drho, drho1a)
2706 0 : ELSE IF (nspins /= 1) THEN
2707 0 : CALL prepare_dr1dr(drb1drb, drhob, drho1b)
2708 0 : CALL prepare_dr1dr(dr1dr, drho, drho1)
2709 : ELSE
2710 0 : CPABORT("Exchange-correlation's third derivative for closed-shell not yet implemented")
2711 : END IF
2712 :
2713 : ! Create vectors for partial integration term
2714 0 : ALLOCATE (v_drhoa(nspins), v_drhob(nspins))
2715 0 : DO ispin = 1, nspins
2716 0 : CALL allocate_pw(v_drhoa(ispin), pw_pool, bo)
2717 0 : CALL allocate_pw(v_drhob(ispin), pw_pool, bo)
2718 : END DO
2719 :
2720 : END IF
2721 :
2722 0 : IF (laplace_f) THEN
2723 0 : CPABORT("Exchange-correlation's laplace analytic third derivative not implemented")
2724 : END IF
2725 :
2726 0 : IF (tau_f) THEN
2727 0 : CPABORT("Exchange-correlation's mGGA analytic third derivative not implemented")
2728 : END IF
2729 :
2730 0 : IF (nspins /= 1) THEN
2731 :
2732 0 : IF (.NOT. do_spinflip) THEN
2733 : ! Analytic third derivative of the excchange-correlation functional
2734 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
2735 :
2736 : ELSE
2737 :
2738 : ! vxc contributions
2739 : ! vxca = (vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
2740 : ! vxcb =-(vxc^{\alpha}-vxc^{\beta})*rho1/|rhoa-rhob|^2
2741 : ! Alpha LDA contribution
2742 : ! | d e_xc d e_xc | rho1a
2743 : ! vxca = rho1a*|-------- - --------|*---------------
2744 : ! | drhoa drhob | |rhoa - rhob|^2
2745 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa])
2746 0 : IF (ASSOCIATED(deriv_att)) THEN
2747 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2748 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob])
2749 0 : IF (ASSOCIATED(deriv_att)) THEN
2750 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2751 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2752 0 : !$OMP SHARED(bo,v_xc,deriv_data,deriv_data2,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
2753 : DO k = bo(1, 3), bo(2, 3)
2754 : DO j = bo(1, 2), bo(2, 2)
2755 : DO i = bo(1, 1), bo(2, 1)
2756 : s = rhoa(i, j, k) - rhob(i, j, k)
2757 : s = -SIGN(MAX(s**2, S_THRESH2), s)
2758 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2759 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)**2/s
2760 : END DO
2761 : END DO
2762 : END DO
2763 : !$OMP END PARALLEL DO
2764 : END IF
2765 : END IF
2766 : ! GGA contributions to the spin-flip xcKernel
2767 : ! Alpha GGA contributions
2768 : ! | d e_xc d e_xc | rho1a
2769 : ! vxca += + |----------*dra1dra - ----------*drb1drb|*---------------
2770 : ! | d|drhoa| d|drhob| | |rhoa - rhob|^2
2771 : IF (.NOT. alda0) THEN
2772 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
2773 0 : IF (ASSOCIATED(deriv_att)) THEN
2774 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2775 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
2776 0 : IF (ASSOCIATED(deriv_att)) THEN
2777 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2778 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2779 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_xc,rho1a,rhoa,rhob,S_THRESH2) COLLAPSE(3)
2780 : DO k = bo(1, 3), bo(2, 3)
2781 : DO j = bo(1, 2), bo(2, 2)
2782 : DO i = bo(1, 1), bo(2, 1)
2783 : s = rhoa(i, j, k) - rhob(i, j, k)
2784 : s = -SIGN(MAX(s**2, S_THRESH2), s)
2785 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2786 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k)) &
2787 : *rho1a(i, j, k)/s
2788 : END DO
2789 : END DO
2790 : END DO
2791 : !$OMP END PARALLEL DO
2792 : END IF
2793 : END IF
2794 : END IF
2795 : ! Beta contribution = - alpha
2796 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2797 0 : !$OMP SHARED(bo,v_xc) COLLAPSE(3)
2798 : DO k = bo(1, 3), bo(2, 3)
2799 : DO j = bo(1, 2), bo(2, 2)
2800 : DO i = bo(1, 1), bo(2, 1)
2801 : v_xc(2)%array(i, j, k) = -v_xc(1)%array(i, j, k)
2802 : END DO
2803 : END DO
2804 : END DO
2805 : !$OMP END PARALLEL DO
2806 : ! fxc contributions
2807 : ! vxca = rho1*(fxc^{\alpha\alpha}-fxc^{\alpha\beta})*rho1/|rhoa-rhob|
2808 : ! vxcb = rho1*(fxc^{\beta\alpha}-fxc^{\beta\beta})*rho1/|rhoa-rhob|
2809 : ! Alpha LDA contribution
2810 : ! | d^2 e_xc d^2 e_xc | rho1a
2811 : ! vxca += rho1a*|------------- - -------------|*-------------
2812 : ! | drhoa drhoa drhoa drhob | |rhoa - rhob|
2813 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhob])
2814 0 : IF (ASSOCIATED(deriv_att)) THEN
2815 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2816 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_rhoa])
2817 0 : IF (ASSOCIATED(deriv_att)) THEN
2818 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2819 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2820 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2821 : DO k = bo(1, 3), bo(2, 3)
2822 : DO j = bo(1, 2), bo(2, 2)
2823 : DO i = bo(1, 1), bo(2, 1)
2824 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2825 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2826 : rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
2827 : END DO
2828 : END DO
2829 : END DO
2830 : !$OMP END PARALLEL DO
2831 : END IF
2832 : END IF
2833 : ! Beta LDA contribution
2834 : ! | d^2 e_xc d^2 e_xc | rho1a
2835 : ! vxcb += rho1a*|------------- - -------------|*-------------
2836 : ! | drhob drhoa drhob drhob | |rhoa - rhob|
2837 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhob])
2838 0 : IF (ASSOCIATED(deriv_att)) THEN
2839 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2840 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_rhoa])
2841 0 : IF (ASSOCIATED(deriv_att)) THEN
2842 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2843 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2844 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2845 : DO k = bo(1, 3), bo(2, 3)
2846 : DO j = bo(1, 2), bo(2, 2)
2847 : DO i = bo(1, 1), bo(2, 1)
2848 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2849 : v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
2850 : rho1a(i, j, k)**2*(deriv_data(i, j, k) - deriv_data2(i, j, k))/s
2851 : END DO
2852 : END DO
2853 : END DO
2854 : !$OMP END PARALLEL DO
2855 : END IF
2856 : END IF
2857 : ! Alpha GGA contribution
2858 : IF (.NOT. alda0) THEN
2859 : ! rho1a | d^2 e_xc d^2 e_xc |
2860 : ! vxca += + -------------*|----------------*dra1dra - ----------------*drb1drb|
2861 : ! |rhoa - rhob| | drhoa d|drhoa| drhoa d|drhob| |
2862 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhob])
2863 0 : IF (ASSOCIATED(deriv_att)) THEN
2864 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2865 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhoa, deriv_norm_drhoa])
2866 0 : IF (ASSOCIATED(deriv_att)) THEN
2867 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2868 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2869 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2870 : DO k = bo(1, 3), bo(2, 3)
2871 : DO j = bo(1, 2), bo(2, 2)
2872 : DO i = bo(1, 1), bo(2, 1)
2873 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2874 : v_xc(1)%array(i, j, k) = v_xc(1)%array(i, j, k) + &
2875 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
2876 : rho1a(i, j, k)/s
2877 : END DO
2878 : END DO
2879 : END DO
2880 : !$OMP END PARALLEL DO
2881 : END IF
2882 : END IF
2883 : ! Beta GGA contribution
2884 : ! rho1a | d^2 e_xc d^2 e_xc |
2885 : ! vxcb += + -------------*|----------------*dra1dra - ----------------*drb1drb|
2886 : ! |rhoa - rhob| | drhob d|drhoa| drhob d|drhob| |
2887 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhob])
2888 0 : IF (ASSOCIATED(deriv_att)) THEN
2889 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2890 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_rhob, deriv_norm_drhoa])
2891 0 : IF (ASSOCIATED(deriv_att)) THEN
2892 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2893 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
2894 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,rho1a,v_xc,rhoa,rhob,S_THRESH) COLLAPSE(3)
2895 : DO k = bo(1, 3), bo(2, 3)
2896 : DO j = bo(1, 2), bo(2, 2)
2897 : DO i = bo(1, 1), bo(2, 1)
2898 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
2899 : v_xc(2)%array(i, j, k) = v_xc(2)%array(i, j, k) + &
2900 : (deriv_data(i, j, k)*dra1dra(i, j, k) - deriv_data2(i, j, k)*drb1drb(i, j, k))* &
2901 : rho1a(i, j, k)/s
2902 : END DO
2903 : END DO
2904 : END DO
2905 : !$OMP END PARALLEL DO
2906 : END IF
2907 : END IF
2908 : !
2909 : !
2910 : ! Calculate the vector for the partial integration term of GGA functionals
2911 : ! First contribution alpha
2912 : ! | d^2 e_xc d^2 e_xc |
2913 : ! v_drhoa(1) += -|---------------- - ----------------|*rho1a
2914 : ! | d|drhoa| drhoa d|drhoa| drhob |
2915 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhob])
2916 0 : IF (ASSOCIATED(deriv_att)) THEN
2917 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2918 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_rhoa])
2919 0 : IF (ASSOCIATED(deriv_att)) THEN
2920 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2921 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2922 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhoa) COLLAPSE(3)
2923 : DO k = bo(1, 3), bo(2, 3)
2924 : DO j = bo(1, 2), bo(2, 2)
2925 : DO i = bo(1, 1), bo(2, 1)
2926 : v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
2927 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2928 : END DO
2929 : END DO
2930 : END DO
2931 : !$OMP END PARALLEL DO
2932 : END IF
2933 : END IF
2934 : ! First contribution beta
2935 : ! | d^2 e_xc d^2 e_xc |
2936 : ! v_drhob(2) += +|---------------- - ----------------|*rho1a
2937 : ! | d|drhob| drhob d|drhob| drhoa |
2938 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhoa])
2939 0 : IF (ASSOCIATED(deriv_att)) THEN
2940 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2941 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_rhob])
2942 0 : IF (ASSOCIATED(deriv_att)) THEN
2943 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2944 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2945 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drhob) COLLAPSE(3)
2946 : DO k = bo(1, 3), bo(2, 3)
2947 : DO j = bo(1, 2), bo(2, 2)
2948 : DO i = bo(1, 1), bo(2, 1)
2949 : v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) + &
2950 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2951 : END DO
2952 : END DO
2953 : END DO
2954 : !$OMP END PARALLEL DO
2955 : END IF
2956 : END IF
2957 : ! First contribution spinless
2958 : ! | d^2 e_xc d^2 e_xc |
2959 : ! v_drho(1) += -|--------------- - ---------------|*rho1a
2960 : ! | d|drho| drhoa d|drho| drhob |
2961 : !
2962 : ! | d^2 e_xc d^2 e_xc |
2963 : ! v_drho(2) += -|--------------- - ---------------|*rho1a
2964 : ! | d|drho| drhoa d|drho| drhob |
2965 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhoa])
2966 0 : IF (ASSOCIATED(deriv_att)) THEN
2967 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2968 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_rhob])
2969 0 : IF (ASSOCIATED(deriv_att)) THEN
2970 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2971 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2972 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,rho1a,v_drho) COLLAPSE(3)
2973 : DO k = bo(1, 3), bo(2, 3)
2974 : DO j = bo(1, 2), bo(2, 2)
2975 : DO i = bo(1, 1), bo(2, 1)
2976 : v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
2977 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2978 : v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
2979 : (deriv_data(i, j, k) - deriv_data2(i, j, k))*rho1a(i, j, k)
2980 : END DO
2981 : END DO
2982 : END DO
2983 : !$OMP END PARALLEL DO
2984 : END IF
2985 : END IF
2986 : ! Second contribution
2987 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhob])
2988 0 : IF (ASSOCIATED(deriv_att)) THEN
2989 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
2990 : ! d^2 e_xc d^2 e_xc
2991 : ! v_drhoa(1) += - -------------------*dra1dra + ------------------*drb1drb
2992 : ! d|drhoa| d|drhoa| d|drhoa| d|drhob|
2993 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa, deriv_norm_drhoa])
2994 0 : IF (ASSOCIATED(deriv_att)) THEN
2995 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
2996 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
2997 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhoa) COLLAPSE(3)
2998 : DO k = bo(1, 3), bo(2, 3)
2999 : DO j = bo(1, 2), bo(2, 2)
3000 : DO i = bo(1, 1), bo(2, 1)
3001 : v_drhoa(1)%array(i, j, k) = v_drhoa(1)%array(i, j, k) - &
3002 : deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
3003 : END DO
3004 : END DO
3005 : END DO
3006 : !$OMP END PARALLEL DO
3007 : END IF
3008 : ! d^2 e_xc d^2 e_xc
3009 : ! v_drhob(2) += - -------------------*dra1dra + -------------------*drb1drb
3010 : ! d|drhoa| d|drhob| d|drhob| d|drhob|
3011 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob, deriv_norm_drhob])
3012 0 : IF (ASSOCIATED(deriv_att)) THEN
3013 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3014 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
3015 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drhob) COLLAPSE(3)
3016 : DO k = bo(1, 3), bo(2, 3)
3017 : DO j = bo(1, 2), bo(2, 2)
3018 : DO i = bo(1, 1), bo(2, 1)
3019 : v_drhob(2)%array(i, j, k) = v_drhob(2)%array(i, j, k) - &
3020 : deriv_data(i, j, k)*dra1dra(i, j, k) + deriv_data2(i, j, k)*drb1drb(i, j, k)
3021 : END DO
3022 : END DO
3023 : END DO
3024 : !$OMP END PARALLEL DO
3025 : END IF
3026 : END IF
3027 : ! d^2 e_xc d^2 e_xc
3028 : ! v_drho(1) += - ------------------*dra1dra + ------------------*drb1drb
3029 : ! d|drho| d|drhoa| d|drho| d|drhob|
3030 : !
3031 : ! d^2 e_xc d^2 e_xc
3032 : ! v_drho(2) += - ------------------*dra1dra + ------------------*drb1drb
3033 : ! d|drho| d|drhoa| d|drho| d|drhob|
3034 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhob])
3035 0 : IF (ASSOCIATED(deriv_att)) THEN
3036 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data2)
3037 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drho, deriv_norm_drhoa])
3038 0 : IF (ASSOCIATED(deriv_att)) THEN
3039 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3040 : !$OMP PARALLEL DO PRIVATE(k,j,i) DEFAULT(NONE)&
3041 0 : !$OMP SHARED(bo,deriv_data,deriv_data2,dra1dra,drb1drb,v_drho) COLLAPSE(3)
3042 : DO k = bo(1, 3), bo(2, 3)
3043 : DO j = bo(1, 2), bo(2, 2)
3044 : DO i = bo(1, 1), bo(2, 1)
3045 : v_drho(1)%array(i, j, k) = v_drho(1)%array(i, j, k) - &
3046 : deriv_data(i, j, k)*dra1dra(i, j, k) + &
3047 : deriv_data2(i, j, k)*drb1drb(i, j, k)
3048 : v_drho(2)%array(i, j, k) = v_drho(2)%array(i, j, k) - &
3049 : deriv_data(i, j, k)*dra1dra(i, j, k) + &
3050 : deriv_data2(i, j, k)*drb1drb(i, j, k)
3051 : END DO
3052 : END DO
3053 : END DO
3054 : !$OMP END PARALLEL DO
3055 : END IF
3056 : END IF
3057 : !
3058 :
3059 : ! Last GGA contribution
3060 : ! Alpha contribution
3061 : ! d e_xc
3062 : ! v_drhoa(1) += + ----------*dra1dra
3063 : ! d|drhoa|
3064 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhoa])
3065 0 : IF (ASSOCIATED(deriv_att)) THEN
3066 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3067 0 : CALL xc_derivative_get(deriv_att, deriv_data=e_drhoa)
3068 :
3069 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dra1dra,gradient_cut,norm_drhoa,v_drhoa,deriv_data)
3070 : v_drhoa(1)%array(:, :, :) = v_drhoa(1)%array(:, :, :) + &
3071 : deriv_data(:, :, :)*dra1dra(:, :, :)/MAX(gradient_cut, norm_drhoa(:, :, :))**2
3072 : !$OMP END PARALLEL WORKSHARE
3073 : END IF
3074 : ! Beta contribution
3075 : ! d e_xc
3076 : ! v_drhob(2) += - ----------*drb1drb
3077 : ! d|drhob|
3078 0 : deriv_att => xc_dset_get_derivative(deriv_set, [deriv_norm_drhob])
3079 0 : IF (ASSOCIATED(deriv_att)) THEN
3080 0 : CALL xc_derivative_get(deriv_att, deriv_data=deriv_data)
3081 0 : CALL xc_derivative_get(deriv_att, deriv_data=e_drhob)
3082 :
3083 0 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drb1drb,gradient_cut,norm_drhob,v_drhob,deriv_data)
3084 : v_drhob(2)%array(:, :, :) = v_drhob(2)%array(:, :, :) - &
3085 : deriv_data(:, :, :)*drb1drb(:, :, :)/MAX(gradient_cut, norm_drhob(:, :, :))**2
3086 : !$OMP END PARALLEL WORKSHARE
3087 : END IF
3088 : END IF ! If ALDA0
3089 : END IF
3090 :
3091 : ELSE
3092 :
3093 : ! Analytic third derivative for closed-shell
3094 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
3095 :
3096 : END IF
3097 :
3098 0 : IF (gradient_f) THEN
3099 : IF (.NOT. alda0) THEN
3100 :
3101 : ! partial integration
3102 0 : DO idir = 1, 3
3103 :
3104 : ! GGA contributions to the spin-flip xc-Kernel
3105 : !
3106 : ! v_drhoa(1)*drhoa(:)*rhoa1 v_drhob(1)*drhob(:)*rhoa1 v_drho(1)*drho(:)*rhoa1
3107 : ! v_drho_r(:,1) = --------------------------- + --------------------------- + -------------------------
3108 : ! |rhoa - rhob| |rhoa - rhob| |rhoa - rhob|
3109 : !
3110 : ! v_drhoa(2)*drhoa(:)*rhoa1 v_drhob(2)*drhob(:)*rhoa1 v_drho(2)*drho(:)*rhoa1
3111 : ! v_drho_r(:,2) = --------------------------- + --------------------------- + -------------------------
3112 : ! |rhoa - rhob| |rhoa - rhob| |rhoa - rhob|
3113 0 : IF (do_spinflip) THEN
3114 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3115 0 : !$OMP SHARED(bo,v_drho_r,v_drho,v_drhoa,v_drhob,rhoa,rhob,drho,drhoa,drhob,rho1a,idir,S_THRESH) COLLAPSE(3)
3116 : DO k = bo(1, 3), bo(2, 3)
3117 : DO j = bo(1, 2), bo(2, 2)
3118 : DO i = bo(1, 1), bo(2, 1)
3119 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3120 : DO ispin = 1, 2
3121 : v_drho_r(idir, ispin)%array(i, j, k) = v_drho_r(idir, ispin)%array(i, j, k) + &
3122 : v_drhoa(ispin)%array(i, j, k)*drhoa(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
3123 : v_drhob(ispin)%array(i, j, k)*drhob(idir)%array(i, j, k)*rho1a(i, j, k)/s + &
3124 : v_drho(ispin)%array(i, j, k)*drho(idir)%array(i, j, k)*rho1a(i, j, k)/s
3125 : END DO
3126 : END DO
3127 : END DO
3128 : END DO
3129 : !$OMP END PARALLEL DO
3130 : END IF
3131 : ! Last GGA contribution
3132 : ! Alpha contribution
3133 : ! rho1a d e_xc
3134 : ! v_drho_r(:,1) += - -------------*----------*drho1a(:)
3135 : ! |rhoa - rhob| d|drhoa|
3136 0 : IF (ASSOCIATED(e_drhoa)) THEN
3137 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3138 0 : !$OMP SHARED(bo,e_drhoa,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
3139 : DO k = bo(1, 3), bo(2, 3)
3140 : DO j = bo(1, 2), bo(2, 2)
3141 : DO i = bo(1, 1), bo(2, 1)
3142 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3143 : v_drho_r(idir, 1)%array(i, j, k) = v_drho_r(idir, 1)%array(i, j, k) - &
3144 : e_drhoa(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
3145 : END DO
3146 : END DO
3147 : END DO
3148 : !$OMP END PARALLEL DO
3149 : END IF
3150 : ! Beta contribution
3151 : ! rho1a d e_xc
3152 : ! v_drho_r(:,2) += + -------------*----------*drho1a(:)
3153 : ! |rhoa - rhob| d|drhob|
3154 0 : IF (ASSOCIATED(e_drhob)) THEN
3155 : !$OMP PARALLEL DO PRIVATE(k,j,i,s) DEFAULT(NONE)&
3156 0 : !$OMP SHARED(bo,e_drhob,v_drho_r,drho1a,rho1a,rhoa,rhob,S_THRESH,idir) COLLAPSE(3)
3157 : DO k = bo(1, 3), bo(2, 3)
3158 : DO j = bo(1, 2), bo(2, 2)
3159 : DO i = bo(1, 1), bo(2, 1)
3160 : s = MAX(ABS(rhoa(i, j, k) - rhob(i, j, k)), S_THRESH)
3161 : v_drho_r(idir, 2)%array(i, j, k) = v_drho_r(idir, 2)%array(i, j, k) + &
3162 : e_drhob(i, j, k)*drho1a(idir)%array(i, j, k)*rho1a(i, j, k)/s
3163 : END DO
3164 : END DO
3165 : END DO
3166 : !$OMP END PARALLEL DO
3167 : END IF
3168 : END DO
3169 :
3170 : ! partial integration: v_xc = v_xc - \nabla \cdot vdrho_r
3171 0 : DO ispin = 1, nspins
3172 0 : CALL xc_pw_divergence(xc_deriv_method_id, v_drho_r(:, ispin), tmp_g, vxc_g, v_xc(ispin))
3173 : END DO ! ispin
3174 : END IF ! ALDA0
3175 :
3176 0 : DO idir = 1, 3
3177 0 : DEALLOCATE (drho(idir)%array)
3178 0 : DEALLOCATE (drho1(idir)%array)
3179 : END DO
3180 :
3181 0 : DO ispin = 1, nspins
3182 0 : CALL deallocate_pw(v_drhoa(ispin), pw_pool)
3183 0 : CALL deallocate_pw(v_drhob(ispin), pw_pool)
3184 : END DO
3185 :
3186 0 : DEALLOCATE (v_drhoa, v_drhob)
3187 :
3188 : END IF ! gradient_f
3189 :
3190 : ELSE
3191 :
3192 : !-----------------!
3193 : ! restricted case !
3194 : !-----------------!
3195 0 : CPABORT("Exchange-correlation's analytic third derivative not implemented")
3196 :
3197 : END IF
3198 :
3199 0 : IF (gradient_f) THEN
3200 :
3201 0 : DO ispin = 1, nspins
3202 0 : CALL deallocate_pw(v_drho(ispin), pw_pool)
3203 0 : DO idir = 1, 3
3204 0 : CALL deallocate_pw(v_drho_r(idir, ispin), pw_pool)
3205 : END DO
3206 : END DO
3207 0 : DEALLOCATE (v_drho, v_drho_r)
3208 :
3209 : END IF
3210 :
3211 0 : IF (ASSOCIATED(tmp_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
3212 0 : CALL pw_pool%give_back_pw(tmp_g)
3213 : END IF
3214 :
3215 0 : IF (ASSOCIATED(vxc_g%pw_grid) .AND. ASSOCIATED(pw_pool)) THEN
3216 0 : CALL pw_pool%give_back_pw(vxc_g)
3217 : END IF
3218 :
3219 0 : CALL timestop(handle)
3220 0 : END SUBROUTINE xc_calc_3rd_deriv_analytical
3221 :
3222 : ! **************************************************************************************************
3223 : !> \brief allocates grids using pw_pool (if associated) or with bounds
3224 : !> \param pw ...
3225 : !> \param pw_pool ...
3226 : !> \param bo ...
3227 : ! **************************************************************************************************
3228 136930 : SUBROUTINE allocate_pw(pw, pw_pool, bo)
3229 : TYPE(pw_r3d_rs_type), INTENT(OUT) :: pw
3230 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
3231 : INTEGER, DIMENSION(2, 3), INTENT(IN) :: bo
3232 :
3233 136930 : IF (ASSOCIATED(pw_pool)) THEN
3234 76102 : CALL pw_pool%create_pw(pw)
3235 76102 : CALL pw_zero(pw)
3236 : ELSE
3237 304140 : ALLOCATE (pw%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)))
3238 155233056 : pw%array = 0.0_dp
3239 : END IF
3240 :
3241 136930 : END SUBROUTINE allocate_pw
3242 :
3243 : ! **************************************************************************************************
3244 : !> \brief deallocates grid allocated with allocate_pw
3245 : !> \param pw ...
3246 : !> \param pw_pool ...
3247 : ! **************************************************************************************************
3248 136930 : SUBROUTINE deallocate_pw(pw, pw_pool)
3249 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: pw
3250 : TYPE(pw_pool_type), INTENT(IN), POINTER :: pw_pool
3251 :
3252 136930 : IF (ASSOCIATED(pw_pool)) THEN
3253 76102 : CALL pw_pool%give_back_pw(pw)
3254 : ELSE
3255 60828 : CALL pw%release()
3256 : END IF
3257 :
3258 136930 : END SUBROUTINE deallocate_pw
3259 :
3260 : ! **************************************************************************************************
3261 : !> \brief updates virial from first derivative w.r.t. norm_drho
3262 : !> \param virial_pw ...
3263 : !> \param drho ...
3264 : !> \param drho1 ...
3265 : !> \param deriv_data ...
3266 : !> \param virial_xc ...
3267 : ! **************************************************************************************************
3268 304 : SUBROUTINE virial_drho_drho1(virial_pw, drho, drho1, deriv_data, virial_xc)
3269 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
3270 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
3271 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
3272 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3273 :
3274 : INTEGER :: idir, jdir
3275 : REAL(KIND=dp) :: tmp
3276 :
3277 1216 : DO idir = 1, 3
3278 912 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,virial_pw,deriv_data)
3279 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*deriv_data(:, :, :)
3280 : !$OMP END PARALLEL WORKSHARE
3281 3952 : DO jdir = 1, 3
3282 : tmp = virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
3283 2736 : drho1(jdir)%array(:, :, :))
3284 2736 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
3285 3648 : virial_xc(idir, jdir) = virial_xc(idir, jdir) + tmp
3286 : END DO
3287 : END DO
3288 :
3289 304 : END SUBROUTINE virial_drho_drho1
3290 :
3291 : ! **************************************************************************************************
3292 : !> \brief Adds virial contribution from second order potential parts
3293 : !> \param virial_pw ...
3294 : !> \param drho ...
3295 : !> \param v_drho ...
3296 : !> \param virial_xc ...
3297 : ! **************************************************************************************************
3298 298 : SUBROUTINE virial_drho_drho(virial_pw, drho, v_drho, virial_xc)
3299 : TYPE(pw_r3d_rs_type), INTENT(IN) :: virial_pw
3300 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho
3301 : TYPE(pw_r3d_rs_type), INTENT(IN) :: v_drho
3302 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3303 :
3304 : INTEGER :: idir, jdir
3305 : REAL(KIND=dp) :: tmp
3306 :
3307 1192 : DO idir = 1, 3
3308 894 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,idir,v_drho,virial_pw)
3309 : virial_pw%array(:, :, :) = drho(idir)%array(:, :, :)*v_drho%array(:, :, :)
3310 : !$OMP END PARALLEL WORKSHARE
3311 2980 : DO jdir = 1, idir
3312 : tmp = -virial_pw%pw_grid%dvol*accurate_dot_product(virial_pw%array(:, :, :), &
3313 1788 : drho(jdir)%array(:, :, :))
3314 1788 : virial_xc(jdir, idir) = virial_xc(jdir, idir) + tmp
3315 2682 : virial_xc(idir, jdir) = virial_xc(jdir, idir)
3316 : END DO
3317 : END DO
3318 :
3319 298 : END SUBROUTINE virial_drho_drho
3320 :
3321 : ! **************************************************************************************************
3322 : !> \brief ...
3323 : !> \param rho_r ...
3324 : !> \param pw_pool ...
3325 : !> \param virial_xc ...
3326 : !> \param deriv_data ...
3327 : ! **************************************************************************************************
3328 150 : SUBROUTINE virial_laplace(rho_r, pw_pool, virial_xc, deriv_data)
3329 : TYPE(pw_r3d_rs_type), TARGET :: rho_r
3330 : TYPE(pw_pool_type), POINTER, INTENT(IN) :: pw_pool
3331 : REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT) :: virial_xc
3332 : REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN) :: deriv_data
3333 :
3334 : CHARACTER(len=*), PARAMETER :: routineN = 'virial_laplace'
3335 :
3336 : INTEGER :: handle, idir, jdir
3337 : TYPE(pw_r3d_rs_type), POINTER :: virial_pw
3338 : TYPE(pw_c1d_gs_type), POINTER :: tmp_g, rho_g
3339 : INTEGER, DIMENSION(3) :: my_deriv
3340 :
3341 150 : CALL timeset(routineN, handle)
3342 :
3343 150 : NULLIFY (virial_pw, tmp_g, rho_g)
3344 150 : ALLOCATE (virial_pw, tmp_g, rho_g)
3345 150 : CALL pw_pool%create_pw(virial_pw)
3346 150 : CALL pw_pool%create_pw(tmp_g)
3347 150 : CALL pw_pool%create_pw(rho_g)
3348 150 : CALL pw_zero(virial_pw)
3349 150 : CALL pw_transfer(rho_r, rho_g)
3350 600 : DO idir = 1, 3
3351 1500 : DO jdir = idir, 3
3352 900 : CALL pw_copy(rho_g, tmp_g)
3353 :
3354 900 : my_deriv = 0
3355 900 : my_deriv(idir) = 1
3356 900 : my_deriv(jdir) = my_deriv(jdir) + 1
3357 :
3358 900 : CALL pw_derive(tmp_g, my_deriv)
3359 900 : CALL pw_transfer(tmp_g, virial_pw)
3360 : virial_xc(idir, jdir) = virial_xc(idir, jdir) - 2.0_dp*virial_pw%pw_grid%dvol* &
3361 : accurate_dot_product(virial_pw%array(:, :, :), &
3362 900 : deriv_data(:, :, :))
3363 1350 : virial_xc(jdir, idir) = virial_xc(idir, jdir)
3364 : END DO
3365 : END DO
3366 150 : CALL pw_pool%give_back_pw(virial_pw)
3367 150 : CALL pw_pool%give_back_pw(tmp_g)
3368 150 : CALL pw_pool%give_back_pw(rho_g)
3369 150 : DEALLOCATE (virial_pw, tmp_g, rho_g)
3370 :
3371 150 : CALL timestop(handle)
3372 :
3373 150 : END SUBROUTINE virial_laplace
3374 :
3375 : ! **************************************************************************************************
3376 : !> \brief Prepare objects for the calculation of the 2nd derivatives of the density functional.
3377 : !> The calculation must then be performed with xc_calc_2nd_deriv.
3378 : !> \param deriv_set object containing the XC derivatives (out)
3379 : !> \param rho_set object that will contain the density at which the
3380 : !> derivatives were calculated
3381 : !> \param rho_r the place where you evaluate the derivative
3382 : !> \param pw_pool the pool for the grids
3383 : !> \param weights integration weights
3384 : !> \param xc_section which functional should be used and how to calculate it
3385 : !> \param tau_r kinetic energy density in real space
3386 : ! **************************************************************************************************
3387 14128 : SUBROUTINE xc_prep_2nd_deriv(deriv_set, &
3388 : rho_set, rho_r, pw_pool, weights, xc_section, tau_r)
3389 :
3390 : TYPE(xc_derivative_set_type) :: deriv_set
3391 : TYPE(xc_rho_set_type) :: rho_set
3392 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3393 : TYPE(pw_pool_type), POINTER :: pw_pool
3394 : TYPE(pw_r3d_rs_type), POINTER :: weights
3395 : TYPE(section_vals_type), POINTER :: xc_section
3396 : TYPE(pw_r3d_rs_type), DIMENSION(:), &
3397 : OPTIONAL, POINTER :: tau_r
3398 :
3399 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_prep_2nd_deriv'
3400 :
3401 : INTEGER :: handle, nspins
3402 : LOGICAL :: lsd
3403 14128 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
3404 14128 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
3405 :
3406 14128 : CALL timeset(routineN, handle)
3407 :
3408 14128 : CPASSERT(ASSOCIATED(xc_section))
3409 14128 : CPASSERT(ASSOCIATED(pw_pool))
3410 :
3411 14128 : IF (xc_section_uses_gauxc(xc_section)) THEN
3412 0 : CALL cp_abort(__LOCATION__, gauxc_high_deriv_message)
3413 : END IF
3414 :
3415 14128 : nspins = SIZE(rho_r)
3416 14128 : lsd = (nspins /= 1)
3417 :
3418 14128 : NULLIFY (rho_g, tau)
3419 14128 : IF (PRESENT(tau_r)) &
3420 13454 : tau => tau_r
3421 :
3422 14128 : IF (section_get_lval(xc_section, "2ND_DERIV_ANALYTICAL")) THEN
3423 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 2, &
3424 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3425 14044 : calc_potential=.TRUE.)
3426 : ELSE
3427 : CALL xc_rho_set_and_dset_create(rho_set, deriv_set, 1, &
3428 : rho_r, rho_g, tau, xc_section, pw_pool, weights, &
3429 84 : calc_potential=.TRUE.)
3430 : END IF
3431 :
3432 14128 : CALL timestop(handle)
3433 :
3434 14128 : END SUBROUTINE xc_prep_2nd_deriv
3435 :
3436 : ! **************************************************************************************************
3437 : !> \brief Prepare deriv_set for the calculation of the 3rd derivatives of the density functional.
3438 : !> The calculation must then be performed with xc_calc_3rd_deriv.
3439 : !> \param deriv_set object containing the XC derivatives (out)
3440 : !> \param rho_set object that will contain the density at which the
3441 : !> derivatives were calculated
3442 : !> \param rho_r the place where you evaluate the derivative
3443 : !> \param pw_pool the pool for the grids
3444 : !> \param weights integration weights
3445 : !> \param xc_section which functional should be used and how to calculate it
3446 : !> \param tau_r kinetic energy density in real space
3447 : !> \param do_sf Flag to activate the noncollinear kernel for spin flip calculations
3448 : !> \par History
3449 : !> * 07.2024 Created [LHS]
3450 : ! **************************************************************************************************
3451 0 : SUBROUTINE xc_prep_3rd_deriv(deriv_set, rho_set, rho_r, pw_pool, weights, &
3452 : xc_section, tau_r, do_sf)
3453 :
3454 : TYPE(xc_derivative_set_type) :: deriv_set
3455 : TYPE(xc_rho_set_type) :: rho_set
3456 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3457 : TYPE(pw_pool_type), POINTER :: pw_pool
3458 : TYPE(pw_r3d_rs_type), POINTER :: weights
3459 : TYPE(section_vals_type), POINTER :: xc_section
3460 : TYPE(pw_r3d_rs_type), DIMENSION(:), &
3461 : OPTIONAL, POINTER :: tau_r
3462 : LOGICAL, OPTIONAL :: do_sf
3463 :
3464 : CHARACTER(len=*), PARAMETER :: routineN = 'xc_prep_3rd_deriv'
3465 :
3466 : INTEGER :: handle, nspins
3467 : LOGICAL :: lsd, my_do_sf
3468 0 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
3469 0 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
3470 :
3471 0 : CALL timeset(routineN, handle)
3472 :
3473 0 : CPASSERT(ASSOCIATED(xc_section))
3474 0 : CPASSERT(ASSOCIATED(pw_pool))
3475 :
3476 0 : IF (xc_section_uses_gauxc(xc_section)) THEN
3477 0 : CALL cp_abort(__LOCATION__, gauxc_high_deriv_message)
3478 : END IF
3479 :
3480 0 : nspins = SIZE(rho_r)
3481 0 : lsd = (nspins /= 1)
3482 :
3483 0 : NULLIFY (rho_g, tau)
3484 0 : IF (PRESENT(tau_r)) &
3485 0 : 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 173623 : 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 173623 : INTEGER, DIMENSION(:), POINTER :: split_desc
3517 : INTEGER :: idesc
3518 : INTEGER, DIMENSION(2, 3) :: bo
3519 : REAL(KIND=dp) :: drho_cutoff
3520 173623 : REAL(KIND=dp), DIMENSION(:, :, :), POINTER :: norm_drho, norm_drhoa, norm_drhob
3521 2083476 : 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 1736230 : 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 173623 : drho=drho, drhoa=drhoa, drhob=drhob, can_return_null=.TRUE.)
3531 :
3532 173623 : pos => deriv_set%derivs
3533 758301 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
3534 584678 : CALL xc_derivative_get(deriv_att, split_desc=split_desc)
3535 1264404 : DO idesc = 1, SIZE(split_desc)
3536 584678 : SELECT CASE (split_desc(idesc))
3537 : CASE (deriv_norm_drho)
3538 161225 : IF (ASSOCIATED(norm_drho)) THEN
3539 161225 : !$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 23652 : IF (ASSOCIATED(norm_drhoa)) THEN
3562 23652 : !$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 23648 : IF (ASSOCIATED(norm_drhob)) THEN
3578 23648 : !$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 215662 : IF (lsd) &
3594 0 : CPABORT(TRIM(id_to_desc(split_desc(idesc)))//" not handled in lsd!'")
3595 : CASE (deriv_rhoa, deriv_rhob, deriv_tau_a, deriv_tau_b, deriv_laplace_rhoa, deriv_laplace_rhob)
3596 : CASE default
3597 506103 : CPABORT("Unknown derivative id")
3598 : END SELECT
3599 : END DO
3600 : END DO
3601 :
3602 173623 : END SUBROUTINE divide_by_norm_drho
3603 :
3604 : ! **************************************************************************************************
3605 : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
3606 : !> \param drho ...
3607 : !> \param drhoa ...
3608 : !> \param drhob ...
3609 : ! **************************************************************************************************
3610 27096 : SUBROUTINE calc_drho_from_ab(drho, drhoa, drhob)
3611 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT) :: drho
3612 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa, drhob
3613 :
3614 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_drho_from_ab'
3615 :
3616 : INTEGER :: handle, idir
3617 :
3618 6774 : CALL timeset(routineN, handle)
3619 :
3620 27096 : DO idir = 1, 3
3621 20322 : NULLIFY (drho(idir)%array)
3622 : ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3623 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3624 101610 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3625 27096 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,drhob,idir)
3626 : drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :) + drhob(idir)%array(:, :, :)
3627 : !$OMP END PARALLEL WORKSHARE
3628 : END DO
3629 :
3630 6774 : CALL timestop(handle)
3631 :
3632 6774 : END SUBROUTINE calc_drho_from_ab
3633 :
3634 : ! **************************************************************************************************
3635 : !> \brief allocates and calculates drho from given spin densities drhoa, drhob
3636 : !> \param drho ...
3637 : !> \param drhoa ...
3638 : !> \param drhob ...
3639 : ! **************************************************************************************************
3640 1048 : SUBROUTINE calc_drho_from_a(drho, drhoa)
3641 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(OUT) :: drho
3642 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa
3643 :
3644 : CHARACTER(len=*), PARAMETER :: routineN = 'calc_drho_from_a'
3645 :
3646 : INTEGER :: handle, idir
3647 :
3648 262 : CALL timeset(routineN, handle)
3649 :
3650 1048 : DO idir = 1, 3
3651 786 : NULLIFY (drho(idir)%array)
3652 : ALLOCATE (drho(idir)%array(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3653 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3654 3930 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3655 1048 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(drho,drhoa,idir)
3656 : drho(idir)%array(:, :, :) = drhoa(idir)%array(:, :, :)
3657 : !$OMP END PARALLEL WORKSHARE
3658 : END DO
3659 :
3660 262 : CALL timestop(handle)
3661 :
3662 262 : END SUBROUTINE calc_drho_from_a
3663 :
3664 : ! **************************************************************************************************
3665 : !> \brief allocates and calculates dot products of two density gradients
3666 : !> \param dr1dr ...
3667 : !> \param drho ...
3668 : !> \param drho1 ...
3669 : ! **************************************************************************************************
3670 34806 : SUBROUTINE prepare_dr1dr(dr1dr, drho, drho1)
3671 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
3672 : INTENT(OUT) :: dr1dr
3673 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drho, drho1
3674 :
3675 : CHARACTER(len=*), PARAMETER :: routineN = 'prepare_dr1dr'
3676 :
3677 : INTEGER :: handle, idir
3678 :
3679 34806 : CALL timeset(routineN, handle)
3680 :
3681 0 : ALLOCATE (dr1dr(LBOUND(drho(1)%array, 1):UBOUND(drho(1)%array, 1), &
3682 : LBOUND(drho(1)%array, 2):UBOUND(drho(1)%array, 2), &
3683 174030 : LBOUND(drho(1)%array, 3):UBOUND(drho(1)%array, 3)))
3684 :
3685 34806 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1)
3686 : dr1dr(:, :, :) = drho(1)%array(:, :, :)*drho1(1)%array(:, :, :)
3687 : !$OMP END PARALLEL WORKSHARE
3688 104418 : DO idir = 2, 3
3689 104418 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(dr1dr,drho,drho1,idir)
3690 : dr1dr(:, :, :) = dr1dr(:, :, :) + drho(idir)%array(:, :, :)*drho1(idir)%array(:, :, :)
3691 : !$OMP END PARALLEL WORKSHARE
3692 : END DO
3693 :
3694 34806 : CALL timestop(handle)
3695 :
3696 34806 : END SUBROUTINE prepare_dr1dr
3697 :
3698 : ! **************************************************************************************************
3699 : !> \brief allocates and calculates dot product of two densities for triplets
3700 : !> \param dr1dr ...
3701 : !> \param drhoa ...
3702 : !> \param drhob ...
3703 : !> \param drho1a ...
3704 : !> \param drho1b ...
3705 : !> \param fac ...
3706 : ! **************************************************************************************************
3707 1150 : SUBROUTINE prepare_dr1dr_ab(dr1dr, drhoa, drhob, drho1a, drho1b, fac)
3708 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
3709 : INTENT(OUT) :: dr1dr
3710 : TYPE(cp_3d_r_cp_type), DIMENSION(3), INTENT(IN) :: drhoa, drhob, drho1a, drho1b
3711 : REAL(KIND=dp), INTENT(IN) :: fac
3712 :
3713 : CHARACTER(len=*), PARAMETER :: routineN = 'prepare_dr1dr_ab'
3714 :
3715 : INTEGER :: handle, idir
3716 :
3717 1150 : CALL timeset(routineN, handle)
3718 :
3719 0 : ALLOCATE (dr1dr(LBOUND(drhoa(1)%array, 1):UBOUND(drhoa(1)%array, 1), &
3720 : LBOUND(drhoa(1)%array, 2):UBOUND(drhoa(1)%array, 2), &
3721 5750 : LBOUND(drhoa(1)%array, 3):UBOUND(drhoa(1)%array, 3)))
3722 :
3723 1150 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob)
3724 : dr1dr(:, :, :) = drhoa(1)%array(:, :, :)*(drho1a(1)%array(:, :, :) + &
3725 : fac*drho1b(1)%array(:, :, :)) + &
3726 : drhob(1)%array(:, :, :)*(fac*drho1a(1)%array(:, :, :) + &
3727 : drho1b(1)%array(:, :, :))
3728 : !$OMP END PARALLEL WORKSHARE
3729 3450 : DO idir = 2, 3
3730 3450 : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) SHARED(fac,dr1dr,drho1a,drho1b,drhoa,drhob,idir)
3731 : dr1dr(:, :, :) = dr1dr(:, :, :) + &
3732 : drhoa(idir)%array(:, :, :)*(drho1a(idir)%array(:, :, :) + &
3733 : fac*drho1b(idir)%array(:, :, :)) + &
3734 : drhob(idir)%array(:, :, :)*(fac*drho1a(idir)%array(:, :, :) + &
3735 : drho1b(idir)%array(:, :, :))
3736 : !$OMP END PARALLEL WORKSHARE
3737 : END DO
3738 :
3739 1150 : CALL timestop(handle)
3740 :
3741 1150 : END SUBROUTINE prepare_dr1dr_ab
3742 :
3743 : ! **************************************************************************************************
3744 : !> \brief checks for gradients
3745 : !> \param deriv_set ...
3746 : !> \param lsd ...
3747 : !> \param gradient_f ...
3748 : !> \param tau_f ...
3749 : !> \param laplace_f ...
3750 : ! **************************************************************************************************
3751 173235 : SUBROUTINE check_for_derivatives(deriv_set, lsd, rho_f, gradient_f, tau_f, laplace_f)
3752 : TYPE(xc_derivative_set_type), INTENT(IN) :: deriv_set
3753 : LOGICAL, INTENT(IN) :: lsd
3754 : LOGICAL, INTENT(OUT) :: rho_f, gradient_f, tau_f, laplace_f
3755 :
3756 : CHARACTER(len=*), PARAMETER :: routineN = 'check_for_derivatives'
3757 :
3758 : INTEGER :: handle, iorder, order
3759 173235 : INTEGER, DIMENSION(:), POINTER :: split_desc
3760 : TYPE(cp_sll_xc_deriv_type), POINTER :: pos
3761 : TYPE(xc_derivative_type), POINTER :: deriv_att
3762 :
3763 173235 : CALL timeset(routineN, handle)
3764 :
3765 173235 : rho_f = .FALSE.
3766 173235 : gradient_f = .FALSE.
3767 173235 : tau_f = .FALSE.
3768 173235 : laplace_f = .FALSE.
3769 : ! check for unknown derivatives
3770 173235 : pos => deriv_set%derivs
3771 811607 : DO WHILE (cp_sll_xc_deriv_next(pos, el_att=deriv_att))
3772 : CALL xc_derivative_get(deriv_att, order=order, &
3773 638372 : split_desc=split_desc)
3774 811607 : IF (lsd) THEN
3775 383989 : DO iorder = 1, size(split_desc)
3776 185447 : SELECT CASE (split_desc(iorder))
3777 : CASE (deriv_rhoa, deriv_rhob)
3778 102544 : rho_f = .TRUE.
3779 : CASE (deriv_norm_drho, deriv_norm_drhoa, deriv_norm_drhob)
3780 91910 : gradient_f = .TRUE.
3781 : CASE (deriv_tau_a, deriv_tau_b)
3782 2776 : tau_f = .TRUE.
3783 : CASE (deriv_laplace_rhoa, deriv_laplace_rhob)
3784 1312 : laplace_f = .TRUE.
3785 : CASE (deriv_rho, deriv_tau, deriv_laplace_rho)
3786 0 : CPABORT("Derivative not handled in lsd!")
3787 : CASE default
3788 198542 : CPABORT("Unknown derivative id")
3789 : END SELECT
3790 : END DO
3791 : ELSE
3792 854214 : DO iorder = 1, size(split_desc)
3793 452925 : SELECT CASE (split_desc(iorder))
3794 : CASE (deriv_rho)
3795 235012 : rho_f = .TRUE.
3796 : CASE (deriv_tau)
3797 5452 : tau_f = .TRUE.
3798 : CASE (deriv_norm_drho)
3799 159387 : gradient_f = .TRUE.
3800 : CASE (deriv_laplace_rho)
3801 1438 : laplace_f = .TRUE.
3802 : CASE default
3803 401289 : CPABORT("Unknown derivative id")
3804 : END SELECT
3805 : END DO
3806 : END IF
3807 : END DO
3808 :
3809 173235 : CALL timestop(handle)
3810 :
3811 173235 : END SUBROUTINE check_for_derivatives
3812 :
3813 : END MODULE xc
|