(git:6344619)
Loading...
Searching...
No Matches
qmmm_image_charge.F
Go to the documentation of this file.
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 Routines for image charge calculation within QM/MM
10!> \par History
11!> 12.2011 created
12!> \author Dorothea Golze
13! **************************************************************************************************
16 USE cell_types, ONLY: cell_type,&
17 pbc
21 USE cp_files, ONLY: close_file,&
25 USE cp_output_handling, ONLY: cp_p_file,&
31 USE input_constants, ONLY: calc_always,&
32 calc_once,&
39 USE kinds, ONLY: default_path_length,&
40 dp
41 USE mathconstants, ONLY: pi
42 USE mathlib, ONLY: invmat_symm
45 USE pw_env_types, ONLY: pw_env_get,&
47 USE pw_methods, ONLY: pw_axpy,&
49 pw_scale,&
55 USE pw_types, ONLY: pw_c1d_gs_type,&
63 USE qs_integrate_potential, ONLY: integrate_pgf_product
67 USE util, ONLY: get_limit
68 USE virial_types, ONLY: virial_type
69#include "./base/base_uses.f90"
70
71 IMPLICIT NONE
72 PRIVATE
73
74 LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .true.
75 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qmmm_image_charge'
76
77 PUBLIC :: calculate_image_pot, &
82
83!***
84CONTAINS
85! **************************************************************************************************
86!> \brief determines coefficients by solving image_matrix*coeff=-pot_const by
87!> Gaussian elimination or in an iterative fashion and calculates
88!> image/metal potential with these coefficients
89!> \param v_hartree_rspace Hartree potential in real space
90!> \param rho_hartree_gspace Kohn Sham density in reciprocal space
91!> \param energy structure where energies are stored
92!> \param qmmm_env qmmm environment
93!> \param qs_env qs environment
94! **************************************************************************************************
95 SUBROUTINE calculate_image_pot(v_hartree_rspace, rho_hartree_gspace, energy, &
96 qmmm_env, qs_env)
97
98 TYPE(pw_r3d_rs_type), INTENT(IN) :: v_hartree_rspace
99 TYPE(pw_c1d_gs_type), INTENT(IN) :: rho_hartree_gspace
100 TYPE(qs_energy_type), POINTER :: energy
101 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
102 TYPE(qs_environment_type), POINTER :: qs_env
103
104 CHARACTER(LEN=*), PARAMETER :: routinen = 'calculate_image_pot'
105
106 INTEGER :: handle
107
108 CALL timeset(routinen, handle)
109
110 IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
111 !calculate preconditioner matrix for CG if necessary
112 IF (qs_env%calc_image_preconditioner) THEN
113 IF (qmmm_env%image_charge_pot%image_restart) THEN
114 CALL restart_image_matrix(image_matrix=qs_env%image_matrix, &
115 qs_env=qs_env, qmmm_env=qmmm_env)
116 ELSE
117 CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
118 qs_env=qs_env, qmmm_env=qmmm_env)
119 END IF
120 END IF
121 CALL calc_image_coeff_iterative(v_hartree_rspace=v_hartree_rspace, &
122 coeff=qs_env%image_coeff, qmmm_env=qmmm_env, &
123 qs_env=qs_env)
124
125 ELSE
126 CALL calc_image_coeff_gaussalgorithm(v_hartree_rspace=v_hartree_rspace, &
127 coeff=qs_env%image_coeff, qmmm_env=qmmm_env, &
128 qs_env=qs_env)
129 END IF
130
131 ! calculate the image/metal potential with the optimized coefficients
132 ALLOCATE (qs_env%ks_qmmm_env%v_metal_rspace)
133 CALL calculate_potential_metal(v_metal_rspace= &
134 qs_env%ks_qmmm_env%v_metal_rspace, coeff=qs_env%image_coeff, &
135 rho_hartree_gspace=rho_hartree_gspace, &
136 energy=energy, qs_env=qs_env)
137
138 CALL timestop(handle)
139
140 END SUBROUTINE calculate_image_pot
141
142! **************************************************************************************************
143!> \brief determines coefficients by solving the linear set of equations
144!> image_matrix*coeff=-pot_const using a Gaussian elimination scheme
145!> \param v_hartree_rspace Hartree potential in real space
146!> \param coeff expansion coefficients of the image charge density, i.e.
147!> rho_metal=sum_a c_a*g_a
148!> \param qmmm_env qmmm environment
149!> \param qs_env qs environment
150! **************************************************************************************************
151 SUBROUTINE calc_image_coeff_gaussalgorithm(v_hartree_rspace, coeff, qmmm_env, &
152 qs_env)
153
154 TYPE(pw_r3d_rs_type), INTENT(IN) :: v_hartree_rspace
155 REAL(kind=dp), DIMENSION(:), POINTER :: coeff
156 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
157 TYPE(qs_environment_type), POINTER :: qs_env
158
159 CHARACTER(LEN=*), PARAMETER :: routinen = 'calc_image_coeff_gaussalgorithm'
160
161 INTEGER :: handle, info, natom
162 REAL(kind=dp) :: eta, v0
163 REAL(kind=dp), DIMENSION(:), POINTER :: pot_const
164
165 CALL timeset(routinen, handle)
166
167 NULLIFY (pot_const)
168
169 !minus sign V0: account for the fact that v_hartree has the opposite sign
170 v0 = -qmmm_env%image_charge_pot%V0
171 eta = qmmm_env%image_charge_pot%eta
172 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
173
174 ALLOCATE (pot_const(natom))
175 IF (.NOT. ASSOCIATED(coeff)) THEN
176 ALLOCATE (coeff(natom))
177 END IF
178 coeff = 0.0_dp
179
180 CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
181 pot_const)
182 !add integral V0*ga(r)
183 pot_const(:) = -pot_const(:) + v0*sqrt((pi/eta)**3)
184
185 !solve linear system of equations T*coeff=-pot_const
186 !LU factorization of T by DGETRF done in calculate_image_matrix
187 CALL dgetrs('N', natom, 1, qs_env%image_matrix, natom, qs_env%ipiv, &
188 pot_const, natom, info)
189 cpassert(info == 0)
190
191 coeff = pot_const
192
193 DEALLOCATE (pot_const)
194
195 CALL timestop(handle)
196
197 END SUBROUTINE calc_image_coeff_gaussalgorithm
198
199! **************************************************************************************************
200!> \brief determines image coefficients iteratively
201!> \param v_hartree_rspace Hartree potential in real space
202!> \param coeff expansion coefficients of the image charge density, i.e.
203!> rho_metal=sum_a c_a*g_a
204!> \param qmmm_env qmmm environment
205!> \param qs_env qs environment
206! **************************************************************************************************
207 SUBROUTINE calc_image_coeff_iterative(v_hartree_rspace, coeff, qmmm_env, &
208 qs_env)
209
210 TYPE(pw_r3d_rs_type), INTENT(IN) :: v_hartree_rspace
211 REAL(kind=dp), DIMENSION(:), POINTER :: coeff
212 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
213 TYPE(qs_environment_type), POINTER :: qs_env
214
215 CHARACTER(LEN=*), PARAMETER :: routinen = 'calc_image_coeff_iterative'
216 REAL(kind=dp), PARAMETER :: eps_rsnew = 1.0e-16_dp
217
218 INTEGER :: handle, iter_steps, natom, output_unit
219 REAL(kind=dp) :: alpha, eta, rsnew, rsold, v0
220 REAL(kind=dp), DIMENSION(:), POINTER :: ad, d, pot_const, r, vmetal_const, z
221 TYPE(cp_logger_type), POINTER :: logger
222 TYPE(pw_r3d_rs_type) :: auxpot_ad_rspace, v_metal_rspace_guess
223 TYPE(section_vals_type), POINTER :: input
224
225 CALL timeset(routinen, handle)
226
227 NULLIFY (pot_const, vmetal_const, logger, input)
228 logger => cp_get_default_logger()
229
230 !minus sign V0: account for the fact that v_hartree has the opposite sign
231 v0 = -qmmm_env%image_charge_pot%V0
232 eta = qmmm_env%image_charge_pot%eta
233 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
234
235 ALLOCATE (pot_const(natom))
236 ALLOCATE (vmetal_const(natom))
237 ALLOCATE (r(natom))
238 ALLOCATE (d(natom))
239 ALLOCATE (z(natom))
240 ALLOCATE (ad(natom))
241 IF (.NOT. ASSOCIATED(coeff)) THEN
242 ALLOCATE (coeff(natom))
243 END IF
244
245 CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
246 pot_const)
247
248 !add integral V0*ga(r)
249 pot_const(:) = -pot_const(:) + v0*sqrt((pi/eta)**3)
250
251 !initial guess for coeff
252 coeff = 1.0_dp
253 d = 0.0_dp
254 z = 0.0_dp
255 r = 0.0_dp
256 rsold = 0.0_dp
257 rsnew = 0.0_dp
258 iter_steps = 0
259
260 !calculate first guess of image/metal potential
261 CALL calculate_potential_metal(v_metal_rspace=v_metal_rspace_guess, &
262 coeff=coeff, qs_env=qs_env)
263 CALL integrate_potential_ga_rspace(potential=v_metal_rspace_guess, &
264 qmmm_env=qmmm_env, qs_env=qs_env, int_res=vmetal_const)
265
266 ! modify coefficients iteratively
267 r = pot_const - vmetal_const
268 z = matmul(qs_env%image_matrix, r)
269 d = z
270 rsold = dot_product(r, z)
271
272 DO
273 !calculate A*d
274 ad = 0.0_dp
275 CALL calculate_potential_metal(v_metal_rspace= &
276 auxpot_ad_rspace, coeff=d, qs_env=qs_env)
277 CALL integrate_potential_ga_rspace(potential= &
278 auxpot_ad_rspace, qmmm_env=qmmm_env, &
279 qs_env=qs_env, int_res=ad)
280
281 alpha = rsold/dot_product(d, ad)
282 coeff = coeff + alpha*d
283
284 r = r - alpha*ad
285 z = matmul(qs_env%image_matrix, r)
286 rsnew = dot_product(r, z)
287 iter_steps = iter_steps + 1
288 ! SQRT(rsnew) < 1.0E-08
289 IF (rsnew < eps_rsnew) THEN
290 CALL auxpot_ad_rspace%release()
291 EXIT
292 END IF
293 d = z + rsnew/rsold*d
294 rsold = rsnew
295 CALL auxpot_ad_rspace%release()
296 END DO
297
298 ! print iteration info
299 CALL get_qs_env(qs_env=qs_env, &
300 input=input)
301 output_unit = cp_print_key_unit_nr(logger, input, &
302 "QMMM%PRINT%PROGRAM_RUN_INFO", &
303 extension=".qmmmLog")
304 IF (output_unit > 0) WRITE (unit=output_unit, fmt="(T3,A,T74,I7)") &
305 "Number of iteration steps for determination of image coefficients:", iter_steps
306 CALL cp_print_key_finished_output(output_unit, logger, input, &
307 "QMMM%PRINT%PROGRAM_RUN_INFO")
308
309 IF (iter_steps < 25) THEN
310 qs_env%calc_image_preconditioner = .false.
311 ELSE
312 qs_env%calc_image_preconditioner = .true.
313 END IF
314
315 CALL v_metal_rspace_guess%release()
316 DEALLOCATE (pot_const)
317 DEALLOCATE (vmetal_const)
318 DEALLOCATE (r)
319 DEALLOCATE (d, z)
320 DEALLOCATE (ad)
321
322 CALL timestop(handle)
323
324 END SUBROUTINE calc_image_coeff_iterative
325
326! ****************************************************************************
327!> \brief calculates the integral V(r)*ga(r)
328!> \param potential any potential
329!> \param qmmm_env qmmm environment
330!> \param qs_env qs environment
331!> \param int_res result of the integration
332!> \param atom_num atom index, needed when calculating image_matrix
333!> \param atom_num_ref index of reference atom, needed when calculating
334!> image_matrix
335! **************************************************************************************************
336 SUBROUTINE integrate_potential_ga_rspace(potential, qmmm_env, qs_env, int_res, &
337 atom_num, atom_num_ref)
338
339 TYPE(pw_r3d_rs_type), INTENT(IN) :: potential
340 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
341 TYPE(qs_environment_type), POINTER :: qs_env
342 REAL(kind=dp), DIMENSION(:), POINTER :: int_res
343 INTEGER, INTENT(IN), OPTIONAL :: atom_num, atom_num_ref
344
345 CHARACTER(LEN=*), PARAMETER :: routinen = 'integrate_potential_ga_rspace'
346
347 INTEGER :: atom_a, atom_b, atom_ref, handle, iatom, &
348 j, k, natom, npme
349 INTEGER, DIMENSION(:), POINTER :: cores
350 REAL(kind=dp) :: eps_rho_rspace, radius
351 REAL(kind=dp), DIMENSION(3) :: ra
352 REAL(kind=dp), DIMENSION(:, :), POINTER :: hab
353 TYPE(cell_type), POINTER :: cell
354 TYPE(dft_control_type), POINTER :: dft_control
355 TYPE(mp_para_env_type), POINTER :: para_env
356 TYPE(pw_env_type), POINTER :: pw_env
357 TYPE(realspace_grid_desc_type), POINTER :: auxbas_rs_desc
358 TYPE(realspace_grid_type), POINTER :: rs_v
359
360 CALL timeset(routinen, handle)
361
362 NULLIFY (cores, hab, cell, auxbas_rs_desc, pw_env, para_env, &
363 dft_control, rs_v)
364 ALLOCATE (hab(1, 1))
365
366 CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
367 CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
368 auxbas_rs_grid=rs_v)
369 CALL transfer_pw2rs(rs_v, potential)
370
371 CALL get_qs_env(qs_env=qs_env, &
372 cell=cell, &
373 dft_control=dft_control, &
374 para_env=para_env, pw_env=pw_env)
375
376 eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
377
378 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
379 k = 1
380 IF (PRESENT(atom_num)) k = atom_num
381
382 CALL reallocate(cores, 1, natom - k + 1)
383 int_res = 0.0_dp
384 npme = 0
385 cores = 0
386
387 DO iatom = k, natom
388 IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
389 ! replicated realspace grid, split the atoms up between procs
390 IF (modulo(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
391 npme = npme + 1
392 cores(npme) = iatom
393 END IF
394 ELSE
395 npme = npme + 1
396 cores(npme) = iatom
397 END IF
398 END DO
399
400 DO j = 1, npme
401
402 iatom = cores(j)
403 atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
404
405 IF (PRESENT(atom_num) .AND. PRESENT(atom_num_ref)) THEN
406 ! shift the function since potential only calculate for ref atom
407 atom_b = qmmm_env%image_charge_pot%image_mm_list(k)
408 atom_ref = qmmm_env%image_charge_pot%image_mm_list(atom_num_ref)
409 ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell) &
410 - pbc(qmmm_env%image_charge_pot%particles_all(atom_b)%r, cell) &
411 + pbc(qmmm_env%image_charge_pot%particles_all(atom_ref)%r, cell)
412
413 ELSE
414 ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
415 END IF
416
417 hab(1, 1) = 0.0_dp
418
419 radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
420 ra=ra, rb=ra, rp=ra, &
421 zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
422 prefactor=1.0_dp, cutoff=1.0_dp)
423
424 CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
425 0, 0.0_dp, 0, ra, [0.0_dp, 0.0_dp, 0.0_dp], &
426 rs_v, hab, o1=0, o2=0, &
427 radius=radius, calculate_forces=.false., &
428 use_subpatch=.true., subpatch_pattern=0)
429
430 int_res(iatom) = hab(1, 1)
431
432 END DO
433
434 CALL para_env%sum(int_res)
435
436 DEALLOCATE (hab, cores)
437
438 CALL timestop(handle)
439
440 END SUBROUTINE integrate_potential_ga_rspace
441
442! **************************************************************************************************
443!> \brief calculates the image forces on the MM atoms
444!> \param potential any potential, in this case: Hartree potential
445!> \param coeff expansion coefficients of the image charge density, i.e.
446!> rho_metal=sum_a c_a*g_a
447!> \param forces structure storing the force contribution of the image charges
448!> for the metal (MM) atoms
449!> \param qmmm_env qmmm environment
450!> \param qs_env qs environment
451! **************************************************************************************************
452 SUBROUTINE integrate_potential_devga_rspace(potential, coeff, forces, qmmm_env, &
453 qs_env)
454
455 TYPE(pw_r3d_rs_type), INTENT(IN) :: potential
456 REAL(kind=dp), DIMENSION(:), POINTER :: coeff
457 REAL(kind=dp), DIMENSION(:, :), POINTER :: forces
458 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
459 TYPE(qs_environment_type), POINTER :: qs_env
460
461 CHARACTER(LEN=*), PARAMETER :: routinen = 'integrate_potential_devga_rspace'
462
463 INTEGER :: atom_a, handle, iatom, j, natom, npme
464 INTEGER, DIMENSION(:), POINTER :: cores
465 LOGICAL :: use_virial
466 REAL(kind=dp) :: eps_rho_rspace, radius
467 REAL(kind=dp), DIMENSION(3) :: force_a, force_b, ra
468 REAL(kind=dp), DIMENSION(:, :), POINTER :: hab, pab
469 TYPE(cell_type), POINTER :: cell
470 TYPE(dft_control_type), POINTER :: dft_control
471 TYPE(mp_para_env_type), POINTER :: para_env
472 TYPE(pw_env_type), POINTER :: pw_env
473 TYPE(realspace_grid_desc_type), POINTER :: auxbas_rs_desc
474 TYPE(realspace_grid_type), POINTER :: rs_v
475 TYPE(virial_type), POINTER :: virial
476
477 CALL timeset(routinen, handle)
478
479 NULLIFY (cores, hab, pab, cell, auxbas_rs_desc, pw_env, para_env, &
480 dft_control, rs_v, virial)
481 use_virial = .false.
482
483 ALLOCATE (hab(1, 1))
484 ALLOCATE (pab(1, 1))
485
486 CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
487 CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
488 auxbas_rs_grid=rs_v)
489 CALL transfer_pw2rs(rs_v, potential)
490
491 CALL get_qs_env(qs_env=qs_env, &
492 cell=cell, &
493 dft_control=dft_control, &
494 para_env=para_env, pw_env=pw_env, &
495 virial=virial)
496
497 use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
498
499 IF (use_virial) THEN
500 cpabort("Virial not implemented for image charge method")
501 END IF
502
503 eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
504
505 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
506
507 IF (.NOT. ASSOCIATED(forces)) THEN
508 ALLOCATE (forces(3, natom))
509 END IF
510
511 forces(:, :) = 0.0_dp
512
513 CALL reallocate(cores, 1, natom)
514 npme = 0
515 cores = 0
516
517 DO iatom = 1, natom
518 IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
519 ! replicated realspace grid, split the atoms up between procs
520 IF (modulo(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
521 npme = npme + 1
522 cores(npme) = iatom
523 END IF
524 ELSE
525 npme = npme + 1
526 cores(npme) = iatom
527 END IF
528 END DO
529
530 DO j = 1, npme
531
532 iatom = cores(j)
533 atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
534 ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
535 hab(1, 1) = 0.0_dp
536 pab(1, 1) = 1.0_dp
537 force_a(:) = 0.0_dp
538 force_b(:) = 0.0_dp
539
540 radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
541 ra=ra, rb=ra, rp=ra, &
542 zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
543 pab=pab, o1=0, o2=0, & ! without map_consistent
544 prefactor=1.0_dp, cutoff=1.0_dp)
545
546 CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
547 0, 0.0_dp, 0, ra, [0.0_dp, 0.0_dp, 0.0_dp], &
548 rs_v, hab, pab, o1=0, o2=0, &
549 radius=radius, calculate_forces=.true., &
550 force_a=force_a, force_b=force_b, use_subpatch=.true., &
551 subpatch_pattern=0)
552
553 force_a(:) = coeff(iatom)*force_a(:)
554 forces(:, iatom) = force_a(:)
555
556 END DO
557
558 CALL para_env%sum(forces)
559
560 DEALLOCATE (hab, pab, cores)
561
562 ! print info on gradients if wanted
563 CALL print_gradients_image_atoms(forces, qs_env)
564
565 CALL timestop(handle)
566
568
569!****************************************************************************
570!> \brief calculate image matrix T depending on constraints on image atoms
571!> in case coefficients are estimated not iteratively
572!> \param qs_env qs environment
573!> \param qmmm_env qmmm environment
574! **************************************************************************************************
575 SUBROUTINE conditional_calc_image_matrix(qs_env, qmmm_env)
576
577 TYPE(qs_environment_type), POINTER :: qs_env
578 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
579
580 IF (.NOT. qmmm_env%image_charge_pot%coeff_iterative) THEN
581 SELECT CASE (qmmm_env%image_charge_pot%state_image_matrix)
582 CASE (calc_always)
583 CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
584 ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
585 CASE (calc_once)
586 !if all image atoms are fully constrained, calculate image matrix
587 !only for the first MD or GEO_OPT step
588 CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
589 ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
590 qmmm_env%image_charge_pot%state_image_matrix = calc_once_done
591 IF (qmmm_env%center_qm_subsys0) THEN
592 CALL cp_warn(__location__, &
593 "The image atoms are fully "// &
594 "constrained and the image matrix is only calculated once. "// &
595 "To be safe, set CENTER to NEVER ")
596 END IF
597 CASE (calc_once_done)
598 ! do nothing image matrix is stored
599 CASE DEFAULT
600 cpabort("No initialization for image charges available?")
601 END SELECT
602 END IF
603
604 END SUBROUTINE conditional_calc_image_matrix
605
606!****************************************************************************
607!> \brief calculate image matrix T
608!> \param image_matrix matrix T
609!> \param ipiv pivoting prior to DGETRS (for Gaussian elimination)
610!> \param qs_env qs environment
611!> \param qmmm_env qmmm environment
612! **************************************************************************************************
613 SUBROUTINE calculate_image_matrix(image_matrix, ipiv, qs_env, qmmm_env)
614
615 REAL(kind=dp), DIMENSION(:, :), POINTER :: image_matrix
616 INTEGER, DIMENSION(:), OPTIONAL, POINTER :: ipiv
617 TYPE(qs_environment_type), POINTER :: qs_env
618 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
619
620 CHARACTER(LEN=*), PARAMETER :: routinen = 'calculate_image_matrix'
621
622 INTEGER :: handle, natom, output_unit, stat
623 TYPE(cp_logger_type), POINTER :: logger
624 TYPE(section_vals_type), POINTER :: input
625
626 CALL timeset(routinen, handle)
627 NULLIFY (input, logger)
628
629 logger => cp_get_default_logger()
630
631 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
632
633 IF (.NOT. ASSOCIATED(image_matrix)) THEN
634 ALLOCATE (image_matrix(natom, natom))
635 END IF
636 IF (PRESENT(ipiv)) THEN
637 IF (.NOT. ASSOCIATED(ipiv)) THEN
638 ALLOCATE (ipiv(natom))
639 END IF
640 ipiv = 0
641 END IF
642
643 CALL get_qs_env(qs_env, input=input)
644 !print info
645 output_unit = cp_print_key_unit_nr(logger, input, &
646 "QMMM%PRINT%PROGRAM_RUN_INFO", &
647 extension=".qmmmLog")
648 IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
649 IF (output_unit > 0) WRITE (unit=output_unit, fmt="(T3,A)") &
650 "Calculating image matrix"
651 ELSE
652 IF (output_unit > 0) WRITE (unit=output_unit, fmt="(T2,A)") &
653 "Calculating image matrix"
654 END IF
655 CALL cp_print_key_finished_output(output_unit, logger, input, &
656 "QMMM%PRINT%PROGRAM_RUN_INFO")
657
658 ! Calculate image matrix using either GPW or MME method
659 SELECT CASE (qmmm_env%image_charge_pot%image_matrix_method)
660 CASE (do_eri_gpw)
661 CALL calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
662 CASE (do_eri_mme)
663 CALL calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
664 CASE DEFAULT
665 cpabort("Unknown method for calculating image matrix")
666 END SELECT
667
668 IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
669 !inversion --> preconditioner matrix for CG
670 CALL invmat_symm(qs_env%image_matrix)
671 CALL write_image_matrix(qs_env%image_matrix, qs_env)
672 ELSE
673 !pivoting prior to DGETRS (Gaussian elimination)
674 IF (PRESENT(ipiv)) THEN
675 CALL dgetrf(natom, natom, image_matrix, natom, ipiv, stat)
676 cpassert(stat == 0)
677 END IF
678 END IF
679
680 CALL timestop(handle)
681
682 END SUBROUTINE calculate_image_matrix
683
684! **************************************************************************************************
685!> \brief calculate image matrix T using GPW method
686!> \param image_matrix matrix T
687!> \param qs_env qs environment
688!> \param qmmm_env qmmm environment
689! **************************************************************************************************
690 SUBROUTINE calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
691 REAL(kind=dp), DIMENSION(:, :), POINTER :: image_matrix
692 TYPE(qs_environment_type), POINTER :: qs_env
693 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
694
695 CHARACTER(LEN=*), PARAMETER :: routinen = 'calculate_image_matrix_gpw'
696
697 INTEGER :: handle, iatom, iatom_ref, natom
698 REAL(kind=dp), DIMENSION(:), POINTER :: int_res
699 TYPE(mp_para_env_type), POINTER :: para_env
700 TYPE(pw_c1d_gs_type) :: rho_gb, vb_gspace
701 TYPE(pw_env_type), POINTER :: pw_env
702 TYPE(pw_poisson_type), POINTER :: poisson_env
703 TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
704 TYPE(pw_r3d_rs_type) :: vb_rspace
705
706 CALL timeset(routinen, handle)
707 NULLIFY (pw_env, auxbas_pw_pool, poisson_env, para_env, int_res)
708
709 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
710 ALLOCATE (int_res(natom))
711
712 image_matrix = 0.0_dp
713
714 CALL get_qs_env(qs_env, pw_env=pw_env, para_env=para_env)
715
716 CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
717 poisson_env=poisson_env)
718 CALL auxbas_pw_pool%create_pw(rho_gb)
719 CALL auxbas_pw_pool%create_pw(vb_gspace)
720 CALL auxbas_pw_pool%create_pw(vb_rspace)
721
722 ! calculate vb only once for one reference atom
723 iatom_ref = 1 !
724 !collocate gaussian of reference MM atom on grid
725 CALL pw_zero(rho_gb)
726 CALL calculate_rho_single_gaussian(rho_gb, qs_env, iatom_ref)
727 !calculate potential vb like hartree potential
728 CALL pw_zero(vb_gspace)
729 CALL pw_poisson_solve(poisson_env, rho_gb, vhartree=vb_gspace)
730 CALL pw_zero(vb_rspace)
731 CALL pw_transfer(vb_gspace, vb_rspace)
732 CALL pw_scale(vb_rspace, vb_rspace%pw_grid%dvol)
733
734 DO iatom = 1, natom
735 !calculate integral vb_rspace*ga
736 int_res = 0.0_dp
737 CALL integrate_potential_ga_rspace(vb_rspace, qs_env%qmmm_env_qm, &
738 qs_env, int_res, atom_num=iatom, &
739 atom_num_ref=iatom_ref)
740 image_matrix(iatom, iatom:natom) = int_res(iatom:natom)
741 image_matrix(iatom + 1:natom, iatom) = int_res(iatom + 1:natom)
742 END DO
743
744 CALL vb_gspace%release()
745 CALL vb_rspace%release()
746 CALL rho_gb%release()
747
748 DEALLOCATE (int_res)
749
750 CALL timestop(handle)
751 END SUBROUTINE calculate_image_matrix_gpw
752
753! **************************************************************************************************
754!> \brief calculate image matrix T using MME (MiniMax-Ewald) method
755!> \param image_matrix matrix T
756!> \param qs_env qs environment
757!> \param qmmm_env qmmm environment
758! **************************************************************************************************
759 SUBROUTINE calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
760 REAL(kind=dp), DIMENSION(:, :), POINTER :: image_matrix
761 TYPE(qs_environment_type), POINTER :: qs_env
762 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
763
764 CHARACTER(LEN=*), PARAMETER :: routinen = 'calculate_image_matrix_mme'
765
766 INTEGER :: atom_a, handle, iatom, natom
767 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: zeta
768 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: ra
769 TYPE(mp_para_env_type), POINTER :: para_env
770
771 CALL timeset(routinen, handle)
772 NULLIFY (para_env)
773
774 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
775 ALLOCATE (zeta(natom), ra(3, natom))
776
777 zeta(:) = qmmm_env%image_charge_pot%eta
778
779 DO iatom = 1, natom
780 atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
781 ra(:, iatom) = qmmm_env%image_charge_pot%particles_all(atom_a)%r(:)
782 END DO
783
784 CALL get_qs_env(qs_env, para_env=para_env)
785
786 CALL integrate_s_mme(qmmm_env%image_charge_pot%eri_mme_param, &
787 zeta, zeta, ra, ra, image_matrix, para_env)
788
789 CALL timestop(handle)
790 END SUBROUTINE calculate_image_matrix_mme
791
792! **************************************************************************************************
793!> \brief high-level integration routine for 2c integrals over s-type functions.
794!> Parallelization over pairs of functions.
795!> \param param ...
796!> \param zeta ...
797!> \param zetb ...
798!> \param ra ...
799!> \param rb ...
800!> \param hab ...
801!> \param para_env ...
802! **************************************************************************************************
803 SUBROUTINE integrate_s_mme(param, zeta, zetb, ra, rb, hab, para_env)
804 TYPE(cp_eri_mme_param), INTENT(INOUT) :: param
805 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: zeta, zetb
806 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ra, rb
807 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: hab
808 TYPE(mp_para_env_type), INTENT(IN), POINTER :: para_env
809
810 CHARACTER(len=*), PARAMETER :: routinen = 'integrate_s_mme'
811
812 INTEGER :: g_count, handle, ipgf, ipgf_prod, jpgf, &
813 npgf_prod, npgfa, npgfb, r_count
814 INTEGER, DIMENSION(2) :: limits
815 REAL(kind=dp), DIMENSION(3) :: rab
816
817 CALL timeset(routinen, handle)
818 g_count = 0; r_count = 0
819
820 hab(:, :) = 0.0_dp
821
822 npgfa = SIZE(zeta)
823 npgfb = SIZE(zetb)
824 npgf_prod = npgfa*npgfb ! total number of integrals
825
826 limits = get_limit(npgf_prod, para_env%num_pe, para_env%mepos)
827
828 DO ipgf_prod = limits(1), limits(2)
829 ipgf = (ipgf_prod - 1)/npgfb + 1
830 jpgf = mod(ipgf_prod - 1, npgfb) + 1
831 rab(:) = ra(:, ipgf) - rb(:, jpgf)
832 CALL eri_mme_2c_integrate(param%par, 0, 0, 0, 0, zeta(ipgf), &
833 zetb(jpgf), rab, hab, ipgf - 1, jpgf - 1, g_count=g_count, r_count=r_count)
834 END DO
835
836 CALL cp_eri_mme_update_local_counts(param, para_env, g_count_2c=g_count, r_count_2c=r_count)
837 CALL para_env%sum(hab)
838 CALL timestop(handle)
839
840 END SUBROUTINE integrate_s_mme
841
842! **************************************************************************************************
843!> \brief calculates potential of the metal (image potential) given a set of
844!> coefficients coeff
845!> \param v_metal_rspace potential generated by rho_metal in real space
846!> \param coeff expansion coefficients of the image charge density, i.e.
847!> rho_metal=sum_a c_a*g_a
848!> \param rho_hartree_gspace Kohn Sham density in reciprocal space
849!> \param energy structure where energies are stored
850!> \param qs_env qs environment
851! **************************************************************************************************
852 SUBROUTINE calculate_potential_metal(v_metal_rspace, coeff, rho_hartree_gspace, energy, &
853 qs_env)
854
855 TYPE(pw_r3d_rs_type), INTENT(OUT) :: v_metal_rspace
856 REAL(kind=dp), DIMENSION(:), POINTER :: coeff
857 TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL :: rho_hartree_gspace
858 TYPE(qs_energy_type), OPTIONAL, POINTER :: energy
859 TYPE(qs_environment_type), POINTER :: qs_env
860
861 CHARACTER(len=*), PARAMETER :: routinen = 'calculate_potential_metal'
862
863 INTEGER :: handle
864 REAL(kind=dp) :: en_external, en_vmetal_rhohartree, &
865 total_rho_metal
866 TYPE(pw_c1d_gs_type) :: rho_metal, v_metal_gspace
867 TYPE(pw_env_type), POINTER :: pw_env
868 TYPE(pw_poisson_type), POINTER :: poisson_env
869 TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
870
871 CALL timeset(routinen, handle)
872
873 NULLIFY (pw_env, auxbas_pw_pool, poisson_env)
874 en_vmetal_rhohartree = 0.0_dp
875 en_external = 0.0_dp
876
877 CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
878 CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
879 poisson_env=poisson_env)
880
881 CALL auxbas_pw_pool%create_pw(rho_metal)
882
883 CALL auxbas_pw_pool%create_pw(v_metal_gspace)
884
885 CALL auxbas_pw_pool%create_pw(v_metal_rspace)
886
887 CALL pw_zero(rho_metal)
888 CALL calculate_rho_metal(rho_metal, coeff, total_rho_metal=total_rho_metal, &
889 qs_env=qs_env)
890
891 CALL pw_zero(v_metal_gspace)
892 CALL pw_poisson_solve(poisson_env, rho_metal, &
893 vhartree=v_metal_gspace)
894
895 IF (PRESENT(rho_hartree_gspace)) THEN
896 en_vmetal_rhohartree = 0.5_dp*pw_integral_ab(v_metal_gspace, &
897 rho_hartree_gspace)
898 en_external = qs_env%qmmm_env_qm%image_charge_pot%V0*total_rho_metal
899 energy%image_charge = en_vmetal_rhohartree - 0.5_dp*en_external
900 CALL print_image_energy_terms(en_vmetal_rhohartree, en_external, &
901 total_rho_metal, qs_env)
902 END IF
903
904 CALL pw_zero(v_metal_rspace)
905 CALL pw_transfer(v_metal_gspace, v_metal_rspace)
906 CALL pw_scale(v_metal_rspace, v_metal_rspace%pw_grid%dvol)
907 CALL v_metal_gspace%release()
908 CALL rho_metal%release()
909
910 CALL timestop(handle)
911
912 END SUBROUTINE calculate_potential_metal
913
914! ****************************************************************************
915!> \brief Add potential of metal (image charge pot) to Hartree Potential
916!> \param v_hartree Hartree potential (in real space)
917!> \param v_metal potential generated by rho_metal (in real space)
918!> \param qs_env qs environment
919! **************************************************************************************************
920 SUBROUTINE add_image_pot_to_hartree_pot(v_hartree, v_metal, qs_env)
921
922 TYPE(pw_r3d_rs_type), INTENT(INOUT) :: v_hartree
923 TYPE(pw_r3d_rs_type), INTENT(IN) :: v_metal
924 TYPE(qs_environment_type), POINTER :: qs_env
925
926 CHARACTER(len=*), PARAMETER :: routinen = 'add_image_pot_to_hartree_pot'
927
928 INTEGER :: handle, output_unit
929 TYPE(cp_logger_type), POINTER :: logger
930 TYPE(section_vals_type), POINTER :: input
931
932 CALL timeset(routinen, handle)
933
934 NULLIFY (input, logger)
935 logger => cp_get_default_logger()
936
937 !add image charge potential
938 CALL pw_axpy(v_metal, v_hartree)
939
940 ! print info
941 CALL get_qs_env(qs_env=qs_env, &
942 input=input)
943 output_unit = cp_print_key_unit_nr(logger, input, &
944 "QMMM%PRINT%PROGRAM_RUN_INFO", &
945 extension=".qmmmLog")
946 IF (output_unit > 0) WRITE (unit=output_unit, fmt="(T3,A)") &
947 "Adding image charge potential to the Hartree potential."
948 CALL cp_print_key_finished_output(output_unit, logger, input, &
949 "QMMM%PRINT%PROGRAM_RUN_INFO")
950
951 CALL timestop(handle)
952
953 END SUBROUTINE add_image_pot_to_hartree_pot
954
955!****************************************************************************
956!> \brief writes image matrix T to file when used as preconditioner for
957!> calculating image coefficients iteratively
958!> \param image_matrix matrix T
959!> \param qs_env qs environment
960! **************************************************************************************************
961 SUBROUTINE write_image_matrix(image_matrix, qs_env)
962
963 REAL(kind=dp), DIMENSION(:, :), POINTER :: image_matrix
964 TYPE(qs_environment_type), POINTER :: qs_env
965
966 CHARACTER(LEN=*), PARAMETER :: routinen = 'write_image_matrix'
967
968 CHARACTER(LEN=default_path_length) :: filename
969 INTEGER :: handle, rst_unit
970 TYPE(cp_logger_type), POINTER :: logger
971 TYPE(mp_para_env_type), POINTER :: para_env
972 TYPE(section_vals_type), POINTER :: print_key, qmmm_section
973
974 CALL timeset(routinen, handle)
975
976 NULLIFY (qmmm_section, print_key, logger, para_env)
977 logger => cp_get_default_logger()
978 rst_unit = -1
979
980 CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
981 input=qmmm_section)
982
983 print_key => section_vals_get_subs_vals(qmmm_section, &
984 "QMMM%PRINT%IMAGE_CHARGE_RESTART")
985
986 IF (btest(cp_print_key_should_output(logger%iter_info, &
987 qmmm_section, "QMMM%PRINT%IMAGE_CHARGE_RESTART"), &
988 cp_p_file)) THEN
989
990 rst_unit = cp_print_key_unit_nr(logger, qmmm_section, &
991 "QMMM%PRINT%IMAGE_CHARGE_RESTART", &
992 extension=".Image", &
993 file_status="REPLACE", &
994 file_action="WRITE", &
995 file_form="UNFORMATTED")
996
997 IF (rst_unit > 0) filename = cp_print_key_generate_filename(logger, &
998 print_key, extension=".IMAGE", &
999 my_local=.false.)
1000
1001 IF (rst_unit > 0) THEN
1002 WRITE (rst_unit) image_matrix
1003 END IF
1004
1005 CALL cp_print_key_finished_output(rst_unit, logger, qmmm_section, &
1006 "QMMM%PRINT%IMAGE_CHARGE_RESTART")
1007 END IF
1008
1009 CALL timestop(handle)
1010
1011 END SUBROUTINE write_image_matrix
1012
1013!****************************************************************************
1014!> \brief restarts image matrix T when used as preconditioner for calculating
1015!> image coefficients iteratively
1016!> \param image_matrix matrix T
1017!> \param qs_env qs environment
1018!> \param qmmm_env qmmm environment
1019! **************************************************************************************************
1020 SUBROUTINE restart_image_matrix(image_matrix, qs_env, qmmm_env)
1021
1022 REAL(kind=dp), DIMENSION(:, :), POINTER :: image_matrix
1023 TYPE(qs_environment_type), POINTER :: qs_env
1024 TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
1025
1026 CHARACTER(LEN=*), PARAMETER :: routinen = 'restart_image_matrix'
1027
1028 CHARACTER(LEN=default_path_length) :: image_filename
1029 INTEGER :: handle, natom, output_unit, rst_unit
1030 LOGICAL :: exist
1031 TYPE(cp_logger_type), POINTER :: logger
1032 TYPE(mp_para_env_type), POINTER :: para_env
1033 TYPE(section_vals_type), POINTER :: qmmm_section
1034
1035 CALL timeset(routinen, handle)
1036
1037 NULLIFY (qmmm_section, logger, para_env)
1038 logger => cp_get_default_logger()
1039 exist = .false.
1040 rst_unit = -1
1041
1042 natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
1043
1044 IF (.NOT. ASSOCIATED(image_matrix)) THEN
1045 ALLOCATE (image_matrix(natom, natom))
1046 END IF
1047
1048 image_matrix = 0.0_dp
1049
1050 CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
1051 input=qmmm_section)
1052
1053 CALL section_vals_val_get(qmmm_section, "QMMM%IMAGE_CHARGE%IMAGE_RESTART_FILE_NAME", &
1054 c_val=image_filename)
1055
1056 INQUIRE (file=image_filename, exist=exist)
1057
1058 IF (exist) THEN
1059 IF (para_env%is_source()) THEN
1060 CALL open_file(file_name=image_filename, &
1061 file_status="OLD", &
1062 file_form="UNFORMATTED", &
1063 file_action="READ", &
1064 unit_number=rst_unit)
1065
1066 READ (rst_unit) qs_env%image_matrix
1067 END IF
1068
1069 CALL para_env%bcast(qs_env%image_matrix)
1070
1071 IF (para_env%is_source()) CALL close_file(unit_number=rst_unit)
1072
1073 output_unit = cp_print_key_unit_nr(logger, qmmm_section, &
1074 "QMMM%PRINT%PROGRAM_RUN_INFO", &
1075 extension=".qmmmLog")
1076 IF (output_unit > 0) WRITE (unit=output_unit, fmt="(T3,A)") &
1077 "Restarted image matrix"
1078 ELSE
1079 cpabort("Restart file for image matrix not found")
1080 END IF
1081
1082 qmmm_env%image_charge_pot%image_restart = .false.
1083
1084 CALL timestop(handle)
1085
1086 END SUBROUTINE restart_image_matrix
1087
1088! ****************************************************************************
1089!> \brief Print info on image gradients on image MM atoms
1090!> \param forces structure storing the force contribution of the image charges
1091!> for the metal (MM) atoms (actually these are only the gradients)
1092!> \param qs_env qs environment
1093! **************************************************************************************************
1094 SUBROUTINE print_gradients_image_atoms(forces, qs_env)
1095
1096 REAL(kind=dp), DIMENSION(:, :), POINTER :: forces
1097 TYPE(qs_environment_type), POINTER :: qs_env
1098
1099 INTEGER :: atom_a, iatom, natom, output_unit
1100 REAL(kind=dp), DIMENSION(3) :: sum_gradients
1101 TYPE(cp_logger_type), POINTER :: logger
1102 TYPE(section_vals_type), POINTER :: input
1103
1104 NULLIFY (input, logger)
1105 logger => cp_get_default_logger()
1106
1107 sum_gradients = 0.0_dp
1108 natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
1109
1110 DO iatom = 1, natom
1111 sum_gradients(:) = sum_gradients(:) + forces(:, iatom)
1112 END DO
1113
1114 CALL get_qs_env(qs_env=qs_env, input=input)
1115
1116 output_unit = cp_print_key_unit_nr(logger, input, &
1117 "QMMM%PRINT%DERIVATIVES", extension=".Log")
1118 IF (output_unit > 0) THEN
1119 WRITE (unit=output_unit, fmt="(/1X,A)") &
1120 "Image gradients [a.u.] on MM image charge atoms after QMMM calculation: "
1121 WRITE (unit=output_unit, fmt="(T4,A4,T27,A1,T50,A1,T74,A1)") &
1122 "Atom", "X", "Y", "Z"
1123 DO iatom = 1, natom
1124 atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
1125 WRITE (unit=output_unit, fmt="(T2,I6,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
1126 atom_a, forces(:, iatom)
1127 END DO
1128
1129 WRITE (unit=output_unit, fmt="(T2,A)") repeat("-", 79)
1130 WRITE (unit=output_unit, fmt="(T2,A,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
1131 "sum gradients:", sum_gradients
1132 WRITE (unit=output_unit, fmt="(/)")
1133 END IF
1134
1135 CALL cp_print_key_finished_output(output_unit, logger, input, &
1136 "QMMM%PRINT%DERIVATIVES")
1137
1138 END SUBROUTINE print_gradients_image_atoms
1139
1140! ****************************************************************************
1141!> \brief Print image coefficients
1142!> \param image_coeff expansion coefficients of the image charge density
1143!> \param qs_env qs environment
1144! **************************************************************************************************
1145 SUBROUTINE print_image_coefficients(image_coeff, qs_env)
1146
1147 REAL(kind=dp), DIMENSION(:), POINTER :: image_coeff
1148 TYPE(qs_environment_type), POINTER :: qs_env
1149
1150 INTEGER :: atom_a, iatom, natom, output_unit
1151 REAL(kind=dp) :: normalize_factor, sum_coeff
1152 TYPE(cp_logger_type), POINTER :: logger
1153 TYPE(section_vals_type), POINTER :: input
1154
1155 NULLIFY (input, logger)
1156 logger => cp_get_default_logger()
1157
1158 sum_coeff = 0.0_dp
1159 natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
1160 normalize_factor = sqrt((qs_env%qmmm_env_qm%image_charge_pot%eta/pi)**3)
1161
1162 DO iatom = 1, natom
1163 sum_coeff = sum_coeff + image_coeff(iatom)
1164 END DO
1165
1166 CALL get_qs_env(qs_env=qs_env, input=input)
1167
1168 output_unit = cp_print_key_unit_nr(logger, input, &
1169 "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
1170 IF (output_unit > 0) THEN
1171 WRITE (unit=output_unit, fmt="(/)")
1172 WRITE (unit=output_unit, fmt="(T2,A)") &
1173 "Image charges [a.u.] after QMMM calculation: "
1174 WRITE (unit=output_unit, fmt="(T4,A4,T67,A)") "Atom", "Image charge"
1175 WRITE (unit=output_unit, fmt="(T4,A,T67,A)") repeat("-", 4), repeat("-", 12)
1176
1177 DO iatom = 1, natom
1178 atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
1179 !opposite sign for image_coeff; during the calculation they have
1180 !the 'wrong' sign to ensure consistency with v_hartree which has
1181 !the opposite sign
1182 WRITE (unit=output_unit, fmt="(T2,I6,T65,ES16.9)") &
1183 atom_a, -image_coeff(iatom)/normalize_factor
1184 END DO
1185
1186 WRITE (unit=output_unit, fmt="(T2,A)") repeat("-", 79)
1187 WRITE (unit=output_unit, fmt="(T2,A,T65,ES16.9)") &
1188 "sum image charges:", -sum_coeff/normalize_factor
1189 END IF
1190
1191 CALL cp_print_key_finished_output(output_unit, logger, input, &
1192 "QMMM%PRINT%IMAGE_CHARGE_INFO")
1193
1194 END SUBROUTINE print_image_coefficients
1195
1196! ****************************************************************************
1197!> \brief Print detailed image charge energies
1198!> \param en_vmetal_rhohartree energy contribution of the image charges
1199!> without external potential, i.e. 0.5*integral(v_metal*rho_hartree)
1200!> \param en_external additional energy contribution of the image charges due
1201!> to an external potential, i.e. V0*total_rho_metal
1202!> \param total_rho_metal total induced image charge density
1203!> \param qs_env qs environment
1204! **************************************************************************************************
1205 SUBROUTINE print_image_energy_terms(en_vmetal_rhohartree, en_external, &
1206 total_rho_metal, qs_env)
1207
1208 REAL(kind=dp), INTENT(IN) :: en_vmetal_rhohartree, en_external, &
1209 total_rho_metal
1210 TYPE(qs_environment_type), POINTER :: qs_env
1211
1212 INTEGER :: output_unit
1213 TYPE(cp_logger_type), POINTER :: logger
1214 TYPE(section_vals_type), POINTER :: input
1215
1216 NULLIFY (input, logger)
1217 logger => cp_get_default_logger()
1218
1219 CALL get_qs_env(qs_env=qs_env, input=input)
1220
1221 output_unit = cp_print_key_unit_nr(logger, input, &
1222 "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
1223
1224 IF (output_unit > 0) THEN
1225 WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1226 "Total induced charge density [a.u.]:", total_rho_metal
1227 WRITE (unit=output_unit, fmt="(T3,A)") "Image energy terms: "
1228 WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1229 "Coulomb energy of QM and image charge density [a.u.]:", en_vmetal_rhohartree
1230 WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1231 "External potential energy term [a.u.]:", -0.5_dp*en_external
1232 WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1233 "Total image charge energy [a.u.]:", en_vmetal_rhohartree - 0.5_dp*en_external
1234 END IF
1235
1236 CALL cp_print_key_finished_output(output_unit, logger, input, &
1237 "QMMM%PRINT%IMAGE_CHARGE_INFO")
1238
1239 END SUBROUTINE print_image_energy_terms
1240
1241END MODULE qmmm_image_charge
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
All kind of helpful little routines.
Definition ao_util.F:14
real(kind=dp) function, public exp_radius_very_extended(la_min, la_max, lb_min, lb_max, pab, o1, o2, ra, rb, rp, zetp, eps, prefactor, cutoff, epsabs)
computes the radius of the Gaussian outside of which it is smaller than eps
Definition ao_util.F:208
Handles all functions related to the CELL.
Definition cell_types.F:15
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
Interface to Minimax-Ewald method for periodic ERI's to be used in CP2K.
subroutine, public cp_eri_mme_update_local_counts(param, para_env, g_count_2c, r_count_2c, gg_count_3c, gr_count_3c, rr_count_3c)
Update local counters to gather statistics on different paths taken in MME algorithm (each Ewald sum ...
Utility routines to open and close files.
Definition cp_files.F:22
subroutine, public open_file(file_name, unit_number, file_status, file_form, file_action, file_position, file_pad, file_access, debug)
Opens a file and returns its logical unit number.
Definition cp_files.F:197
subroutine, public close_file(unit_number, file_status)
Closes an open file given by its logical unit number.
Definition cp_files.F:64
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)
...
character(len=default_path_length) function, public cp_print_key_generate_filename(logger, print_key, middle_name, extension, my_local)
Utility function that returns a unit number to write the print key. Might open a file with a unique f...
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,...
integer, parameter, public cp_p_file
integer function, public cp_print_key_should_output(iteration_info, basis_section, print_key_path, used_print_key, first_time)
returns what should be done with the given property if btest(res,cp_p_store) then the property should...
Minimax-Ewald (MME) method for calculating 2-center and 3-center electron repulsion integrals (ERI) o...
subroutine, public eri_mme_2c_integrate(param, la_min, la_max, lb_min, lb_max, zeta, zetb, rab, hab, o1, o2, g_count, r_count, normalize, potential, pot_par)
Low-level integration routine for 2-center ERIs.
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public do_eri_mme
integer, parameter, public calc_once_done
integer, parameter, public calc_once
integer, parameter, public calc_always
integer, parameter, public do_eri_gpw
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
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_path_length
Definition kinds.F:58
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
subroutine, public invmat_symm(a, potrf, uplo)
returns inverse of real symmetric, positive definite matrix
Definition mathlib.F:588
Utility routines for the memory handling.
Interface to the message passing library MPI.
container for various plainwaves related things
subroutine, public pw_env_get(pw_env, pw_pools, cube_info, gridlevel_info, auxbas_pw_pool, auxbas_grid, auxbas_rs_desc, auxbas_rs_grid, rs_descs, rs_grids, xc_pw_pool, vdw_pw_pool, poisson_env, interp_section)
returns the various attributes of the pw env
functions related to the poisson solver on regular grids
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Routines for image charge calculation within QM/MM.
subroutine, public calculate_image_pot(v_hartree_rspace, rho_hartree_gspace, energy, qmmm_env, qs_env)
determines coefficients by solving image_matrix*coeff=-pot_const by Gaussian elimination or in an ite...
subroutine, public print_image_coefficients(image_coeff, qs_env)
Print image coefficients.
subroutine, public integrate_potential_devga_rspace(potential, coeff, forces, qmmm_env, qs_env)
calculates the image forces on the MM atoms
subroutine, public conditional_calc_image_matrix(qs_env, qmmm_env)
calculate image matrix T depending on constraints on image atoms in case coefficients are estimated n...
subroutine, public add_image_pot_to_hartree_pot(v_hartree, v_metal, qs_env)
Add potential of metal (image charge pot) to Hartree Potential.
Calculate the plane wave density by collocating the primitive Gaussian functions (pgf).
subroutine, public calculate_rho_metal(rho_metal, coeff, total_rho_metal, qs_env)
computes the image charge density on the grid (including coeffcients)
subroutine, public calculate_rho_single_gaussian(rho_gb, qs_env, iatom_in)
collocate a single Gaussian on the grid
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, mimic, 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_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, 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, matrix_vhxc, 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, xcint_weights, 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, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_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, harris_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, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Integrate single or product functions over a potential on a RS grid.
subroutine, public transfer_pw2rs(rs, pw)
...
All kind of helpful little routines.
Definition util.F:14
pure integer function, dimension(2), public get_limit(m, n, me)
divide m entries into n parts, return size of part me
Definition util.F:333
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment
contained for different pw related things
environment for the poisson solver
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...