Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Routines for image charge calculation within QM/MM
10 : !> \par History
11 : !> 12.2011 created
12 : !> \author Dorothea Golze
13 : ! **************************************************************************************************
14 : MODULE qmmm_image_charge
15 : USE ao_util, ONLY: exp_radius_very_extended
16 : USE cell_types, ONLY: cell_type,&
17 : pbc
18 : USE cp_control_types, ONLY: dft_control_type
19 : USE cp_eri_mme_interface, ONLY: cp_eri_mme_param,&
20 : cp_eri_mme_update_local_counts
21 : USE cp_files, ONLY: close_file,&
22 : open_file
23 : USE cp_log_handling, ONLY: cp_get_default_logger,&
24 : cp_logger_type
25 : USE cp_output_handling, ONLY: cp_p_file,&
26 : cp_print_key_finished_output,&
27 : cp_print_key_generate_filename,&
28 : cp_print_key_should_output,&
29 : cp_print_key_unit_nr
30 : USE eri_mme_integrate, ONLY: eri_mme_2c_integrate
31 : USE input_constants, ONLY: calc_always,&
32 : calc_once,&
33 : calc_once_done,&
34 : do_eri_gpw,&
35 : do_eri_mme
36 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
37 : section_vals_type,&
38 : section_vals_val_get
39 : USE kinds, ONLY: default_path_length,&
40 : dp
41 : USE mathconstants, ONLY: pi
42 : USE mathlib, ONLY: invmat_symm
43 : USE memory_utilities, ONLY: reallocate
44 : USE message_passing, ONLY: mp_para_env_type
45 : USE pw_env_types, ONLY: pw_env_get,&
46 : pw_env_type
47 : USE pw_methods, ONLY: pw_axpy,&
48 : pw_integral_ab,&
49 : pw_scale,&
50 : pw_transfer,&
51 : pw_zero
52 : USE pw_poisson_methods, ONLY: pw_poisson_solve
53 : USE pw_poisson_types, ONLY: pw_poisson_type
54 : USE pw_pool_types, ONLY: pw_pool_type
55 : USE pw_types, ONLY: pw_c1d_gs_type,&
56 : pw_r3d_rs_type
57 : USE qmmm_types_low, ONLY: qmmm_env_qm_type
58 : USE qs_collocate_density, ONLY: calculate_rho_metal,&
59 : calculate_rho_single_gaussian
60 : USE qs_energy_types, ONLY: qs_energy_type
61 : USE qs_environment_types, ONLY: get_qs_env,&
62 : qs_environment_type
63 : USE qs_integrate_potential, ONLY: integrate_pgf_product
64 : USE realspace_grid_types, ONLY: realspace_grid_desc_type,&
65 : realspace_grid_type,&
66 : transfer_pw2rs
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, &
78 : integrate_potential_devga_rspace, &
79 : conditional_calc_image_matrix, &
80 : add_image_pot_to_hartree_pot, &
81 : print_image_coefficients
82 :
83 : !***
84 : CONTAINS
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 60 : 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 60 : CALL timeset(routineN, handle)
109 :
110 60 : IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
111 : !calculate preconditioner matrix for CG if necessary
112 12 : IF (qs_env%calc_image_preconditioner) THEN
113 2 : IF (qmmm_env%image_charge_pot%image_restart) THEN
114 : CALL restart_image_matrix(image_matrix=qs_env%image_matrix, &
115 0 : qs_env=qs_env, qmmm_env=qmmm_env)
116 : ELSE
117 : CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
118 2 : 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 12 : 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 48 : qs_env=qs_env)
129 : END IF
130 :
131 : ! calculate the image/metal potential with the optimized coefficients
132 60 : 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 60 : energy=energy, qs_env=qs_env)
137 :
138 60 : CALL timestop(handle)
139 :
140 60 : 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 48 : 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 48 : 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 48 : V0 = -qmmm_env%image_charge_pot%V0
171 48 : eta = qmmm_env%image_charge_pot%eta
172 48 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
173 :
174 144 : ALLOCATE (pot_const(natom))
175 48 : IF (.NOT. ASSOCIATED(coeff)) THEN
176 16 : ALLOCATE (coeff(natom))
177 : END IF
178 144 : coeff = 0.0_dp
179 :
180 : CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
181 48 : pot_const)
182 : !add integral V0*ga(r)
183 144 : 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 48 : pot_const, natom, info)
189 48 : CPASSERT(info == 0)
190 :
191 240 : coeff = pot_const
192 :
193 48 : DEALLOCATE (pot_const)
194 :
195 48 : CALL timestop(handle)
196 :
197 48 : 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 12 : 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 :
217 : INTEGER :: handle, iter_steps, natom, output_unit
218 : REAL(KIND=dp) :: alpha, eta, rsnew, rsold, V0
219 12 : REAL(KIND=dp), DIMENSION(:), POINTER :: Ad, d, pot_const, r, vmetal_const, z
220 : TYPE(cp_logger_type), POINTER :: logger
221 : TYPE(pw_r3d_rs_type) :: auxpot_Ad_rspace, v_metal_rspace_guess
222 : TYPE(section_vals_type), POINTER :: input
223 :
224 12 : CALL timeset(routineN, handle)
225 :
226 12 : NULLIFY (pot_const, vmetal_const, logger, input)
227 12 : logger => cp_get_default_logger()
228 :
229 : !minus sign V0: account for the fact that v_hartree has the opposite sign
230 12 : V0 = -qmmm_env%image_charge_pot%V0
231 12 : eta = qmmm_env%image_charge_pot%eta
232 12 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
233 :
234 36 : ALLOCATE (pot_const(natom))
235 24 : ALLOCATE (vmetal_const(natom))
236 24 : ALLOCATE (r(natom))
237 24 : ALLOCATE (d(natom))
238 24 : ALLOCATE (z(natom))
239 24 : ALLOCATE (Ad(natom))
240 12 : IF (.NOT. ASSOCIATED(coeff)) THEN
241 4 : ALLOCATE (coeff(natom))
242 : END IF
243 :
244 : CALL integrate_potential_ga_rspace(v_hartree_rspace, qmmm_env, qs_env, &
245 12 : pot_const)
246 :
247 : !add integral V0*ga(r)
248 36 : pot_const(:) = -pot_const(:) + V0*SQRT((pi/eta)**3)
249 :
250 : !initial guess for coeff
251 36 : coeff = 1.0_dp
252 36 : d = 0.0_dp
253 36 : z = 0.0_dp
254 36 : r = 0.0_dp
255 12 : rsold = 0.0_dp
256 12 : rsnew = 0.0_dp
257 12 : iter_steps = 0
258 :
259 : !calculate first guess of image/metal potential
260 : CALL calculate_potential_metal(v_metal_rspace=v_metal_rspace_guess, &
261 12 : coeff=coeff, qs_env=qs_env)
262 : CALL integrate_potential_ga_rspace(potential=v_metal_rspace_guess, &
263 12 : qmmm_env=qmmm_env, qs_env=qs_env, int_res=vmetal_const)
264 :
265 : ! modify coefficients iteratively
266 60 : r = pot_const - vmetal_const
267 276 : z = MATMUL(qs_env%image_matrix, r)
268 60 : d = z
269 36 : rsold = DOT_PRODUCT(r, z)
270 :
271 6 : DO
272 : !calculate A*d
273 54 : Ad = 0.0_dp
274 : CALL calculate_potential_metal(v_metal_rspace= &
275 18 : auxpot_Ad_rspace, coeff=d, qs_env=qs_env)
276 : CALL integrate_potential_ga_rspace(potential= &
277 : auxpot_Ad_rspace, qmmm_env=qmmm_env, &
278 18 : qs_env=qs_env, int_res=Ad)
279 :
280 54 : alpha = rsold/DOT_PRODUCT(d, Ad)
281 90 : coeff = coeff + alpha*d
282 :
283 90 : r = r - alpha*Ad
284 414 : z = MATMUL(qs_env%image_matrix, r)
285 54 : rsnew = DOT_PRODUCT(r, z)
286 18 : iter_steps = iter_steps + 1
287 : ! SQRT(rsnew) < 1.0E-08
288 18 : IF (rsnew < 1.0E-16) THEN
289 12 : CALL auxpot_Ad_rspace%release()
290 : EXIT
291 : END IF
292 30 : d = z + rsnew/rsold*d
293 6 : rsold = rsnew
294 24 : CALL auxpot_Ad_rspace%release()
295 : END DO
296 :
297 : ! print iteration info
298 : CALL get_qs_env(qs_env=qs_env, &
299 12 : input=input)
300 : output_unit = cp_print_key_unit_nr(logger, input, &
301 : "QMMM%PRINT%PROGRAM_RUN_INFO", &
302 12 : extension=".qmmmLog")
303 12 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A,T74,I7)") &
304 6 : "Number of iteration steps for determination of image coefficients:", iter_steps
305 : CALL cp_print_key_finished_output(output_unit, logger, input, &
306 12 : "QMMM%PRINT%PROGRAM_RUN_INFO")
307 :
308 12 : IF (iter_steps < 25) THEN
309 12 : qs_env%calc_image_preconditioner = .FALSE.
310 : ELSE
311 0 : qs_env%calc_image_preconditioner = .TRUE.
312 : END IF
313 :
314 12 : CALL v_metal_rspace_guess%release()
315 12 : DEALLOCATE (pot_const)
316 12 : DEALLOCATE (vmetal_const)
317 12 : DEALLOCATE (r)
318 12 : DEALLOCATE (d, z)
319 12 : DEALLOCATE (Ad)
320 :
321 12 : CALL timestop(handle)
322 :
323 24 : END SUBROUTINE calc_image_coeff_iterative
324 :
325 : ! ****************************************************************************
326 : !> \brief calculates the integral V(r)*ga(r)
327 : !> \param potential any potential
328 : !> \param qmmm_env qmmm environment
329 : !> \param qs_env qs environment
330 : !> \param int_res result of the integration
331 : !> \param atom_num atom index, needed when calculating image_matrix
332 : !> \param atom_num_ref index of reference atom, needed when calculating
333 : !> image_matrix
334 : ! **************************************************************************************************
335 98 : SUBROUTINE integrate_potential_ga_rspace(potential, qmmm_env, qs_env, int_res, &
336 : atom_num, atom_num_ref)
337 :
338 : TYPE(pw_r3d_rs_type), INTENT(IN) :: potential
339 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
340 : TYPE(qs_environment_type), POINTER :: qs_env
341 : REAL(KIND=dp), DIMENSION(:), POINTER :: int_res
342 : INTEGER, INTENT(IN), OPTIONAL :: atom_num, atom_num_ref
343 :
344 : CHARACTER(LEN=*), PARAMETER :: routineN = 'integrate_potential_ga_rspace'
345 :
346 : INTEGER :: atom_a, atom_b, atom_ref, handle, iatom, &
347 : j, k, natom, npme
348 98 : INTEGER, DIMENSION(:), POINTER :: cores
349 : REAL(KIND=dp) :: eps_rho_rspace, radius
350 : REAL(KIND=dp), DIMENSION(3) :: ra
351 98 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: hab
352 : TYPE(cell_type), POINTER :: cell
353 : TYPE(dft_control_type), POINTER :: dft_control
354 : TYPE(mp_para_env_type), POINTER :: para_env
355 : TYPE(pw_env_type), POINTER :: pw_env
356 : TYPE(realspace_grid_desc_type), POINTER :: auxbas_rs_desc
357 : TYPE(realspace_grid_type), POINTER :: rs_v
358 :
359 98 : CALL timeset(routineN, handle)
360 :
361 98 : NULLIFY (cores, hab, cell, auxbas_rs_desc, pw_env, para_env, &
362 98 : dft_control, rs_v)
363 98 : ALLOCATE (hab(1, 1))
364 :
365 98 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
366 : CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
367 98 : auxbas_rs_grid=rs_v)
368 98 : CALL transfer_pw2rs(rs_v, potential)
369 :
370 : CALL get_qs_env(qs_env=qs_env, &
371 : cell=cell, &
372 : dft_control=dft_control, &
373 98 : para_env=para_env, pw_env=pw_env)
374 :
375 98 : eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
376 :
377 98 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
378 98 : k = 1
379 98 : IF (PRESENT(atom_num)) k = atom_num
380 :
381 98 : CALL reallocate(cores, 1, natom - k + 1)
382 294 : int_res = 0.0_dp
383 98 : npme = 0
384 290 : cores = 0
385 :
386 290 : DO iatom = k, natom
387 290 : IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
388 : ! replicated realspace grid, split the atoms up between procs
389 192 : IF (MODULO(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
390 96 : npme = npme + 1
391 96 : cores(npme) = iatom
392 : END IF
393 : ELSE
394 0 : npme = npme + 1
395 0 : cores(npme) = iatom
396 : END IF
397 : END DO
398 :
399 194 : DO j = 1, npme
400 :
401 96 : iatom = cores(j)
402 96 : atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
403 :
404 96 : IF (PRESENT(atom_num) .AND. PRESENT(atom_num_ref)) THEN
405 : ! shift the function since potential only calculate for ref atom
406 6 : atom_b = qmmm_env%image_charge_pot%image_mm_list(k)
407 6 : atom_ref = qmmm_env%image_charge_pot%image_mm_list(atom_num_ref)
408 : ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell) &
409 : - pbc(qmmm_env%image_charge_pot%particles_all(atom_b)%r, cell) &
410 24 : + pbc(qmmm_env%image_charge_pot%particles_all(atom_ref)%r, cell)
411 :
412 : ELSE
413 90 : ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
414 : END IF
415 :
416 96 : hab(1, 1) = 0.0_dp
417 :
418 : radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
419 : ra=ra, rb=ra, rp=ra, &
420 : zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
421 96 : prefactor=1.0_dp, cutoff=1.0_dp)
422 :
423 : CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
424 : 0, 0.0_dp, 0, ra, [0.0_dp, 0.0_dp, 0.0_dp], &
425 : rs_v, hab, o1=0, o2=0, &
426 : radius=radius, calculate_forces=.FALSE., &
427 96 : use_subpatch=.TRUE., subpatch_pattern=0)
428 :
429 194 : int_res(iatom) = hab(1, 1)
430 :
431 : END DO
432 :
433 490 : CALL para_env%sum(int_res)
434 :
435 98 : DEALLOCATE (hab, cores)
436 :
437 98 : CALL timestop(handle)
438 :
439 98 : END SUBROUTINE integrate_potential_ga_rspace
440 :
441 : ! **************************************************************************************************
442 : !> \brief calculates the image forces on the MM atoms
443 : !> \param potential any potential, in this case: Hartree potential
444 : !> \param coeff expansion coefficients of the image charge density, i.e.
445 : !> rho_metal=sum_a c_a*g_a
446 : !> \param forces structure storing the force contribution of the image charges
447 : !> for the metal (MM) atoms
448 : !> \param qmmm_env qmmm environment
449 : !> \param qs_env qs environment
450 : ! **************************************************************************************************
451 20 : SUBROUTINE integrate_potential_devga_rspace(potential, coeff, forces, qmmm_env, &
452 : qs_env)
453 :
454 : TYPE(pw_r3d_rs_type), INTENT(IN) :: potential
455 : REAL(KIND=dp), DIMENSION(:), POINTER :: coeff
456 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: forces
457 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
458 : TYPE(qs_environment_type), POINTER :: qs_env
459 :
460 : CHARACTER(LEN=*), PARAMETER :: routineN = 'integrate_potential_devga_rspace'
461 :
462 : INTEGER :: atom_a, handle, iatom, j, natom, npme
463 20 : INTEGER, DIMENSION(:), POINTER :: cores
464 : LOGICAL :: use_virial
465 : REAL(KIND=dp) :: eps_rho_rspace, radius
466 : REAL(KIND=dp), DIMENSION(3) :: force_a, force_b, ra
467 20 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: hab, pab
468 : TYPE(cell_type), POINTER :: cell
469 : TYPE(dft_control_type), POINTER :: dft_control
470 : TYPE(mp_para_env_type), POINTER :: para_env
471 : TYPE(pw_env_type), POINTER :: pw_env
472 : TYPE(realspace_grid_desc_type), POINTER :: auxbas_rs_desc
473 : TYPE(realspace_grid_type), POINTER :: rs_v
474 : TYPE(virial_type), POINTER :: virial
475 :
476 20 : CALL timeset(routineN, handle)
477 :
478 20 : NULLIFY (cores, hab, pab, cell, auxbas_rs_desc, pw_env, para_env, &
479 20 : dft_control, rs_v, virial)
480 20 : use_virial = .FALSE.
481 :
482 20 : ALLOCATE (hab(1, 1))
483 20 : ALLOCATE (pab(1, 1))
484 :
485 20 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
486 : CALL pw_env_get(pw_env=pw_env, auxbas_rs_desc=auxbas_rs_desc, &
487 20 : auxbas_rs_grid=rs_v)
488 20 : CALL transfer_pw2rs(rs_v, potential)
489 :
490 : CALL get_qs_env(qs_env=qs_env, &
491 : cell=cell, &
492 : dft_control=dft_control, &
493 : para_env=para_env, pw_env=pw_env, &
494 20 : virial=virial)
495 :
496 20 : use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
497 :
498 : IF (use_virial) THEN
499 0 : CPABORT("Virial not implemented for image charge method")
500 : END IF
501 :
502 20 : eps_rho_rspace = dft_control%qs_control%eps_rho_rspace
503 :
504 20 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
505 :
506 20 : IF (.NOT. ASSOCIATED(forces)) THEN
507 30 : ALLOCATE (forces(3, natom))
508 : END IF
509 :
510 180 : forces(:, :) = 0.0_dp
511 :
512 20 : CALL reallocate(cores, 1, natom)
513 20 : npme = 0
514 60 : cores = 0
515 :
516 60 : DO iatom = 1, natom
517 60 : IF (rs_v%desc%parallel .AND. .NOT. rs_v%desc%distributed) THEN
518 : ! replicated realspace grid, split the atoms up between procs
519 40 : IF (MODULO(iatom, rs_v%desc%group_size) == rs_v%desc%my_pos) THEN
520 20 : npme = npme + 1
521 20 : cores(npme) = iatom
522 : END IF
523 : ELSE
524 0 : npme = npme + 1
525 0 : cores(npme) = iatom
526 : END IF
527 : END DO
528 :
529 40 : DO j = 1, npme
530 :
531 20 : iatom = cores(j)
532 20 : atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
533 20 : ra(:) = pbc(qmmm_env%image_charge_pot%particles_all(atom_a)%r, cell)
534 20 : hab(1, 1) = 0.0_dp
535 20 : pab(1, 1) = 1.0_dp
536 20 : force_a(:) = 0.0_dp
537 20 : force_b(:) = 0.0_dp
538 :
539 : radius = exp_radius_very_extended(la_min=0, la_max=0, lb_min=0, lb_max=0, &
540 : ra=ra, rb=ra, rp=ra, &
541 : zetp=qmmm_env%image_charge_pot%eta, eps=eps_rho_rspace, &
542 : pab=pab, o1=0, o2=0, & ! without map_consistent
543 20 : prefactor=1.0_dp, cutoff=1.0_dp)
544 :
545 : CALL integrate_pgf_product(0, qmmm_env%image_charge_pot%eta, 0, &
546 : 0, 0.0_dp, 0, ra, [0.0_dp, 0.0_dp, 0.0_dp], &
547 : rs_v, hab, pab, o1=0, o2=0, &
548 : radius=radius, calculate_forces=.TRUE., &
549 : force_a=force_a, force_b=force_b, use_subpatch=.TRUE., &
550 20 : subpatch_pattern=0)
551 :
552 80 : force_a(:) = coeff(iatom)*force_a(:)
553 100 : forces(:, iatom) = force_a(:)
554 :
555 : END DO
556 :
557 340 : CALL para_env%sum(forces)
558 :
559 20 : DEALLOCATE (hab, pab, cores)
560 :
561 : ! print info on gradients if wanted
562 20 : CALL print_gradients_image_atoms(forces, qs_env)
563 :
564 20 : CALL timestop(handle)
565 :
566 20 : END SUBROUTINE integrate_potential_devga_rspace
567 :
568 : !****************************************************************************
569 : !> \brief calculate image matrix T depending on constraints on image atoms
570 : !> in case coefficients are estimated not iteratively
571 : !> \param qs_env qs environment
572 : !> \param qmmm_env qmmm environment
573 : ! **************************************************************************************************
574 20 : SUBROUTINE conditional_calc_image_matrix(qs_env, qmmm_env)
575 :
576 : TYPE(qs_environment_type), POINTER :: qs_env
577 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
578 :
579 20 : IF (.NOT. qmmm_env%image_charge_pot%coeff_iterative) THEN
580 28 : SELECT CASE (qmmm_env%image_charge_pot%state_image_matrix)
581 : CASE (calc_always)
582 : CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
583 12 : ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
584 : CASE (calc_once)
585 : !if all image atoms are fully constrained, calculate image matrix
586 : !only for the first MD or GEO_OPT step
587 : CALL calculate_image_matrix(image_matrix=qs_env%image_matrix, &
588 2 : ipiv=qs_env%ipiv, qs_env=qs_env, qmmm_env=qmmm_env)
589 2 : qmmm_env%image_charge_pot%state_image_matrix = calc_once_done
590 2 : IF (qmmm_env%center_qm_subsys0) THEN
591 : CALL cp_warn(__LOCATION__, &
592 : "The image atoms are fully "// &
593 : "constrained and the image matrix is only calculated once. "// &
594 0 : "To be safe, set CENTER to NEVER ")
595 : END IF
596 : CASE (calc_once_done)
597 : ! do nothing image matrix is stored
598 : CASE DEFAULT
599 16 : CPABORT("No initialization for image charges available?")
600 : END SELECT
601 : END IF
602 :
603 20 : END SUBROUTINE conditional_calc_image_matrix
604 :
605 : !****************************************************************************
606 : !> \brief calculate image matrix T
607 : !> \param image_matrix matrix T
608 : !> \param ipiv pivoting prior to DGETRS (for Gaussian elimination)
609 : !> \param qs_env qs environment
610 : !> \param qmmm_env qmmm environment
611 : ! **************************************************************************************************
612 16 : SUBROUTINE calculate_image_matrix(image_matrix, ipiv, qs_env, qmmm_env)
613 :
614 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: image_matrix
615 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: ipiv
616 : TYPE(qs_environment_type), POINTER :: qs_env
617 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
618 :
619 : CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix'
620 :
621 : INTEGER :: handle, natom, output_unit, stat
622 : TYPE(cp_logger_type), POINTER :: logger
623 : TYPE(section_vals_type), POINTER :: input
624 :
625 16 : CALL timeset(routineN, handle)
626 16 : NULLIFY (input, logger)
627 :
628 16 : logger => cp_get_default_logger()
629 :
630 16 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
631 :
632 16 : IF (.NOT. ASSOCIATED(image_matrix)) THEN
633 40 : ALLOCATE (image_matrix(natom, natom))
634 : END IF
635 16 : IF (PRESENT(ipiv)) THEN
636 14 : IF (.NOT. ASSOCIATED(ipiv)) THEN
637 24 : ALLOCATE (ipiv(natom))
638 : END IF
639 42 : ipiv = 0
640 : END IF
641 :
642 16 : CALL get_qs_env(qs_env, input=input)
643 : !print info
644 : output_unit = cp_print_key_unit_nr(logger, input, &
645 : "QMMM%PRINT%PROGRAM_RUN_INFO", &
646 16 : extension=".qmmmLog")
647 16 : IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
648 2 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
649 1 : "Calculating image matrix"
650 : ELSE
651 14 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T2,A)") &
652 7 : "Calculating image matrix"
653 : END IF
654 : CALL cp_print_key_finished_output(output_unit, logger, input, &
655 16 : "QMMM%PRINT%PROGRAM_RUN_INFO")
656 :
657 : ! Calculate image matrix using either GPW or MME method
658 20 : SELECT CASE (qmmm_env%image_charge_pot%image_matrix_method)
659 : CASE (do_eri_gpw)
660 4 : CALL calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
661 : CASE (do_eri_mme)
662 12 : CALL calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
663 : CASE DEFAULT
664 16 : CPABORT("Unknown method for calculating image matrix")
665 : END SELECT
666 :
667 16 : IF (qmmm_env%image_charge_pot%coeff_iterative) THEN
668 : !inversion --> preconditioner matrix for CG
669 2 : CALL invmat_symm(qs_env%image_matrix)
670 2 : CALL write_image_matrix(qs_env%image_matrix, qs_env)
671 : ELSE
672 : !pivoting prior to DGETRS (Gaussian elimination)
673 14 : IF (PRESENT(ipiv)) THEN
674 14 : CALL dgetrf(natom, natom, image_matrix, natom, ipiv, stat)
675 14 : CPASSERT(stat == 0)
676 : END IF
677 : END IF
678 :
679 16 : CALL timestop(handle)
680 :
681 16 : END SUBROUTINE calculate_image_matrix
682 :
683 : ! **************************************************************************************************
684 : !> \brief calculate image matrix T using GPW method
685 : !> \param image_matrix matrix T
686 : !> \param qs_env qs environment
687 : !> \param qmmm_env qmmm environment
688 : ! **************************************************************************************************
689 4 : SUBROUTINE calculate_image_matrix_gpw(image_matrix, qs_env, qmmm_env)
690 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: image_matrix
691 : TYPE(qs_environment_type), POINTER :: qs_env
692 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
693 :
694 : CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix_gpw'
695 :
696 : INTEGER :: handle, iatom, iatom_ref, natom
697 : REAL(KIND=dp), DIMENSION(:), POINTER :: int_res
698 : TYPE(mp_para_env_type), POINTER :: para_env
699 : TYPE(pw_c1d_gs_type) :: rho_gb, vb_gspace
700 : TYPE(pw_env_type), POINTER :: pw_env
701 : TYPE(pw_poisson_type), POINTER :: poisson_env
702 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
703 : TYPE(pw_r3d_rs_type) :: vb_rspace
704 :
705 4 : CALL timeset(routineN, handle)
706 4 : NULLIFY (pw_env, auxbas_pw_pool, poisson_env, para_env, int_res)
707 :
708 4 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
709 12 : ALLOCATE (int_res(natom))
710 :
711 28 : image_matrix = 0.0_dp
712 :
713 4 : CALL get_qs_env(qs_env, pw_env=pw_env, para_env=para_env)
714 :
715 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
716 4 : poisson_env=poisson_env)
717 4 : CALL auxbas_pw_pool%create_pw(rho_gb)
718 4 : CALL auxbas_pw_pool%create_pw(vb_gspace)
719 4 : CALL auxbas_pw_pool%create_pw(vb_rspace)
720 :
721 : ! calculate vb only once for one reference atom
722 4 : iatom_ref = 1 !
723 : !collocate gaussian of reference MM atom on grid
724 4 : CALL pw_zero(rho_gb)
725 4 : CALL calculate_rho_single_gaussian(rho_gb, qs_env, iatom_ref)
726 : !calculate potential vb like hartree potential
727 4 : CALL pw_zero(vb_gspace)
728 4 : CALL pw_poisson_solve(poisson_env, rho_gb, vhartree=vb_gspace)
729 4 : CALL pw_zero(vb_rspace)
730 4 : CALL pw_transfer(vb_gspace, vb_rspace)
731 4 : CALL pw_scale(vb_rspace, vb_rspace%pw_grid%dvol)
732 :
733 12 : DO iatom = 1, natom
734 : !calculate integral vb_rspace*ga
735 24 : int_res = 0.0_dp
736 : CALL integrate_potential_ga_rspace(vb_rspace, qs_env%qmmm_env_qm, &
737 : qs_env, int_res, atom_num=iatom, &
738 8 : atom_num_ref=iatom_ref)
739 40 : image_matrix(iatom, iatom:natom) = int_res(iatom:natom)
740 28 : image_matrix(iatom + 1:natom, iatom) = int_res(iatom + 1:natom)
741 : END DO
742 :
743 4 : CALL vb_gspace%release()
744 4 : CALL vb_rspace%release()
745 4 : CALL rho_gb%release()
746 :
747 4 : DEALLOCATE (int_res)
748 :
749 4 : CALL timestop(handle)
750 4 : END SUBROUTINE calculate_image_matrix_gpw
751 :
752 : ! **************************************************************************************************
753 : !> \brief calculate image matrix T using MME (MiniMax-Ewald) method
754 : !> \param image_matrix matrix T
755 : !> \param qs_env qs environment
756 : !> \param qmmm_env qmmm environment
757 : ! **************************************************************************************************
758 12 : SUBROUTINE calculate_image_matrix_mme(image_matrix, qs_env, qmmm_env)
759 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: image_matrix
760 : TYPE(qs_environment_type), POINTER :: qs_env
761 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
762 :
763 : CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_image_matrix_mme'
764 :
765 : INTEGER :: atom_a, handle, iatom, natom
766 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: zeta
767 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: ra
768 : TYPE(mp_para_env_type), POINTER :: para_env
769 :
770 12 : CALL timeset(routineN, handle)
771 12 : NULLIFY (para_env)
772 :
773 12 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
774 60 : ALLOCATE (zeta(natom), ra(3, natom))
775 :
776 36 : zeta(:) = qmmm_env%image_charge_pot%eta
777 :
778 36 : DO iatom = 1, natom
779 24 : atom_a = qmmm_env%image_charge_pot%image_mm_list(iatom)
780 108 : ra(:, iatom) = qmmm_env%image_charge_pot%particles_all(atom_a)%r(:)
781 : END DO
782 :
783 12 : CALL get_qs_env(qs_env, para_env=para_env)
784 :
785 : CALL integrate_s_mme(qmmm_env%image_charge_pot%eri_mme_param, &
786 12 : zeta, zeta, ra, ra, image_matrix, para_env)
787 :
788 12 : CALL timestop(handle)
789 24 : END SUBROUTINE calculate_image_matrix_mme
790 :
791 : ! **************************************************************************************************
792 : !> \brief high-level integration routine for 2c integrals over s-type functions.
793 : !> Parallelization over pairs of functions.
794 : !> \param param ...
795 : !> \param zeta ...
796 : !> \param zetb ...
797 : !> \param ra ...
798 : !> \param rb ...
799 : !> \param hab ...
800 : !> \param para_env ...
801 : ! **************************************************************************************************
802 12 : SUBROUTINE integrate_s_mme(param, zeta, zetb, ra, rb, hab, para_env)
803 : TYPE(cp_eri_mme_param), INTENT(INOUT) :: param
804 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: zeta, zetb
805 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: ra, rb
806 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: hab
807 : TYPE(mp_para_env_type), INTENT(IN), POINTER :: para_env
808 :
809 : CHARACTER(len=*), PARAMETER :: routineN = 'integrate_s_mme'
810 :
811 : INTEGER :: G_count, handle, ipgf, ipgf_prod, jpgf, &
812 : npgf_prod, npgfa, npgfb, R_count
813 : INTEGER, DIMENSION(2) :: limits
814 : REAL(KIND=dp), DIMENSION(3) :: rab
815 :
816 12 : CALL timeset(routineN, handle)
817 12 : G_count = 0; R_count = 0
818 :
819 84 : hab(:, :) = 0.0_dp
820 :
821 12 : npgfa = SIZE(zeta)
822 12 : npgfb = SIZE(zetb)
823 12 : npgf_prod = npgfa*npgfb ! total number of integrals
824 :
825 12 : limits = get_limit(npgf_prod, para_env%num_pe, para_env%mepos)
826 :
827 36 : DO ipgf_prod = limits(1), limits(2)
828 24 : ipgf = (ipgf_prod - 1)/npgfb + 1
829 24 : jpgf = MOD(ipgf_prod - 1, npgfb) + 1
830 96 : rab(:) = ra(:, ipgf) - rb(:, jpgf)
831 : CALL eri_mme_2c_integrate(param%par, 0, 0, 0, 0, zeta(ipgf), &
832 36 : zetb(jpgf), rab, hab, ipgf - 1, jpgf - 1, G_count=G_count, R_count=R_count)
833 : END DO
834 :
835 12 : CALL cp_eri_mme_update_local_counts(param, para_env, G_count_2c=G_count, R_count_2c=R_count)
836 156 : CALL para_env%sum(hab)
837 12 : CALL timestop(handle)
838 :
839 12 : END SUBROUTINE integrate_s_mme
840 :
841 : ! **************************************************************************************************
842 : !> \brief calculates potential of the metal (image potential) given a set of
843 : !> coefficients coeff
844 : !> \param v_metal_rspace potential generated by rho_metal in real space
845 : !> \param coeff expansion coefficients of the image charge density, i.e.
846 : !> rho_metal=sum_a c_a*g_a
847 : !> \param rho_hartree_gspace Kohn Sham density in reciprocal space
848 : !> \param energy structure where energies are stored
849 : !> \param qs_env qs environment
850 : ! **************************************************************************************************
851 180 : SUBROUTINE calculate_potential_metal(v_metal_rspace, coeff, rho_hartree_gspace, energy, &
852 : qs_env)
853 :
854 : TYPE(pw_r3d_rs_type), INTENT(OUT) :: v_metal_rspace
855 : REAL(KIND=dp), DIMENSION(:), POINTER :: coeff
856 : TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL :: rho_hartree_gspace
857 : TYPE(qs_energy_type), OPTIONAL, POINTER :: energy
858 : TYPE(qs_environment_type), POINTER :: qs_env
859 :
860 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_potential_metal'
861 :
862 : INTEGER :: handle
863 : REAL(KIND=dp) :: en_external, en_vmetal_rhohartree, &
864 : total_rho_metal
865 : TYPE(pw_c1d_gs_type) :: rho_metal, v_metal_gspace
866 : TYPE(pw_env_type), POINTER :: pw_env
867 : TYPE(pw_poisson_type), POINTER :: poisson_env
868 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
869 :
870 90 : CALL timeset(routineN, handle)
871 :
872 90 : NULLIFY (pw_env, auxbas_pw_pool, poisson_env)
873 : en_vmetal_rhohartree = 0.0_dp
874 : en_external = 0.0_dp
875 :
876 90 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
877 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
878 90 : poisson_env=poisson_env)
879 :
880 90 : CALL auxbas_pw_pool%create_pw(rho_metal)
881 :
882 90 : CALL auxbas_pw_pool%create_pw(v_metal_gspace)
883 :
884 90 : CALL auxbas_pw_pool%create_pw(v_metal_rspace)
885 :
886 90 : CALL pw_zero(rho_metal)
887 : CALL calculate_rho_metal(rho_metal, coeff, total_rho_metal=total_rho_metal, &
888 90 : qs_env=qs_env)
889 :
890 90 : CALL pw_zero(v_metal_gspace)
891 : CALL pw_poisson_solve(poisson_env, rho_metal, &
892 90 : vhartree=v_metal_gspace)
893 :
894 90 : IF (PRESENT(rho_hartree_gspace)) THEN
895 : en_vmetal_rhohartree = 0.5_dp*pw_integral_ab(v_metal_gspace, &
896 60 : rho_hartree_gspace)
897 60 : en_external = qs_env%qmmm_env_qm%image_charge_pot%V0*total_rho_metal
898 60 : energy%image_charge = en_vmetal_rhohartree - 0.5_dp*en_external
899 : CALL print_image_energy_terms(en_vmetal_rhohartree, en_external, &
900 60 : total_rho_metal, qs_env)
901 : END IF
902 :
903 90 : CALL pw_zero(v_metal_rspace)
904 90 : CALL pw_transfer(v_metal_gspace, v_metal_rspace)
905 90 : CALL pw_scale(v_metal_rspace, v_metal_rspace%pw_grid%dvol)
906 90 : CALL v_metal_gspace%release()
907 90 : CALL rho_metal%release()
908 :
909 90 : CALL timestop(handle)
910 :
911 90 : END SUBROUTINE calculate_potential_metal
912 :
913 : ! ****************************************************************************
914 : !> \brief Add potential of metal (image charge pot) to Hartree Potential
915 : !> \param v_hartree Hartree potential (in real space)
916 : !> \param v_metal potential generated by rho_metal (in real space)
917 : !> \param qs_env qs environment
918 : ! **************************************************************************************************
919 60 : SUBROUTINE add_image_pot_to_hartree_pot(v_hartree, v_metal, qs_env)
920 :
921 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: v_hartree
922 : TYPE(pw_r3d_rs_type), INTENT(IN) :: v_metal
923 : TYPE(qs_environment_type), POINTER :: qs_env
924 :
925 : CHARACTER(len=*), PARAMETER :: routineN = 'add_image_pot_to_hartree_pot'
926 :
927 : INTEGER :: handle, output_unit
928 : TYPE(cp_logger_type), POINTER :: logger
929 : TYPE(section_vals_type), POINTER :: input
930 :
931 60 : CALL timeset(routineN, handle)
932 :
933 60 : NULLIFY (input, logger)
934 60 : logger => cp_get_default_logger()
935 :
936 : !add image charge potential
937 60 : CALL pw_axpy(v_metal, v_hartree)
938 :
939 : ! print info
940 : CALL get_qs_env(qs_env=qs_env, &
941 60 : input=input)
942 : output_unit = cp_print_key_unit_nr(logger, input, &
943 : "QMMM%PRINT%PROGRAM_RUN_INFO", &
944 60 : extension=".qmmmLog")
945 60 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
946 30 : "Adding image charge potential to the Hartree potential."
947 : CALL cp_print_key_finished_output(output_unit, logger, input, &
948 60 : "QMMM%PRINT%PROGRAM_RUN_INFO")
949 :
950 60 : CALL timestop(handle)
951 :
952 60 : END SUBROUTINE add_image_pot_to_hartree_pot
953 :
954 : !****************************************************************************
955 : !> \brief writes image matrix T to file when used as preconditioner for
956 : !> calculating image coefficients iteratively
957 : !> \param image_matrix matrix T
958 : !> \param qs_env qs environment
959 : ! **************************************************************************************************
960 2 : SUBROUTINE write_image_matrix(image_matrix, qs_env)
961 :
962 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: image_matrix
963 : TYPE(qs_environment_type), POINTER :: qs_env
964 :
965 : CHARACTER(LEN=*), PARAMETER :: routineN = 'write_image_matrix'
966 :
967 : CHARACTER(LEN=default_path_length) :: filename
968 : INTEGER :: handle, rst_unit
969 : TYPE(cp_logger_type), POINTER :: logger
970 : TYPE(mp_para_env_type), POINTER :: para_env
971 : TYPE(section_vals_type), POINTER :: print_key, qmmm_section
972 :
973 2 : CALL timeset(routineN, handle)
974 :
975 2 : NULLIFY (qmmm_section, print_key, logger, para_env)
976 2 : logger => cp_get_default_logger()
977 : rst_unit = -1
978 :
979 : CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
980 2 : input=qmmm_section)
981 :
982 : print_key => section_vals_get_subs_vals(qmmm_section, &
983 2 : "QMMM%PRINT%IMAGE_CHARGE_RESTART")
984 :
985 2 : IF (BTEST(cp_print_key_should_output(logger%iter_info, &
986 : qmmm_section, "QMMM%PRINT%IMAGE_CHARGE_RESTART"), &
987 : cp_p_file)) THEN
988 :
989 : rst_unit = cp_print_key_unit_nr(logger, qmmm_section, &
990 : "QMMM%PRINT%IMAGE_CHARGE_RESTART", &
991 : extension=".Image", &
992 : file_status="REPLACE", &
993 : file_action="WRITE", &
994 2 : file_form="UNFORMATTED")
995 :
996 2 : IF (rst_unit > 0) filename = cp_print_key_generate_filename(logger, &
997 : print_key, extension=".IMAGE", &
998 1 : my_local=.FALSE.)
999 :
1000 2 : IF (rst_unit > 0) THEN
1001 7 : WRITE (rst_unit) image_matrix
1002 : END IF
1003 :
1004 : CALL cp_print_key_finished_output(rst_unit, logger, qmmm_section, &
1005 2 : "QMMM%PRINT%IMAGE_CHARGE_RESTART")
1006 : END IF
1007 :
1008 2 : CALL timestop(handle)
1009 :
1010 2 : END SUBROUTINE write_image_matrix
1011 :
1012 : !****************************************************************************
1013 : !> \brief restarts image matrix T when used as preconditioner for calculating
1014 : !> image coefficients iteratively
1015 : !> \param image_matrix matrix T
1016 : !> \param qs_env qs environment
1017 : !> \param qmmm_env qmmm environment
1018 : ! **************************************************************************************************
1019 0 : SUBROUTINE restart_image_matrix(image_matrix, qs_env, qmmm_env)
1020 :
1021 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: image_matrix
1022 : TYPE(qs_environment_type), POINTER :: qs_env
1023 : TYPE(qmmm_env_qm_type), POINTER :: qmmm_env
1024 :
1025 : CHARACTER(LEN=*), PARAMETER :: routineN = 'restart_image_matrix'
1026 :
1027 : CHARACTER(LEN=default_path_length) :: image_filename
1028 : INTEGER :: handle, natom, output_unit, rst_unit
1029 : LOGICAL :: exist
1030 : TYPE(cp_logger_type), POINTER :: logger
1031 : TYPE(mp_para_env_type), POINTER :: para_env
1032 : TYPE(section_vals_type), POINTER :: qmmm_section
1033 :
1034 0 : CALL timeset(routineN, handle)
1035 :
1036 0 : NULLIFY (qmmm_section, logger, para_env)
1037 0 : logger => cp_get_default_logger()
1038 0 : exist = .FALSE.
1039 0 : rst_unit = -1
1040 :
1041 0 : natom = SIZE(qmmm_env%image_charge_pot%image_mm_list)
1042 :
1043 0 : IF (.NOT. ASSOCIATED(image_matrix)) THEN
1044 0 : ALLOCATE (image_matrix(natom, natom))
1045 : END IF
1046 :
1047 0 : image_matrix = 0.0_dp
1048 :
1049 : CALL get_qs_env(qs_env=qs_env, para_env=para_env, &
1050 0 : input=qmmm_section)
1051 :
1052 : CALL section_vals_val_get(qmmm_section, "QMMM%IMAGE_CHARGE%IMAGE_RESTART_FILE_NAME", &
1053 0 : c_val=image_filename)
1054 :
1055 0 : INQUIRE (FILE=image_filename, exist=exist)
1056 :
1057 0 : IF (exist) THEN
1058 0 : IF (para_env%is_source()) THEN
1059 : CALL open_file(file_name=image_filename, &
1060 : file_status="OLD", &
1061 : file_form="UNFORMATTED", &
1062 : file_action="READ", &
1063 0 : unit_number=rst_unit)
1064 :
1065 0 : READ (rst_unit) qs_env%image_matrix
1066 : END IF
1067 :
1068 0 : CALL para_env%bcast(qs_env%image_matrix)
1069 :
1070 0 : IF (para_env%is_source()) CALL close_file(unit_number=rst_unit)
1071 :
1072 : output_unit = cp_print_key_unit_nr(logger, qmmm_section, &
1073 : "QMMM%PRINT%PROGRAM_RUN_INFO", &
1074 0 : extension=".qmmmLog")
1075 0 : IF (output_unit > 0) WRITE (UNIT=output_unit, FMT="(T3,A)") &
1076 0 : "Restarted image matrix"
1077 : ELSE
1078 0 : CPABORT("Restart file for image matrix not found")
1079 : END IF
1080 :
1081 0 : qmmm_env%image_charge_pot%image_restart = .FALSE.
1082 :
1083 0 : CALL timestop(handle)
1084 :
1085 0 : END SUBROUTINE restart_image_matrix
1086 :
1087 : ! ****************************************************************************
1088 : !> \brief Print info on image gradients on image MM atoms
1089 : !> \param forces structure storing the force contribution of the image charges
1090 : !> for the metal (MM) atoms (actually these are only the gradients)
1091 : !> \param qs_env qs environment
1092 : ! **************************************************************************************************
1093 20 : SUBROUTINE print_gradients_image_atoms(forces, qs_env)
1094 :
1095 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: forces
1096 : TYPE(qs_environment_type), POINTER :: qs_env
1097 :
1098 : INTEGER :: atom_a, iatom, natom, output_unit
1099 : REAL(KIND=dp), DIMENSION(3) :: sum_gradients
1100 : TYPE(cp_logger_type), POINTER :: logger
1101 : TYPE(section_vals_type), POINTER :: input
1102 :
1103 20 : NULLIFY (input, logger)
1104 20 : logger => cp_get_default_logger()
1105 :
1106 20 : sum_gradients = 0.0_dp
1107 20 : natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
1108 :
1109 60 : DO iatom = 1, natom
1110 180 : sum_gradients(:) = sum_gradients(:) + forces(:, iatom)
1111 : END DO
1112 :
1113 20 : CALL get_qs_env(qs_env=qs_env, input=input)
1114 :
1115 : output_unit = cp_print_key_unit_nr(logger, input, &
1116 20 : "QMMM%PRINT%DERIVATIVES", extension=".Log")
1117 20 : IF (output_unit > 0) THEN
1118 : WRITE (unit=output_unit, fmt="(/1X,A)") &
1119 0 : "Image gradients [a.u.] on MM image charge atoms after QMMM calculation: "
1120 : WRITE (unit=output_unit, fmt="(T4,A4,T27,A1,T50,A1,T74,A1)") &
1121 0 : "Atom", "X", "Y", "Z"
1122 0 : DO iatom = 1, natom
1123 0 : atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
1124 : WRITE (unit=output_unit, fmt="(T2,I6,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
1125 0 : atom_a, forces(:, iatom)
1126 : END DO
1127 :
1128 0 : WRITE (unit=output_unit, fmt="(T2,A)") REPEAT("-", 79)
1129 : WRITE (unit=output_unit, fmt="(T2,A,T22,ES12.5,T45,ES12.5,T69,ES12.5)") &
1130 0 : "sum gradients:", sum_gradients
1131 0 : WRITE (unit=output_unit, fmt="(/)")
1132 : END IF
1133 :
1134 : CALL cp_print_key_finished_output(output_unit, logger, input, &
1135 20 : "QMMM%PRINT%DERIVATIVES")
1136 :
1137 20 : END SUBROUTINE print_gradients_image_atoms
1138 :
1139 : ! ****************************************************************************
1140 : !> \brief Print image coefficients
1141 : !> \param image_coeff expansion coefficients of the image charge density
1142 : !> \param qs_env qs environment
1143 : ! **************************************************************************************************
1144 10 : SUBROUTINE print_image_coefficients(image_coeff, qs_env)
1145 :
1146 : REAL(KIND=dp), DIMENSION(:), POINTER :: image_coeff
1147 : TYPE(qs_environment_type), POINTER :: qs_env
1148 :
1149 : INTEGER :: atom_a, iatom, natom, output_unit
1150 : REAL(KIND=dp) :: normalize_factor, sum_coeff
1151 : TYPE(cp_logger_type), POINTER :: logger
1152 : TYPE(section_vals_type), POINTER :: input
1153 :
1154 10 : NULLIFY (input, logger)
1155 10 : logger => cp_get_default_logger()
1156 :
1157 10 : sum_coeff = 0.0_dp
1158 10 : natom = SIZE(qs_env%qmmm_env_qm%image_charge_pot%image_mm_list)
1159 10 : normalize_factor = SQRT((qs_env%qmmm_env_qm%image_charge_pot%eta/pi)**3)
1160 :
1161 30 : DO iatom = 1, natom
1162 30 : sum_coeff = sum_coeff + image_coeff(iatom)
1163 : END DO
1164 :
1165 10 : CALL get_qs_env(qs_env=qs_env, input=input)
1166 :
1167 : output_unit = cp_print_key_unit_nr(logger, input, &
1168 10 : "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
1169 10 : IF (output_unit > 0) THEN
1170 2 : WRITE (unit=output_unit, fmt="(/)")
1171 : WRITE (unit=output_unit, fmt="(T2,A)") &
1172 2 : "Image charges [a.u.] after QMMM calculation: "
1173 2 : WRITE (unit=output_unit, fmt="(T4,A4,T67,A)") "Atom", "Image charge"
1174 2 : WRITE (unit=output_unit, fmt="(T4,A,T67,A)") REPEAT("-", 4), REPEAT("-", 12)
1175 :
1176 6 : DO iatom = 1, natom
1177 4 : atom_a = qs_env%qmmm_env_qm%image_charge_pot%image_mm_list(iatom)
1178 : !opposite sign for image_coeff; during the calculation they have
1179 : !the 'wrong' sign to ensure consistency with v_hartree which has
1180 : !the opposite sign
1181 : WRITE (unit=output_unit, fmt="(T2,I6,T65,ES16.9)") &
1182 6 : atom_a, -image_coeff(iatom)/normalize_factor
1183 : END DO
1184 :
1185 2 : WRITE (unit=output_unit, fmt="(T2,A)") REPEAT("-", 79)
1186 : WRITE (unit=output_unit, fmt="(T2,A,T65,ES16.9)") &
1187 2 : "sum image charges:", -sum_coeff/normalize_factor
1188 : END IF
1189 :
1190 : CALL cp_print_key_finished_output(output_unit, logger, input, &
1191 10 : "QMMM%PRINT%IMAGE_CHARGE_INFO")
1192 :
1193 10 : END SUBROUTINE print_image_coefficients
1194 :
1195 : ! ****************************************************************************
1196 : !> \brief Print detailed image charge energies
1197 : !> \param en_vmetal_rhohartree energy contribution of the image charges
1198 : !> without external potential, i.e. 0.5*integral(v_metal*rho_hartree)
1199 : !> \param en_external additional energy contribution of the image charges due
1200 : !> to an external potential, i.e. V0*total_rho_metal
1201 : !> \param total_rho_metal total induced image charge density
1202 : !> \param qs_env qs environment
1203 : ! **************************************************************************************************
1204 60 : SUBROUTINE print_image_energy_terms(en_vmetal_rhohartree, en_external, &
1205 : total_rho_metal, qs_env)
1206 :
1207 : REAL(KIND=dp), INTENT(IN) :: en_vmetal_rhohartree, en_external, &
1208 : total_rho_metal
1209 : TYPE(qs_environment_type), POINTER :: qs_env
1210 :
1211 : INTEGER :: output_unit
1212 : TYPE(cp_logger_type), POINTER :: logger
1213 : TYPE(section_vals_type), POINTER :: input
1214 :
1215 60 : NULLIFY (input, logger)
1216 60 : logger => cp_get_default_logger()
1217 :
1218 60 : CALL get_qs_env(qs_env=qs_env, input=input)
1219 :
1220 : output_unit = cp_print_key_unit_nr(logger, input, &
1221 60 : "QMMM%PRINT%IMAGE_CHARGE_INFO", extension=".Log")
1222 :
1223 60 : IF (output_unit > 0) THEN
1224 : WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1225 6 : "Total induced charge density [a.u.]:", total_rho_metal
1226 6 : WRITE (unit=output_unit, fmt="(T3,A)") "Image energy terms: "
1227 : WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1228 6 : "Coulomb energy of QM and image charge density [a.u.]:", en_vmetal_rhohartree
1229 : WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1230 6 : "External potential energy term [a.u.]:", -0.5_dp*en_external
1231 : WRITE (unit=output_unit, fmt="(T3,A,T56,F25.14)") &
1232 6 : "Total image charge energy [a.u.]:", en_vmetal_rhohartree - 0.5_dp*en_external
1233 : END IF
1234 :
1235 : CALL cp_print_key_finished_output(output_unit, logger, input, &
1236 60 : "QMMM%PRINT%IMAGE_CHARGE_INFO")
1237 :
1238 60 : END SUBROUTINE print_image_energy_terms
1239 :
1240 30 : END MODULE qmmm_image_charge
|