(git:374b731)
Loading...
Searching...
No Matches
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
13MODULE qs_dcdr
14
16 USE cell_types, ONLY: cell_type,&
17 pbc
25 USE cp_fm_types, ONLY: cp_fm_create,&
35 USE dbcsr_api, ONLY: dbcsr_add,&
36 dbcsr_copy,&
37 dbcsr_desymmetrize,&
38 dbcsr_p_type,&
39 dbcsr_set
42 USE kinds, ONLY: dp
48 core_dr,&
50 d_vhxc_dr,&
59 USE qs_kind_types, ONLY: get_qs_kind,&
64 USE qs_mo_types, ONLY: get_mo_set,&
70#include "./base/base_uses.f90"
71
72 IMPLICIT NONE
73
74 PRIVATE
76
77 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dcdr'
78
79CONTAINS
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
697END MODULE qs_dcdr
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
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
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp)
creates a new full matrix with the given structure
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 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 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 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.
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.
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.
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)
...
Define the neighbor list data types and the corresponding functionality.
basis types for the calculation of the perturbation of density theory.
Type defining parameters related to the simulation cell.
Definition cell_types.F:55
represent a pointer to a 2d array
represent a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...
Provides all information about a quickstep kind.
General settings for linear response calculations.
Represent a qs system that is perturbed. Can calculate the linear operator and the rhs of the system ...