(git:34ef472)
qs_dcdr.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
9 !> \brief Calculate the derivatives of the MO coefficients wrt nuclear coordinates
10 !> \author Sandra Luber, Edward Ditler
11 ! **************************************************************************************************
12 
13 MODULE qs_dcdr
14 
16  USE cell_types, ONLY: cell_type,&
17  pbc
18  USE cp_array_utils, ONLY: cp_2d_r_p_type
22  USE cp_fm_basic_linalg, ONLY: cp_fm_scale,&
24  cp_fm_trace
25  USE cp_fm_types, ONLY: cp_fm_create,&
27  cp_fm_release,&
29  cp_fm_to_fm,&
30  cp_fm_type
32  cp_logger_type
35  USE dbcsr_api, ONLY: dbcsr_add,&
36  dbcsr_copy,&
37  dbcsr_desymmetrize,&
38  dbcsr_p_type,&
39  dbcsr_set
41  section_vals_type
42  USE kinds, ONLY: dp
43  USE molecule_types, ONLY: molecule_of_atom,&
44  molecule_type
45  USE parallel_gemm_api, ONLY: parallel_gemm
46  USE particle_types, ONLY: particle_type
48  core_dr,&
50  d_vhxc_dr,&
53  USE qs_dcdr_utils, ONLY: dcdr_read_restart,&
57  USE qs_environment_types, ONLY: get_qs_env,&
58  qs_environment_type
59  USE qs_kind_types, ONLY: get_qs_kind,&
60  qs_kind_type
62  USE qs_linres_types, ONLY: dcdr_env_type,&
63  linres_control_type
64  USE qs_mo_types, ONLY: get_mo_set,&
65  mo_set_type
68  USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type
69  USE qs_p_env_types, ONLY: qs_p_env_type
70 #include "./base/base_uses.f90"
71 
72  IMPLICIT NONE
73 
74  PRIVATE
76 
77  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dcdr'
78 
79 CONTAINS
80 
81 ! **************************************************************************************************
82 !> \brief Prepare the environment for a choice of lambda
83 !> \param dcdr_env ...
84 !> \param qs_env ...
85 !> \author Edward Ditler
86 ! **************************************************************************************************
87  SUBROUTINE prepare_per_atom(dcdr_env, qs_env)
88  TYPE(dcdr_env_type) :: dcdr_env
89  TYPE(qs_environment_type), POINTER :: qs_env
90 
91  CHARACTER(LEN=*), PARAMETER :: routinen = 'prepare_per_atom'
92 
93  INTEGER :: handle, i, ispin, j, natom
94  TYPE(neighbor_list_set_p_type), DIMENSION(:), &
95  POINTER :: sab_all
96  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
97  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
98 
99  CALL timeset(routinen, handle)
100 
101  NULLIFY (sab_all, qs_kind_set, particle_set)
102  CALL get_qs_env(qs_env=qs_env, &
103  sab_all=sab_all, &
104  qs_kind_set=qs_kind_set, &
105  particle_set=particle_set)
106 
107  natom = SIZE(particle_set)
108  IF (dcdr_env%distributed_origin) dcdr_env%ref_point(:) = particle_set(dcdr_env%lambda)%r(:)
109 
110  dcdr_env%delta_basis_function = 0._dp
111  dcdr_env%delta_basis_function(:, dcdr_env%lambda) = 1._dp
112 
113  ! S matrix
114  ! S1 = - < da/dr | b > * delta_a - < a | db/dr > * delta_b
115 
116  ! matrix_s(2:4) are anti-symmetric matrices and contain derivatives wrt. to < a |
117  ! = < da/dR | b > = - < da/dr | b > = < a | db/dr >
118  ! matrix_s1(2:4) = d/dR < a | b >
119  ! and it's built as
120  ! = - matrix_s * delta_b + matrix_s * delta_a
121  ! = - < da/dR | b > * delta_b + < da/dR | b > * delta_a
122  ! = + < da/dr | b > * delta_b - < da/dr | b > * delta_a
123  ! = - < a | db/dr > * delta_b - < da/dr | b > * delta_a
124 
125  DO i = 1, 3
126  ! S matrix
127  CALL dbcsr_set(dcdr_env%matrix_nosym_temp(i)%matrix, 0._dp)
128  CALL dbcsr_desymmetrize(dcdr_env%matrix_s(1 + i)%matrix, dcdr_env%matrix_s1(1 + i)%matrix)
129  CALL dbcsr_desymmetrize(dcdr_env%matrix_s(1 + i)%matrix, dcdr_env%matrix_nosym_temp(i)%matrix)
130 
131  CALL hr_mult_by_delta_1d(dcdr_env%matrix_s1(1 + i)%matrix, qs_kind_set, "ORB", &
132  sab_all, dcdr_env%lambda, direction_or=.true.)
133  CALL hr_mult_by_delta_1d(dcdr_env%matrix_nosym_temp(i)%matrix, qs_kind_set, "ORB", &
134  sab_all, dcdr_env%lambda, direction_or=.false.)
135 
136  CALL dbcsr_add(dcdr_env%matrix_s1(1 + i)%matrix, dcdr_env%matrix_nosym_temp(i)%matrix, -1._dp, +1._dp)
137  CALL dbcsr_set(dcdr_env%matrix_nosym_temp(i)%matrix, 0._dp)
138 
139  ! T matrix
140  CALL dbcsr_set(dcdr_env%matrix_nosym_temp(i)%matrix, 0._dp)
141  CALL dbcsr_desymmetrize(dcdr_env%matrix_t(1 + i)%matrix, dcdr_env%matrix_t1(1 + i)%matrix)
142  CALL dbcsr_desymmetrize(dcdr_env%matrix_t(1 + i)%matrix, dcdr_env%matrix_nosym_temp(i)%matrix)
143 
144  CALL hr_mult_by_delta_1d(dcdr_env%matrix_t1(1 + i)%matrix, qs_kind_set, "ORB", &
145  sab_all, dcdr_env%lambda, direction_or=.true.)
146  CALL hr_mult_by_delta_1d(dcdr_env%matrix_nosym_temp(i)%matrix, qs_kind_set, "ORB", &
147  sab_all, dcdr_env%lambda, direction_or=.false.)
148 
149  CALL dbcsr_add(dcdr_env%matrix_t1(1 + i)%matrix, dcdr_env%matrix_nosym_temp(i)%matrix, -1._dp, +1._dp)
150  CALL dbcsr_set(dcdr_env%matrix_nosym_temp(i)%matrix, 0._dp)
151  END DO
152 
153  ! Operator:
154  DO ispin = 1, dcdr_env%nspins
155  DO i = 1, 3
156  CALL dbcsr_set(dcdr_env%matrix_ppnl_1(i)%matrix, 0.0_dp)
157  CALL dbcsr_set(dcdr_env%matrix_hc(i)%matrix, 0.0_dp)
158  CALL dbcsr_set(dcdr_env%matrix_vhxc_perturbed_basis(ispin, i)%matrix, 0.0_dp)
159  CALL dbcsr_set(dcdr_env%matrix_vhxc_perturbed_basis(ispin, i + 3)%matrix, 0.0_dp)
160  CALL dbcsr_set(dcdr_env%matrix_d_vhxc_dR(i, ispin)%matrix, 0.0_dp)
161  CALL dbcsr_set(dcdr_env%matrix_core_charge_1(i)%matrix, 0.0_dp)
162  END DO
163  END DO
164 
165  CALL core_dr(qs_env, dcdr_env) ! dcdr_env%matrix_ppnl_1, hc
166  CALL d_vhxc_dr(qs_env, dcdr_env) ! dcdr_env%matrix_d_vhxc_dR
167  CALL d_core_charge_density_dr(qs_env, dcdr_env) ! dcdr_env%matrix_core_charge_1
168  CALL vhxc_r_perturbed_basis_functions(qs_env, dcdr_env) ! dcdr_env%matrix_vhxc_perturbed_basis
169 
170  ! APT:
171  DO i = 1, 3
172  DO j = 1, 3
173  CALL dbcsr_set(dcdr_env%matrix_difdip(i, j)%matrix, 0._dp)
174  END DO
175  END DO
176 
177  CALL dipole_deriv_ao(qs_env, dcdr_env%matrix_difdip, dcdr_env%delta_basis_function, 1, dcdr_env%ref_point)
178 
179  CALL timestop(handle)
180  END SUBROUTINE prepare_per_atom
181 
182 ! **************************************************************************************************
183 !> \brief Build the operator for the position perturbation
184 !> \param dcdr_env ...
185 !> \param qs_env ...
186 !> \authors SL, ED
187 ! **************************************************************************************************
188  SUBROUTINE dcdr_build_op_dr(dcdr_env, qs_env)
189 
190  TYPE(dcdr_env_type) :: dcdr_env
191  TYPE(qs_environment_type), POINTER :: qs_env
192 
193  CHARACTER(LEN=*), PARAMETER :: routinen = 'dcdr_build_op_dR'
194  REAL(kind=dp), PARAMETER :: one = 1.0_dp, zero = 0.0_dp
195 
196  INTEGER :: handle, ispin, nao, nmo
197  TYPE(cp_fm_type) :: buf
198  TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: opdr_sym
199 
200  CALL timeset(routinen, handle)
201 
202  nao = dcdr_env%nao
203 
204  ! allocate matrix for the sum of the perturbation terms of the operator (dbcsr matrix)
205  NULLIFY (opdr_sym)
206  CALL dbcsr_allocate_matrix_set(opdr_sym, 1)
207  ALLOCATE (opdr_sym(1)%matrix)
208  CALL dbcsr_copy(opdr_sym(1)%matrix, dcdr_env%matrix_s1(1)%matrix) ! symmetric
209  CALL dbcsr_set(opdr_sym(1)%matrix, 0.0_dp)
210 
211  DO ispin = 1, dcdr_env%nspins
212  nmo = dcdr_env%nmo(ispin)
213 
214  CALL apply_op_constant_term(qs_env, dcdr_env) ! dcdr_env%matrix_apply_op_constant
215  ! Hartree and Exchange-Correlation contributions
216  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_core_charge_1(dcdr_env%beta)%matrix, zero, one)
217  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_d_vhxc_dR(dcdr_env%beta, ispin)%matrix, one, one)
218  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_vhxc_perturbed_basis(ispin, dcdr_env%beta)%matrix, one, one)
219 
220  ! Core Hamiltonian contributions
221  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_hc(dcdr_env%beta)%matrix, one, one)
222  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_ppnl_1(dcdr_env%beta)%matrix, one, one)
223  CALL dbcsr_add(opdr_sym(1)%matrix, dcdr_env%matrix_apply_op_constant(ispin)%matrix, one, one)
224 
225  CALL dbcsr_desymmetrize(opdr_sym(1)%matrix, dcdr_env%hamiltonian1(1)%matrix)
226  CALL dbcsr_add(dcdr_env%hamiltonian1(1)%matrix, dcdr_env%matrix_t1(dcdr_env%beta + 1)%matrix, one, one)
227 
228  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%hamiltonian1(1)%matrix, dcdr_env%mo_coeff(ispin), &
229  dcdr_env%op_dR(ispin), ncol=nmo)
230 
231  ! The overlap derivative terms for the Sternheimer equation
232  ! buf = mo * (-mo * matrix_ks * mo)
233  CALL cp_fm_create(buf, dcdr_env%likemos_fm_struct(ispin)%struct)
234  CALL parallel_gemm('N', 'N', nao, nmo, nmo, &
235  -1.0_dp, dcdr_env%mo_coeff(ispin), dcdr_env%chc(ispin), &
236  0.0_dp, buf)
237 
238  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%matrix_s1(dcdr_env%beta + 1)%matrix, buf, dcdr_env%op_dR(ispin), &
239  nmo, alpha=1.0_dp, beta=1.0_dp)
240  CALL cp_fm_release(buf)
241 
242  ! SL multiply by -1 for response solver (H-S<H> C + dR_coupled= - (op_dR)
243  CALL cp_fm_scale(-1.0_dp, dcdr_env%op_dR(ispin))
244  END DO
245 
246  CALL dbcsr_deallocate_matrix_set(opdr_sym)
247 
248  CALL timestop(handle)
249  END SUBROUTINE dcdr_build_op_dr
250 
251 ! **************************************************************************************************
252 !> \brief Get the dC/dR by solving the Sternheimer equation, using the op_dR matrix
253 !> \param dcdr_env ...
254 !> \param p_env ...
255 !> \param qs_env ...
256 !> \authors SL, ED
257 ! **************************************************************************************************
258  SUBROUTINE dcdr_response_dr(dcdr_env, p_env, qs_env)
259 
260  TYPE(dcdr_env_type) :: dcdr_env
261  TYPE(qs_p_env_type) :: p_env
262  TYPE(qs_environment_type), POINTER :: qs_env
263 
264  CHARACTER(LEN=*), PARAMETER :: routinen = 'dcdr_response_dR'
265 
266  INTEGER :: handle, ispin, output_unit
267  LOGICAL :: should_stop
268  TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: h1_psi0, psi0_order, psi1
269  TYPE(cp_fm_type), POINTER :: mo_coeff
270  TYPE(cp_logger_type), POINTER :: logger
271  TYPE(linres_control_type), POINTER :: linres_control
272  TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
273  TYPE(section_vals_type), POINTER :: lr_section
274 
275  CALL timeset(routinen, handle)
276  NULLIFY (linres_control, lr_section, logger)
277 
278  CALL get_qs_env(qs_env=qs_env, &
279  linres_control=linres_control, &
280  mos=mos)
281 
282  logger => cp_get_default_logger()
283  lr_section => section_vals_get_subs_vals(qs_env%input, "PROPERTIES%LINRES")
284 
285  output_unit = cp_print_key_unit_nr(logger, lr_section, "PRINT%PROGRAM_RUN_INFO", &
286  extension=".linresLog")
287  IF (output_unit > 0) THEN
288  WRITE (unit=output_unit, fmt="(T10,A,/)") &
289  "*** Self consistent optimization of the response wavefunction ***"
290  END IF
291 
292  ! allocate the vectors
293  ALLOCATE (psi0_order(dcdr_env%nspins))
294  ALLOCATE (psi1(dcdr_env%nspins))
295  ALLOCATE (h1_psi0(dcdr_env%nspins))
296 
297  DO ispin = 1, dcdr_env%nspins
298  CALL cp_fm_create(psi1(ispin), dcdr_env%likemos_fm_struct(ispin)%struct)
299  CALL cp_fm_create(h1_psi0(ispin), dcdr_env%likemos_fm_struct(ispin)%struct)
300  CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff)
301  psi0_order(ispin) = mo_coeff
302  END DO
303 
304  ! Restart
305  IF (linres_control%linres_restart) THEN
306  CALL dcdr_read_restart(qs_env, lr_section, psi1, dcdr_env%lambda, dcdr_env%beta, "dCdR")
307  ELSE
308  DO ispin = 1, dcdr_env%nspins
309  CALL cp_fm_set_all(psi1(ispin), 0.0_dp)
310  END DO
311  END IF
312 
313  IF (output_unit > 0) THEN
314  WRITE (output_unit, "(T10,A,I4,A)") &
315  "Response to the perturbation operator referring to atom ", dcdr_env%lambda, &
316  " displaced in "//achar(dcdr_env%beta + 119)
317  END IF
318  DO ispin = 1, dcdr_env%nspins
319  CALL cp_fm_set_all(dcdr_env%dCR(ispin), 0.0_dp)
320  CALL cp_fm_to_fm(dcdr_env%op_dR(ispin), h1_psi0(ispin))
321  END DO
322 
323  linres_control%lr_triplet = .false. ! we do singlet response
324  linres_control%do_kernel = .true.
325  linres_control%converged = .false.
326 
327  ! Position perturbation to get dCR
328  ! (H0-E0) psi1 = (H1-E1) psi0
329  ! psi1 = the perturbed wavefunction
330  ! h1_psi0 = (H1-E1-S1*\varepsilon)
331  ! psi0_order = the unperturbed wavefunction
332  CALL linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, &
333  output_unit, should_stop)
334  DO ispin = 1, dcdr_env%nspins
335  CALL cp_fm_to_fm(psi1(ispin), dcdr_env%dCR(ispin))
336  END DO
337 
338  ! Write the new result to the restart file
339  IF (linres_control%linres_restart) THEN
340  CALL dcdr_write_restart(qs_env, lr_section, psi1, dcdr_env%lambda, dcdr_env%beta, "dCdR")
341  END IF
342 
343  ! clean up
344  DO ispin = 1, dcdr_env%nspins
345  CALL cp_fm_release(psi1(ispin))
346  CALL cp_fm_release(h1_psi0(ispin))
347  END DO
348  DEALLOCATE (psi1, h1_psi0, psi0_order)
349  CALL cp_print_key_finished_output(output_unit, logger, lr_section, &
350  "PRINT%PROGRAM_RUN_INFO")
351 
352  CALL timestop(handle)
353 
354  END SUBROUTINE dcdr_response_dr
355 
356 ! **************************************************************************************************
357 !> \brief Calculate atomic polar tensor
358 !> \param qs_env ...
359 !> \param dcdr_env ...
360 !> \author Edward Ditler
361 ! **************************************************************************************************
362  SUBROUTINE apt_dr(qs_env, dcdr_env)
363  TYPE(qs_environment_type), POINTER :: qs_env
364  TYPE(dcdr_env_type) :: dcdr_env
365 
366  CHARACTER(LEN=*), PARAMETER :: routinen = 'apt_dR'
367 
368  INTEGER :: alpha, handle, ikind, ispin, nao, nmo
369  LOGICAL :: ghost
370  REAL(dp) :: apt_basis_derivative, &
371  apt_coeff_derivative, charge, f_spin
372  REAL(dp), DIMENSION(:, :, :), POINTER :: apt_el, apt_nuc
373  TYPE(cp_fm_type) :: overlap1_mo, tmp_fm_like_mos
374  TYPE(cp_fm_type), POINTER :: mo_coeff
375  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
376  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
377 
378  apt_basis_derivative = 0._dp
379  apt_coeff_derivative = 0._dp
380 
381  CALL timeset(routinen, handle)
382 
383  NULLIFY (qs_kind_set, particle_set)
384  CALL get_qs_env(qs_env=qs_env, &
385  qs_kind_set=qs_kind_set, &
386  particle_set=particle_set)
387 
388  nao = dcdr_env%nao
389  apt_el => dcdr_env%apt_el_dcdr
390  apt_nuc => dcdr_env%apt_nuc_dcdr
391 
392  f_spin = 2._dp/dcdr_env%nspins
393 
394  DO ispin = 1, dcdr_env%nspins
395  ! Compute S^(1,R)_(ij)
396  CALL cp_fm_create(tmp_fm_like_mos, dcdr_env%likemos_fm_struct(ispin)%struct)
397  CALL cp_fm_create(overlap1_mo, dcdr_env%momo_fm_struct(ispin)%struct)
398  nmo = dcdr_env%nmo(ispin)
399  mo_coeff => dcdr_env%mo_coeff(ispin)
400  CALL cp_fm_set_all(tmp_fm_like_mos, 0.0_dp)
401  CALL cp_fm_scale_and_add(0._dp, dcdr_env%dCR_prime(ispin), 1._dp, dcdr_env%dCR(ispin))
402  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%matrix_s1(dcdr_env%beta + 1)%matrix, mo_coeff, &
403  tmp_fm_like_mos, ncol=nmo)
404  CALL parallel_gemm("T", "N", nmo, nmo, nao, &
405  1.0_dp, mo_coeff, tmp_fm_like_mos, &
406  0.0_dp, overlap1_mo)
407 
408  ! C^1 <- -dCR - 0.5 * mo_coeff @ S1_ij
409  ! We get the negative of the coefficients out of the linres solver
410  ! And apply the constant correction due to the overlap derivative.
411  CALL parallel_gemm("N", "N", nao, nmo, nmo, &
412  -0.5_dp, mo_coeff, overlap1_mo, &
413  -1.0_dp, dcdr_env%dCR_prime(ispin))
414  CALL cp_fm_release(overlap1_mo)
415 
416  DO alpha = 1, 3
417  ! FIRST CONTRIBUTION: dCR * moments * mo
418  CALL cp_fm_set_all(tmp_fm_like_mos, 0._dp)
419  CALL dbcsr_desymmetrize(dcdr_env%matrix_s1(1)%matrix, dcdr_env%matrix_nosym_temp(1)%matrix)
420  CALL dbcsr_desymmetrize(dcdr_env%moments(alpha)%matrix, dcdr_env%matrix_nosym_temp(2)%matrix)
421  CALL dbcsr_add(dcdr_env%matrix_nosym_temp(1)%matrix, dcdr_env%matrix_nosym_temp(2)%matrix, &
422  -dcdr_env%ref_point(alpha), 1._dp)
423 
424  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%matrix_nosym_temp(1)%matrix, dcdr_env%dCR_prime(ispin), &
425  tmp_fm_like_mos, ncol=nmo)
426  CALL cp_fm_trace(mo_coeff, tmp_fm_like_mos, apt_coeff_derivative)
427 
428  apt_coeff_derivative = (-2._dp)*f_spin*apt_coeff_derivative
429  apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) &
430  = apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) + apt_coeff_derivative
431 
432  ! SECOND CONTRIBUTION: We assemble all combinations of r_i, d(chi)/d(idir)
433  ! difdip contains derivatives with respect to atom dcdr_env%lambda
434  ! difdip(alpha, beta): < a | r_alpha | db/dR_beta >
435  ! Multiply by the MO coefficients
436  CALL cp_fm_set_all(tmp_fm_like_mos, 0.0_dp)
437  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%matrix_difdip(alpha, dcdr_env%beta)%matrix, mo_coeff, &
438  tmp_fm_like_mos, ncol=nmo)
439  CALL cp_fm_trace(mo_coeff, tmp_fm_like_mos, apt_basis_derivative)
440 
441  ! The negative sign is due to dipole_deriv_ao computing the derivatives with respect to nuclear coordinates.
442  apt_basis_derivative = -f_spin*apt_basis_derivative
443  apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) = &
444  apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) + apt_basis_derivative
445  END DO ! alpha
446 
447  CALL cp_fm_release(tmp_fm_like_mos)
448  END DO !ispin
449 
450  ! Finally the nuclear contribution: nuclear charge * Kronecker_delta_{dcdr_env%beta,i}
451  CALL get_atomic_kind(particle_set(dcdr_env%lambda)%atomic_kind, kind_number=ikind)
452  CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost)
453  IF (.NOT. ghost) THEN
454  apt_nuc(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda) = &
455  apt_nuc(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda) + charge
456  END IF
457 
458  ! And deallocate all the things!
459  CALL cp_fm_release(tmp_fm_like_mos)
460  CALL cp_fm_release(overlap1_mo)
461 
462  CALL timestop(handle)
463  END SUBROUTINE apt_dr
464 
465 ! **************************************************************************************************
466 !> \brief Calculate atomic polar tensor using the localized dipole operator
467 !> \param qs_env ...
468 !> \param dcdr_env ...
469 !> \author Edward Ditler
470 ! **************************************************************************************************
471  SUBROUTINE apt_dr_localization(qs_env, dcdr_env)
472  TYPE(qs_environment_type), POINTER :: qs_env
473  TYPE(dcdr_env_type) :: dcdr_env
474 
475  CHARACTER(LEN=*), PARAMETER :: routinen = 'apt_dR_localization'
476 
477  INTEGER :: alpha, handle, i, icenter, ikind, ispin, &
478  map_atom, map_molecule, &
479  max_nbr_center, nao, natom, nmo, &
480  nsubset
481  INTEGER, ALLOCATABLE, DIMENSION(:) :: mapping_atom_molecule
482  INTEGER, ALLOCATABLE, DIMENSION(:, :) :: mapping_wannier_atom
483  LOGICAL :: ghost
484  REAL(dp) :: apt_basis_derivative, &
485  apt_coeff_derivative, charge, f_spin, &
486  smallest_r, this_factor, tmp_aptcontr, &
487  tmp_r
488  REAL(dp), ALLOCATABLE, DIMENSION(:) :: diagonal_elements
489  REAL(dp), DIMENSION(3) :: distance, r_shifted
490  REAL(dp), DIMENSION(:, :, :), POINTER :: apt_el, apt_nuc
491  REAL(dp), DIMENSION(:, :, :, :), POINTER :: apt_center, apt_subset
492  TYPE(cell_type), POINTER :: cell
493  TYPE(cp_2d_r_p_type), DIMENSION(:), POINTER :: centers_set
494  TYPE(cp_fm_type), POINTER :: mo_coeff, overlap1_mo, tmp_fm, &
495  tmp_fm_like_mos, tmp_fm_momo
496  TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
497  TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
498  TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
499 
500  CALL timeset(routinen, handle)
501 
502  NULLIFY (qs_kind_set, particle_set, molecule_set, cell)
503 
504  CALL get_qs_env(qs_env=qs_env, &
505  qs_kind_set=qs_kind_set, &
506  particle_set=particle_set, &
507  molecule_set=molecule_set, &
508  cell=cell)
509 
510  nsubset = SIZE(molecule_set)
511  natom = SIZE(particle_set)
512  apt_el => dcdr_env%apt_el_dcdr
513  apt_nuc => dcdr_env%apt_nuc_dcdr
514  apt_subset => dcdr_env%apt_el_dcdr_per_subset
515  apt_center => dcdr_env%apt_el_dcdr_per_center
516 
517  ! Map wannier functions to atoms
518  IF (dcdr_env%nspins == 1) THEN
519  max_nbr_center = dcdr_env%nbr_center(1)
520  ELSE
521  max_nbr_center = max(dcdr_env%nbr_center(1), dcdr_env%nbr_center(2))
522  END IF
523  ALLOCATE (mapping_wannier_atom(max_nbr_center, dcdr_env%nspins))
524  ALLOCATE (mapping_atom_molecule(natom))
525  centers_set => dcdr_env%centers_set
526 
527  DO ispin = 1, dcdr_env%nspins
528  DO icenter = 1, dcdr_env%nbr_center(ispin)
529  ! For every center we check which atom is closest
530  CALL shift_wannier_into_cell(r=centers_set(ispin)%array(1:3, icenter), &
531  cell=cell, &
532  r_shifted=r_shifted)
533 
534  smallest_r = huge(0._dp)
535  DO i = 1, natom
536  distance = pbc(r_shifted, particle_set(i)%r(1:3), cell)
537  tmp_r = sum(distance**2)
538  IF (tmp_r < smallest_r) THEN
539  mapping_wannier_atom(icenter, ispin) = i
540  smallest_r = tmp_r
541  END IF
542  END DO
543  END DO
544 
545  ! Map atoms to molecules
546  CALL molecule_of_atom(molecule_set, atom_to_mol=mapping_atom_molecule)
547  IF (dcdr_env%lambda == 1 .AND. dcdr_env%beta == 1) THEN
548  DO icenter = 1, dcdr_env%nbr_center(ispin)
549  map_atom = mapping_wannier_atom(icenter, ispin)
550  map_molecule = mapping_atom_molecule(map_atom)
551  END DO
552  END IF
553  END DO !ispin
554 
555  nao = dcdr_env%nao
556  f_spin = 2._dp/dcdr_env%nspins
557 
558  DO ispin = 1, dcdr_env%nspins
559  ! Compute S^(1,R)_(ij)
560 
561  ALLOCATE (tmp_fm_like_mos)
562  ALLOCATE (overlap1_mo)
563  CALL cp_fm_create(tmp_fm_like_mos, dcdr_env%likemos_fm_struct(ispin)%struct)
564  CALL cp_fm_create(overlap1_mo, dcdr_env%momo_fm_struct(ispin)%struct)
565  nmo = dcdr_env%nmo(ispin)
566  mo_coeff => dcdr_env%mo_coeff(ispin)
567  CALL cp_fm_set_all(tmp_fm_like_mos, 0.0_dp)
568  CALL cp_fm_scale_and_add(0._dp, dcdr_env%dCR_prime(ispin), 1._dp, dcdr_env%dCR(ispin))
569  CALL cp_dbcsr_sm_fm_multiply(dcdr_env%matrix_s1(dcdr_env%beta + 1)%matrix, mo_coeff, &
570  tmp_fm_like_mos, ncol=nmo)
571  CALL parallel_gemm("T", "N", nmo, nmo, nao, &
572  1.0_dp, mo_coeff, tmp_fm_like_mos, &
573  0.0_dp, overlap1_mo)
574 
575  ! C^1 <- -dCR - 0.5 * mo_coeff @ S1_ij
576  ! We get the negative of the coefficients out of the linres solver
577  ! And apply the constant correction due to the overlap derivative.
578  CALL parallel_gemm("N", "N", nao, nmo, nmo, &
579  -0.5_dp, mo_coeff, overlap1_mo, &
580  -1.0_dp, dcdr_env%dCR_prime(ispin))
581  CALL cp_fm_release(overlap1_mo)
582 
583  ALLOCATE (diagonal_elements(nmo))
584 
585  ! Allocate temporary matrices
586  ALLOCATE (tmp_fm)
587  ALLOCATE (tmp_fm_momo)
588  CALL cp_fm_create(tmp_fm, dcdr_env%likemos_fm_struct(ispin)%struct)
589  CALL cp_fm_create(tmp_fm_momo, dcdr_env%momo_fm_struct(ispin)%struct)
590 
591  ! FIRST CONTRIBUTION: dCR * moments * mo
592  this_factor = -2._dp*f_spin
593  DO alpha = 1, 3
594  DO icenter = 1, dcdr_env%nbr_center(ispin)
595  CALL dbcsr_set(dcdr_env%moments(alpha)%matrix, 0.0_dp)
596  CALL build_local_moment_matrix(qs_env, dcdr_env%moments, 1, &
597  ref_point=centers_set(ispin)%array(1:3, icenter))
598  CALL multiply_localization(ao_matrix=dcdr_env%moments(alpha)%matrix, &
599  mo_coeff=dcdr_env%dCR_prime(ispin), work=tmp_fm, nmo=nmo, &
600  icenter=icenter, &
601  res=tmp_fm_like_mos)
602  END DO
603 
604  CALL parallel_gemm("T", "N", nmo, nmo, nao, &
605  1.0_dp, mo_coeff, tmp_fm_like_mos, &
606  0.0_dp, tmp_fm_momo)
607  CALL cp_fm_get_diag(tmp_fm_momo, diagonal_elements)
608 
609  DO icenter = 1, dcdr_env%nbr_center(ispin)
610  map_atom = mapping_wannier_atom(icenter, ispin)
611  map_molecule = mapping_atom_molecule(map_atom)
612  tmp_aptcontr = this_factor*diagonal_elements(icenter)
613 
614  apt_subset(dcdr_env%beta, alpha, dcdr_env%lambda, map_molecule) &
615  = apt_subset(dcdr_env%beta, alpha, dcdr_env%lambda, map_molecule) + tmp_aptcontr
616 
617  apt_center(dcdr_env%beta, alpha, dcdr_env%lambda, icenter) &
618  = apt_center(dcdr_env%beta, alpha, dcdr_env%lambda, icenter) + tmp_aptcontr
619  END DO
620 
621  apt_coeff_derivative = this_factor*sum(diagonal_elements)
622  apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) &
623  = apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) + apt_coeff_derivative
624  END DO
625 
626  ! SECOND CONTRIBUTION: We assemble all combinations of r_i, dphi/d(idir)
627  ! build part with AOs differentiated with respect to nuclear coordinates
628  ! difdip contains derivatives with respect to atom dcdr_env%lambda
629  ! difdip(alpha, beta): < a | r_alpha | d b/dR_beta >
630  this_factor = -f_spin
631  DO alpha = 1, 3
632  DO icenter = 1, dcdr_env%nbr_center(ispin)
633  ! Build the AO matrix with the right wannier center as reference point
634  CALL dbcsr_set(dcdr_env%matrix_difdip(1, dcdr_env%beta)%matrix, 0._dp)
635  CALL dbcsr_set(dcdr_env%matrix_difdip(2, dcdr_env%beta)%matrix, 0._dp)
636  CALL dbcsr_set(dcdr_env%matrix_difdip(3, dcdr_env%beta)%matrix, 0._dp)
637  CALL dipole_deriv_ao(qs_env, dcdr_env%matrix_difdip, dcdr_env%delta_basis_function, &
638  1, centers_set(ispin)%array(1:3, icenter))
639  CALL multiply_localization(ao_matrix=dcdr_env%matrix_difdip(alpha, dcdr_env%beta)%matrix, &
640  mo_coeff=mo_coeff, work=tmp_fm, nmo=nmo, &
641  icenter=icenter, &
642  res=tmp_fm_like_mos)
643  END DO ! icenter
644 
645  CALL parallel_gemm("T", "N", nmo, nmo, nao, &
646  1.0_dp, mo_coeff, tmp_fm_like_mos, &
647  0.0_dp, tmp_fm_momo)
648  CALL cp_fm_get_diag(tmp_fm_momo, diagonal_elements)
649 
650  DO icenter = 1, dcdr_env%nbr_center(ispin)
651  map_atom = mapping_wannier_atom(icenter, ispin)
652  map_molecule = mapping_atom_molecule(map_atom)
653  tmp_aptcontr = this_factor*diagonal_elements(icenter)
654 
655  apt_subset(dcdr_env%beta, alpha, dcdr_env%lambda, map_molecule) &
656  = apt_subset(dcdr_env%beta, alpha, dcdr_env%lambda, map_molecule) + tmp_aptcontr
657 
658  apt_center(dcdr_env%beta, alpha, dcdr_env%lambda, icenter) &
659  = apt_center(dcdr_env%beta, alpha, dcdr_env%lambda, icenter) + tmp_aptcontr
660  END DO
661 
662  ! The negative sign is due to dipole_deriv_ao computing the derivatives with respect to nuclear coordinates.
663  apt_basis_derivative = this_factor*sum(diagonal_elements)
664 
665  apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) &
666  = apt_el(dcdr_env%beta, alpha, dcdr_env%lambda) + apt_basis_derivative
667 
668  END DO ! alpha
669  DEALLOCATE (diagonal_elements)
670 
671  CALL cp_fm_release(tmp_fm)
672  CALL cp_fm_release(tmp_fm_like_mos)
673  CALL cp_fm_release(tmp_fm_momo)
674  DEALLOCATE (overlap1_mo)
675  DEALLOCATE (tmp_fm)
676  DEALLOCATE (tmp_fm_like_mos)
677  DEALLOCATE (tmp_fm_momo)
678  END DO !ispin
679 
680  ! Finally the nuclear contribution: nuclear charge * Kronecker_delta_{dcdr_env%beta,i}
681  CALL get_atomic_kind(particle_set(dcdr_env%lambda)%atomic_kind, kind_number=ikind)
682  CALL get_qs_kind(qs_kind_set(ikind), core_charge=charge, ghost=ghost)
683  IF (.NOT. ghost) THEN
684  apt_nuc(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda) = &
685  apt_nuc(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda) + charge
686 
687  map_molecule = mapping_atom_molecule(dcdr_env%lambda)
688  apt_subset(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda, map_molecule) &
689  = apt_subset(dcdr_env%beta, dcdr_env%beta, dcdr_env%lambda, map_molecule) + charge
690  END IF
691 
692  ! And deallocate all the things!
693 
694  CALL timestop(handle)
695  END SUBROUTINE apt_dr_localization
696 
697 END MODULE qs_dcdr
subroutine pbc(r, r_pbc, s, s_pbc, a, b, c, alpha, beta, gamma, debug, info, pbc0, h, hinv)
...
Definition: dumpdcd.F:1203
Define the atomic kind types and their sub types.
subroutine, public get_atomic_kind(atomic_kind, fist_potential, element_symbol, name, mass, kind_number, natom, atom_list, rcov, rvdw, z, qeff, apol, cpol, mm_radius, shell, shell_active, damping)
Get attributes of an atomic kind.
Handles all functions related to the CELL.
Definition: cell_types.F:15
various utilities that regard array of different kinds: output, allocation,... maybe it is not a good...
DBCSR operations in CP2K.
subroutine, public cp_dbcsr_sm_fm_multiply(matrix, fm_in, fm_out, ncol, alpha, beta)
multiply a dbcsr with a fm matrix
basic linear algebra operations for full matrices
subroutine, public cp_fm_scale_and_add(alpha, matrix_a, beta, matrix_b)
calc A <- alpha*A + beta*B optimized for alpha == 1.0 (just add beta*B) and beta == 0....
subroutine, public cp_fm_scale(alpha, matrix_a)
scales a matrix matrix_a = alpha * matrix_b
represent a full matrix distributed on many processors
Definition: cp_fm_types.F:15
subroutine, public cp_fm_get_diag(matrix, diag)
returns the diagonal elements of a fm
Definition: cp_fm_types.F:570
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
Definition: cp_fm_types.F:535
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp)
creates a new full matrix with the given structure
Definition: cp_fm_types.F:167
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
subroutine, public cp_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, on_file, mpi_io)
should be called after you finish working with a unit obtained with cp_print_key_unit_nr,...
objects that represent the structure of input sections and the data contained in an input section
recursive type(section_vals_type) function, pointer, public section_vals_get_subs_vals(section_vals, subsection_name, i_rep_section, can_return_null)
returns the values of the requested subsection
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Define the data structure for the molecule information.
subroutine, public molecule_of_atom(molecule_set, atom_to_mol)
finds for each atom the molecule it belongs to
basic linear algebra operations for full matrixes
Define the data structure for the particle information.
Calculate the derivatives of the MO coefficients wrt nuclear coordinates.
Definition: qs_dcdr_ao.F:13
subroutine, public core_dr(qs_env, dcdr_env)
Core Hamiltonian contributions to the operator (the pseudopotentials)
Definition: qs_dcdr_ao.F:399
subroutine, public apply_op_constant_term(qs_env, dcdr_env, overlap1)
Build the perturbed density matrix correction depending on the overlap derivative.
Definition: qs_dcdr_ao.F:117
subroutine, public vhxc_r_perturbed_basis_functions(qs_env, dcdr_env)
The derivatives of the basis functions over which the HXC potential is integrated,...
Definition: qs_dcdr_ao.F:632
subroutine, public hr_mult_by_delta_1d(matrix, qs_kind_set, basis_type, sab_nl, lambda, direction_Or)
Enforce that one of the basis functions in < a | O | b > is centered on atom lambda.
Definition: qs_dcdr_ao.F:703
subroutine, public d_vhxc_dr(qs_env, dcdr_env)
The derivatives of the basis functions going into the HXC potential wrt nuclear positions.
Definition: qs_dcdr_ao.F:504
subroutine, public d_core_charge_density_dr(qs_env, dcdr_env)
Calculate the derivative of the Hartree term due to the core charge density.
Definition: qs_dcdr_ao.F:327
Calculate the derivatives of the MO coefficients wrt nuclear coordinates.
Definition: qs_dcdr_utils.F:13
subroutine, public multiply_localization(ao_matrix, mo_coeff, work, nmo, icenter, res)
Multiply (ao_matrix @ mo_coeff) and store the column icenter in res.
subroutine, public dcdr_read_restart(qs_env, linres_section, vec, lambda, beta, tag)
Copied from linres_read_restart.
subroutine, public shift_wannier_into_cell(r, cell, r_shifted)
...
subroutine, public dcdr_write_restart(qs_env, linres_section, vec, lambda, beta, tag)
Copied from linres_write_restart.
Calculate the derivatives of the MO coefficients wrt nuclear coordinates.
Definition: qs_dcdr.F:13
subroutine, public prepare_per_atom(dcdr_env, qs_env)
Prepare the environment for a choice of lambda.
Definition: qs_dcdr.F:88
subroutine, public apt_dr_localization(qs_env, dcdr_env)
Calculate atomic polar tensor using the localized dipole operator.
Definition: qs_dcdr.F:472
subroutine, public apt_dr(qs_env, dcdr_env)
Calculate atomic polar tensor.
Definition: qs_dcdr.F:363
subroutine, public dcdr_response_dr(dcdr_env, p_env, qs_env)
Get the dC/dR by solving the Sternheimer equation, using the op_dR matrix.
Definition: qs_dcdr.F:259
subroutine, public dcdr_build_op_dr(dcdr_env, qs_env)
Build the operator for the position perturbation.
Definition: qs_dcdr.F:189
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, ecoul_1c, rho0_s_rs, rho0_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, WannierCentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, rhs)
Get the QUICKSTEP environment.
Define the quickstep kind type and their sub types.
Definition: qs_kind_types.F:23
subroutine, public get_qs_kind(qs_kind, basis_set, basis_type, ncgf, nsgf, all_potential, tnadd_potential, gth_potential, sgp_potential, upf_potential, se_parameter, dftb_parameter, xtb_parameter, dftb3_param, zeff, elec_conf, mao, lmax_dftb, alpha_core_charge, ccore_charge, core_charge, core_charge_radius, paw_proj_set, paw_atom, hard_radius, hard0_radius, max_rad_local, covalent_radius, vdw_radius, gpw_r3d_rs_type_forced, harmonics, max_iso_not0, max_s_harm, grid_atom, ngrid_ang, ngrid_rad, lmax_rho0, dft_plus_u_atom, l_of_dft_plus_u, n_of_dft_plus_u, u_minus_j, U_of_dft_plus_u, J_of_dft_plus_u, alpha_of_dft_plus_u, beta_of_dft_plus_u, J0_of_dft_plus_u, occupation_of_dft_plus_u, dispersion, bs_occupation, magnetization, no_optimize, addel, laddel, naddel, orbitals, max_scf, eps_scf, smear, u_ramping, u_minus_j_target, eps_u_ramping, init_u_ramping_each_scf, reltmat, ghost, floating, name, element_symbol, pao_basis_size, pao_potentials, pao_descriptors, nelec)
Get attributes of an atomic kind.
localize wavefunctions linear response scf
subroutine, public linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, iounit, should_stop)
scf loop to optimize the first order wavefunctions (psi1) given a perturbation as an operator applied...
Type definitiona for linear response calculations.
Definition and initialisation of the mo data type.
Definition: qs_mo_types.F:22
subroutine, public get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, uniform_occupation, kTS, mu, flexible_electron_count)
Get the components of a MO set data structure.
Definition: qs_mo_types.F:397
Calculates the moment integrals <a|r^m|b> and <a|r x d/dr|b>
Definition: qs_moments.F:14
subroutine, public build_local_moment_matrix(qs_env, moments, nmoments, ref_point, ref_points, basis_type)
...
Definition: qs_moments.F:558
subroutine, public dipole_deriv_ao(qs_env, difdip, deltaR, order, rcc)
...
Definition: qs_moments.F:3094
Define the neighbor list data types and the corresponding functionality.
basis types for the calculation of the perturbation of density theory.