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 : MODULE optimize_embedding_potential
9 :
10 : USE atomic_kind_types, ONLY: atomic_kind_type,&
11 : get_atomic_kind,&
12 : get_atomic_kind_set
13 : USE cell_types, ONLY: cell_type
14 : USE cp_blacs_env, ONLY: cp_blacs_env_create,&
15 : cp_blacs_env_release,&
16 : cp_blacs_env_type
17 : USE cp_control_types, ONLY: dft_control_type
18 : USE cp_dbcsr_api, ONLY: dbcsr_p_type
19 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
20 : dbcsr_deallocate_matrix_set
21 : USE cp_files, ONLY: close_file,&
22 : open_file
23 : USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale,&
24 : cp_fm_scale,&
25 : cp_fm_scale_and_add,&
26 : cp_fm_trace
27 : USE cp_fm_diag, ONLY: choose_eigv_solver
28 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
29 : cp_fm_struct_release,&
30 : cp_fm_struct_type
31 : USE cp_fm_types, ONLY: &
32 : cp_fm_copy_general, cp_fm_create, cp_fm_get_element, cp_fm_get_info, cp_fm_release, &
33 : cp_fm_set_all, cp_fm_to_fm, cp_fm_to_fm_submat, cp_fm_type, cp_fm_write_unformatted
34 : USE cp_log_handling, ONLY: cp_get_default_logger,&
35 : cp_logger_type
36 : USE cp_output_handling, ONLY: cp_p_file,&
37 : cp_print_key_finished_output,&
38 : cp_print_key_should_output,&
39 : cp_print_key_unit_nr
40 : USE cp_realspace_grid_cube, ONLY: cp_cube_to_pw,&
41 : cp_pw_to_cube,&
42 : cp_pw_to_simple_volumetric
43 : USE embed_types, ONLY: opt_embed_pot_type
44 : USE force_env_types, ONLY: force_env_type
45 : USE input_constants, ONLY: &
46 : embed_diff, embed_fa, embed_grid_angstrom, embed_grid_bohr, embed_level_shift, embed_none, &
47 : embed_quasi_newton, embed_resp, embed_steep_desc
48 : USE input_section_types, ONLY: section_get_ival,&
49 : section_get_ivals,&
50 : section_get_rval,&
51 : section_vals_get_subs_vals,&
52 : section_vals_type,&
53 : section_vals_val_get
54 : USE kinds, ONLY: default_path_length,&
55 : dp
56 : USE lri_environment_types, ONLY: lri_kind_type
57 : USE mathconstants, ONLY: pi
58 : USE message_passing, ONLY: mp_para_env_type
59 : USE mixed_environment_utils, ONLY: get_subsys_map_index
60 : USE parallel_gemm_api, ONLY: parallel_gemm
61 : USE particle_list_types, ONLY: particle_list_type
62 : USE particle_types, ONLY: particle_type
63 : USE pw_env_types, ONLY: pw_env_get,&
64 : pw_env_type
65 : USE pw_methods, ONLY: &
66 : pw_axpy, pw_copy, pw_derive, pw_dr2, pw_integral_ab, pw_integrate_function, pw_scale, &
67 : pw_transfer, pw_zero
68 : USE pw_poisson_methods, ONLY: pw_poisson_solve
69 : USE pw_poisson_types, ONLY: pw_poisson_type
70 : USE pw_pool_types, ONLY: pw_pool_type
71 : USE pw_types, ONLY: pw_c1d_gs_type,&
72 : pw_r3d_rs_type
73 : USE qs_collocate_density, ONLY: calculate_rho_resp_all,&
74 : calculate_wavefunction,&
75 : collocate_function
76 : USE qs_environment_types, ONLY: get_qs_env,&
77 : qs_environment_type,&
78 : set_qs_env
79 : USE qs_integrate_potential_single, ONLY: integrate_v_rspace_one_center
80 : USE qs_kind_types, ONLY: get_qs_kind,&
81 : qs_kind_type
82 : USE qs_kinetic, ONLY: build_kinetic_matrix
83 : USE qs_ks_types, ONLY: qs_ks_env_type
84 : USE qs_mo_types, ONLY: get_mo_set,&
85 : mo_set_type
86 : USE qs_neighbor_list_types, ONLY: neighbor_list_set_p_type
87 : USE qs_rho_types, ONLY: qs_rho_get,&
88 : qs_rho_type
89 : USE qs_subsys_types, ONLY: qs_subsys_get,&
90 : qs_subsys_type
91 : USE xc, ONLY: smooth_cutoff
92 : USE xc_rho_cflags_types, ONLY: xc_rho_cflags_setall,&
93 : xc_rho_cflags_type
94 : USE xc_rho_set_types, ONLY: xc_rho_set_create,&
95 : xc_rho_set_release,&
96 : xc_rho_set_type,&
97 : xc_rho_set_update
98 : #include "./base/base_uses.f90"
99 :
100 : IMPLICIT NONE
101 :
102 : PRIVATE
103 :
104 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'optimize_embedding_potential'
105 :
106 : PUBLIC :: prepare_embed_opt, init_embed_pot, release_opt_embed, calculate_embed_pot_grad, &
107 : opt_embed_step, print_rho_diff, step_control, max_dens_diff, print_emb_opt_info, &
108 : conv_check_embed, make_subsys_embed_pot, print_embed_restart, find_aux_dimen, &
109 : read_embed_pot, understand_spin_states, given_embed_pot, print_rho_spin_diff, &
110 : print_pot_simple_grid, get_prev_density, get_max_subsys_diff, Coulomb_guess
111 :
112 : CONTAINS
113 :
114 : ! **************************************************************************************************
115 : !> \brief Find out whether we need to swap alpha- and beta- spind densities in the second subsystem
116 : !> \brief It's only needed because by default alpha-spins go first in a subsystem.
117 : !> \brief By swapping we impose the constraint:
118 : !> \brief rho_1(alpha) + rho_2(alpha) = rho_total(alpha)
119 : !> \brief rho_1(beta) + rho_2(beta) = rho_total(beta)
120 : !> \param force_env ...
121 : !> \param ref_subsys_number ...
122 : !> \param change_spin ...
123 : !> \param open_shell_embed ...
124 : !> \param all_nspins ...
125 : !> \return ...
126 : !> \author Vladimir Rybkin
127 : ! **************************************************************************************************
128 24 : SUBROUTINE understand_spin_states(force_env, ref_subsys_number, change_spin, open_shell_embed, all_nspins)
129 : TYPE(force_env_type), POINTER :: force_env
130 : INTEGER :: ref_subsys_number
131 : LOGICAL :: change_spin, open_shell_embed
132 : INTEGER, ALLOCATABLE, DIMENSION(:) :: all_nspins
133 :
134 : INTEGER :: i_force_eval, nspins, sub_spin_1, &
135 : sub_spin_2, total_spin
136 : INTEGER, DIMENSION(2) :: nelectron_spin
137 : INTEGER, DIMENSION(2, 3) :: all_spins
138 : TYPE(dft_control_type), POINTER :: dft_control
139 :
140 24 : change_spin = .FALSE.
141 24 : open_shell_embed = .FALSE.
142 72 : ALLOCATE (all_nspins(ref_subsys_number))
143 24 : IF (ref_subsys_number == 3) THEN
144 24 : all_spins = 0
145 96 : DO i_force_eval = 1, ref_subsys_number
146 : CALL get_qs_env(qs_env=force_env%sub_force_env(i_force_eval)%force_env%qs_env, &
147 72 : nelectron_spin=nelectron_spin, dft_control=dft_control)
148 216 : all_spins(:, i_force_eval) = nelectron_spin
149 72 : nspins = dft_control%nspins
150 96 : all_nspins(i_force_eval) = nspins
151 : END DO
152 :
153 : ! Find out whether we need a spin-dependend embedding potential
154 24 : IF (.NOT. ((all_nspins(1) == 1) .AND. (all_nspins(2) == 1) .AND. (all_nspins(3) == 1))) THEN
155 12 : open_shell_embed = .TRUE.
156 : END IF
157 :
158 : ! If it's open shell, we need to check spin states
159 24 : IF (open_shell_embed) THEN
160 :
161 12 : IF (all_nspins(3) == 1) THEN
162 : total_spin = 0
163 : ELSE
164 10 : total_spin = all_spins(1, 3) - all_spins(2, 3)
165 : END IF
166 12 : IF (all_nspins(1) == 1) THEN
167 : sub_spin_1 = 0
168 : ELSE
169 12 : sub_spin_1 = all_spins(1, 1) - all_spins(2, 1)
170 : END IF
171 12 : IF (all_nspins(2) == 1) THEN
172 : sub_spin_2 = 0
173 : ELSE
174 12 : sub_spin_2 = all_spins(1, 2) - all_spins(2, 2)
175 : END IF
176 12 : IF ((sub_spin_1 + sub_spin_2) == total_spin) THEN
177 10 : change_spin = .FALSE.
178 : ELSE
179 2 : IF (ABS(sub_spin_1 - sub_spin_2) == total_spin) THEN
180 2 : change_spin = .TRUE.
181 : ELSE
182 0 : CPABORT("Spin states of subsystems are not compatible.")
183 : END IF
184 : END IF
185 :
186 : END IF ! not open_shell
187 : ELSE
188 0 : CPABORT("Reference subsystem must be the third FORCE_EVAL.")
189 : END IF
190 :
191 24 : END SUBROUTINE understand_spin_states
192 :
193 : ! **************************************************************************************************
194 : !> \brief ...
195 : !> \param qs_env ...
196 : !> \param embed_pot ...
197 : !> \param add_const_pot ...
198 : !> \param Fermi_Amaldi ...
199 : !> \param const_pot ...
200 : !> \param open_shell_embed ...
201 : !> \param spin_embed_pot ...
202 : !> \param pot_diff ...
203 : !> \param Coulomb_guess ...
204 : !> \param grid_opt ...
205 : ! **************************************************************************************************
206 24 : SUBROUTINE init_embed_pot(qs_env, embed_pot, add_const_pot, Fermi_Amaldi, const_pot, open_shell_embed, &
207 : spin_embed_pot, pot_diff, Coulomb_guess, grid_opt)
208 : TYPE(qs_environment_type), POINTER :: qs_env
209 : TYPE(pw_r3d_rs_type), POINTER :: embed_pot
210 : LOGICAL :: add_const_pot, Fermi_Amaldi
211 : TYPE(pw_r3d_rs_type), POINTER :: const_pot
212 : LOGICAL :: open_shell_embed
213 : TYPE(pw_r3d_rs_type), POINTER :: spin_embed_pot, pot_diff
214 : LOGICAL :: Coulomb_guess, grid_opt
215 :
216 : INTEGER :: nelectrons
217 : INTEGER, DIMENSION(2) :: nelectron_spin
218 : REAL(KIND=dp) :: factor
219 : TYPE(pw_env_type), POINTER :: pw_env
220 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
221 : TYPE(pw_r3d_rs_type), POINTER :: v_hartree_r_space
222 :
223 : ! Extract plane waves environment
224 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env, &
225 : nelectron_spin=nelectron_spin, &
226 24 : v_hartree_rspace=v_hartree_r_space)
227 :
228 : ! Prepare plane-waves pool
229 24 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
230 :
231 : ! Create embedding potential and set to zero
232 : NULLIFY (embed_pot)
233 24 : ALLOCATE (embed_pot)
234 24 : CALL auxbas_pw_pool%create_pw(embed_pot)
235 24 : CALL pw_zero(embed_pot)
236 :
237 : ! Spin embedding potential if asked
238 24 : IF (open_shell_embed) THEN
239 : NULLIFY (spin_embed_pot)
240 12 : ALLOCATE (spin_embed_pot)
241 12 : CALL auxbas_pw_pool%create_pw(spin_embed_pot)
242 12 : CALL pw_zero(spin_embed_pot)
243 : END IF
244 :
245 : ! Coulomb guess/constant potential
246 24 : IF (Coulomb_guess) THEN
247 : NULLIFY (pot_diff)
248 2 : ALLOCATE (pot_diff)
249 2 : CALL auxbas_pw_pool%create_pw(pot_diff)
250 2 : CALL pw_zero(pot_diff)
251 : END IF
252 :
253 : ! Initialize constant part of the embedding potential
254 24 : IF (add_const_pot .AND. (.NOT. grid_opt)) THEN
255 : ! Now the constant potential is the Coulomb one
256 : NULLIFY (const_pot)
257 4 : ALLOCATE (const_pot)
258 4 : CALL auxbas_pw_pool%create_pw(const_pot)
259 4 : CALL pw_zero(const_pot)
260 : END IF
261 :
262 : ! Add Fermi-Amaldi potential if requested
263 24 : IF (Fermi_Amaldi) THEN
264 :
265 : ! Extract Hartree potential
266 6 : NULLIFY (v_hartree_r_space)
267 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env, &
268 6 : v_hartree_rspace=v_hartree_r_space)
269 6 : CALL pw_copy(v_hartree_r_space, embed_pot)
270 :
271 : ! Calculate the number of electrons
272 6 : nelectrons = nelectron_spin(1) + nelectron_spin(2)
273 6 : factor = (REAL(nelectrons, dp) - 1.0_dp)/(REAL(nelectrons, dp))
274 :
275 : ! Scale the Hartree potential to get Fermi-Amaldi
276 6 : CALL pw_scale(embed_pot, a=factor)
277 :
278 : ! Copy Fermi-Amaldi to embedding potential for basis-based optimization
279 6 : IF (.NOT. grid_opt) CALL pw_copy(embed_pot, embed_pot)
280 :
281 : END IF
282 :
283 24 : END SUBROUTINE init_embed_pot
284 :
285 : ! **************************************************************************************************
286 : !> \brief Creates and allocates objects for optimization of embedding potential
287 : !> \param qs_env ...
288 : !> \param opt_embed ...
289 : !> \param opt_embed_section ...
290 : !> \author Vladimir Rybkin
291 : ! **************************************************************************************************
292 24 : SUBROUTINE prepare_embed_opt(qs_env, opt_embed, opt_embed_section)
293 : TYPE(qs_environment_type), POINTER :: qs_env
294 : TYPE(opt_embed_pot_type) :: opt_embed
295 : TYPE(section_vals_type), POINTER :: opt_embed_section
296 :
297 : INTEGER :: diff_size, i_dens, size_prev_dens
298 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
299 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
300 : TYPE(mp_para_env_type), POINTER :: para_env
301 : TYPE(pw_env_type), POINTER :: pw_env
302 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
303 :
304 : !TYPE(pw_env_type), POINTER :: pw_env
305 : !TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
306 :
307 : ! First, read the input
308 :
309 24 : CALL read_opt_embed_section(opt_embed, opt_embed_section)
310 :
311 : ! All these are needed for optimization in a finite Gaussian basis
312 24 : IF (.NOT. opt_embed%grid_opt) THEN
313 : ! Create blacs environment
314 : CALL get_qs_env(qs_env=qs_env, &
315 14 : para_env=para_env)
316 14 : NULLIFY (blacs_env)
317 14 : CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env)
318 :
319 : ! Reveal the dimension of the RI basis
320 14 : CALL find_aux_dimen(qs_env, opt_embed%dimen_aux)
321 :
322 : ! Prepare the object for integrals
323 14 : CALL make_lri_object(qs_env, opt_embed%lri)
324 :
325 : ! In case if spin embedding potential has to be optimized,
326 : ! the dimension of variational space is two times larger
327 14 : IF (opt_embed%open_shell_embed) THEN
328 6 : opt_embed%dimen_var_aux = 2*opt_embed%dimen_aux
329 : ELSE
330 8 : opt_embed%dimen_var_aux = opt_embed%dimen_aux
331 : END IF
332 :
333 : ! Allocate expansion coefficients and gradient
334 14 : NULLIFY (opt_embed%embed_pot_grad, opt_embed%embed_pot_coef, opt_embed%step, fm_struct)
335 :
336 14 : NULLIFY (opt_embed%prev_embed_pot_grad, opt_embed%prev_embed_pot_coef, opt_embed%prev_step)
337 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
338 14 : nrow_global=opt_embed%dimen_var_aux, ncol_global=1)
339 : ALLOCATE (opt_embed%embed_pot_grad, opt_embed%embed_pot_coef, &
340 : opt_embed%prev_embed_pot_grad, opt_embed%prev_embed_pot_coef, &
341 14 : opt_embed%step, opt_embed%prev_step)
342 14 : CALL cp_fm_create(opt_embed%embed_pot_grad, fm_struct, name="pot_grad")
343 14 : CALL cp_fm_create(opt_embed%embed_pot_coef, fm_struct, name="pot_coef")
344 14 : CALL cp_fm_create(opt_embed%prev_embed_pot_grad, fm_struct, name="prev_pot_grad")
345 14 : CALL cp_fm_create(opt_embed%prev_embed_pot_coef, fm_struct, name="prev_pot_coef")
346 14 : CALL cp_fm_create(opt_embed%step, fm_struct, name="step")
347 14 : CALL cp_fm_create(opt_embed%prev_step, fm_struct, name="prev_step")
348 :
349 14 : CALL cp_fm_struct_release(fm_struct)
350 14 : CALL cp_fm_set_all(opt_embed%embed_pot_grad, 0.0_dp)
351 14 : CALL cp_fm_set_all(opt_embed%prev_embed_pot_grad, 0.0_dp)
352 14 : CALL cp_fm_set_all(opt_embed%embed_pot_coef, 0.0_dp)
353 14 : CALL cp_fm_set_all(opt_embed%prev_embed_pot_coef, 0.0_dp)
354 14 : CALL cp_fm_set_all(opt_embed%step, 0.0_dp)
355 :
356 14 : CALL cp_fm_set_all(opt_embed%prev_step, 0.0_dp)
357 :
358 : ! Allocate Hessian
359 14 : NULLIFY (opt_embed%embed_pot_hess, opt_embed%prev_embed_pot_hess, fm_struct)
360 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
361 14 : nrow_global=opt_embed%dimen_var_aux, ncol_global=opt_embed%dimen_var_aux)
362 14 : ALLOCATE (opt_embed%embed_pot_hess, opt_embed%prev_embed_pot_hess)
363 14 : CALL cp_fm_create(opt_embed%embed_pot_hess, fm_struct, name="pot_Hess")
364 14 : CALL cp_fm_create(opt_embed%prev_embed_pot_hess, fm_struct, name="prev_pot_Hess")
365 14 : CALL cp_fm_struct_release(fm_struct)
366 :
367 : ! Special structure for the kinetic energy matrix
368 14 : NULLIFY (fm_struct, opt_embed%kinetic_mat)
369 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
370 14 : nrow_global=opt_embed%dimen_aux, ncol_global=opt_embed%dimen_aux)
371 14 : ALLOCATE (opt_embed%kinetic_mat)
372 14 : CALL cp_fm_create(opt_embed%kinetic_mat, fm_struct, name="kinetic_mat")
373 14 : CALL cp_fm_struct_release(fm_struct)
374 14 : CALL cp_fm_set_all(opt_embed%kinetic_mat, 0.0_dp)
375 :
376 : ! Hessian is set as a unit matrix
377 14 : CALL cp_fm_set_all(opt_embed%embed_pot_hess, 0.0_dp, -1.0_dp)
378 14 : CALL cp_fm_set_all(opt_embed%prev_embed_pot_hess, 0.0_dp, -1.0_dp)
379 :
380 : ! Release blacs environment
381 14 : CALL cp_blacs_env_release(blacs_env)
382 :
383 : END IF
384 :
385 24 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
386 24 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
387 24 : NULLIFY (opt_embed%prev_subsys_dens)
388 72 : size_prev_dens = SUM(opt_embed%all_nspins(1:(SIZE(opt_embed%all_nspins) - 1)))
389 144 : ALLOCATE (opt_embed%prev_subsys_dens(size_prev_dens))
390 96 : DO i_dens = 1, size_prev_dens
391 72 : CALL auxbas_pw_pool%create_pw(opt_embed%prev_subsys_dens(i_dens))
392 96 : CALL pw_zero(opt_embed%prev_subsys_dens(i_dens))
393 : END DO
394 72 : ALLOCATE (opt_embed%max_subsys_dens_diff(size_prev_dens))
395 :
396 : ! Array to store functional values
397 72 : ALLOCATE (opt_embed%w_func(opt_embed%n_iter))
398 1136 : opt_embed%w_func = 0.0_dp
399 :
400 : ! Allocate max_diff and int_diff
401 24 : diff_size = 1
402 24 : IF (opt_embed%open_shell_embed) diff_size = 2
403 48 : ALLOCATE (opt_embed%max_diff(diff_size))
404 48 : ALLOCATE (opt_embed%int_diff(diff_size))
405 48 : ALLOCATE (opt_embed%int_diff_square(diff_size))
406 :
407 : ! FAB update
408 24 : IF (opt_embed%fab) THEN
409 : NULLIFY (opt_embed%prev_embed_pot)
410 2 : ALLOCATE (opt_embed%prev_embed_pot)
411 2 : CALL auxbas_pw_pool%create_pw(opt_embed%prev_embed_pot)
412 2 : CALL pw_zero(opt_embed%prev_embed_pot)
413 2 : IF (opt_embed%open_shell_embed) THEN
414 : NULLIFY (opt_embed%prev_spin_embed_pot)
415 0 : ALLOCATE (opt_embed%prev_spin_embed_pot)
416 0 : CALL auxbas_pw_pool%create_pw(opt_embed%prev_spin_embed_pot)
417 0 : CALL pw_zero(opt_embed%prev_spin_embed_pot)
418 : END IF
419 : END IF
420 :
421 : ! Set allowed energy decrease parameter
422 24 : opt_embed%allowed_decrease = 0.0001_dp
423 :
424 : ! Regularization contribution is set to zero
425 24 : opt_embed%reg_term = 0.0_dp
426 :
427 : ! Step is accepted in the beginning
428 24 : opt_embed%accept_step = .TRUE.
429 24 : opt_embed%newton_step = .FALSE.
430 24 : opt_embed%last_accepted = 1
431 :
432 : ! Set maximum and minimum trust radii
433 24 : opt_embed%max_trad = opt_embed%trust_rad*7.900_dp
434 24 : opt_embed%min_trad = opt_embed%trust_rad*0.125*0.065_dp
435 :
436 24 : END SUBROUTINE prepare_embed_opt
437 :
438 : ! **************************************************************************************************
439 : !> \brief ...
440 : !> \param opt_embed ...
441 : !> \param opt_embed_section ...
442 : ! **************************************************************************************************
443 72 : SUBROUTINE read_opt_embed_section(opt_embed, opt_embed_section)
444 : TYPE(opt_embed_pot_type) :: opt_embed
445 : TYPE(section_vals_type), POINTER :: opt_embed_section
446 :
447 : INTEGER :: embed_guess, embed_optimizer
448 :
449 : ! Read keywords
450 : CALL section_vals_val_get(opt_embed_section, "REG_LAMBDA", &
451 24 : r_val=opt_embed%lambda)
452 :
453 : CALL section_vals_val_get(opt_embed_section, "N_ITER", &
454 24 : i_val=opt_embed%n_iter)
455 :
456 : CALL section_vals_val_get(opt_embed_section, "TRUST_RAD", &
457 24 : r_val=opt_embed%trust_rad)
458 :
459 : CALL section_vals_val_get(opt_embed_section, "DENS_CONV_MAX", &
460 24 : r_val=opt_embed%conv_max)
461 :
462 : CALL section_vals_val_get(opt_embed_section, "DENS_CONV_INT", &
463 24 : r_val=opt_embed%conv_int)
464 :
465 : CALL section_vals_val_get(opt_embed_section, "SPIN_DENS_CONV_MAX", &
466 24 : r_val=opt_embed%conv_max_spin)
467 :
468 : CALL section_vals_val_get(opt_embed_section, "SPIN_DENS_CONV_INT", &
469 24 : r_val=opt_embed%conv_int_spin)
470 :
471 : CALL section_vals_val_get(opt_embed_section, "CHARGE_DISTR_WIDTH", &
472 24 : r_val=opt_embed%eta)
473 :
474 : CALL section_vals_val_get(opt_embed_section, "READ_EMBED_POT", &
475 24 : l_val=opt_embed%read_embed_pot)
476 :
477 : CALL section_vals_val_get(opt_embed_section, "READ_EMBED_POT_CUBE", &
478 24 : l_val=opt_embed%read_embed_pot_cube)
479 :
480 : CALL section_vals_val_get(opt_embed_section, "GRID_OPT", &
481 24 : l_val=opt_embed%grid_opt)
482 :
483 : CALL section_vals_val_get(opt_embed_section, "LEEUWEN-BAERENDS", &
484 24 : l_val=opt_embed%leeuwen)
485 :
486 : CALL section_vals_val_get(opt_embed_section, "FAB", &
487 24 : l_val=opt_embed%fab)
488 :
489 : CALL section_vals_val_get(opt_embed_section, "VW_CUTOFF", &
490 24 : r_val=opt_embed%vw_cutoff)
491 :
492 : CALL section_vals_val_get(opt_embed_section, "VW_SMOOTH_CUT_RANGE", &
493 24 : r_val=opt_embed%vw_smooth_cutoff_range)
494 :
495 24 : CALL section_vals_val_get(opt_embed_section, "OPTIMIZER", i_val=embed_optimizer)
496 14 : SELECT CASE (embed_optimizer)
497 : CASE (embed_steep_desc)
498 14 : opt_embed%steep_desc = .TRUE.
499 : CASE (embed_quasi_newton)
500 4 : opt_embed%steep_desc = .FALSE.
501 4 : opt_embed%level_shift = .FALSE.
502 : CASE (embed_level_shift)
503 6 : opt_embed%steep_desc = .FALSE.
504 6 : opt_embed%level_shift = .TRUE.
505 : CASE DEFAULT
506 24 : opt_embed%steep_desc = .TRUE.
507 : END SELECT
508 :
509 24 : CALL section_vals_val_get(opt_embed_section, "POT_GUESS", i_val=embed_guess)
510 16 : SELECT CASE (embed_guess)
511 : CASE (embed_none)
512 16 : opt_embed%add_const_pot = .FALSE.
513 16 : opt_embed%Fermi_Amaldi = .FALSE.
514 16 : opt_embed%Coulomb_guess = .FALSE.
515 16 : opt_embed%diff_guess = .FALSE.
516 : CASE (embed_diff)
517 2 : opt_embed%add_const_pot = .TRUE.
518 2 : opt_embed%Fermi_Amaldi = .FALSE.
519 2 : opt_embed%Coulomb_guess = .FALSE.
520 2 : opt_embed%diff_guess = .TRUE.
521 : CASE (embed_fa)
522 4 : opt_embed%add_const_pot = .TRUE.
523 4 : opt_embed%Fermi_Amaldi = .TRUE.
524 4 : opt_embed%Coulomb_guess = .FALSE.
525 4 : opt_embed%diff_guess = .FALSE.
526 : CASE (embed_resp)
527 2 : opt_embed%add_const_pot = .TRUE.
528 2 : opt_embed%Fermi_Amaldi = .TRUE.
529 2 : opt_embed%Coulomb_guess = .TRUE.
530 2 : opt_embed%diff_guess = .FALSE.
531 : CASE DEFAULT
532 0 : opt_embed%add_const_pot = .FALSE.
533 0 : opt_embed%Fermi_Amaldi = .FALSE.
534 0 : opt_embed%Coulomb_guess = .FALSE.
535 24 : opt_embed%diff_guess = .FALSE.
536 : END SELECT
537 :
538 24 : END SUBROUTINE read_opt_embed_section
539 :
540 : ! **************************************************************************************************
541 : !> \brief Find the dimension of the auxiliary basis for the expansion of the embedding potential
542 : !> \param qs_env ...
543 : !> \param dimen_aux ...
544 : ! **************************************************************************************************
545 18 : SUBROUTINE find_aux_dimen(qs_env, dimen_aux)
546 : TYPE(qs_environment_type), POINTER :: qs_env
547 : INTEGER :: dimen_aux
548 :
549 : INTEGER :: iatom, ikind, nsgf
550 18 : INTEGER, ALLOCATABLE, DIMENSION(:) :: kind_of
551 18 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
552 18 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
553 18 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
554 :
555 : ! First, reveal the dimension of the RI basis
556 : CALL get_qs_env(qs_env=qs_env, &
557 : particle_set=particle_set, &
558 : qs_kind_set=qs_kind_set, &
559 18 : atomic_kind_set=atomic_kind_set)
560 :
561 18 : CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
562 :
563 18 : dimen_aux = 0
564 82 : DO iatom = 1, SIZE(particle_set)
565 64 : ikind = kind_of(iatom)
566 64 : CALL get_qs_kind(qs_kind=qs_kind_set(ikind), nsgf=nsgf, basis_type="RI_AUX")
567 82 : dimen_aux = dimen_aux + nsgf
568 : END DO
569 :
570 36 : END SUBROUTINE find_aux_dimen
571 :
572 : ! **************************************************************************************************
573 : !> \brief Prepare the lri_kind_type object for integrals between density and aux. basis functions
574 : !> \param qs_env ...
575 : !> \param lri ...
576 : ! **************************************************************************************************
577 14 : SUBROUTINE make_lri_object(qs_env, lri)
578 : TYPE(qs_environment_type), POINTER :: qs_env
579 : TYPE(lri_kind_type), DIMENSION(:), POINTER :: lri
580 :
581 : INTEGER :: ikind, natom, nkind, nsgf
582 14 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
583 : TYPE(atomic_kind_type), POINTER :: atomic_kind
584 14 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
585 :
586 14 : NULLIFY (atomic_kind, lri)
587 : CALL get_qs_env(qs_env=qs_env, atomic_kind_set=atomic_kind_set, &
588 14 : qs_kind_set=qs_kind_set)
589 14 : nkind = SIZE(atomic_kind_set)
590 :
591 62 : ALLOCATE (lri(nkind))
592 : ! Here we need only v_int and acoef (the latter as dummies)
593 34 : DO ikind = 1, nkind
594 20 : NULLIFY (lri(ikind)%acoef)
595 20 : NULLIFY (lri(ikind)%v_int)
596 20 : atomic_kind => atomic_kind_set(ikind)
597 20 : CALL get_atomic_kind(atomic_kind=atomic_kind, natom=natom)
598 20 : CALL get_qs_kind(qs_kind=qs_kind_set(ikind), nsgf=nsgf, basis_type="RI_AUX")
599 80 : ALLOCATE (lri(ikind)%acoef(natom, nsgf))
600 2672 : lri(ikind)%acoef = 0._dp
601 60 : ALLOCATE (lri(ikind)%v_int(natom, nsgf))
602 2706 : lri(ikind)%v_int = 0._dp
603 : END DO
604 :
605 14 : END SUBROUTINE make_lri_object
606 :
607 : ! **************************************************************************************************
608 : !> \brief Read the external embedding potential, not to be optimized
609 : !> \param qs_env ...
610 : ! **************************************************************************************************
611 2 : SUBROUTINE given_embed_pot(qs_env)
612 : TYPE(qs_environment_type), POINTER :: qs_env
613 :
614 : LOGICAL :: open_shell_embed
615 : TYPE(dft_control_type), POINTER :: dft_control
616 : TYPE(pw_env_type), POINTER :: pw_env
617 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool_subsys
618 : TYPE(pw_r3d_rs_type), POINTER :: embed_pot, spin_embed_pot
619 : TYPE(section_vals_type), POINTER :: input, qs_section
620 :
621 2 : qs_env%given_embed_pot = .TRUE.
622 2 : NULLIFY (input, dft_control, embed_pot, spin_embed_pot, embed_pot, spin_embed_pot, &
623 2 : qs_section)
624 : CALL get_qs_env(qs_env=qs_env, &
625 : input=input, &
626 : dft_control=dft_control, &
627 2 : pw_env=pw_env)
628 2 : qs_section => section_vals_get_subs_vals(input, "DFT%QS")
629 2 : open_shell_embed = .FALSE.
630 2 : IF (dft_control%nspins == 2) open_shell_embed = .TRUE.
631 :
632 : ! Prepare plane-waves pool
633 2 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool_subsys)
634 :
635 : ! Create embedding potential
636 : !CALL get_qs_env(qs_env=qs_env, &
637 : ! embed_pot=embed_pot)
638 2 : ALLOCATE (embed_pot)
639 2 : CALL auxbas_pw_pool_subsys%create_pw(embed_pot)
640 2 : IF (open_shell_embed) THEN
641 : ! Create spin embedding potential
642 2 : ALLOCATE (spin_embed_pot)
643 2 : CALL auxbas_pw_pool_subsys%create_pw(spin_embed_pot)
644 : END IF
645 : ! Read the cubes
646 2 : CALL read_embed_pot_cube(embed_pot, spin_embed_pot, qs_section, open_shell_embed)
647 :
648 2 : IF (.NOT. open_shell_embed) THEN
649 0 : CALL set_qs_env(qs_env=qs_env, embed_pot=embed_pot)
650 : ELSE
651 2 : CALL set_qs_env(qs_env=qs_env, embed_pot=embed_pot, spin_embed_pot=spin_embed_pot)
652 : END IF
653 :
654 2 : END SUBROUTINE given_embed_pot
655 :
656 : ! **************************************************************************************************
657 : !> \brief ...
658 : !> \param qs_env ...
659 : !> \param embed_pot ...
660 : !> \param spin_embed_pot ...
661 : !> \param section ...
662 : !> \param opt_embed ...
663 : ! **************************************************************************************************
664 6 : SUBROUTINE read_embed_pot(qs_env, embed_pot, spin_embed_pot, section, opt_embed)
665 : TYPE(qs_environment_type), POINTER :: qs_env
666 : TYPE(pw_r3d_rs_type), POINTER :: embed_pot, spin_embed_pot
667 : TYPE(section_vals_type), POINTER :: section
668 : TYPE(opt_embed_pot_type) :: opt_embed
669 :
670 : ! Read the potential as a vector in the auxiliary basis
671 6 : IF (opt_embed%read_embed_pot) THEN
672 : CALL read_embed_pot_vector(qs_env, embed_pot, spin_embed_pot, section, &
673 4 : opt_embed%embed_pot_coef, opt_embed%open_shell_embed)
674 : END IF
675 : ! Read the potential as a cube (two cubes for open shell)
676 6 : IF (opt_embed%read_embed_pot_cube) THEN
677 2 : CALL read_embed_pot_cube(embed_pot, spin_embed_pot, section, opt_embed%open_shell_embed)
678 : END IF
679 :
680 6 : END SUBROUTINE read_embed_pot
681 :
682 : ! **************************************************************************************************
683 : !> \brief ...
684 : !> \param embed_pot ...
685 : !> \param spin_embed_pot ...
686 : !> \param section ...
687 : !> \param open_shell_embed ...
688 : ! **************************************************************************************************
689 4 : SUBROUTINE read_embed_pot_cube(embed_pot, spin_embed_pot, section, open_shell_embed)
690 : TYPE(pw_r3d_rs_type), INTENT(IN) :: embed_pot, spin_embed_pot
691 : TYPE(section_vals_type), POINTER :: section
692 : LOGICAL :: open_shell_embed
693 :
694 : CHARACTER(LEN=default_path_length) :: filename
695 : LOGICAL :: exist
696 : REAL(KIND=dp) :: scaling_factor
697 :
698 4 : exist = .FALSE.
699 4 : CALL section_vals_val_get(section, "EMBED_CUBE_FILE_NAME", c_val=filename)
700 4 : INQUIRE (FILE=filename, exist=exist)
701 4 : IF (.NOT. exist) THEN
702 0 : CPABORT("Embedding cube file not found. ")
703 : END IF
704 :
705 4 : scaling_factor = 1.0_dp
706 4 : CALL cp_cube_to_pw(embed_pot, filename, scaling_factor)
707 :
708 : ! Spin-dependent part of the potential
709 4 : IF (open_shell_embed) THEN
710 4 : exist = .FALSE.
711 4 : CALL section_vals_val_get(section, "EMBED_SPIN_CUBE_FILE_NAME", c_val=filename)
712 4 : INQUIRE (FILE=filename, exist=exist)
713 4 : IF (.NOT. exist) THEN
714 0 : CPABORT("Embedding spin cube file not found. ")
715 : END IF
716 :
717 : scaling_factor = 1.0_dp
718 4 : CALL cp_cube_to_pw(spin_embed_pot, filename, scaling_factor)
719 : END IF
720 :
721 4 : END SUBROUTINE read_embed_pot_cube
722 :
723 : ! **************************************************************************************************
724 : !> \brief Read the embedding potential from the binary file
725 : !> \param qs_env ...
726 : !> \param embed_pot ...
727 : !> \param spin_embed_pot ...
728 : !> \param section ...
729 : !> \param embed_pot_coef ...
730 : !> \param open_shell_embed ...
731 : ! **************************************************************************************************
732 4 : SUBROUTINE read_embed_pot_vector(qs_env, embed_pot, spin_embed_pot, section, embed_pot_coef, open_shell_embed)
733 : TYPE(qs_environment_type), POINTER :: qs_env
734 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
735 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
736 : TYPE(section_vals_type), POINTER :: section
737 : TYPE(cp_fm_type), INTENT(IN) :: embed_pot_coef
738 : LOGICAL, INTENT(IN) :: open_shell_embed
739 :
740 : CHARACTER(LEN=default_path_length) :: filename
741 : INTEGER :: dimen_aux, dimen_restart_basis, &
742 : dimen_var_aux, l_global, LLL, &
743 : nrow_local, restart_unit
744 4 : INTEGER, DIMENSION(:), POINTER :: row_indices
745 4 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: coef, coef_read
746 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
747 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
748 : TYPE(cp_fm_type) :: my_embed_pot_coef
749 : TYPE(mp_para_env_type), POINTER :: para_env
750 :
751 : ! Get the vector dimension
752 4 : CALL find_aux_dimen(qs_env, dimen_aux)
753 4 : IF (open_shell_embed) THEN
754 2 : dimen_var_aux = dimen_aux*2
755 : ELSE
756 2 : dimen_var_aux = dimen_aux
757 : END IF
758 :
759 : ! We need a temporary vector of coefficients
760 : CALL get_qs_env(qs_env=qs_env, &
761 4 : para_env=para_env)
762 4 : NULLIFY (blacs_env)
763 4 : NULLIFY (fm_struct)
764 4 : CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env)
765 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
766 4 : nrow_global=dimen_var_aux, ncol_global=1)
767 4 : CALL cp_fm_create(my_embed_pot_coef, fm_struct, name="my_pot_coef")
768 :
769 4 : CALL cp_fm_struct_release(fm_struct)
770 4 : CALL cp_fm_set_all(my_embed_pot_coef, 0.0_dp)
771 :
772 : ! Read the coefficients vector
773 4 : restart_unit = -1
774 :
775 : ! Allocate the attay to read the coefficients
776 12 : ALLOCATE (coef(dimen_var_aux))
777 4 : coef = 0.0_dp
778 :
779 4 : IF (para_env%is_source()) THEN
780 :
781 : ! Get the restart file name
782 2 : CALL embed_restart_file_name(filename, section)
783 :
784 : CALL open_file(file_name=filename, &
785 : file_action="READ", &
786 : file_form="UNFORMATTED", &
787 : file_status="OLD", &
788 2 : unit_number=restart_unit)
789 :
790 2 : READ (restart_unit) dimen_restart_basis
791 : ! Check the dimensions of the bases: the actual and the restart one
792 2 : IF (.NOT. (dimen_restart_basis == dimen_aux)) THEN
793 0 : CPABORT("Wrong dimension of the embedding basis in the restart file.")
794 : END IF
795 :
796 4 : ALLOCATE (coef_read(dimen_var_aux))
797 2 : coef_read = 0.0_dp
798 :
799 2 : READ (restart_unit) coef_read
800 318 : coef(:) = coef_read(:)
801 2 : DEALLOCATE (coef_read)
802 :
803 : ! Close restart file
804 2 : CALL close_file(unit_number=restart_unit)
805 :
806 : END IF
807 :
808 : ! Broadcast the coefficients on all processes
809 4 : CALL para_env%bcast(coef)
810 :
811 : ! Copy to fm_type structure
812 : ! Information about full matrix gradient
813 : CALL cp_fm_get_info(matrix=my_embed_pot_coef, &
814 : nrow_local=nrow_local, &
815 4 : row_indices=row_indices)
816 :
817 320 : DO LLL = 1, nrow_local
818 316 : l_global = row_indices(LLL)
819 320 : my_embed_pot_coef%local_data(LLL, 1) = coef(l_global)
820 : END DO
821 :
822 4 : DEALLOCATE (coef)
823 :
824 : ! Copy to the my_embed_pot_coef to embed_pot_coef
825 4 : CALL cp_fm_copy_general(my_embed_pot_coef, embed_pot_coef, para_env)
826 :
827 : ! Build the embedding potential on the grid
828 : CALL update_embed_pot(embed_pot_coef, dimen_aux, embed_pot, spin_embed_pot, &
829 4 : qs_env, .FALSE., open_shell_embed)
830 :
831 : ! Release my_embed_pot_coef
832 4 : CALL cp_fm_release(my_embed_pot_coef)
833 :
834 : ! Release blacs environment
835 4 : CALL cp_blacs_env_release(blacs_env)
836 :
837 16 : END SUBROUTINE read_embed_pot_vector
838 :
839 : ! **************************************************************************************************
840 : !> \brief Find the embedding restart file name
841 : !> \param filename ...
842 : !> \param section ...
843 : ! **************************************************************************************************
844 2 : SUBROUTINE embed_restart_file_name(filename, section)
845 : CHARACTER(LEN=default_path_length), INTENT(OUT) :: filename
846 : TYPE(section_vals_type), POINTER :: section
847 :
848 : LOGICAL :: exist
849 :
850 2 : exist = .FALSE.
851 2 : CALL section_vals_val_get(section, "EMBED_RESTART_FILE_NAME", c_val=filename)
852 2 : INQUIRE (FILE=filename, exist=exist)
853 2 : IF (.NOT. exist) THEN
854 0 : CPABORT("Embedding restart file not found. ")
855 : END IF
856 :
857 2 : END SUBROUTINE embed_restart_file_name
858 :
859 : ! **************************************************************************************************
860 : !> \brief Deallocate stuff for optimizing embedding potential
861 : !> \param opt_embed ...
862 : ! **************************************************************************************************
863 24 : SUBROUTINE release_opt_embed(opt_embed)
864 : TYPE(opt_embed_pot_type) :: opt_embed
865 :
866 : INTEGER :: i_dens, i_spin, ikind
867 :
868 24 : IF (.NOT. opt_embed%grid_opt) THEN
869 14 : CALL cp_fm_release(opt_embed%embed_pot_grad)
870 14 : CALL cp_fm_release(opt_embed%embed_pot_coef)
871 14 : CALL cp_fm_release(opt_embed%step)
872 14 : CALL cp_fm_release(opt_embed%prev_step)
873 14 : CALL cp_fm_release(opt_embed%embed_pot_hess)
874 14 : CALL cp_fm_release(opt_embed%prev_embed_pot_grad)
875 14 : CALL cp_fm_release(opt_embed%prev_embed_pot_coef)
876 14 : CALL cp_fm_release(opt_embed%prev_embed_pot_hess)
877 14 : CALL cp_fm_release(opt_embed%kinetic_mat)
878 0 : DEALLOCATE (opt_embed%embed_pot_grad, opt_embed%embed_pot_coef, &
879 0 : opt_embed%step, opt_embed%prev_step, opt_embed%embed_pot_hess, &
880 0 : opt_embed%prev_embed_pot_grad, opt_embed%prev_embed_pot_coef, &
881 14 : opt_embed%prev_embed_pot_hess, opt_embed%kinetic_mat)
882 14 : DEALLOCATE (opt_embed%w_func)
883 14 : DEALLOCATE (opt_embed%max_diff)
884 14 : DEALLOCATE (opt_embed%int_diff)
885 :
886 34 : DO ikind = 1, SIZE(opt_embed%lri)
887 20 : DEALLOCATE (opt_embed%lri(ikind)%v_int)
888 34 : DEALLOCATE (opt_embed%lri(ikind)%acoef)
889 : END DO
890 14 : DEALLOCATE (opt_embed%lri)
891 : END IF
892 :
893 24 : IF (ASSOCIATED(opt_embed%prev_subsys_dens)) THEN
894 96 : DO i_dens = 1, SIZE(opt_embed%prev_subsys_dens)
895 96 : CALL opt_embed%prev_subsys_dens(i_dens)%release()
896 : END DO
897 24 : DEALLOCATE (opt_embed%prev_subsys_dens)
898 : END IF
899 24 : DEALLOCATE (opt_embed%max_subsys_dens_diff)
900 :
901 24 : DEALLOCATE (opt_embed%all_nspins)
902 :
903 24 : IF (ASSOCIATED(opt_embed%const_pot)) THEN
904 4 : CALL opt_embed%const_pot%release()
905 4 : DEALLOCATE (opt_embed%const_pot)
906 : END IF
907 :
908 24 : IF (ASSOCIATED(opt_embed%pot_diff)) THEN
909 2 : CALL opt_embed%pot_diff%release()
910 2 : DEALLOCATE (opt_embed%pot_diff)
911 : END IF
912 :
913 24 : IF (ASSOCIATED(opt_embed%prev_embed_pot)) THEN
914 2 : CALL opt_embed%prev_embed_pot%release()
915 2 : DEALLOCATE (opt_embed%prev_embed_pot)
916 : END IF
917 24 : IF (ASSOCIATED(opt_embed%prev_spin_embed_pot)) THEN
918 0 : CALL opt_embed%prev_spin_embed_pot%release()
919 0 : DEALLOCATE (opt_embed%prev_spin_embed_pot)
920 : END IF
921 24 : IF (ASSOCIATED(opt_embed%v_w)) THEN
922 4 : DO i_spin = 1, SIZE(opt_embed%v_w)
923 4 : CALL opt_embed%v_w(i_spin)%release()
924 : END DO
925 2 : DEALLOCATE (opt_embed%v_w)
926 : END IF
927 :
928 24 : END SUBROUTINE release_opt_embed
929 :
930 : ! **************************************************************************************************
931 : !> \brief Calculates subsystem Coulomb potential from the RESP charges of the total system
932 : !> \param v_rspace ...
933 : !> \param rhs ...
934 : !> \param mapping_section ...
935 : !> \param qs_env ...
936 : !> \param nforce_eval ...
937 : !> \param iforce_eval ...
938 : !> \param eta ...
939 : ! **************************************************************************************************
940 4 : SUBROUTINE Coulomb_guess(v_rspace, rhs, mapping_section, qs_env, nforce_eval, iforce_eval, eta)
941 : TYPE(pw_r3d_rs_type) :: v_rspace
942 : REAL(KIND=dp), DIMENSION(:), POINTER :: rhs
943 : TYPE(section_vals_type), POINTER :: mapping_section
944 : TYPE(qs_environment_type), POINTER :: qs_env
945 : INTEGER :: nforce_eval, iforce_eval
946 : REAL(KIND=dp) :: eta
947 :
948 : INTEGER :: iparticle, jparticle, natom
949 4 : INTEGER, DIMENSION(:), POINTER :: map_index
950 : REAL(KIND=dp) :: dvol, normalize_factor
951 4 : REAL(KIND=dp), DIMENSION(:), POINTER :: rhs_subsys
952 : TYPE(particle_list_type), POINTER :: particles
953 : TYPE(pw_c1d_gs_type) :: v_resp_gspace
954 : TYPE(pw_env_type), POINTER :: pw_env
955 : TYPE(pw_poisson_type), POINTER :: poisson_env
956 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
957 : TYPE(pw_r3d_rs_type) :: rho_resp, v_resp_rspace
958 : TYPE(qs_subsys_type), POINTER :: subsys
959 :
960 : ! Get available particles
961 4 : NULLIFY (subsys)
962 4 : CALL get_qs_env(qs_env=qs_env, subsys=subsys, pw_env=pw_env)
963 4 : CALL qs_subsys_get(subsys, particles=particles)
964 4 : natom = particles%n_els
965 :
966 12 : ALLOCATE (rhs_subsys(natom))
967 :
968 4 : NULLIFY (map_index)
969 : CALL get_subsys_map_index(mapping_section, natom, iforce_eval, nforce_eval, &
970 4 : map_index, .TRUE.)
971 :
972 : ! Mapping particles from iforce_eval environment to the embed env
973 14 : DO iparticle = 1, natom
974 10 : jparticle = map_index(iparticle)
975 14 : rhs_subsys(iparticle) = rhs(jparticle)
976 : END DO
977 :
978 : ! Prepare plane waves
979 4 : NULLIFY (auxbas_pw_pool)
980 :
981 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
982 4 : poisson_env=poisson_env)
983 :
984 4 : CALL auxbas_pw_pool%create_pw(v_resp_gspace)
985 :
986 4 : CALL auxbas_pw_pool%create_pw(v_resp_rspace)
987 :
988 4 : CALL auxbas_pw_pool%create_pw(rho_resp)
989 :
990 : ! Calculate charge density
991 4 : CALL pw_zero(rho_resp)
992 4 : CALL calculate_rho_resp_all(rho_resp, rhs_subsys, natom, eta, qs_env)
993 :
994 : ! Calculate potential
995 : CALL pw_poisson_solve(poisson_env, rho_resp, &
996 4 : vhartree=v_resp_rspace)
997 4 : dvol = v_resp_rspace%pw_grid%dvol
998 4 : CALL pw_scale(v_resp_rspace, dvol)
999 4 : normalize_factor = SQRT((eta/pi)**3)
1000 : !normalize_factor = -2.0_dp
1001 4 : CALL pw_scale(v_resp_rspace, normalize_factor)
1002 :
1003 : ! Hard copy potential
1004 4 : CALL pw_copy(v_resp_rspace, v_rspace)
1005 :
1006 : ! Release plane waves
1007 4 : CALL v_resp_gspace%release()
1008 4 : CALL v_resp_rspace%release()
1009 4 : CALL rho_resp%release()
1010 :
1011 : ! Deallocate map_index array
1012 4 : DEALLOCATE (map_index)
1013 : ! Deallocate charges
1014 4 : DEALLOCATE (rhs_subsys)
1015 :
1016 4 : END SUBROUTINE Coulomb_guess
1017 :
1018 : ! **************************************************************************************************
1019 : !> \brief Creates a subsystem embedding potential
1020 : !> \param qs_env ...
1021 : !> \param embed_pot ...
1022 : !> \param embed_pot_subsys ...
1023 : !> \param spin_embed_pot ...
1024 : !> \param spin_embed_pot_subsys ...
1025 : !> \param open_shell_embed ...
1026 : !> \param change_spin_sign ...
1027 : !> \author Vladimir Rybkin
1028 : ! **************************************************************************************************
1029 120 : SUBROUTINE make_subsys_embed_pot(qs_env, embed_pot, embed_pot_subsys, &
1030 : spin_embed_pot, spin_embed_pot_subsys, open_shell_embed, &
1031 : change_spin_sign)
1032 : TYPE(qs_environment_type), POINTER :: qs_env
1033 : TYPE(pw_r3d_rs_type), INTENT(IN) :: embed_pot
1034 : TYPE(pw_r3d_rs_type), POINTER :: embed_pot_subsys
1035 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
1036 : TYPE(pw_r3d_rs_type), POINTER :: spin_embed_pot_subsys
1037 : LOGICAL :: open_shell_embed, change_spin_sign
1038 :
1039 : TYPE(pw_env_type), POINTER :: pw_env
1040 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool_subsys
1041 :
1042 : ! Extract plane waves environment
1043 120 : CALL get_qs_env(qs_env, pw_env=pw_env)
1044 :
1045 : ! Prepare plane-waves pool
1046 120 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool_subsys)
1047 :
1048 : ! Create embedding potential and set to zero
1049 : NULLIFY (embed_pot_subsys)
1050 120 : ALLOCATE (embed_pot_subsys)
1051 120 : CALL auxbas_pw_pool_subsys%create_pw(embed_pot_subsys)
1052 :
1053 : ! Hard copy the grid
1054 120 : CALL pw_copy(embed_pot, embed_pot_subsys)
1055 :
1056 120 : IF (open_shell_embed) THEN
1057 : NULLIFY (spin_embed_pot_subsys)
1058 64 : ALLOCATE (spin_embed_pot_subsys)
1059 64 : CALL auxbas_pw_pool_subsys%create_pw(spin_embed_pot_subsys)
1060 : ! Hard copy the grid
1061 64 : IF (change_spin_sign) THEN
1062 8 : CALL pw_axpy(spin_embed_pot, spin_embed_pot_subsys, -1.0_dp, 0.0_dp, allow_noncompatible_grids=.TRUE.)
1063 : ELSE
1064 56 : CALL pw_copy(spin_embed_pot, spin_embed_pot_subsys)
1065 : END IF
1066 : END IF
1067 :
1068 120 : END SUBROUTINE make_subsys_embed_pot
1069 :
1070 : ! **************************************************************************************************
1071 : !> \brief Calculates the derivative of the embedding potential wrt to the expansion coefficients
1072 : !> \param qs_env ...
1073 : !> \param diff_rho_r ...
1074 : !> \param diff_rho_spin ...
1075 : !> \param opt_embed ...
1076 : !> \author Vladimir Rybkin
1077 : ! **************************************************************************************************
1078 :
1079 32 : SUBROUTINE calculate_embed_pot_grad(qs_env, diff_rho_r, diff_rho_spin, opt_embed)
1080 : TYPE(qs_environment_type), POINTER :: qs_env
1081 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r, diff_rho_spin
1082 : TYPE(opt_embed_pot_type) :: opt_embed
1083 :
1084 : CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_embed_pot_grad'
1085 :
1086 : INTEGER :: handle
1087 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1088 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1089 : TYPE(cp_fm_type) :: embed_pot_coeff_spin, &
1090 : embed_pot_coeff_spinless, &
1091 : regular_term, spin_reg, spinless_reg
1092 : TYPE(mp_para_env_type), POINTER :: para_env
1093 : TYPE(pw_env_type), POINTER :: pw_env
1094 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
1095 :
1096 16 : CALL timeset(routineN, handle)
1097 :
1098 : ! We destroy the previous gradient and Hessian:
1099 : ! current data are now previous data
1100 16 : CALL cp_fm_to_fm(opt_embed%embed_pot_grad, opt_embed%prev_embed_pot_grad)
1101 16 : CALL cp_fm_to_fm(opt_embed%embed_pot_Hess, opt_embed%prev_embed_pot_Hess)
1102 :
1103 16 : NULLIFY (pw_env)
1104 :
1105 16 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env, para_env=para_env)
1106 :
1107 : ! Get plane waves pool
1108 16 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
1109 :
1110 : ! Calculate potential gradient coefficients
1111 : CALL calculate_embed_pot_grad_inner(qs_env, opt_embed%dimen_aux, diff_rho_r, diff_rho_spin, &
1112 : opt_embed%embed_pot_grad, &
1113 16 : opt_embed%open_shell_embed, opt_embed%lri)
1114 :
1115 : ! Add regularization with kinetic matrix
1116 16 : IF (opt_embed%i_iter == 1) THEN ! Else it is kept in memory
1117 12 : CALL compute_kinetic_mat(qs_env, opt_embed%kinetic_mat)
1118 : END IF
1119 :
1120 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_grad, &
1121 16 : matrix_struct=fm_struct)
1122 16 : CALL cp_fm_create(regular_term, fm_struct, name="regular_term")
1123 16 : CALL cp_fm_set_all(regular_term, 0.0_dp)
1124 :
1125 : ! In case of open shell embedding we need two terms of dimen_aux=dimen_var_aux/2 for
1126 : ! the spinless and the spin parts
1127 16 : IF (opt_embed%open_shell_embed) THEN
1128 : ! Prepare auxiliary full matrices
1129 10 : NULLIFY (fm_struct, blacs_env)
1130 :
1131 : !CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env)
1132 :
1133 10 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_coef, context=blacs_env)
1134 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
1135 10 : nrow_global=opt_embed%dimen_aux, ncol_global=1)
1136 10 : CALL cp_fm_create(embed_pot_coeff_spinless, fm_struct, name="pot_coeff_spinless")
1137 10 : CALL cp_fm_create(embed_pot_coeff_spin, fm_struct, name="pot_coeff_spin")
1138 10 : CALL cp_fm_create(spinless_reg, fm_struct, name="spinless_reg")
1139 10 : CALL cp_fm_create(spin_reg, fm_struct, name="spin_reg")
1140 10 : CALL cp_fm_set_all(embed_pot_coeff_spinless, 0.0_dp)
1141 10 : CALL cp_fm_set_all(embed_pot_coeff_spin, 0.0_dp)
1142 10 : CALL cp_fm_set_all(spinless_reg, 0.0_dp)
1143 10 : CALL cp_fm_set_all(spin_reg, 0.0_dp)
1144 10 : CALL cp_fm_struct_release(fm_struct)
1145 :
1146 : ! Copy coefficients to the auxiliary structures
1147 : CALL cp_fm_to_fm_submat(msource=opt_embed%embed_pot_coef, &
1148 : mtarget=embed_pot_coeff_spinless, &
1149 : nrow=opt_embed%dimen_aux, ncol=1, &
1150 : s_firstrow=1, s_firstcol=1, &
1151 10 : t_firstrow=1, t_firstcol=1)
1152 : CALL cp_fm_to_fm_submat(msource=opt_embed%embed_pot_coef, &
1153 : mtarget=embed_pot_coeff_spin, &
1154 : nrow=opt_embed%dimen_aux, ncol=1, &
1155 : s_firstrow=opt_embed%dimen_aux + 1, s_firstcol=1, &
1156 10 : t_firstrow=1, t_firstcol=1)
1157 : ! Multiply
1158 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_aux, n=1, &
1159 : k=opt_embed%dimen_aux, alpha=1.0_dp, &
1160 : matrix_a=opt_embed%kinetic_mat, matrix_b=embed_pot_coeff_spinless, &
1161 10 : beta=0.0_dp, matrix_c=spinless_reg)
1162 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_aux, n=1, &
1163 : k=opt_embed%dimen_aux, alpha=1.0_dp, &
1164 : matrix_a=opt_embed%kinetic_mat, matrix_b=embed_pot_coeff_spin, &
1165 10 : beta=0.0_dp, matrix_c=spin_reg)
1166 : ! Copy from the auxiliary structures to the full regularization term
1167 : CALL cp_fm_to_fm_submat(msource=spinless_reg, &
1168 : mtarget=regular_term, &
1169 : nrow=opt_embed%dimen_aux, ncol=1, &
1170 : s_firstrow=1, s_firstcol=1, &
1171 10 : t_firstrow=1, t_firstcol=1)
1172 : CALL cp_fm_to_fm_submat(msource=spin_reg, &
1173 : mtarget=regular_term, &
1174 : nrow=opt_embed%dimen_aux, ncol=1, &
1175 : s_firstrow=1, s_firstcol=1, &
1176 10 : t_firstrow=opt_embed%dimen_aux + 1, t_firstcol=1)
1177 : ! Release internally used auxiliary structures
1178 10 : CALL cp_fm_release(embed_pot_coeff_spinless)
1179 10 : CALL cp_fm_release(embed_pot_coeff_spin)
1180 10 : CALL cp_fm_release(spin_reg)
1181 10 : CALL cp_fm_release(spinless_reg)
1182 :
1183 : ELSE ! Simply multiply
1184 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_var_aux, n=1, &
1185 : k=opt_embed%dimen_var_aux, alpha=1.0_dp, &
1186 : matrix_a=opt_embed%kinetic_mat, matrix_b=opt_embed%embed_pot_coef, &
1187 6 : beta=0.0_dp, matrix_c=regular_term)
1188 : END IF
1189 :
1190 : ! Scale by the regularization parameter and add to the gradient
1191 16 : CALL cp_fm_scale_and_add(1.0_dp, opt_embed%embed_pot_grad, 4.0_dp*opt_embed%lambda, regular_term)
1192 :
1193 : ! Calculate the regularization contribution to the energy functional
1194 16 : CALL cp_fm_trace(opt_embed%embed_pot_coef, regular_term, opt_embed%reg_term)
1195 16 : opt_embed%reg_term = 2.0_dp*opt_embed%lambda*opt_embed%reg_term
1196 :
1197 : ! Deallocate regular term
1198 16 : CALL cp_fm_release(regular_term)
1199 :
1200 16 : CALL timestop(handle)
1201 :
1202 16 : END SUBROUTINE calculate_embed_pot_grad
1203 :
1204 : ! **************************************************************************************************
1205 : !> \brief Performs integration for the embedding potential gradient
1206 : !> \param qs_env ...
1207 : !> \param dimen_aux ...
1208 : !> \param rho_r ...
1209 : !> \param rho_spin ...
1210 : !> \param embed_pot_grad ...
1211 : !> \param open_shell_embed ...
1212 : !> \param lri ...
1213 : !> \author Vladimir Rybkin
1214 : ! **************************************************************************************************
1215 16 : SUBROUTINE calculate_embed_pot_grad_inner(qs_env, dimen_aux, rho_r, rho_spin, embed_pot_grad, &
1216 : open_shell_embed, lri)
1217 : TYPE(qs_environment_type), POINTER :: qs_env
1218 : INTEGER :: dimen_aux
1219 : TYPE(pw_r3d_rs_type), INTENT(IN) :: rho_r, rho_spin
1220 : TYPE(cp_fm_type), INTENT(IN) :: embed_pot_grad
1221 : LOGICAL :: open_shell_embed
1222 : TYPE(lri_kind_type), DIMENSION(:), POINTER :: lri
1223 :
1224 : CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_embed_pot_grad_inner'
1225 :
1226 : INTEGER :: handle, iatom, ikind, l_global, LLL, &
1227 : nrow_local, nsgf, start_pos
1228 16 : INTEGER, DIMENSION(:), POINTER :: row_indices
1229 16 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: pot_grad
1230 16 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1231 : TYPE(cell_type), POINTER :: cell
1232 : TYPE(dft_control_type), POINTER :: dft_control
1233 : TYPE(mp_para_env_type), POINTER :: para_env
1234 16 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1235 16 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1236 :
1237 : ! Needed to store integrals
1238 :
1239 16 : CALL timeset(routineN, handle)
1240 :
1241 : CALL get_qs_env(qs_env=qs_env, &
1242 : particle_set=particle_set, &
1243 : qs_kind_set=qs_kind_set, &
1244 : dft_control=dft_control, &
1245 : cell=cell, &
1246 : atomic_kind_set=atomic_kind_set, &
1247 16 : para_env=para_env)
1248 :
1249 : ! Create wf_vector and gradient
1250 16 : IF (open_shell_embed) THEN
1251 30 : ALLOCATE (pot_grad(dimen_aux*2))
1252 : ELSE
1253 18 : ALLOCATE (pot_grad(dimen_aux))
1254 : END IF
1255 :
1256 : ! Use lri subroutine
1257 38 : DO ikind = 1, SIZE(lri)
1258 2750 : lri(ikind)%v_int = 0.0_dp
1259 : END DO
1260 :
1261 : CALL integrate_v_rspace_one_center(rho_r, qs_env, lri, &
1262 16 : .FALSE., "RI_AUX")
1263 38 : DO ikind = 1, SIZE(lri)
1264 5462 : CALL para_env%sum(lri(ikind)%v_int)
1265 : END DO
1266 :
1267 16 : pot_grad = 0.0_dp
1268 16 : start_pos = 1
1269 38 : DO ikind = 1, SIZE(lri)
1270 88 : DO iatom = 1, SIZE(lri(ikind)%v_int, DIM=1)
1271 50 : nsgf = SIZE(lri(ikind)%v_int(iatom, :))
1272 1826 : pot_grad(start_pos:start_pos + nsgf - 1) = lri(ikind)%v_int(iatom, :)
1273 72 : start_pos = start_pos + nsgf
1274 : END DO
1275 : END DO
1276 :
1277 : ! Open-shell embedding
1278 16 : IF (open_shell_embed) THEN
1279 20 : DO ikind = 1, SIZE(lri)
1280 920 : lri(ikind)%v_int = 0.0_dp
1281 : END DO
1282 :
1283 : CALL integrate_v_rspace_one_center(rho_spin, qs_env, lri, &
1284 10 : .FALSE., "RI_AUX")
1285 20 : DO ikind = 1, SIZE(lri)
1286 1820 : CALL para_env%sum(lri(ikind)%v_int)
1287 : END DO
1288 :
1289 10 : start_pos = dimen_aux + 1
1290 20 : DO ikind = 1, SIZE(lri)
1291 40 : DO iatom = 1, SIZE(lri(ikind)%v_int, DIM=1)
1292 20 : nsgf = SIZE(lri(ikind)%v_int(iatom, :))
1293 620 : pot_grad(start_pos:start_pos + nsgf - 1) = lri(ikind)%v_int(iatom, :)
1294 30 : start_pos = start_pos + nsgf
1295 : END DO
1296 : END DO
1297 : END IF
1298 :
1299 : ! Scale by the cell volume
1300 2392 : pot_grad = pot_grad*rho_r%pw_grid%dvol
1301 :
1302 : ! Information about full matrix gradient
1303 : CALL cp_fm_get_info(matrix=embed_pot_grad, &
1304 : nrow_local=nrow_local, &
1305 16 : row_indices=row_indices)
1306 :
1307 : ! Copy the gradient into the full matrix
1308 1204 : DO LLL = 1, nrow_local
1309 1188 : l_global = row_indices(LLL)
1310 1204 : embed_pot_grad%local_data(LLL, 1) = pot_grad(l_global)
1311 : END DO
1312 :
1313 16 : DEALLOCATE (pot_grad)
1314 :
1315 16 : CALL timestop(handle)
1316 :
1317 16 : END SUBROUTINE calculate_embed_pot_grad_inner
1318 :
1319 : ! **************************************************************************************************
1320 : !> \brief Calculates kinetic energy matrix in auxiliary basis in the fm format
1321 : !> \param qs_env ...
1322 : !> \param kinetic_mat ...
1323 : !> \author Vladimir Rybkin
1324 : ! **************************************************************************************************
1325 12 : SUBROUTINE compute_kinetic_mat(qs_env, kinetic_mat)
1326 : TYPE(qs_environment_type), POINTER :: qs_env
1327 : TYPE(cp_fm_type), INTENT(INOUT) :: kinetic_mat
1328 :
1329 : CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_kinetic_mat'
1330 :
1331 : INTEGER :: handle
1332 12 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_t
1333 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1334 12 : POINTER :: sab_orb
1335 : TYPE(qs_ks_env_type), POINTER :: ks_env
1336 :
1337 12 : CALL timeset(routineN, handle)
1338 :
1339 12 : NULLIFY (ks_env, sab_orb, matrix_t)
1340 :
1341 : ! First, get the dbcsr structure from the overlap matrix
1342 12 : CALL get_qs_env(qs_env=qs_env, ks_env=ks_env, sab_orb=sab_orb)
1343 :
1344 : ! Calculate kinetic matrix
1345 : CALL build_kinetic_matrix(ks_env, matrix_t=matrix_t, &
1346 : matrix_name="KINETIC ENERGY MATRIX", &
1347 : basis_type="RI_AUX", &
1348 12 : sab_nl=sab_orb, calculate_forces=.FALSE.)
1349 :
1350 : ! Change to the fm format
1351 12 : CALL copy_dbcsr_to_fm(matrix_t(1)%matrix, kinetic_mat)
1352 :
1353 : ! Release memory
1354 12 : CALL dbcsr_deallocate_matrix_set(matrix_t)
1355 :
1356 12 : CALL timestop(handle)
1357 :
1358 12 : END SUBROUTINE compute_kinetic_mat
1359 :
1360 : ! **************************************************************************************************
1361 : !> \brief Regularizes the Wu-Yang potential on the grid
1362 : !> \param potential ...
1363 : !> \param pw_env ...
1364 : !> \param lambda ...
1365 : !> \param reg_term ...
1366 : ! **************************************************************************************************
1367 6 : SUBROUTINE grid_regularize(potential, pw_env, lambda, reg_term)
1368 :
1369 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: potential
1370 : TYPE(pw_env_type), POINTER :: pw_env
1371 : REAL(KIND=dp) :: lambda, reg_term
1372 :
1373 : INTEGER :: i, j, k
1374 : INTEGER, DIMENSION(3) :: lb, n, ub
1375 : TYPE(pw_c1d_gs_type) :: dr2_pot, grid_reg_g, potential_g
1376 24 : TYPE(pw_c1d_gs_type), DIMENSION(3) :: dpot_g
1377 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
1378 : TYPE(pw_r3d_rs_type) :: grid_reg, square_norm_dpot
1379 24 : TYPE(pw_r3d_rs_type), DIMENSION(3) :: dpot
1380 :
1381 : !
1382 : ! First, the contribution to the gradient
1383 : !
1384 :
1385 : ! Get some of the grids ready
1386 6 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
1387 :
1388 6 : CALL auxbas_pw_pool%create_pw(potential_g)
1389 :
1390 6 : CALL auxbas_pw_pool%create_pw(dr2_pot)
1391 :
1392 6 : CALL auxbas_pw_pool%create_pw(grid_reg)
1393 :
1394 6 : CALL auxbas_pw_pool%create_pw(grid_reg_g)
1395 6 : CALL pw_zero(grid_reg_g)
1396 :
1397 : ! Transfer potential to the reciprocal space
1398 6 : CALL pw_transfer(potential, potential_g)
1399 :
1400 : ! Calculate second derivatives: dx^2, dy^2, dz^2
1401 24 : DO i = 1, 3
1402 18 : CALL pw_dr2(potential_g, dr2_pot, i, i)
1403 24 : CALL pw_axpy(dr2_pot, grid_reg_g, 1.0_dp)
1404 : END DO
1405 : ! Transfer potential to the real space
1406 6 : CALL pw_transfer(grid_reg_g, grid_reg)
1407 :
1408 : ! Update the potential with a regularization term
1409 6 : CALL pw_axpy(grid_reg, potential, -4.0_dp*lambda)
1410 :
1411 : !
1412 : ! Second, the contribution to the functional
1413 : !
1414 24 : DO i = 1, 3
1415 18 : CALL auxbas_pw_pool%create_pw(dpot(i))
1416 24 : CALL auxbas_pw_pool%create_pw(dpot_g(i))
1417 : END DO
1418 :
1419 6 : CALL auxbas_pw_pool%create_pw(square_norm_dpot)
1420 :
1421 24 : DO i = 1, 3
1422 18 : n(:) = 0
1423 18 : n(i) = 1
1424 18 : CALL pw_copy(potential_g, dpot_g(i))
1425 18 : CALL pw_derive(dpot_g(i), n(:))
1426 24 : CALL pw_transfer(dpot_g(i), dpot(i))
1427 : END DO
1428 :
1429 24 : lb(1:3) = square_norm_dpot%pw_grid%bounds_local(1, 1:3)
1430 24 : ub(1:3) = square_norm_dpot%pw_grid%bounds_local(2, 1:3)
1431 : !$OMP PARALLEL DO DEFAULT(NONE) &
1432 : !$OMP PRIVATE(i,j,k) &
1433 6 : !$OMP SHARED(dpot, lb, square_norm_dpot, ub)
1434 : DO k = lb(3), ub(3)
1435 : DO j = lb(2), ub(2)
1436 : DO i = lb(1), ub(1)
1437 : square_norm_dpot%array(i, j, k) = (dpot(1)%array(i, j, k)* &
1438 : dpot(1)%array(i, j, k) + &
1439 : dpot(2)%array(i, j, k)* &
1440 : dpot(2)%array(i, j, k) + &
1441 : dpot(3)%array(i, j, k)* &
1442 : dpot(3)%array(i, j, k))
1443 : END DO
1444 : END DO
1445 : END DO
1446 : !$OMP END PARALLEL DO
1447 :
1448 6 : reg_term = 2*lambda*pw_integrate_function(fun=square_norm_dpot)
1449 :
1450 : ! Release
1451 6 : CALL auxbas_pw_pool%give_back_pw(potential_g)
1452 6 : CALL auxbas_pw_pool%give_back_pw(dr2_pot)
1453 6 : CALL auxbas_pw_pool%give_back_pw(grid_reg)
1454 6 : CALL auxbas_pw_pool%give_back_pw(grid_reg_g)
1455 6 : CALL auxbas_pw_pool%give_back_pw(square_norm_dpot)
1456 24 : DO i = 1, 3
1457 18 : CALL auxbas_pw_pool%give_back_pw(dpot(i))
1458 24 : CALL auxbas_pw_pool%give_back_pw(dpot_g(i))
1459 : END DO
1460 :
1461 6 : END SUBROUTINE grid_regularize
1462 :
1463 : ! **************************************************************************************************
1464 : !> \brief Takes maximization step in embedding potential optimization
1465 : !> \param diff_rho_r ...
1466 : !> \param diff_rho_spin ...
1467 : !> \param opt_embed ...
1468 : !> \param embed_pot ...
1469 : !> \param spin_embed_pot ...
1470 : !> \param rho_r_ref ...
1471 : !> \param qs_env ...
1472 : !> \author Vladimir Rybkin
1473 : ! **************************************************************************************************
1474 24 : SUBROUTINE opt_embed_step(diff_rho_r, diff_rho_spin, opt_embed, embed_pot, spin_embed_pot, rho_r_ref, qs_env)
1475 :
1476 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: diff_rho_r, diff_rho_spin
1477 : TYPE(opt_embed_pot_type) :: opt_embed
1478 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
1479 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
1480 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r_ref
1481 : TYPE(qs_environment_type), POINTER :: qs_env
1482 :
1483 : CHARACTER(LEN=*), PARAMETER :: routineN = 'opt_embed_step'
1484 : REAL(KIND=dp), PARAMETER :: thresh = 0.000001_dp
1485 :
1486 : INTEGER :: handle, l_global, LLL, nrow_local
1487 24 : INTEGER, DIMENSION(:), POINTER :: row_indices
1488 24 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval
1489 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1490 : TYPE(cp_fm_type) :: diag_grad, diag_step, fm_U, fm_U_scale
1491 : TYPE(pw_env_type), POINTER :: pw_env
1492 :
1493 24 : CALL timeset(routineN, handle)
1494 :
1495 24 : IF (opt_embed%grid_opt) THEN ! Grid based optimization
1496 :
1497 8 : opt_embed%step_len = opt_embed%trust_rad
1498 8 : CALL get_qs_env(qs_env=qs_env, pw_env=pw_env)
1499 8 : IF (opt_embed%leeuwen) THEN
1500 : CALL Leeuwen_Baerends_potential_update(pw_env, embed_pot, spin_embed_pot, diff_rho_r, diff_rho_spin, &
1501 2 : rho_r_ref, opt_embed%open_shell_embed, opt_embed%trust_rad)
1502 : ELSE
1503 6 : IF (opt_embed%fab) THEN
1504 : CALL FAB_update(qs_env, rho_r_ref, opt_embed%prev_embed_pot, opt_embed%prev_spin_embed_pot, &
1505 : embed_pot, spin_embed_pot, &
1506 : diff_rho_r, diff_rho_spin, opt_embed%v_w, opt_embed%i_iter, opt_embed%trust_rad, &
1507 2 : opt_embed%open_shell_embed, opt_embed%vw_cutoff, opt_embed%vw_smooth_cutoff_range)
1508 : ELSE
1509 4 : CALL grid_based_step(diff_rho_r, diff_rho_spin, pw_env, opt_embed, embed_pot, spin_embed_pot)
1510 : END IF
1511 : END IF
1512 :
1513 : ELSE ! Finite basis optimization
1514 : ! If the previous step has been rejected, we go back to the previous expansion coefficients
1515 16 : IF (.NOT. opt_embed%accept_step) THEN
1516 0 : CALL cp_fm_scale_and_add(1.0_dp, opt_embed%embed_pot_coef, -1.0_dp, opt_embed%step)
1517 : END IF
1518 :
1519 : ! Do a simple steepest descent
1520 16 : IF (opt_embed%steep_desc) THEN
1521 6 : IF (opt_embed%i_iter > 2) THEN
1522 : opt_embed%trust_rad = Barzilai_Borwein(opt_embed%step, opt_embed%prev_step, &
1523 0 : opt_embed%embed_pot_grad, opt_embed%prev_embed_pot_grad)
1524 : END IF
1525 6 : IF (ABS(opt_embed%trust_rad) > opt_embed%max_trad) THEN
1526 0 : IF (opt_embed%trust_rad > 0.0_dp) THEN
1527 0 : opt_embed%trust_rad = opt_embed%max_trad
1528 : ELSE
1529 0 : opt_embed%trust_rad = -opt_embed%max_trad
1530 : END IF
1531 : END IF
1532 :
1533 6 : CALL cp_fm_to_fm(opt_embed%step, opt_embed%prev_step)
1534 6 : CALL cp_fm_scale_and_add(0.0_dp, opt_embed%prev_step, 1.0_dp, opt_embed%step)
1535 6 : CALL cp_fm_set_all(opt_embed%step, 0.0_dp)
1536 6 : CALL cp_fm_scale_and_add(1.0_dp, opt_embed%step, opt_embed%trust_rad, opt_embed%embed_pot_grad)
1537 6 : opt_embed%step_len = opt_embed%trust_rad
1538 : ELSE
1539 :
1540 : ! First, update the Hessian inverse if needed
1541 10 : IF (opt_embed%i_iter > 1) THEN
1542 2 : IF (opt_embed%accept_step) THEN
1543 : ! We don't update Hessian if the step has been rejected
1544 : CALL symm_rank_one_update(opt_embed%embed_pot_grad, opt_embed%prev_embed_pot_grad, &
1545 2 : opt_embed%step, opt_embed%prev_embed_pot_Hess, opt_embed%embed_pot_Hess)
1546 : END IF
1547 : END IF
1548 :
1549 : ! Add regularization term to the Hessian
1550 : !CALL cp_fm_scale_and_add(1.0_dp, opt_embed%embed_pot_Hess, 4.0_dp*opt_embed%lambda, &
1551 : ! opt_embed%kinetic_mat)
1552 :
1553 : ! Else use the first initial Hessian. Now it's just the unit matrix: embed_pot_hess
1554 : ! Second, invert the Hessian
1555 30 : ALLOCATE (eigenval(opt_embed%dimen_var_aux))
1556 10 : eigenval = 0.0_dp
1557 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_hess, &
1558 10 : matrix_struct=fm_struct)
1559 10 : CALL cp_fm_create(fm_U, fm_struct, name="fm_U")
1560 10 : CALL cp_fm_create(fm_U_scale, fm_struct, name="fm_U")
1561 10 : CALL cp_fm_set_all(fm_U, 0.0_dp)
1562 10 : CALL cp_fm_set_all(fm_U_scale, 0.0_dp)
1563 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_grad, &
1564 10 : matrix_struct=fm_struct)
1565 10 : CALL cp_fm_create(diag_grad, fm_struct, name="diag_grad")
1566 10 : CALL cp_fm_set_all(diag_grad, 0.0_dp)
1567 10 : CALL cp_fm_create(diag_step, fm_struct, name="diag_step")
1568 10 : CALL cp_fm_set_all(diag_step, 0.0_dp)
1569 :
1570 : ! Store the Hessian as it will be destroyed in diagonalization: use fm_U_scal for it
1571 10 : CALL cp_fm_to_fm(opt_embed%embed_pot_hess, fm_U_scale)
1572 :
1573 : ! Diagonalize Hessian
1574 10 : CALL choose_eigv_solver(opt_embed%embed_pot_hess, fm_U, eigenval)
1575 :
1576 : ! Copy the Hessian back
1577 10 : CALL cp_fm_to_fm(fm_U_scale, opt_embed%embed_pot_hess)
1578 :
1579 : ! Find the step in diagonal representation, begin with gradient
1580 : CALL parallel_gemm(transa="T", transb="N", m=opt_embed%dimen_var_aux, n=1, &
1581 : k=opt_embed%dimen_var_aux, alpha=1.0_dp, &
1582 : matrix_a=fm_U, matrix_b=opt_embed%embed_pot_grad, beta=0.0_dp, &
1583 10 : matrix_c=diag_grad)
1584 :
1585 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_coef, &
1586 : nrow_local=nrow_local, &
1587 10 : row_indices=row_indices)
1588 :
1589 838 : DO LLL = 1, nrow_local
1590 828 : l_global = row_indices(LLL)
1591 838 : IF (ABS(eigenval(l_global)) >= thresh) THEN
1592 : diag_step%local_data(LLL, 1) = &
1593 828 : -diag_grad%local_data(LLL, 1)/(eigenval(l_global))
1594 : ELSE
1595 0 : diag_step%local_data(LLL, 1) = 0.0_dp
1596 : END IF
1597 : END DO
1598 10 : CALL cp_fm_trace(diag_step, diag_step, opt_embed%step_len)
1599 :
1600 : ! Transform step to a non-diagonal representation
1601 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_var_aux, n=1, &
1602 : k=opt_embed%dimen_var_aux, alpha=1.0_dp, &
1603 : matrix_a=fm_U, matrix_b=diag_step, beta=0.0_dp, &
1604 10 : matrix_c=opt_embed%step)
1605 :
1606 : ! Now use fm_U_scale for scaled eigenvectors
1607 10 : CALL cp_fm_to_fm(fm_U, fm_U_scale)
1608 10 : CALL cp_fm_column_scale(fm_U_scale, eigenval)
1609 :
1610 10 : CALL cp_fm_release(fm_U_scale)
1611 :
1612 : ! Scale the step to fit within the trust radius: it it's less already,
1613 : ! then take the Newton step
1614 10 : CALL cp_fm_trace(opt_embed%step, opt_embed%step, opt_embed%step_len)
1615 10 : IF (opt_embed%step_len > opt_embed%trust_rad) THEN
1616 :
1617 2 : IF (opt_embed%level_shift) THEN
1618 : ! Find a level shift parameter and apply it
1619 2 : CALL level_shift(opt_embed, diag_grad, eigenval, diag_step)
1620 : ELSE ! Just scale
1621 0 : CALL cp_fm_trace(diag_step, diag_step, opt_embed%step_len)
1622 0 : CALL cp_fm_scale(opt_embed%trust_rad/opt_embed%step_len, diag_step)
1623 : END IF
1624 2 : CALL cp_fm_trace(diag_step, diag_step, opt_embed%step_len)
1625 : ! Transform step to a non-diagonal representation
1626 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_var_aux, n=1, &
1627 : k=opt_embed%dimen_var_aux, alpha=1.0_dp, &
1628 : matrix_a=fm_U, matrix_b=diag_step, beta=0.0_dp, &
1629 2 : matrix_c=opt_embed%step)
1630 2 : CALL cp_fm_trace(opt_embed%step, opt_embed%step, opt_embed%step_len)
1631 :
1632 : ! Recalculate step in diagonal representation
1633 2 : opt_embed%newton_step = .FALSE.
1634 : ELSE
1635 8 : opt_embed%newton_step = .TRUE.
1636 : END IF
1637 :
1638 : ! Release some memory
1639 10 : DEALLOCATE (eigenval)
1640 : ! Release more memory
1641 10 : CALL cp_fm_release(diag_grad)
1642 10 : CALL cp_fm_release(diag_step)
1643 50 : CALL cp_fm_release(fm_U)
1644 :
1645 : END IF ! grad_descent
1646 :
1647 : ! Update the coefficients
1648 16 : CALL cp_fm_scale_and_add(1.0_dp, opt_embed%embed_pot_coef, 1.0_dp, opt_embed%step)
1649 :
1650 : ! Update the embedding potential
1651 : CALL update_embed_pot(opt_embed%embed_pot_coef, opt_embed%dimen_aux, embed_pot, &
1652 : spin_embed_pot, qs_env, opt_embed%add_const_pot, &
1653 16 : opt_embed%open_shell_embed, opt_embed%const_pot)
1654 : END IF ! Grid-based optimization
1655 :
1656 24 : CALL timestop(handle)
1657 :
1658 48 : END SUBROUTINE opt_embed_step
1659 :
1660 : !
1661 : ! **************************************************************************************************
1662 : !> \brief ...
1663 : !> \param diff_rho_r ...
1664 : !> \param diff_rho_spin ...
1665 : !> \param pw_env ...
1666 : !> \param opt_embed ...
1667 : !> \param embed_pot ...
1668 : !> \param spin_embed_pot ...
1669 : ! **************************************************************************************************
1670 4 : SUBROUTINE grid_based_step(diff_rho_r, diff_rho_spin, pw_env, opt_embed, embed_pot, spin_embed_pot)
1671 :
1672 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: diff_rho_r, diff_rho_spin
1673 : TYPE(pw_env_type), POINTER :: pw_env
1674 : TYPE(opt_embed_pot_type) :: opt_embed
1675 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
1676 : TYPE(pw_r3d_rs_type), POINTER :: spin_embed_pot
1677 :
1678 : CHARACTER(LEN=*), PARAMETER :: routineN = 'grid_based_step'
1679 :
1680 : INTEGER :: handle
1681 : REAL(KIND=dp) :: my_reg_term
1682 :
1683 4 : CALL timeset(routineN, handle)
1684 :
1685 : ! Take the step for spin-free part
1686 4 : CALL pw_axpy(diff_rho_r, embed_pot, opt_embed%step_len)
1687 : ! Regularize
1688 4 : CALL grid_regularize(embed_pot, pw_env, opt_embed%lambda, my_reg_term)
1689 4 : opt_embed%reg_term = opt_embed%reg_term + my_reg_term
1690 :
1691 4 : IF (opt_embed%open_shell_embed) THEN
1692 2 : CALL pw_axpy(diff_rho_spin, spin_embed_pot, opt_embed%step_len)
1693 2 : CALL grid_regularize(spin_embed_pot, pw_env, opt_embed%lambda, my_reg_term)
1694 2 : opt_embed%reg_term = opt_embed%reg_term + my_reg_term
1695 : END IF
1696 :
1697 4 : CALL timestop(handle)
1698 :
1699 4 : END SUBROUTINE grid_based_step
1700 :
1701 : ! **************************************************************************************************
1702 : !> \brief ... Adds variable part of to the embedding potential
1703 : !> \param embed_pot_coef ...
1704 : !> \param dimen_aux ...
1705 : !> \param embed_pot ...
1706 : !> \param spin_embed_pot ...
1707 : !> \param qs_env ...
1708 : !> \param add_const_pot ...
1709 : !> \param open_shell_embed ...
1710 : !> \param const_pot ...
1711 : !> \author Vladimir Rybkin
1712 : ! **************************************************************************************************
1713 :
1714 20 : SUBROUTINE update_embed_pot(embed_pot_coef, dimen_aux, embed_pot, spin_embed_pot, &
1715 : qs_env, add_const_pot, open_shell_embed, const_pot)
1716 : TYPE(cp_fm_type), INTENT(IN) :: embed_pot_coef
1717 : INTEGER :: dimen_aux
1718 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
1719 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
1720 : TYPE(qs_environment_type), POINTER :: qs_env
1721 : LOGICAL :: add_const_pot, open_shell_embed
1722 : TYPE(pw_r3d_rs_type), INTENT(IN), OPTIONAL :: const_pot
1723 :
1724 : CHARACTER(LEN=*), PARAMETER :: routineN = 'update_embed_pot'
1725 :
1726 : INTEGER :: handle, l_global, LLL, nrow_local
1727 20 : INTEGER, DIMENSION(:), POINTER :: row_indices
1728 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: wf_vector
1729 20 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1730 : TYPE(cell_type), POINTER :: cell
1731 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
1732 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
1733 : TYPE(cp_fm_type) :: embed_pot_coef_spin, &
1734 : embed_pot_coef_spinless
1735 : TYPE(cp_fm_type), POINTER :: mo_coeff
1736 : TYPE(dft_control_type), POINTER :: dft_control
1737 20 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1738 : TYPE(mp_para_env_type), POINTER :: para_env
1739 20 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1740 : TYPE(pw_c1d_gs_type) :: rho_g
1741 : TYPE(pw_env_type), POINTER :: pw_env
1742 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
1743 : TYPE(pw_r3d_rs_type) :: psi_L
1744 20 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1745 :
1746 20 : CALL timeset(routineN, handle)
1747 : ! Get MO coefficients: we need only the structure, therefore don't care about the spin
1748 : CALL get_qs_env(qs_env=qs_env, &
1749 : particle_set=particle_set, &
1750 : qs_kind_set=qs_kind_set, &
1751 : dft_control=dft_control, &
1752 : cell=cell, &
1753 : atomic_kind_set=atomic_kind_set, &
1754 20 : pw_env=pw_env, mos=mos, para_env=para_env)
1755 20 : CALL get_mo_set(mo_set=mos(1), mo_coeff=mo_coeff)
1756 :
1757 : ! Get plane waves pool
1758 20 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
1759 :
1760 : ! get some of the grids ready
1761 20 : CALL auxbas_pw_pool%create_pw(rho_g)
1762 :
1763 20 : CALL auxbas_pw_pool%create_pw(psi_L)
1764 :
1765 : ! Create wf_vector and auxiliary wave functions
1766 60 : ALLOCATE (wf_vector(dimen_aux))
1767 20 : wf_vector = 0.0_dp
1768 :
1769 : ! Create auxiliary full matrices for open-shell case
1770 20 : IF (open_shell_embed) THEN
1771 12 : NULLIFY (blacs_env)
1772 12 : CALL cp_fm_get_info(matrix=embed_pot_coef, context=blacs_env)
1773 : CALL cp_fm_struct_create(fm_struct, para_env=para_env, context=blacs_env, &
1774 12 : nrow_global=dimen_aux, ncol_global=1)
1775 12 : CALL cp_fm_create(embed_pot_coef_spinless, fm_struct, name="pot_coeff_spinless")
1776 12 : CALL cp_fm_create(embed_pot_coef_spin, fm_struct, name="pot_coeff_spin")
1777 12 : CALL cp_fm_set_all(embed_pot_coef_spinless, 0.0_dp)
1778 12 : CALL cp_fm_set_all(embed_pot_coef_spin, 0.0_dp)
1779 12 : CALL cp_fm_struct_release(fm_struct)
1780 :
1781 : ! Copy coefficients to the auxiliary structures
1782 : CALL cp_fm_to_fm_submat(embed_pot_coef, &
1783 : mtarget=embed_pot_coef_spinless, &
1784 : nrow=dimen_aux, ncol=1, &
1785 : s_firstrow=1, s_firstcol=1, &
1786 12 : t_firstrow=1, t_firstcol=1)
1787 : CALL cp_fm_to_fm_submat(embed_pot_coef, &
1788 : mtarget=embed_pot_coef_spin, &
1789 : nrow=dimen_aux, ncol=1, &
1790 : s_firstrow=dimen_aux + 1, s_firstcol=1, &
1791 12 : t_firstrow=1, t_firstcol=1)
1792 :
1793 : ! Spinless potential
1794 : CALL cp_fm_get_info(matrix=embed_pot_coef_spinless, &
1795 : nrow_local=nrow_local, &
1796 12 : row_indices=row_indices)
1797 :
1798 : ! Copy fm_coeff to an array
1799 372 : DO LLL = 1, nrow_local
1800 360 : l_global = row_indices(LLL)
1801 372 : wf_vector(l_global) = embed_pot_coef_spinless%local_data(LLL, 1)
1802 : END DO
1803 12 : CALL para_env%sum(wf_vector)
1804 :
1805 : ! Calculate the variable part of the embedding potential
1806 : CALL collocate_function(wf_vector, psi_L, rho_g, atomic_kind_set, &
1807 : qs_kind_set, cell, particle_set, pw_env, &
1808 : dft_control%qs_control%eps_rho_rspace, &
1809 12 : basis_type="RI_AUX")
1810 : ! Update the full embedding potential
1811 12 : IF (add_const_pot) THEN
1812 0 : CALL pw_copy(const_pot, embed_pot)
1813 : ELSE
1814 12 : CALL pw_zero(embed_pot)
1815 : END IF
1816 :
1817 12 : CALL pw_axpy(psi_L, embed_pot)
1818 :
1819 : ! Spin-dependent potential
1820 12 : wf_vector = 0.0_dp
1821 : CALL cp_fm_get_info(matrix=embed_pot_coef_spin, &
1822 : nrow_local=nrow_local, &
1823 12 : row_indices=row_indices)
1824 :
1825 : ! Copy fm_coeff to an array
1826 372 : DO LLL = 1, nrow_local
1827 360 : l_global = row_indices(LLL)
1828 372 : wf_vector(l_global) = embed_pot_coef_spin%local_data(LLL, 1)
1829 : END DO
1830 12 : CALL para_env%sum(wf_vector)
1831 :
1832 : ! Calculate the variable part of the embedding potential
1833 : CALL collocate_function(wf_vector, psi_L, rho_g, atomic_kind_set, &
1834 : qs_kind_set, cell, particle_set, pw_env, &
1835 : dft_control%qs_control%eps_rho_rspace, &
1836 12 : basis_type="RI_AUX")
1837 : ! No constant potential for spin-dependent potential
1838 12 : CALL pw_zero(spin_embed_pot)
1839 12 : CALL pw_axpy(psi_L, spin_embed_pot)
1840 :
1841 : ELSE ! Closed shell
1842 :
1843 : CALL cp_fm_get_info(matrix=embed_pot_coef, &
1844 : nrow_local=nrow_local, &
1845 8 : row_indices=row_indices)
1846 :
1847 : ! Copy fm_coeff to an array
1848 792 : DO LLL = 1, nrow_local
1849 784 : l_global = row_indices(LLL)
1850 792 : wf_vector(l_global) = embed_pot_coef%local_data(LLL, 1)
1851 : END DO
1852 8 : CALL para_env%sum(wf_vector)
1853 :
1854 : ! Calculate the variable part of the embedding potential
1855 : CALL calculate_wavefunction(mo_coeff, 1, psi_L, rho_g, atomic_kind_set, &
1856 8 : qs_kind_set, cell, dft_control, particle_set, pw_env)
1857 :
1858 : CALL collocate_function(wf_vector, psi_L, rho_g, atomic_kind_set, &
1859 : qs_kind_set, cell, particle_set, pw_env, &
1860 : dft_control%qs_control%eps_rho_rspace, &
1861 8 : basis_type="RI_AUX")
1862 :
1863 : ! Update the full embedding potential
1864 8 : IF (add_const_pot) THEN
1865 2 : CALL pw_copy(const_pot, embed_pot)
1866 : ELSE
1867 6 : CALL pw_zero(embed_pot)
1868 : END IF
1869 :
1870 8 : CALL pw_axpy(psi_L, embed_pot)
1871 : END IF ! Open/closed shell
1872 :
1873 : ! Deallocate memory and release objects
1874 20 : DEALLOCATE (wf_vector)
1875 20 : CALL auxbas_pw_pool%give_back_pw(psi_L)
1876 20 : CALL auxbas_pw_pool%give_back_pw(rho_g)
1877 :
1878 20 : IF (open_shell_embed) THEN
1879 12 : CALL cp_fm_release(embed_pot_coef_spin)
1880 12 : CALL cp_fm_release(embed_pot_coef_spinless)
1881 : END IF
1882 :
1883 20 : CALL timestop(handle)
1884 :
1885 20 : END SUBROUTINE update_embed_pot
1886 :
1887 : ! **************************************************************************************************
1888 : !> \brief BFGS update of the inverse Hessian in the full matrix format
1889 : !> \param grad ...
1890 : !> \param prev_grad ...
1891 : !> \param step ...
1892 : !> \param prev_inv_Hess ...
1893 : !> \param inv_Hess ...
1894 : !> \author Vladimir Rybkin
1895 : ! **************************************************************************************************
1896 0 : SUBROUTINE inv_Hessian_update(grad, prev_grad, step, prev_inv_Hess, inv_Hess)
1897 : TYPE(cp_fm_type), INTENT(IN) :: grad, prev_grad, step, prev_inv_Hess, &
1898 : inv_Hess
1899 :
1900 : INTEGER :: mat_size
1901 : REAL(KIND=dp) :: factor1, s_dot_y, y_dot_B_inv_y
1902 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_mat, fm_struct_vec
1903 : TYPE(cp_fm_type) :: B_inv_y, B_inv_y_s, s_s, s_y, s_y_B_inv, &
1904 : y
1905 :
1906 : ! Recover the dimension
1907 : CALL cp_fm_get_info(matrix=inv_Hess, &
1908 0 : nrow_global=mat_size)
1909 :
1910 0 : CALL cp_fm_set_all(inv_Hess, 0.0_dp)
1911 0 : CALL cp_fm_to_fm(prev_inv_Hess, inv_Hess)
1912 :
1913 : ! Get full matrix structures
1914 0 : NULLIFY (fm_struct_mat, fm_struct_vec)
1915 :
1916 : CALL cp_fm_get_info(matrix=prev_inv_Hess, &
1917 0 : matrix_struct=fm_struct_mat)
1918 : CALL cp_fm_get_info(matrix=grad, &
1919 0 : matrix_struct=fm_struct_vec)
1920 :
1921 : ! Allocate intermediates
1922 0 : CALL cp_fm_create(B_inv_y, fm_struct_vec, name="B_inv_y")
1923 0 : CALL cp_fm_create(y, fm_struct_vec, name="y")
1924 :
1925 0 : CALL cp_fm_create(s_s, fm_struct_mat, name="s_s")
1926 0 : CALL cp_fm_create(s_y, fm_struct_mat, name="s_y")
1927 0 : CALL cp_fm_create(B_inv_y_s, fm_struct_mat, name="B_inv_y_s")
1928 0 : CALL cp_fm_create(s_y_B_inv, fm_struct_mat, name="s_y_B_inv")
1929 :
1930 0 : CALL cp_fm_set_all(B_inv_y, 0.0_dp)
1931 0 : CALL cp_fm_set_all(s_s, 0.0_dp)
1932 0 : CALL cp_fm_set_all(s_y, 0.0_dp)
1933 0 : CALL cp_fm_set_all(B_inv_y_s, 0.0_dp)
1934 0 : CALL cp_fm_set_all(s_y_B_inv, 0.0_dp)
1935 :
1936 : ! Calculate intermediates
1937 : ! y the is gradient difference
1938 0 : CALL cp_fm_get_info(matrix=grad)
1939 0 : CALL cp_fm_to_fm(grad, y)
1940 0 : CALL cp_fm_scale_and_add(1.0_dp, y, -1.0_dp, prev_grad)
1941 :
1942 : ! First term
1943 : CALL parallel_gemm(transa="N", transb="N", m=mat_size, n=1, &
1944 : k=mat_size, alpha=1.0_dp, &
1945 : matrix_a=prev_inv_Hess, matrix_b=y, beta=0.0_dp, &
1946 0 : matrix_c=B_inv_y)
1947 :
1948 : CALL parallel_gemm(transa="N", transb="T", m=mat_size, n=mat_size, &
1949 : k=1, alpha=1.0_dp, &
1950 : matrix_a=step, matrix_b=step, beta=0.0_dp, &
1951 0 : matrix_c=s_s)
1952 :
1953 : CALL parallel_gemm(transa="N", transb="T", m=mat_size, n=mat_size, &
1954 : k=1, alpha=1.0_dp, &
1955 : matrix_a=step, matrix_b=y, beta=0.0_dp, &
1956 0 : matrix_c=s_y)
1957 :
1958 0 : CALL cp_fm_trace(step, y, s_dot_y)
1959 :
1960 0 : CALL cp_fm_trace(y, y, s_dot_y)
1961 0 : CALL cp_fm_trace(step, step, s_dot_y)
1962 :
1963 0 : CALL cp_fm_trace(y, B_inv_y, y_dot_B_inv_y)
1964 :
1965 0 : factor1 = (s_dot_y + y_dot_B_inv_y)/(s_dot_y)**2
1966 :
1967 0 : CALL cp_fm_scale_and_add(1.0_dp, inv_Hess, factor1, s_s)
1968 :
1969 : ! Second term
1970 : CALL parallel_gemm(transa="N", transb="T", m=mat_size, n=mat_size, &
1971 : k=1, alpha=1.0_dp, &
1972 : matrix_a=B_inv_y, matrix_b=step, beta=0.0_dp, &
1973 0 : matrix_c=B_inv_y_s)
1974 :
1975 : CALL parallel_gemm(transa="N", transb="N", m=mat_size, n=mat_size, &
1976 : k=mat_size, alpha=1.0_dp, &
1977 : matrix_a=s_y, matrix_b=prev_inv_Hess, beta=0.0_dp, &
1978 0 : matrix_c=s_y_B_inv)
1979 :
1980 0 : CALL cp_fm_scale_and_add(1.0_dp, B_inv_y_s, 1.0_dp, s_y_B_inv)
1981 :
1982 : ! Assemble the new inverse Hessian
1983 0 : CALL cp_fm_scale_and_add(1.0_dp, inv_Hess, -s_dot_y, B_inv_y_s)
1984 :
1985 : ! Deallocate intermediates
1986 0 : CALL cp_fm_release(y)
1987 0 : CALL cp_fm_release(B_inv_y)
1988 0 : CALL cp_fm_release(s_s)
1989 0 : CALL cp_fm_release(s_y)
1990 0 : CALL cp_fm_release(B_inv_y_s)
1991 0 : CALL cp_fm_release(s_y_B_inv)
1992 :
1993 0 : END SUBROUTINE inv_Hessian_update
1994 :
1995 : ! **************************************************************************************************
1996 : !> \brief ...
1997 : !> \param grad ...
1998 : !> \param prev_grad ...
1999 : !> \param step ...
2000 : !> \param prev_Hess ...
2001 : !> \param Hess ...
2002 : ! **************************************************************************************************
2003 0 : SUBROUTINE Hessian_update(grad, prev_grad, step, prev_Hess, Hess)
2004 : TYPE(cp_fm_type), INTENT(IN) :: grad, prev_grad, step, prev_Hess, Hess
2005 :
2006 : INTEGER :: mat_size
2007 : REAL(KIND=dp) :: s_b_s, y_t_s
2008 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
2009 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_mat, fm_struct_vec, &
2010 : fm_struct_vec_t
2011 : TYPE(cp_fm_type) :: B_s, B_s_s_B, s_t_B, y, y_y_t
2012 : TYPE(mp_para_env_type), POINTER :: para_env
2013 :
2014 : ! Recover the dimension
2015 : CALL cp_fm_get_info(matrix=Hess, &
2016 0 : nrow_global=mat_size, para_env=para_env)
2017 :
2018 0 : CALL cp_fm_set_all(Hess, 0.0_dp)
2019 0 : CALL cp_fm_to_fm(prev_Hess, Hess)
2020 :
2021 : ! WARNING: our Hessian must be negative-definite, whereas BFGS makes it positive-definite!
2022 : ! Therefore, we change sign in the beginning and in the end.
2023 0 : CALL cp_fm_scale(-1.0_dp, Hess)
2024 :
2025 : ! Create blacs environment
2026 0 : NULLIFY (blacs_env)
2027 0 : CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env)
2028 :
2029 : ! Get full matrix structures
2030 0 : NULLIFY (fm_struct_mat, fm_struct_vec, fm_struct_vec_t)
2031 :
2032 : CALL cp_fm_get_info(matrix=prev_Hess, &
2033 0 : matrix_struct=fm_struct_mat)
2034 : CALL cp_fm_get_info(matrix=grad, &
2035 0 : matrix_struct=fm_struct_vec)
2036 : CALL cp_fm_struct_create(fm_struct_vec_t, para_env=para_env, context=blacs_env, &
2037 0 : nrow_global=1, ncol_global=mat_size)
2038 :
2039 : ! Allocate intermediates
2040 0 : CALL cp_fm_create(B_s, fm_struct_vec, name="B_s")
2041 0 : CALL cp_fm_create(s_t_B, fm_struct_vec_t, name="s_t_B")
2042 0 : CALL cp_fm_create(y, fm_struct_vec, name="y")
2043 :
2044 0 : CALL cp_fm_create(y_y_t, fm_struct_mat, name="y_y_t")
2045 0 : CALL cp_fm_create(B_s_s_B, fm_struct_mat, name="B_s_s_B")
2046 :
2047 0 : CALL cp_fm_set_all(y_y_t, 0.0_dp)
2048 0 : CALL cp_fm_set_all(y, 0.0_dp)
2049 0 : CALL cp_fm_set_all(B_s_s_B, 0.0_dp)
2050 0 : CALL cp_fm_set_all(B_s, 0.0_dp)
2051 0 : CALL cp_fm_set_all(s_t_B, 0.0_dp)
2052 :
2053 : ! Release the structure created only here
2054 0 : CALL cp_fm_struct_release(fm_struct_vec_t)
2055 :
2056 : ! Calculate intermediates
2057 : ! y the is gradient difference
2058 0 : CALL cp_fm_to_fm(grad, y)
2059 0 : CALL cp_fm_scale_and_add(1.0_dp, y, -1.0_dp, prev_grad)
2060 :
2061 : ! First term
2062 : CALL parallel_gemm(transa="N", transb="T", m=mat_size, n=mat_size, &
2063 : k=1, alpha=1.0_dp, &
2064 : matrix_a=y, matrix_b=y, beta=0.0_dp, &
2065 0 : matrix_c=y_y_t)
2066 :
2067 0 : CALL cp_fm_trace(y, step, y_t_s)
2068 :
2069 0 : CALL cp_fm_scale_and_add(1.0_dp, Hess, (1.0_dp/y_t_s), y_y_t)
2070 :
2071 : ! Second term
2072 : CALL parallel_gemm(transa="N", transb="N", m=mat_size, n=1, &
2073 : k=mat_size, alpha=1.0_dp, &
2074 : matrix_a=Hess, matrix_b=step, beta=0.0_dp, &
2075 0 : matrix_c=B_s)
2076 :
2077 0 : CALL cp_fm_trace(B_s, step, s_B_s)
2078 :
2079 : CALL parallel_gemm(transa="T", transb="N", m=1, n=mat_size, &
2080 : k=mat_size, alpha=1.0_dp, &
2081 : matrix_a=step, matrix_b=Hess, beta=0.0_dp, &
2082 0 : matrix_c=s_t_B)
2083 :
2084 : CALL parallel_gemm(transa="N", transb="N", m=mat_size, n=mat_size, &
2085 : k=1, alpha=1.0_dp, &
2086 : matrix_a=B_s, matrix_b=s_t_B, beta=0.0_dp, &
2087 0 : matrix_c=B_s_s_B)
2088 :
2089 0 : CALL cp_fm_scale_and_add(1.0_dp, Hess, -(1.0_dp/s_B_s), B_s_s_B)
2090 :
2091 : ! WARNING: our Hessian must be negative-definite, whereas BFGS makes it positive-definite!
2092 : ! Therefore, we change sign in the beginning and in the end.
2093 0 : CALL cp_fm_scale(-1.0_dp, Hess)
2094 :
2095 : ! Release blacs environment
2096 0 : CALL cp_blacs_env_release(blacs_env)
2097 :
2098 : ! Deallocate intermediates
2099 0 : CALL cp_fm_release(y_y_t)
2100 0 : CALL cp_fm_release(B_s_s_B)
2101 0 : CALL cp_fm_release(B_s)
2102 0 : CALL cp_fm_release(s_t_B)
2103 0 : CALL cp_fm_release(y)
2104 :
2105 0 : END SUBROUTINE Hessian_update
2106 :
2107 : ! **************************************************************************************************
2108 : !> \brief ...
2109 : !> \param grad ...
2110 : !> \param prev_grad ...
2111 : !> \param step ...
2112 : !> \param prev_Hess ...
2113 : !> \param Hess ...
2114 : ! **************************************************************************************************
2115 10 : SUBROUTINE symm_rank_one_update(grad, prev_grad, step, prev_Hess, Hess)
2116 : TYPE(cp_fm_type), INTENT(IN) :: grad, prev_grad, step, prev_Hess, Hess
2117 :
2118 : INTEGER :: mat_size
2119 : REAL(KIND=dp) :: factor
2120 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_mat, fm_struct_vec
2121 : TYPE(cp_fm_type) :: B_x, y, y_B_x_y_B_x
2122 :
2123 : ! Recover the dimension
2124 2 : CALL cp_fm_get_info(matrix=Hess, nrow_global=mat_size)
2125 :
2126 2 : CALL cp_fm_set_all(Hess, 0.0_dp)
2127 2 : CALL cp_fm_to_fm(prev_Hess, Hess)
2128 :
2129 : ! Get full matrix structures
2130 2 : NULLIFY (fm_struct_mat, fm_struct_vec)
2131 :
2132 : CALL cp_fm_get_info(matrix=prev_Hess, &
2133 2 : matrix_struct=fm_struct_mat)
2134 : CALL cp_fm_get_info(matrix=grad, &
2135 2 : matrix_struct=fm_struct_vec)
2136 :
2137 : ! Allocate intermediates
2138 2 : CALL cp_fm_create(y, fm_struct_vec, name="y")
2139 2 : CALL cp_fm_create(B_x, fm_struct_vec, name="B_x")
2140 2 : CALL cp_fm_create(y_B_x_y_B_x, fm_struct_mat, name="y_B_x_y_B_x")
2141 :
2142 2 : CALL cp_fm_set_all(y, 0.0_dp)
2143 2 : CALL cp_fm_set_all(B_x, 0.0_dp)
2144 2 : CALL cp_fm_set_all(y_B_x_y_B_x, 0.0_dp)
2145 :
2146 : ! Calculate intermediates
2147 : ! y the is gradient difference
2148 2 : CALL cp_fm_to_fm(grad, y)
2149 2 : CALL cp_fm_scale_and_add(1.0_dp, y, -1.0_dp, prev_grad)
2150 :
2151 : CALL parallel_gemm(transa="N", transb="N", m=mat_size, n=1, &
2152 : k=mat_size, alpha=1.0_dp, &
2153 : matrix_a=Hess, matrix_b=step, beta=0.0_dp, &
2154 2 : matrix_c=B_x)
2155 :
2156 2 : CALL cp_fm_scale_and_add(1.0_dp, y, -1.0_dp, B_x)
2157 :
2158 : CALL parallel_gemm(transa="N", transb="T", m=mat_size, n=mat_size, &
2159 : k=1, alpha=1.0_dp, &
2160 : matrix_a=y, matrix_b=y, beta=0.0_dp, &
2161 2 : matrix_c=y_B_x_y_B_x)
2162 :
2163 : ! Scaling factor
2164 2 : CALL cp_fm_trace(y, step, factor)
2165 :
2166 : ! Assemble the Hessian
2167 2 : CALL cp_fm_scale_and_add(1.0_dp, Hess, (1.0_dp/factor), y_B_x_y_B_x)
2168 :
2169 : ! Deallocate intermediates
2170 2 : CALL cp_fm_release(y)
2171 2 : CALL cp_fm_release(B_x)
2172 2 : CALL cp_fm_release(y_B_x_y_B_x)
2173 :
2174 2 : END SUBROUTINE symm_rank_one_update
2175 :
2176 : ! **************************************************************************************************
2177 : !> \brief Controls the step, changes the trust radius if needed in maximization of the V_emb
2178 : !> \param opt_embed ...
2179 : !> \author Vladimir Rybkin
2180 : ! **************************************************************************************************
2181 8 : SUBROUTINE step_control(opt_embed)
2182 : TYPE(opt_embed_pot_type) :: opt_embed
2183 :
2184 : CHARACTER(LEN=*), PARAMETER :: routineN = 'step_control'
2185 :
2186 : INTEGER :: handle
2187 : REAL(KIND=dp) :: actual_ener_change, ener_ratio, &
2188 : lin_term, pred_ener_change, quad_term
2189 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
2190 : TYPE(cp_fm_type) :: H_b
2191 :
2192 2 : CALL timeset(routineN, handle)
2193 :
2194 2 : NULLIFY (fm_struct)
2195 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_grad, &
2196 2 : matrix_struct=fm_struct)
2197 2 : CALL cp_fm_create(H_b, fm_struct, name="H_b")
2198 2 : CALL cp_fm_set_all(H_b, 0.0_dp)
2199 :
2200 : ! Calculate the quadratic estimate for the energy
2201 : ! Linear term
2202 2 : CALL cp_fm_trace(opt_embed%step, opt_embed%embed_pot_grad, lin_term)
2203 :
2204 : ! Quadratic term
2205 : CALL parallel_gemm(transa="N", transb="N", m=opt_embed%dimen_aux, n=1, &
2206 : k=opt_embed%dimen_aux, alpha=1.0_dp, &
2207 : matrix_a=opt_embed%embed_pot_Hess, matrix_b=opt_embed%step, &
2208 2 : beta=0.0_dp, matrix_c=H_b)
2209 2 : CALL cp_fm_trace(opt_embed%step, H_b, quad_term)
2210 :
2211 2 : pred_ener_change = lin_term + 0.5_dp*quad_term
2212 :
2213 : ! Reveal actual energy change
2214 : actual_ener_change = opt_embed%w_func(opt_embed%i_iter) - &
2215 2 : opt_embed%w_func(opt_embed%last_accepted)
2216 :
2217 2 : ener_ratio = actual_ener_change/pred_ener_change
2218 :
2219 2 : CALL cp_fm_release(H_b)
2220 :
2221 2 : IF (actual_ener_change > 0.0_dp) THEN ! If energy increases
2222 : ! We accept step
2223 2 : opt_embed%accept_step = .TRUE.
2224 : ! If energy change is larger than the predicted one, increase trust radius twice
2225 : ! Else (between 0 and 1) leave as it is, unless Newton step has been taken and if the step is less than max
2226 2 : IF ((ener_ratio > 1.0_dp) .AND. (.NOT. opt_embed%newton_step) .AND. &
2227 : (opt_embed%trust_rad < opt_embed%max_trad)) THEN
2228 0 : opt_embed%trust_rad = 2.0_dp*opt_embed%trust_rad
2229 : END IF
2230 : ELSE ! Energy decreases
2231 : ! If the decrease is not too large we allow this step to be taken
2232 : ! Otherwise, the step is rejected
2233 0 : IF (ABS(actual_ener_change) >= opt_embed%allowed_decrease) THEN
2234 0 : opt_embed%accept_step = .FALSE.
2235 : END IF
2236 : ! Trust radius is decreased 4 times unless it's smaller than the minimal allowed value
2237 0 : IF (opt_embed%trust_rad >= opt_embed%min_trad) THEN
2238 0 : opt_embed%trust_rad = 0.25_dp*opt_embed%trust_rad
2239 : END IF
2240 : END IF
2241 :
2242 2 : IF (opt_embed%accept_step) opt_embed%last_accepted = opt_embed%i_iter
2243 :
2244 2 : CALL timestop(handle)
2245 :
2246 2 : END SUBROUTINE step_control
2247 :
2248 : ! **************************************************************************************************
2249 : !> \brief ...
2250 : !> \param opt_embed ...
2251 : !> \param diag_grad ...
2252 : !> \param eigenval ...
2253 : !> \param diag_step ...
2254 : ! **************************************************************************************************
2255 2 : SUBROUTINE level_shift(opt_embed, diag_grad, eigenval, diag_step)
2256 : TYPE(opt_embed_pot_type) :: opt_embed
2257 : TYPE(cp_fm_type), INTENT(IN) :: diag_grad
2258 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenval
2259 : TYPE(cp_fm_type), INTENT(IN) :: diag_step
2260 :
2261 : CHARACTER(LEN=*), PARAMETER :: routineN = 'level_shift'
2262 : INTEGER, PARAMETER :: max_iter = 25
2263 : REAL(KIND=dp), PARAMETER :: thresh = 0.00001_dp
2264 :
2265 : INTEGER :: handle, i_iter, l_global, LLL, &
2266 : min_index, nrow_local
2267 2 : INTEGER, ALLOCATABLE, DIMENSION(:) :: red_eigenval_map
2268 2 : INTEGER, DIMENSION(:), POINTER :: row_indices
2269 : LOGICAL :: converged, do_shift
2270 : REAL(KIND=dp) :: diag_grad_norm, grad_min, hess_min, shift, shift_max, shift_min, step_len, &
2271 : step_minus_trad, step_minus_trad_first, step_minus_trad_max, step_minus_trad_min
2272 : TYPE(mp_para_env_type), POINTER :: para_env
2273 :
2274 2 : CALL timeset(routineN, handle)
2275 :
2276 : ! Array properties
2277 : CALL cp_fm_get_info(matrix=opt_embed%embed_pot_coef, &
2278 : nrow_local=nrow_local, &
2279 : row_indices=row_indices, &
2280 2 : para_env=para_env)
2281 :
2282 242 : min_index = MINLOC(ABS(eigenval), dim=1)
2283 2 : hess_min = eigenval(min_index)
2284 2 : CALL cp_fm_get_element(diag_grad, min_index, 1, grad_min)
2285 :
2286 2 : CALL cp_fm_trace(diag_grad, diag_grad, diag_grad_norm)
2287 :
2288 2 : IF (hess_min < 0.0_dp) THEN
2289 : !shift_min = -2.0_dp*(diag_grad_norm/opt_embed%trust_rad - min(hess_min, 0.0_dp))
2290 : !shift_max = max(0.0_dp, -hess_min + 0.5_dp*grad_min/opt_embed%trust_rad)
2291 : !shift_max = MIN(-hess_min+0.5_dp*grad_min/opt_embed%trust_rad, 0.0_dp)
2292 2 : shift_max = hess_min + 0.1
2293 : shift_min = diag_grad_norm/opt_embed%trust_rad
2294 2 : shift_min = 10.0_dp
2295 : !If (abs(shift_max) <= thresh) then
2296 : ! shift_min = -20.0_dp*(diag_grad_norm/opt_embed%trust_rad - min(hess_min, 0.0_dp))
2297 : !Else
2298 : ! shift_min = 20.0_dp*shift_max
2299 : !Endif
2300 :
2301 : ! The boundary values
2302 2 : step_minus_trad_max = shifted_step(diag_grad, eigenval, shift_max, opt_embed%trust_rad)
2303 2 : step_minus_trad_min = shifted_step(diag_grad, eigenval, shift_min, opt_embed%trust_rad)
2304 :
2305 : ! Find zero by bisection
2306 2 : converged = .FALSE.
2307 2 : do_shift = .FALSE.
2308 2 : IF (ABS(step_minus_trad_max) <= thresh) THEN
2309 : shift = shift_max
2310 : ELSE
2311 2 : IF (ABS(step_minus_trad_min) <= thresh) THEN
2312 : shift = shift_min
2313 : ELSE
2314 28 : DO i_iter = 1, max_iter
2315 28 : shift = 0.5_dp*(shift_max + shift_min)
2316 28 : step_minus_trad = shifted_step(diag_grad, eigenval, shift, opt_embed%trust_rad)
2317 28 : IF (i_iter == 1) step_minus_trad_first = step_minus_trad
2318 28 : IF (step_minus_trad > 0.0_dp) shift_max = shift
2319 28 : IF (step_minus_trad < 0.0_dp) shift_min = shift
2320 : !IF (ABS(shift_max-shift_min) < thresh) converged = .TRUE.
2321 28 : IF (ABS(step_minus_trad) < thresh) converged = .TRUE.
2322 0 : IF (converged) EXIT
2323 : END DO
2324 2 : IF (ABS(step_minus_trad) < ABS(step_minus_trad_first)) do_shift = .TRUE.
2325 : END IF
2326 : END IF
2327 : ! Apply level-shifting
2328 0 : IF (converged .OR. do_shift) THEN
2329 122 : DO LLL = 1, nrow_local
2330 120 : l_global = row_indices(LLL)
2331 122 : IF (ABS(eigenval(l_global)) >= thresh) THEN
2332 : diag_step%local_data(LLL, 1) = &
2333 120 : -diag_grad%local_data(LLL, 1)/(eigenval(l_global) - shift)
2334 : ELSE
2335 0 : diag_step%local_data(LLL, 1) = 0.0_dp
2336 : END IF
2337 : END DO
2338 : END IF
2339 2 : IF (.NOT. converged) THEN ! Scale if shift has not been found
2340 0 : CALL cp_fm_trace(diag_step, diag_step, step_len)
2341 0 : CALL cp_fm_scale(opt_embed%trust_rad/step_len, diag_step)
2342 : END IF
2343 :
2344 : ! Special case
2345 : ELSE ! Hess min < 0.0_dp
2346 : ! First, find all positive eigenvalues
2347 0 : ALLOCATE (red_eigenval_map(opt_embed%dimen_var_aux))
2348 0 : red_eigenval_map = 0
2349 0 : DO LLL = 1, nrow_local
2350 0 : l_global = row_indices(LLL)
2351 0 : IF (eigenval(l_global) >= 0.0_dp) THEN
2352 0 : red_eigenval_map(l_global) = 1
2353 : END IF
2354 : END DO
2355 0 : CALL para_env%sum(red_eigenval_map)
2356 :
2357 : ! Set shift as -hess_min and find step on the reduced space of negative-value
2358 : ! eigenvectors
2359 : shift = -hess_min
2360 0 : DO LLL = 1, nrow_local
2361 0 : l_global = row_indices(LLL)
2362 0 : IF (red_eigenval_map(l_global) == 0) THEN
2363 0 : IF (ABS(eigenval(l_global)) >= thresh) THEN
2364 : diag_step%local_data(LLL, 1) = &
2365 0 : -diag_grad%local_data(LLL, 1)/(eigenval(l_global) - shift)
2366 : ELSE
2367 0 : diag_step%local_data(LLL, 1) = 0.0_dp
2368 : END IF
2369 : ELSE
2370 0 : diag_step%local_data(LLL, 1) = 0.0_dp
2371 : END IF
2372 : END DO
2373 :
2374 : ! Find the step length of such a step
2375 0 : CALL cp_fm_trace(diag_step, diag_step, step_len)
2376 :
2377 : END IF
2378 :
2379 2 : CALL timestop(handle)
2380 :
2381 4 : END SUBROUTINE level_shift
2382 :
2383 : ! **************************************************************************************************
2384 : !> \brief ...
2385 : !> \param diag_grad ...
2386 : !> \param eigenval ...
2387 : !> \param shift ...
2388 : !> \param trust_rad ...
2389 : !> \return ...
2390 : ! **************************************************************************************************
2391 32 : FUNCTION shifted_step(diag_grad, eigenval, shift, trust_rad) RESULT(step_minus_trad)
2392 : TYPE(cp_fm_type), INTENT(IN) :: diag_grad
2393 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
2394 : INTENT(IN) :: eigenval
2395 : REAL(KIND=dp), INTENT(IN) :: shift, trust_rad
2396 : REAL(KIND=dp) :: step_minus_trad
2397 :
2398 : REAL(KIND=dp), PARAMETER :: thresh = 0.000001_dp
2399 :
2400 : INTEGER :: l_global, LLL, nrow_local
2401 32 : INTEGER, DIMENSION(:), POINTER :: row_indices
2402 : REAL(KIND=dp) :: step, step_1d
2403 : TYPE(mp_para_env_type), POINTER :: para_env
2404 :
2405 : CALL cp_fm_get_info(matrix=diag_grad, &
2406 : nrow_local=nrow_local, &
2407 : row_indices=row_indices, &
2408 32 : para_env=para_env)
2409 :
2410 32 : step = 0.0_dp
2411 1952 : DO LLL = 1, nrow_local
2412 1920 : l_global = row_indices(LLL)
2413 1952 : IF ((ABS(eigenval(l_global)) >= thresh) .AND. (ABS(diag_grad%local_data(LLL, 1)) >= thresh)) THEN
2414 16 : step_1d = -diag_grad%local_data(LLL, 1)/(eigenval(l_global) + shift)
2415 16 : step = step + step_1d**2
2416 : END IF
2417 : END DO
2418 :
2419 32 : CALL para_env%sum(step)
2420 :
2421 32 : step_minus_trad = SQRT(step) - trust_rad
2422 :
2423 32 : END FUNCTION shifted_step
2424 :
2425 : ! **************************************************************************************************
2426 : !> \brief ...
2427 : !> \param step ...
2428 : !> \param prev_step ...
2429 : !> \param grad ...
2430 : !> \param prev_grad ...
2431 : !> \return ...
2432 : !> \retval length ...
2433 : ! **************************************************************************************************
2434 0 : FUNCTION Barzilai_Borwein(step, prev_step, grad, prev_grad) RESULT(length)
2435 : TYPE(cp_fm_type), INTENT(IN) :: step, prev_step, grad, prev_grad
2436 : REAL(KIND=dp) :: length
2437 :
2438 : REAL(KIND=dp) :: denominator, numerator
2439 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
2440 : TYPE(cp_fm_type) :: grad_diff, step_diff
2441 :
2442 : ! Get full matrix structures
2443 0 : NULLIFY (fm_struct)
2444 :
2445 : CALL cp_fm_get_info(matrix=grad, &
2446 0 : matrix_struct=fm_struct)
2447 :
2448 : ! Allocate intermediates
2449 0 : CALL cp_fm_create(grad_diff, fm_struct, name="grad_diff")
2450 0 : CALL cp_fm_create(step_diff, fm_struct, name="step_diff")
2451 :
2452 : ! Calculate intermediates
2453 0 : CALL cp_fm_to_fm(grad, grad_diff)
2454 0 : CALL cp_fm_to_fm(step, step_diff)
2455 :
2456 0 : CALL cp_fm_scale_and_add(1.0_dp, grad_diff, -1.0_dp, prev_grad)
2457 0 : CALL cp_fm_scale_and_add(1.0_dp, step_diff, -1.0_dp, prev_step)
2458 :
2459 0 : CALL cp_fm_trace(step_diff, grad_diff, numerator)
2460 0 : CALL cp_fm_trace(grad_diff, grad_diff, denominator)
2461 :
2462 : ! Release intermediates
2463 0 : CALL cp_fm_release(grad_diff)
2464 0 : CALL cp_fm_release(step_diff)
2465 :
2466 0 : length = numerator/denominator
2467 :
2468 0 : END FUNCTION Barzilai_Borwein
2469 :
2470 : ! **************************************************************************************************
2471 : !> \brief ...
2472 : !> \param pw_env ...
2473 : !> \param embed_pot ...
2474 : !> \param spin_embed_pot ...
2475 : !> \param diff_rho_r ...
2476 : !> \param diff_rho_spin ...
2477 : !> \param rho_r_ref ...
2478 : !> \param open_shell_embed ...
2479 : !> \param step_len ...
2480 : ! **************************************************************************************************
2481 2 : SUBROUTINE Leeuwen_Baerends_potential_update(pw_env, embed_pot, spin_embed_pot, diff_rho_r, diff_rho_spin, &
2482 : rho_r_ref, open_shell_embed, step_len)
2483 : TYPE(pw_env_type), POINTER :: pw_env
2484 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
2485 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
2486 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r, diff_rho_spin
2487 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r_ref
2488 : LOGICAL, INTENT(IN) :: open_shell_embed
2489 : REAL(KIND=dp), INTENT(IN) :: step_len
2490 :
2491 : CHARACTER(LEN=*), PARAMETER :: routineN = 'Leeuwen_Baerends_potential_update'
2492 :
2493 : INTEGER :: handle, i, i_spin, j, k, nspins
2494 : INTEGER, DIMENSION(3) :: lb, ub
2495 : REAL(KIND=dp) :: my_rho, rho_cutoff
2496 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
2497 2 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: new_embed_pot, rho_n_1, temp_embed_pot
2498 :
2499 2 : CALL timeset(routineN, handle)
2500 :
2501 2 : rho_cutoff = EPSILON(0.0_dp)
2502 :
2503 : ! Prepare plane-waves pool
2504 2 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
2505 2 : NULLIFY (new_embed_pot)
2506 :
2507 2 : nspins = 1
2508 2 : IF (open_shell_embed) nspins = 2
2509 : NULLIFY (new_embed_pot)
2510 8 : ALLOCATE (new_embed_pot(nspins))
2511 6 : DO i_spin = 1, nspins
2512 4 : CALL auxbas_pw_pool%create_pw(new_embed_pot(i_spin))
2513 6 : CALL pw_zero(new_embed_pot(i_spin))
2514 : END DO
2515 :
2516 8 : lb(1:3) = embed_pot%pw_grid%bounds_local(1, 1:3)
2517 8 : ub(1:3) = embed_pot%pw_grid%bounds_local(2, 1:3)
2518 :
2519 2 : IF (.NOT. open_shell_embed) THEN
2520 : !$OMP PARALLEL DO DEFAULT(NONE) &
2521 : !$OMP PRIVATE(i,j,k, my_rho) &
2522 0 : !$OMP SHARED(new_embed_pot, embed_pot, diff_rho_r, rho_r_ref, lb, ub, rho_cutoff, step_len)
2523 : DO k = lb(3), ub(3)
2524 : DO j = lb(2), ub(2)
2525 : DO i = lb(1), ub(1)
2526 : IF (rho_r_ref(1)%array(i, j, k) > rho_cutoff) THEN
2527 : my_rho = rho_r_ref(1)%array(i, j, k)
2528 : ELSE
2529 : my_rho = rho_cutoff
2530 : END IF
2531 : new_embed_pot(1)%array(i, j, k) = step_len*embed_pot%array(i, j, k)* &
2532 : (diff_rho_r%array(i, j, k) + rho_r_ref(1)%array(i, j, k))/my_rho
2533 : END DO
2534 : END DO
2535 : END DO
2536 : !$OMP END PARALLEL DO
2537 0 : CALL pw_copy(new_embed_pot(1), embed_pot)
2538 :
2539 : ELSE
2540 : ! One has to work with spin components rather than with total and spin density
2541 2 : NULLIFY (rho_n_1)
2542 8 : ALLOCATE (rho_n_1(nspins))
2543 2 : NULLIFY (temp_embed_pot)
2544 8 : ALLOCATE (temp_embed_pot(nspins))
2545 6 : DO i_spin = 1, nspins
2546 4 : CALL auxbas_pw_pool%create_pw(rho_n_1(i_spin))
2547 4 : CALL pw_zero(rho_n_1(i_spin))
2548 4 : CALL auxbas_pw_pool%create_pw(temp_embed_pot(i_spin))
2549 6 : CALL pw_zero(temp_embed_pot(i_spin))
2550 : END DO
2551 2 : CALL pw_copy(diff_rho_r, rho_n_1(1))
2552 2 : CALL pw_copy(diff_rho_r, rho_n_1(2))
2553 2 : CALL pw_axpy(diff_rho_spin, rho_n_1(1), 1.0_dp)
2554 2 : CALL pw_axpy(diff_rho_spin, rho_n_1(2), -1.0_dp)
2555 2 : CALL pw_scale(rho_n_1(1), a=0.5_dp)
2556 2 : CALL pw_scale(rho_n_1(2), a=0.5_dp)
2557 :
2558 2 : CALL pw_copy(embed_pot, temp_embed_pot(1))
2559 2 : CALL pw_copy(embed_pot, temp_embed_pot(2))
2560 2 : CALL pw_axpy(spin_embed_pot, temp_embed_pot(1), 1.0_dp)
2561 2 : CALL pw_axpy(spin_embed_pot, temp_embed_pot(2), -1.0_dp)
2562 :
2563 2 : IF (SIZE(rho_r_ref) == 2) THEN
2564 2 : CALL pw_axpy(rho_r_ref(1), rho_n_1(1), 1.0_dp)
2565 2 : CALL pw_axpy(rho_r_ref(2), rho_n_1(2), 1.0_dp)
2566 :
2567 : !$OMP PARALLEL DO DEFAULT(NONE) &
2568 : !$OMP PRIVATE(i,j,k, my_rho) &
2569 2 : !$OMP SHARED(new_embed_pot, temp_embed_pot, rho_r_ref, rho_n_1, lb, ub, rho_cutoff, step_len)
2570 : DO k = lb(3), ub(3)
2571 : DO j = lb(2), ub(2)
2572 : DO i = lb(1), ub(1)
2573 : IF (rho_r_ref(1)%array(i, j, k) > rho_cutoff) THEN
2574 : my_rho = rho_r_ref(1)%array(i, j, k)
2575 : ELSE
2576 : my_rho = rho_cutoff
2577 : END IF
2578 : new_embed_pot(1)%array(i, j, k) = step_len*temp_embed_pot(1)%array(i, j, k)* &
2579 : (rho_n_1(1)%array(i, j, k))/my_rho
2580 : IF (rho_r_ref(2)%array(i, j, k) > rho_cutoff) THEN
2581 : my_rho = rho_r_ref(2)%array(i, j, k)
2582 : ELSE
2583 : my_rho = rho_cutoff
2584 : END IF
2585 : new_embed_pot(2)%array(i, j, k) = step_len*temp_embed_pot(2)%array(i, j, k)* &
2586 : (rho_n_1(2)%array(i, j, k))/my_rho
2587 : END DO
2588 : END DO
2589 : END DO
2590 : !$OMP END PARALLEL DO
2591 :
2592 : ELSE ! Reference system is closed-shell
2593 0 : CALL pw_axpy(rho_r_ref(1), rho_n_1(1), 1.0_dp)
2594 : ! The beta spin component is here equal to the difference: nothing to do
2595 :
2596 : !$OMP PARALLEL DO DEFAULT(NONE) &
2597 : !$OMP PRIVATE(i,j,k, my_rho) &
2598 0 : !$OMP SHARED(new_embed_pot, rho_r_ref, temp_embed_pot, rho_n_1, lb, ub, rho_cutoff, step_len)
2599 : DO k = lb(3), ub(3)
2600 : DO j = lb(2), ub(2)
2601 : DO i = lb(1), ub(1)
2602 : IF (rho_r_ref(1)%array(i, j, k) > rho_cutoff) THEN
2603 : my_rho = 0.5_dp*rho_r_ref(1)%array(i, j, k)
2604 : ELSE
2605 : my_rho = rho_cutoff
2606 : END IF
2607 : new_embed_pot(1)%array(i, j, k) = step_len*temp_embed_pot(1)%array(i, j, k)* &
2608 : (rho_n_1(1)%array(i, j, k))/my_rho
2609 : new_embed_pot(2)%array(i, j, k) = step_len*temp_embed_pot(2)%array(i, j, k)* &
2610 : (rho_n_1(2)%array(i, j, k))/my_rho
2611 : END DO
2612 : END DO
2613 : END DO
2614 : !$OMP END PARALLEL DO
2615 : END IF
2616 :
2617 2 : CALL pw_copy(new_embed_pot(1), embed_pot)
2618 2 : CALL pw_axpy(new_embed_pot(2), embed_pot, 1.0_dp)
2619 2 : CALL pw_scale(embed_pot, a=0.5_dp)
2620 2 : CALL pw_copy(new_embed_pot(1), spin_embed_pot)
2621 2 : CALL pw_axpy(new_embed_pot(2), spin_embed_pot, -1.0_dp)
2622 2 : CALL pw_scale(spin_embed_pot, a=0.5_dp)
2623 :
2624 6 : DO i_spin = 1, nspins
2625 4 : CALL rho_n_1(i_spin)%release()
2626 6 : CALL temp_embed_pot(i_spin)%release()
2627 : END DO
2628 2 : DEALLOCATE (rho_n_1)
2629 2 : DEALLOCATE (temp_embed_pot)
2630 : END IF
2631 :
2632 6 : DO i_spin = 1, nspins
2633 6 : CALL new_embed_pot(i_spin)%release()
2634 : END DO
2635 :
2636 2 : DEALLOCATE (new_embed_pot)
2637 :
2638 2 : CALL timestop(handle)
2639 :
2640 2 : END SUBROUTINE Leeuwen_Baerends_potential_update
2641 :
2642 : ! **************************************************************************************************
2643 : !> \brief ...
2644 : !> \param qs_env ...
2645 : !> \param rho_r_ref ...
2646 : !> \param prev_embed_pot ...
2647 : !> \param prev_spin_embed_pot ...
2648 : !> \param embed_pot ...
2649 : !> \param spin_embed_pot ...
2650 : !> \param diff_rho_r ...
2651 : !> \param diff_rho_spin ...
2652 : !> \param v_w_ref ...
2653 : !> \param i_iter ...
2654 : !> \param step_len ...
2655 : !> \param open_shell_embed ...
2656 : !> \param vw_cutoff ...
2657 : !> \param vw_smooth_cutoff_range ...
2658 : ! **************************************************************************************************
2659 2 : SUBROUTINE FAB_update(qs_env, rho_r_ref, prev_embed_pot, prev_spin_embed_pot, embed_pot, spin_embed_pot, &
2660 : diff_rho_r, diff_rho_spin, v_w_ref, i_iter, step_len, open_shell_embed, &
2661 : vw_cutoff, vw_smooth_cutoff_range)
2662 : TYPE(qs_environment_type), POINTER :: qs_env
2663 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r_ref
2664 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: prev_embed_pot
2665 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: prev_spin_embed_pot
2666 : TYPE(pw_r3d_rs_type), INTENT(INOUT) :: embed_pot
2667 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: spin_embed_pot
2668 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r, diff_rho_spin
2669 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: v_w_ref
2670 : INTEGER, INTENT(IN) :: i_iter
2671 : REAL(KIND=dp) :: step_len
2672 : LOGICAL :: open_shell_embed
2673 : REAL(KIND=dp) :: vw_cutoff, vw_smooth_cutoff_range
2674 :
2675 : CHARACTER(LEN=*), PARAMETER :: routineN = 'FAB_update'
2676 :
2677 : INTEGER :: handle, i_spin, nspins
2678 : TYPE(pw_env_type), POINTER :: pw_env
2679 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
2680 2 : TYPE(pw_r3d_rs_type), ALLOCATABLE, DIMENSION(:) :: new_embed_pot, temp_embed_pot, v_w
2681 2 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: curr_rho
2682 :
2683 2 : CALL timeset(routineN, handle)
2684 :
2685 : ! Update formula: v(n+1) = v(n-1) - v_w(ref) + v_w(n)
2686 :
2687 : CALL get_qs_env(qs_env=qs_env, &
2688 2 : pw_env=pw_env)
2689 : ! Get plane waves pool
2690 2 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
2691 :
2692 : ! We calculate von Weizsaecker potential for the reference density
2693 : ! only at the first iteration
2694 2 : IF (i_iter <= 1) THEN
2695 2 : nspins = SIZE(rho_r_ref)
2696 2 : NULLIFY (v_w_ref)
2697 8 : ALLOCATE (v_w_ref(nspins))
2698 4 : DO i_spin = 1, nspins
2699 4 : CALL auxbas_pw_pool%create_pw(v_w_ref(i_spin))
2700 : END DO
2701 2 : CALL Von_Weizsacker(rho_r_ref, v_w_ref, qs_env, vw_cutoff, vw_smooth_cutoff_range)
2702 : ! For the first step previous are set to current
2703 2 : CALL pw_copy(embed_pot, prev_embed_pot)
2704 2 : CALL pw_axpy(diff_rho_r, embed_pot, 0.5_dp)
2705 2 : IF (open_shell_embed) THEN
2706 0 : CALL pw_copy(spin_embed_pot, prev_spin_embed_pot)
2707 0 : CALL pw_axpy(diff_rho_r, embed_pot, 0.5_dp)
2708 : END IF
2709 :
2710 : ELSE
2711 :
2712 : ! Reference can be closed shell, but total embedding - open shell:
2713 : ! redefine nspins
2714 0 : nspins = 1
2715 0 : IF (open_shell_embed) nspins = 2
2716 0 : ALLOCATE (new_embed_pot(nspins))
2717 0 : ALLOCATE (v_w(nspins))
2718 0 : NULLIFY (curr_rho)
2719 0 : ALLOCATE (curr_rho(nspins))
2720 0 : DO i_spin = 1, nspins
2721 0 : CALL auxbas_pw_pool%create_pw(new_embed_pot(i_spin))
2722 0 : CALL pw_zero(new_embed_pot(i_spin))
2723 :
2724 0 : CALL auxbas_pw_pool%create_pw(v_w(i_spin))
2725 0 : CALL pw_zero(v_w(i_spin))
2726 :
2727 0 : CALL auxbas_pw_pool%create_pw(curr_rho(i_spin))
2728 0 : CALL pw_zero(curr_rho(i_spin))
2729 : END DO
2730 :
2731 : ! Now, deal with the current density
2732 :
2733 0 : IF (.NOT. open_shell_embed) THEN
2734 : ! Reconstruct current density
2735 0 : CALL pw_copy(diff_rho_r, curr_rho(1))
2736 0 : CALL pw_axpy(rho_r_ref(1), curr_rho(1), 1.0_dp)
2737 : ! Compute von Weizsaecker potential
2738 0 : CALL Von_Weizsacker(curr_rho, v_w, qs_env, vw_cutoff, vw_smooth_cutoff_range)
2739 : ! Compute new embedding potential
2740 0 : CALL pw_copy(prev_embed_pot, new_embed_pot(1))
2741 0 : CALL pw_axpy(v_w(1), new_embed_pot(1), step_len)
2742 0 : CALL pw_axpy(v_w_ref(1), new_embed_pot(1), -step_len)
2743 : ! Copy the potentials
2744 :
2745 0 : CALL pw_copy(embed_pot, prev_embed_pot)
2746 0 : CALL pw_copy(new_embed_pot(1), embed_pot)
2747 :
2748 : ELSE
2749 : ! Reconstruct current density
2750 0 : CALL pw_copy(diff_rho_r, curr_rho(1))
2751 0 : CALL pw_copy(diff_rho_r, curr_rho(2))
2752 0 : CALL pw_axpy(diff_rho_spin, curr_rho(1), 1.0_dp)
2753 0 : CALL pw_axpy(diff_rho_spin, curr_rho(2), -1.0_dp)
2754 0 : CALL pw_scale(curr_rho(1), a=0.5_dp)
2755 0 : CALL pw_scale(curr_rho(2), a=0.5_dp)
2756 :
2757 0 : IF (SIZE(rho_r_ref) == 1) THEN ! If reference system is closed-shell
2758 0 : CALL pw_axpy(rho_r_ref(1), curr_rho(1), 0.5_dp)
2759 0 : CALL pw_axpy(rho_r_ref(1), curr_rho(2), 0.5_dp)
2760 : ELSE ! If reference system is open-shell
2761 0 : CALL pw_axpy(rho_r_ref(1), curr_rho(1), 1.0_dp)
2762 0 : CALL pw_axpy(rho_r_ref(2), curr_rho(2), 1.0_dp)
2763 : END IF
2764 :
2765 : ! Compute von Weizsaecker potential
2766 0 : CALL Von_Weizsacker(curr_rho, v_w, qs_env, vw_cutoff, vw_smooth_cutoff_range)
2767 :
2768 : ! Reconstruct corrent spin components of the potential
2769 0 : ALLOCATE (temp_embed_pot(nspins))
2770 0 : DO i_spin = 1, nspins
2771 0 : CALL auxbas_pw_pool%create_pw(temp_embed_pot(i_spin))
2772 0 : CALL pw_zero(temp_embed_pot(i_spin))
2773 : END DO
2774 0 : CALL pw_copy(embed_pot, temp_embed_pot(1))
2775 0 : CALL pw_copy(embed_pot, temp_embed_pot(2))
2776 0 : CALL pw_axpy(spin_embed_pot, temp_embed_pot(1), 1.0_dp)
2777 0 : CALL pw_axpy(spin_embed_pot, temp_embed_pot(2), -1.0_dp)
2778 :
2779 : ! Compute new embedding potential
2780 0 : IF (SIZE(v_w_ref) == 1) THEN ! Reference system is closed-shell
2781 0 : CALL pw_copy(temp_embed_pot(1), new_embed_pot(1))
2782 0 : CALL pw_axpy(v_w(1), new_embed_pot(1), 0.5_dp*step_len)
2783 0 : CALL pw_axpy(v_w_ref(1), new_embed_pot(1), -0.5_dp*step_len)
2784 :
2785 0 : CALL pw_copy(temp_embed_pot(2), new_embed_pot(2))
2786 0 : CALL pw_axpy(v_w(2), new_embed_pot(2), 0.5_dp)
2787 0 : CALL pw_axpy(v_w_ref(1), new_embed_pot(2), -0.5_dp)
2788 :
2789 : ELSE ! Reference system is open-shell
2790 :
2791 0 : DO i_spin = 1, nspins
2792 0 : CALL pw_copy(temp_embed_pot(i_spin), new_embed_pot(i_spin))
2793 0 : CALL pw_axpy(v_w(1), new_embed_pot(i_spin), step_len)
2794 0 : CALL pw_axpy(v_w_ref(i_spin), new_embed_pot(i_spin), -step_len)
2795 : END DO
2796 : END IF
2797 :
2798 : ! Update embedding potentials
2799 0 : CALL pw_copy(embed_pot, prev_embed_pot)
2800 0 : CALL pw_copy(spin_embed_pot, prev_spin_embed_pot)
2801 :
2802 0 : CALL pw_copy(new_embed_pot(1), embed_pot)
2803 0 : CALL pw_axpy(new_embed_pot(2), embed_pot, 1.0_dp)
2804 0 : CALL pw_scale(embed_pot, a=0.5_dp)
2805 0 : CALL pw_copy(new_embed_pot(1), spin_embed_pot)
2806 0 : CALL pw_axpy(new_embed_pot(2), spin_embed_pot, -1.0_dp)
2807 0 : CALL pw_scale(spin_embed_pot, a=0.5_dp)
2808 :
2809 0 : DO i_spin = 1, nspins
2810 0 : CALL temp_embed_pot(i_spin)%release()
2811 : END DO
2812 0 : DEALLOCATE (temp_embed_pot)
2813 :
2814 : END IF
2815 :
2816 0 : DO i_spin = 1, nspins
2817 0 : CALL curr_rho(i_spin)%release()
2818 0 : CALL new_embed_pot(i_spin)%release()
2819 0 : CALL v_w(i_spin)%release()
2820 : END DO
2821 :
2822 0 : DEALLOCATE (new_embed_pot)
2823 0 : DEALLOCATE (v_w)
2824 0 : DEALLOCATE (curr_rho)
2825 :
2826 : END IF
2827 :
2828 2 : CALL timestop(handle)
2829 :
2830 4 : END SUBROUTINE FAB_update
2831 :
2832 : ! **************************************************************************************************
2833 : !> \brief ...
2834 : !> \param rho_r ...
2835 : !> \param v_w ...
2836 : !> \param qs_env ...
2837 : !> \param vw_cutoff ...
2838 : !> \param vw_smooth_cutoff_range ...
2839 : ! **************************************************************************************************
2840 2 : SUBROUTINE Von_Weizsacker(rho_r, v_w, qs_env, vw_cutoff, vw_smooth_cutoff_range)
2841 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
2842 : TYPE(pw_r3d_rs_type), DIMENSION(:), INTENT(IN) :: v_w
2843 : TYPE(qs_environment_type), POINTER :: qs_env
2844 : REAL(KIND=dp), INTENT(IN) :: vw_cutoff, vw_smooth_cutoff_range
2845 :
2846 : REAL(KIND=dp), PARAMETER :: one_4 = 0.25_dp, one_8 = 0.125_dp
2847 :
2848 : INTEGER :: i, i_spin, j, k, nspins
2849 : INTEGER, DIMENSION(3) :: lb, ub
2850 : REAL(KIND=dp) :: density_smooth_cut_range, my_rho, &
2851 : rho_cutoff
2852 2 : REAL(kind=dp), DIMENSION(:, :, :), POINTER :: rhoa, rhob
2853 2 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g
2854 : TYPE(pw_env_type), POINTER :: pw_env
2855 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
2856 2 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: tau
2857 : TYPE(section_vals_type), POINTER :: input, xc_section
2858 : TYPE(xc_rho_cflags_type) :: needs
2859 : TYPE(xc_rho_set_type) :: rho_set
2860 :
2861 2 : rho_cutoff = EPSILON(0.0_dp)
2862 :
2863 2 : nspins = SIZE(rho_r)
2864 :
2865 2 : NULLIFY (xc_section)
2866 :
2867 : CALL get_qs_env(qs_env=qs_env, &
2868 : pw_env=pw_env, &
2869 2 : input=input)
2870 :
2871 : ! Get plane waves pool
2872 2 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
2873 :
2874 : ! get some of the grids ready
2875 2 : NULLIFY (rho_g)
2876 8 : ALLOCATE (rho_g(nspins))
2877 4 : DO i_spin = 1, nspins
2878 2 : CALL auxbas_pw_pool%create_pw(rho_g(i_spin))
2879 4 : CALL pw_transfer(rho_r(i_spin), rho_g(i_spin))
2880 : END DO
2881 :
2882 2 : xc_section => section_vals_get_subs_vals(input, "DFT%XC")
2883 :
2884 : CALL xc_rho_set_create(rho_set, &
2885 : rho_r(1)%pw_grid%bounds_local, &
2886 : rho_cutoff=section_get_rval(xc_section, "density_cutoff"), &
2887 : drho_cutoff=section_get_rval(xc_section, "gradient_cutoff"), &
2888 2 : tau_cutoff=section_get_rval(xc_section, "tau_cutoff"))
2889 :
2890 2 : CALL xc_rho_cflags_setall(needs, .FALSE.)
2891 :
2892 2 : IF (nspins == 2) THEN
2893 0 : needs%rho_spin = .TRUE.
2894 0 : needs%norm_drho_spin = .TRUE.
2895 0 : needs%laplace_rho_spin = .TRUE.
2896 : ELSE
2897 2 : needs%rho = .TRUE.
2898 2 : needs%norm_drho = .TRUE.
2899 2 : needs%laplace_rho = .TRUE.
2900 : END IF
2901 :
2902 : CALL xc_rho_set_update(rho_set, rho_r, rho_g, tau, needs, &
2903 : section_get_ival(xc_section, "XC_GRID%XC_DERIV"), &
2904 : section_get_ival(xc_section, "XC_GRID%XC_SMOOTH_RHO"), &
2905 2 : auxbas_pw_pool)
2906 :
2907 : CALL section_vals_val_get(xc_section, "DENSITY_CUTOFF", &
2908 2 : r_val=rho_cutoff)
2909 : CALL section_vals_val_get(xc_section, "DENSITY_SMOOTH_CUTOFF_RANGE", &
2910 2 : r_val=density_smooth_cut_range)
2911 :
2912 8 : lb(1:3) = rho_r(1)%pw_grid%bounds_local(1, 1:3)
2913 8 : ub(1:3) = rho_r(1)%pw_grid%bounds_local(2, 1:3)
2914 :
2915 2 : IF (nspins == 2) THEN
2916 : !$OMP PARALLEL DO DEFAULT(NONE) &
2917 : !$OMP PRIVATE(i,j,k, my_rho) &
2918 0 : !$OMP SHARED(v_w, rho_r, rho_set, lb, ub, rho_cutoff)
2919 : DO k = lb(3), ub(3)
2920 : DO j = lb(2), ub(2)
2921 : DO i = lb(1), ub(1)
2922 : IF (rho_r(1)%array(i, j, k) > rho_cutoff) THEN
2923 : my_rho = rho_r(1)%array(i, j, k)
2924 : ELSE
2925 : my_rho = rho_cutoff
2926 : END IF
2927 : v_w(1)%array(i, j, k) = one_8*rho_set%norm_drhoa(i, j, k)**2/my_rho**2 - &
2928 : one_4*rho_set%laplace_rhoa(i, j, k)/my_rho
2929 :
2930 : IF (rho_r(2)%array(i, j, k) > rho_cutoff) THEN
2931 : my_rho = rho_r(2)%array(i, j, k)
2932 : ELSE
2933 : my_rho = rho_cutoff
2934 : END IF
2935 : v_w(2)%array(i, j, k) = one_8*rho_set%norm_drhob(i, j, k)**2/my_rho**2 - &
2936 : one_4*rho_set%laplace_rhob(i, j, k)/my_rho
2937 : END DO
2938 : END DO
2939 : END DO
2940 : !$OMP END PARALLEL DO
2941 : ELSE
2942 : !$OMP PARALLEL DO DEFAULT(NONE) &
2943 : !$OMP PRIVATE(i,j,k, my_rho) &
2944 2 : !$OMP SHARED(v_w, rho_r, rho_set, lb, ub, rho_cutoff)
2945 : DO k = lb(3), ub(3)
2946 : DO j = lb(2), ub(2)
2947 : DO i = lb(1), ub(1)
2948 : IF (rho_r(1)%array(i, j, k) > rho_cutoff) THEN
2949 : my_rho = rho_r(1)%array(i, j, k)
2950 : v_w(1)%array(i, j, k) = one_8*rho_set%norm_drho(i, j, k)**2/my_rho**2 - &
2951 : one_4*rho_set%laplace_rho(i, j, k)/my_rho
2952 : ELSE
2953 : v_w(1)%array(i, j, k) = 0.0_dp
2954 : END IF
2955 : END DO
2956 : END DO
2957 : END DO
2958 : !$OMP END PARALLEL DO
2959 :
2960 : END IF
2961 :
2962 : ! Smoothen the von Weizsaecker potential
2963 2 : IF (nspins == 2) THEN
2964 : density_smooth_cut_range = 0.5_dp*density_smooth_cut_range
2965 0 : rho_cutoff = 0.5_dp*rho_cutoff
2966 : END IF
2967 4 : DO i_spin = 1, nspins
2968 : CALL smooth_cutoff(pot=v_w(i_spin)%array, rho=rho_r(i_spin)%array, rhoa=rhoa, rhob=rhob, &
2969 : rho_cutoff=vw_cutoff, &
2970 4 : rho_smooth_cutoff_range=vw_smooth_cutoff_range)
2971 : END DO
2972 :
2973 2 : CALL xc_rho_set_release(rho_set, pw_pool=auxbas_pw_pool)
2974 :
2975 4 : DO i_spin = 1, nspins
2976 4 : CALL rho_g(i_spin)%release()
2977 : END DO
2978 2 : DEALLOCATE (rho_g)
2979 :
2980 46 : END SUBROUTINE Von_Weizsacker
2981 :
2982 : ! **************************************************************************************************
2983 : !> \brief ...
2984 : !> \param diff_rho_r ...
2985 : !> \return ...
2986 : ! **************************************************************************************************
2987 222 : FUNCTION max_dens_diff(diff_rho_r) RESULT(total_max_diff)
2988 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r
2989 : REAL(KIND=dp) :: total_max_diff
2990 :
2991 : INTEGER :: size_x, size_y, size_z
2992 : REAL(KIND=dp) :: max_diff
2993 222 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: grid_3d
2994 :
2995 : !, i_x, i_y, i_z
2996 :
2997 : ! Get the sizes
2998 222 : size_x = SIZE(diff_rho_r%array, 1)
2999 222 : size_y = SIZE(diff_rho_r%array, 2)
3000 222 : size_z = SIZE(diff_rho_r%array, 3)
3001 :
3002 : ! Allocate the density
3003 1110 : ALLOCATE (grid_3d(size_x, size_y, size_z))
3004 :
3005 : ! Copy density
3006 4589181 : grid_3d(:, :, :) = diff_rho_r%array(:, :, :)
3007 :
3008 : ! Find the maximum absolute value
3009 4589181 : max_diff = MAXVAL(ABS(grid_3d))
3010 222 : total_max_diff = max_diff
3011 222 : CALL diff_rho_r%pw_grid%para%group%max(total_max_diff)
3012 :
3013 : ! Deallocate the density
3014 222 : DEALLOCATE (grid_3d)
3015 :
3016 222 : END FUNCTION max_dens_diff
3017 :
3018 : ! **************************************************************************************************
3019 : !> \brief Prints a cube for the (rho_A + rho_B - rho_ref) to be minimized in embedding
3020 : !> \param diff_rho_r ...
3021 : !> \param i_iter ...
3022 : !> \param qs_env ...
3023 : !> \param final_one ...
3024 : !> \author Vladimir Rybkin
3025 : ! **************************************************************************************************
3026 48 : SUBROUTINE print_rho_diff(diff_rho_r, i_iter, qs_env, final_one)
3027 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r
3028 : INTEGER, INTENT(IN) :: i_iter
3029 : TYPE(qs_environment_type), INTENT(IN), POINTER :: qs_env
3030 : LOGICAL, INTENT(IN) :: final_one
3031 :
3032 : CHARACTER(LEN=default_path_length) :: filename, my_pos_cube, title
3033 : INTEGER :: unit_nr
3034 : TYPE(cp_logger_type), POINTER :: logger
3035 : TYPE(particle_list_type), POINTER :: particles
3036 : TYPE(qs_subsys_type), POINTER :: subsys
3037 : TYPE(section_vals_type), POINTER :: dft_section, input
3038 :
3039 48 : NULLIFY (subsys, input)
3040 :
3041 : CALL get_qs_env(qs_env=qs_env, &
3042 : subsys=subsys, &
3043 48 : input=input)
3044 48 : dft_section => section_vals_get_subs_vals(input, "DFT")
3045 48 : CALL qs_subsys_get(subsys, particles=particles)
3046 :
3047 48 : logger => cp_get_default_logger()
3048 48 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3049 : "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF"), cp_p_file)) THEN
3050 10 : my_pos_cube = "REWIND"
3051 10 : IF (.NOT. final_one) THEN
3052 10 : WRITE (filename, '(a5,I3.3,a1,I1.1)') "DIFF_", i_iter
3053 : ELSE
3054 0 : WRITE (filename, '(a5,I3.3,a1,I1.1)') "DIFF"
3055 : END IF
3056 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF", &
3057 : extension=".cube", middle_name=TRIM(filename), file_position=my_pos_cube, &
3058 10 : log_filename=.FALSE.)
3059 :
3060 10 : WRITE (title, *) "EMBEDDING DENSITY DIFFERENCE ", " optimization step ", i_iter
3061 : CALL cp_pw_to_cube(diff_rho_r, unit_nr, title, particles=particles, &
3062 10 : stride=section_get_ivals(dft_section, "QS%OPT_EMBED%EMBED_DENS_DIFF%STRIDE"))
3063 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3064 10 : "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF")
3065 : END IF
3066 :
3067 48 : END SUBROUTINE print_rho_diff
3068 :
3069 : ! **************************************************************************************************
3070 : !> \brief Prints a cube for the (spin_rho_A + spin_rho_B - spin_rho_ref) to be minimized in embedding
3071 : !> \param spin_diff_rho_r ...
3072 : !> \param i_iter ...
3073 : !> \param qs_env ...
3074 : !> \param final_one ...
3075 : !> \author Vladimir Rybkin
3076 : ! **************************************************************************************************
3077 38 : SUBROUTINE print_rho_spin_diff(spin_diff_rho_r, i_iter, qs_env, final_one)
3078 : TYPE(pw_r3d_rs_type), INTENT(IN) :: spin_diff_rho_r
3079 : INTEGER, INTENT(IN) :: i_iter
3080 : TYPE(qs_environment_type), INTENT(IN), POINTER :: qs_env
3081 : LOGICAL, INTENT(IN) :: final_one
3082 :
3083 : CHARACTER(LEN=default_path_length) :: filename, my_pos_cube, title
3084 : INTEGER :: unit_nr
3085 : TYPE(cp_logger_type), POINTER :: logger
3086 : TYPE(particle_list_type), POINTER :: particles
3087 : TYPE(qs_subsys_type), POINTER :: subsys
3088 : TYPE(section_vals_type), POINTER :: dft_section, input
3089 :
3090 38 : NULLIFY (subsys, input)
3091 :
3092 : CALL get_qs_env(qs_env=qs_env, &
3093 : subsys=subsys, &
3094 38 : input=input)
3095 38 : dft_section => section_vals_get_subs_vals(input, "DFT")
3096 38 : CALL qs_subsys_get(subsys, particles=particles)
3097 :
3098 38 : logger => cp_get_default_logger()
3099 38 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3100 : "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF"), cp_p_file)) THEN
3101 0 : my_pos_cube = "REWIND"
3102 0 : IF (.NOT. final_one) THEN
3103 0 : WRITE (filename, '(a5,I3.3,a1,I1.1)') "SPIN_DIFF_", i_iter
3104 : ELSE
3105 0 : WRITE (filename, '(a9,I3.3,a1,I1.1)') "SPIN_DIFF"
3106 : END IF
3107 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF", &
3108 : extension=".cube", middle_name=TRIM(filename), file_position=my_pos_cube, &
3109 0 : log_filename=.FALSE.)
3110 :
3111 0 : WRITE (title, *) "EMBEDDING SPIN DENSITY DIFFERENCE ", " optimization step ", i_iter
3112 : CALL cp_pw_to_cube(spin_diff_rho_r, unit_nr, title, particles=particles, &
3113 0 : stride=section_get_ivals(dft_section, "QS%OPT_EMBED%EMBED_DENS_DIFF%STRIDE"))
3114 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3115 0 : "DFT%QS%OPT_EMBED%EMBED_DENS_DIFF")
3116 : END IF
3117 :
3118 38 : END SUBROUTINE print_rho_spin_diff
3119 : ! **************************************************************************************************
3120 : !> \brief Print embedding potential as a cube and as a binary (for restarting)
3121 : !> \param qs_env ...
3122 : !> \param dimen_aux ...
3123 : !> \param embed_pot_coef ...
3124 : !> \param embed_pot ...
3125 : !> \param i_iter ...
3126 : !> \param embed_pot_spin ...
3127 : !> \param open_shell_embed ...
3128 : !> \param grid_opt ...
3129 : !> \param final_one ...
3130 : ! **************************************************************************************************
3131 72 : SUBROUTINE print_embed_restart(qs_env, dimen_aux, embed_pot_coef, embed_pot, i_iter, &
3132 : embed_pot_spin, open_shell_embed, grid_opt, final_one)
3133 : TYPE(qs_environment_type), POINTER :: qs_env
3134 : INTEGER :: dimen_aux
3135 : TYPE(cp_fm_type), INTENT(IN), POINTER :: embed_pot_coef
3136 : TYPE(pw_r3d_rs_type), INTENT(IN) :: embed_pot
3137 : INTEGER :: i_iter
3138 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: embed_pot_spin
3139 : LOGICAL :: open_shell_embed, grid_opt, final_one
3140 :
3141 : CHARACTER(LEN=default_path_length) :: filename, my_pos_cube, title
3142 : INTEGER :: unit_nr
3143 : TYPE(cp_logger_type), POINTER :: logger
3144 : TYPE(particle_list_type), POINTER :: particles
3145 : TYPE(qs_subsys_type), POINTER :: subsys
3146 : TYPE(section_vals_type), POINTER :: dft_section, input
3147 :
3148 72 : NULLIFY (input)
3149 : CALL get_qs_env(qs_env=qs_env, subsys=subsys, &
3150 72 : input=input)
3151 :
3152 : ! First we print an unformatted file
3153 72 : IF (.NOT. grid_opt) THEN ! Only for finite basis optimization
3154 44 : logger => cp_get_default_logger()
3155 44 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3156 : "DFT%QS%OPT_EMBED%EMBED_POT_VECTOR"), cp_p_file)) THEN
3157 44 : IF (.NOT. final_one) THEN
3158 30 : WRITE (filename, '(a10,I3.3)') "embed_pot_", i_iter
3159 : ELSE
3160 14 : WRITE (filename, '(a10,I3.3)') "embed_pot"
3161 : END IF
3162 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%EMBED_POT_VECTOR", extension=".wfn", &
3163 44 : file_form="UNFORMATTED", middle_name=TRIM(filename), file_position="REWIND")
3164 44 : IF (unit_nr > 0) THEN
3165 22 : WRITE (unit_nr) dimen_aux
3166 : END IF
3167 44 : CALL cp_fm_write_unformatted(embed_pot_coef, unit_nr)
3168 44 : IF (unit_nr > 0) THEN
3169 22 : CALL close_file(unit_nr)
3170 : END IF
3171 : END IF
3172 : END IF
3173 :
3174 : ! Second, cube files
3175 72 : dft_section => section_vals_get_subs_vals(input, "DFT")
3176 72 : CALL qs_subsys_get(subsys, particles=particles)
3177 :
3178 72 : logger => cp_get_default_logger()
3179 72 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3180 : "DFT%QS%OPT_EMBED%EMBED_POT_CUBE"), cp_p_file)) THEN
3181 32 : my_pos_cube = "REWIND"
3182 32 : IF (.NOT. final_one) THEN
3183 20 : WRITE (filename, '(a10,I3.3)') "embed_pot_", i_iter
3184 : ELSE
3185 12 : WRITE (filename, '(a10,I3.3)') "embed_pot"
3186 : END IF
3187 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%EMBED_POT_CUBE", &
3188 : extension=".cube", middle_name=TRIM(filename), file_position=my_pos_cube, &
3189 32 : log_filename=.FALSE.)
3190 :
3191 32 : WRITE (title, *) "EMBEDDING POTENTIAL at optimization step ", i_iter
3192 32 : CALL cp_pw_to_cube(embed_pot, unit_nr, title, particles=particles)
3193 : !, &
3194 : ! stride=section_get_ivals(dft_section, "QS%OPT_EMBED%EMBED_POT_CUBE%STRIDE"))
3195 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3196 32 : "DFT%QS%OPT_EMBED%EMBED_POT_CUBE")
3197 32 : IF (open_shell_embed) THEN ! Print spin part of the embedding potential
3198 16 : my_pos_cube = "REWIND"
3199 16 : IF (.NOT. final_one) THEN
3200 10 : WRITE (filename, '(a15,I3.3)') "spin_embed_pot_", i_iter
3201 : ELSE
3202 6 : WRITE (filename, '(a15,I3.3)') "spin_embed_pot"
3203 : END IF
3204 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%EMBED_POT_CUBE", &
3205 : extension=".cube", middle_name=TRIM(filename), file_position=my_pos_cube, &
3206 16 : log_filename=.FALSE.)
3207 :
3208 16 : WRITE (title, *) "SPIN EMBEDDING POTENTIAL at optimization step ", i_iter
3209 16 : CALL cp_pw_to_cube(embed_pot_spin, unit_nr, title, particles=particles)
3210 : !, &
3211 : ! stride=section_get_ivals(dft_section, "QS%OPT_EMBED%EMBED_POT_CUBE%STRIDE"))
3212 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3213 16 : "DFT%QS%OPT_EMBED%EMBED_POT_CUBE")
3214 : END IF
3215 : END IF
3216 :
3217 72 : END SUBROUTINE print_embed_restart
3218 :
3219 : ! **************************************************************************************************
3220 : !> \brief Prints a volumetric file: X Y Z value for interfacing with external programs.
3221 : !> \param qs_env ...
3222 : !> \param embed_pot ...
3223 : !> \param embed_pot_spin ...
3224 : !> \param i_iter ...
3225 : !> \param open_shell_embed ...
3226 : !> \param final_one ...
3227 : !> \param qs_env_cluster ...
3228 : ! **************************************************************************************************
3229 72 : SUBROUTINE print_pot_simple_grid(qs_env, embed_pot, embed_pot_spin, i_iter, open_shell_embed, &
3230 : final_one, qs_env_cluster)
3231 : TYPE(qs_environment_type), POINTER :: qs_env
3232 : TYPE(pw_r3d_rs_type), INTENT(IN) :: embed_pot
3233 : TYPE(pw_r3d_rs_type), INTENT(IN), POINTER :: embed_pot_spin
3234 : INTEGER :: i_iter
3235 : LOGICAL :: open_shell_embed, final_one
3236 : TYPE(qs_environment_type), POINTER :: qs_env_cluster
3237 :
3238 : CHARACTER(LEN=default_path_length) :: filename
3239 : INTEGER :: my_units, unit_nr
3240 : LOGICAL :: angstrom, bohr
3241 : TYPE(cp_logger_type), POINTER :: logger
3242 : TYPE(pw_env_type), POINTER :: pw_env
3243 : TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
3244 : TYPE(pw_r3d_rs_type) :: pot_alpha, pot_beta
3245 : TYPE(section_vals_type), POINTER :: dft_section, input
3246 :
3247 72 : NULLIFY (input)
3248 72 : CALL get_qs_env(qs_env=qs_env, input=input, pw_env=pw_env)
3249 :
3250 : ! Second, cube files
3251 72 : dft_section => section_vals_get_subs_vals(input, "DFT")
3252 :
3253 72 : NULLIFY (logger)
3254 72 : logger => cp_get_default_logger()
3255 72 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3256 : "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID"), cp_p_file)) THEN
3257 :
3258 : ! Figure out the units
3259 16 : angstrom = .FALSE.
3260 16 : bohr = .TRUE.
3261 16 : CALL section_vals_val_get(dft_section, "QS%OPT_EMBED%WRITE_SIMPLE_GRID%UNITS", i_val=my_units)
3262 : SELECT CASE (my_units)
3263 : CASE (embed_grid_bohr)
3264 16 : bohr = .TRUE.
3265 16 : angstrom = .FALSE.
3266 : CASE (embed_grid_angstrom)
3267 : bohr = .FALSE.
3268 : angstrom = .TRUE.
3269 : CASE DEFAULT
3270 : bohr = .TRUE.
3271 : angstrom = .FALSE.
3272 : END SELECT
3273 :
3274 : ! Get alpha and beta potentials
3275 : ! Prepare plane-waves pool
3276 16 : CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
3277 :
3278 : ! Create embedding potential and set to zero
3279 16 : CALL auxbas_pw_pool%create_pw(pot_alpha)
3280 16 : CALL pw_zero(pot_alpha)
3281 :
3282 16 : CALL pw_copy(embed_pot, pot_alpha)
3283 :
3284 16 : IF (open_shell_embed) THEN
3285 0 : CALL auxbas_pw_pool%create_pw(pot_beta)
3286 0 : CALL pw_copy(embed_pot, pot_beta)
3287 : ! Add spin potential to the alpha, and subtract from the beta part
3288 0 : CALL pw_axpy(embed_pot_spin, pot_alpha, 1.0_dp)
3289 0 : CALL pw_axpy(embed_pot_spin, pot_beta, -1.0_dp)
3290 : END IF
3291 :
3292 16 : IF (.NOT. final_one) THEN
3293 10 : WRITE (filename, '(a10,I3.3)') "embed_pot_", i_iter
3294 : ELSE
3295 6 : WRITE (filename, '(a10,I3.3)') "embed_pot"
3296 : END IF
3297 : unit_nr = cp_print_key_unit_nr(logger, input, "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID", extension=".dat", &
3298 16 : middle_name=TRIM(filename), file_form="FORMATTED", file_position="REWIND")
3299 :
3300 16 : IF (open_shell_embed) THEN ! Print spin part of the embedding potential
3301 : CALL cp_pw_to_simple_volumetric(pw=pot_alpha, unit_nr=unit_nr, &
3302 : stride=section_get_ivals(dft_section, "QS%OPT_EMBED%WRITE_SIMPLE_GRID%STRIDE"), &
3303 0 : pw2=pot_beta)
3304 : ELSE
3305 : CALL cp_pw_to_simple_volumetric(pot_alpha, unit_nr, &
3306 16 : stride=section_get_ivals(dft_section, "QS%OPT_EMBED%WRITE_SIMPLE_GRID%STRIDE"))
3307 : END IF
3308 :
3309 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3310 16 : "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID")
3311 : ! Release structures
3312 16 : CALL pot_alpha%release()
3313 16 : IF (open_shell_embed) THEN
3314 0 : CALL pot_beta%release()
3315 : END IF
3316 :
3317 : END IF
3318 :
3319 : ! Fold the coordinates and write into separate file: needed to have the grid correspond to coordinates
3320 : ! Needed for external software.
3321 72 : CALL print_folded_coordinates(qs_env_cluster, input)
3322 :
3323 72 : END SUBROUTINE print_pot_simple_grid
3324 :
3325 : ! **************************************************************************************************
3326 : !> \brief ...
3327 : !> \param qs_env ...
3328 : !> \param input ...
3329 : ! **************************************************************************************************
3330 72 : SUBROUTINE print_folded_coordinates(qs_env, input)
3331 : TYPE(qs_environment_type), POINTER :: qs_env
3332 : TYPE(section_vals_type), POINTER :: input
3333 :
3334 72 : CHARACTER(LEN=2), ALLOCATABLE, DIMENSION(:) :: particles_el
3335 : CHARACTER(LEN=default_path_length) :: filename
3336 : INTEGER :: iat, n, unit_nr
3337 72 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: particles_r
3338 : REAL(KIND=dp), DIMENSION(3) :: center, r_pbc, s
3339 : TYPE(cell_type), POINTER :: cell
3340 : TYPE(cp_logger_type), POINTER :: logger
3341 : TYPE(particle_list_type), POINTER :: particles
3342 : TYPE(qs_subsys_type), POINTER :: subsys
3343 :
3344 72 : NULLIFY (logger)
3345 72 : logger => cp_get_default_logger()
3346 72 : IF (BTEST(cp_print_key_should_output(logger%iter_info, input, &
3347 : "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID/FOLD_COORD"), cp_p_file)) THEN
3348 16 : CALL get_qs_env(qs_env=qs_env, cell=cell, subsys=subsys)
3349 16 : CALL qs_subsys_get(subsys=subsys, particles=particles)
3350 :
3351 : ! Prepare the file
3352 16 : WRITE (filename, '(a14)') "folded_cluster"
3353 : unit_nr = cp_print_key_unit_nr(logger, input, &
3354 : "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID/FOLD_COORD", extension=".dat", &
3355 16 : middle_name=TRIM(filename), file_form="FORMATTED", file_position="REWIND")
3356 16 : IF (unit_nr > 0) THEN
3357 :
3358 8 : n = particles%n_els
3359 16 : ALLOCATE (particles_el(n))
3360 24 : ALLOCATE (particles_r(3, n))
3361 24 : DO iat = 1, n
3362 16 : CALL get_atomic_kind(particles%els(iat)%atomic_kind, element_symbol=particles_el(iat))
3363 72 : particles_r(:, iat) = particles%els(iat)%r(:)
3364 : END DO
3365 :
3366 : ! Fold the coordinates
3367 32 : center(:) = cell%hmat(:, 1)/2.0_dp + cell%hmat(:, 2)/2.0_dp + cell%hmat(:, 3)/2.0_dp
3368 :
3369 : ! Print folded coordinates to file
3370 24 : DO iat = 1, SIZE(particles_el)
3371 64 : r_pbc(:) = particles_r(:, iat) - center
3372 208 : s = MATMUL(cell%h_inv, r_pbc)
3373 64 : s = s - ANINT(s)
3374 208 : r_pbc = MATMUL(cell%hmat, s)
3375 64 : r_pbc = r_pbc + center
3376 24 : WRITE (unit_nr, '(a4,4f12.6)') particles_el(iat), r_pbc(:)
3377 : END DO
3378 :
3379 : CALL cp_print_key_finished_output(unit_nr, logger, input, &
3380 8 : "DFT%QS%OPT_EMBED%WRITE_SIMPLE_GRID/FOLD_COORD")
3381 :
3382 8 : DEALLOCATE (particles_el)
3383 8 : DEALLOCATE (particles_r)
3384 : END IF
3385 :
3386 : END IF ! Should output
3387 :
3388 72 : END SUBROUTINE print_folded_coordinates
3389 :
3390 : ! **************************************************************************************************
3391 : !> \brief ...
3392 : !> \param output_unit ...
3393 : !> \param step_num ...
3394 : !> \param opt_embed ...
3395 : ! **************************************************************************************************
3396 48 : SUBROUTINE print_emb_opt_info(output_unit, step_num, opt_embed)
3397 : INTEGER :: output_unit, step_num
3398 : TYPE(opt_embed_pot_type) :: opt_embed
3399 :
3400 48 : IF (output_unit > 0) THEN
3401 : WRITE (UNIT=output_unit, FMT="(/,T2,8('-'),A,I5,1X,12('-'))") &
3402 24 : " Optimize embedding potential info at step = ", step_num
3403 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3404 24 : " Functional value = ", opt_embed%w_func(step_num)
3405 24 : IF (step_num > 1) THEN
3406 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3407 12 : " Real energy change = ", opt_embed%w_func(step_num) - &
3408 24 : opt_embed%w_func(step_num - 1)
3409 :
3410 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3411 12 : " Step size = ", opt_embed%step_len
3412 :
3413 : END IF
3414 :
3415 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3416 24 : " Trust radius = ", opt_embed%trust_rad
3417 :
3418 24 : WRITE (UNIT=output_unit, FMT="(T2,51('-'))")
3419 : END IF
3420 :
3421 48 : END SUBROUTINE print_emb_opt_info
3422 :
3423 : ! **************************************************************************************************
3424 : !> \brief ...
3425 : !> \param opt_embed ...
3426 : !> \param force_env ...
3427 : !> \param subsys_num ...
3428 : ! **************************************************************************************************
3429 96 : SUBROUTINE get_prev_density(opt_embed, force_env, subsys_num)
3430 : TYPE(opt_embed_pot_type) :: opt_embed
3431 : TYPE(force_env_type), POINTER :: force_env
3432 : INTEGER :: subsys_num
3433 :
3434 : INTEGER :: i_dens_start, i_spin, nspins
3435 96 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3436 : TYPE(qs_rho_type), POINTER :: rho
3437 :
3438 96 : NULLIFY (rho_r, rho)
3439 96 : CALL get_qs_env(force_env%qs_env, rho=rho)
3440 96 : CALL qs_rho_get(rho_struct=rho, rho_r=rho_r)
3441 :
3442 96 : nspins = opt_embed%all_nspins(subsys_num)
3443 :
3444 240 : i_dens_start = SUM(opt_embed%all_nspins(1:subsys_num)) - nspins + 1
3445 :
3446 244 : DO i_spin = 1, nspins
3447 : opt_embed%prev_subsys_dens(i_dens_start + i_spin - 1)%array(:, :, :) = &
3448 3059550 : rho_r(i_spin)%array(:, :, :)
3449 : END DO
3450 :
3451 96 : END SUBROUTINE get_prev_density
3452 :
3453 : ! **************************************************************************************************
3454 : !> \brief ...
3455 : !> \param opt_embed ...
3456 : !> \param force_env ...
3457 : !> \param subsys_num ...
3458 : ! **************************************************************************************************
3459 96 : SUBROUTINE get_max_subsys_diff(opt_embed, force_env, subsys_num)
3460 : TYPE(opt_embed_pot_type) :: opt_embed
3461 : TYPE(force_env_type), POINTER :: force_env
3462 : INTEGER :: subsys_num
3463 :
3464 : INTEGER :: i_dens_start, i_spin, nspins
3465 96 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
3466 : TYPE(qs_rho_type), POINTER :: rho
3467 :
3468 96 : NULLIFY (rho_r, rho)
3469 96 : CALL get_qs_env(force_env%qs_env, rho=rho)
3470 96 : CALL qs_rho_get(rho_struct=rho, rho_r=rho_r)
3471 :
3472 96 : nspins = opt_embed%all_nspins(subsys_num)
3473 :
3474 240 : i_dens_start = SUM(opt_embed%all_nspins(1:subsys_num)) - nspins + 1
3475 :
3476 244 : DO i_spin = 1, nspins
3477 : CALL pw_axpy(rho_r(i_spin), opt_embed%prev_subsys_dens(i_dens_start + i_spin - 1), 1.0_dp, -1.0_dp, &
3478 148 : allow_noncompatible_grids=.TRUE.)
3479 : opt_embed%max_subsys_dens_diff(i_dens_start + i_spin - 1) = &
3480 244 : max_dens_diff(opt_embed%prev_subsys_dens(i_dens_start + i_spin - 1))
3481 : END DO
3482 :
3483 96 : END SUBROUTINE get_max_subsys_diff
3484 :
3485 : ! **************************************************************************************************
3486 : !> \brief ...
3487 : !> \param opt_embed ...
3488 : !> \param diff_rho_r ...
3489 : !> \param diff_rho_spin ...
3490 : !> \param output_unit ...
3491 : ! **************************************************************************************************
3492 48 : SUBROUTINE conv_check_embed(opt_embed, diff_rho_r, diff_rho_spin, output_unit)
3493 : TYPE(opt_embed_pot_type) :: opt_embed
3494 : TYPE(pw_r3d_rs_type), INTENT(IN) :: diff_rho_r, diff_rho_spin
3495 : INTEGER :: output_unit
3496 :
3497 : INTEGER :: i_dens, i_dens_start, i_spin
3498 : LOGICAL :: conv_int_diff, conv_max_diff
3499 : REAL(KIND=dp) :: int_diff, int_diff_spin, &
3500 : int_diff_square, int_diff_square_spin, &
3501 : max_diff, max_diff_spin
3502 :
3503 : ! Calculate the convergence target values
3504 48 : opt_embed%max_diff(1) = max_dens_diff(diff_rho_r)
3505 48 : opt_embed%int_diff(1) = pw_integrate_function(fun=diff_rho_r, oprt='ABS')
3506 48 : opt_embed%int_diff_square(1) = pw_integral_ab(diff_rho_r, diff_rho_r)
3507 48 : IF (opt_embed%open_shell_embed) THEN
3508 26 : opt_embed%max_diff(2) = max_dens_diff(diff_rho_spin)
3509 26 : opt_embed%int_diff(2) = pw_integrate_function(fun=diff_rho_spin, oprt='ABS')
3510 26 : opt_embed%int_diff_square(2) = pw_integral_ab(diff_rho_spin, diff_rho_spin)
3511 : END IF
3512 :
3513 : ! Find out the convergence
3514 48 : max_diff = opt_embed%max_diff(1)
3515 :
3516 : ! Maximum value criterium
3517 : ! Open shell
3518 48 : IF (opt_embed%open_shell_embed) THEN
3519 26 : max_diff_spin = opt_embed%max_diff(2)
3520 26 : IF ((max_diff <= opt_embed%conv_max) .AND. (max_diff_spin <= opt_embed%conv_max_spin)) THEN
3521 : conv_max_diff = .TRUE.
3522 : ELSE
3523 12 : conv_max_diff = .FALSE.
3524 : END IF
3525 : ELSE
3526 : ! Closed shell
3527 22 : IF (max_diff <= opt_embed%conv_max) THEN
3528 : conv_max_diff = .TRUE.
3529 : ELSE
3530 8 : conv_max_diff = .FALSE.
3531 : END IF
3532 : END IF
3533 :
3534 : ! Integrated value criterium
3535 48 : int_diff = opt_embed%int_diff(1)
3536 : ! Open shell
3537 48 : IF (opt_embed%open_shell_embed) THEN
3538 26 : int_diff_spin = opt_embed%int_diff(2)
3539 26 : IF ((int_diff <= opt_embed%conv_int) .AND. (int_diff_spin <= opt_embed%conv_int_spin)) THEN
3540 : conv_int_diff = .TRUE.
3541 : ELSE
3542 6 : conv_int_diff = .FALSE.
3543 : END IF
3544 : ELSE
3545 : ! Closed shell
3546 22 : IF (int_diff <= opt_embed%conv_int) THEN
3547 : conv_int_diff = .TRUE.
3548 : ELSE
3549 10 : conv_int_diff = .FALSE.
3550 : END IF
3551 : END IF
3552 :
3553 : ! Integrated squared value criterium
3554 48 : int_diff_square = opt_embed%int_diff_square(1)
3555 : ! Open shell
3556 48 : IF (opt_embed%open_shell_embed) int_diff_square_spin = opt_embed%int_diff_square(2)
3557 :
3558 48 : IF ((conv_max_diff) .AND. (conv_int_diff)) THEN
3559 24 : opt_embed%converged = .TRUE.
3560 : ELSE
3561 24 : opt_embed%converged = .FALSE.
3562 : END IF
3563 :
3564 : ! Print the information
3565 48 : IF (output_unit > 0) THEN
3566 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
3567 24 : " Convergence check :"
3568 :
3569 : ! Maximum value of density
3570 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3571 24 : " Maximum density difference = ", max_diff
3572 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3573 24 : " Convergence limit for max. density diff. = ", opt_embed%conv_max
3574 :
3575 24 : IF (opt_embed%open_shell_embed) THEN
3576 :
3577 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3578 13 : " Maximum spin density difference = ", max_diff_spin
3579 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3580 13 : " Convergence limit for max. spin dens.diff.= ", opt_embed%conv_max_spin
3581 :
3582 : END IF
3583 :
3584 24 : IF (conv_max_diff) THEN
3585 : WRITE (UNIT=output_unit, FMT="(T2,2A)") &
3586 14 : " Convergence in max. density diff. = ", &
3587 28 : " YES"
3588 : ELSE
3589 : WRITE (UNIT=output_unit, FMT="(T2,2A)") &
3590 10 : " Convergence in max. density diff. = ", &
3591 20 : " NO"
3592 : END IF
3593 :
3594 : ! Integrated abs. value of density
3595 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3596 24 : " Integrated density difference = ", int_diff
3597 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3598 24 : " Conv. limit for integrated density diff. = ", opt_embed%conv_int
3599 24 : IF (opt_embed%open_shell_embed) THEN
3600 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3601 13 : " Integrated spin density difference = ", int_diff_spin
3602 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3603 13 : " Conv. limit for integrated spin dens.diff.= ", opt_embed%conv_int_spin
3604 : END IF
3605 :
3606 24 : IF (conv_int_diff) THEN
3607 : WRITE (UNIT=output_unit, FMT="(T2,2A)") &
3608 16 : " Convergence in integrated density diff. = ", &
3609 32 : " YES"
3610 : ELSE
3611 : WRITE (UNIT=output_unit, FMT="(T2,2A)") &
3612 8 : " Convergence in integrated density diff. = ", &
3613 16 : " NO"
3614 : END IF
3615 :
3616 : ! Integrated squared value of density
3617 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3618 24 : " Integrated squared density difference = ", int_diff_square
3619 24 : IF (opt_embed%open_shell_embed) THEN
3620 : WRITE (UNIT=output_unit, FMT="(T2,A,F20.10)") &
3621 13 : " Integrated squared spin density difference= ", int_diff_square_spin
3622 : END IF
3623 :
3624 : ! Maximum subsystem density change
3625 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") &
3626 24 : " Maximum density change in:"
3627 72 : DO i_dens = 1, (SIZE(opt_embed%all_nspins) - 1)
3628 120 : i_dens_start = SUM(opt_embed%all_nspins(1:i_dens)) - opt_embed%all_nspins(i_dens) + 1
3629 146 : DO i_spin = 1, opt_embed%all_nspins(i_dens)
3630 : WRITE (UNIT=output_unit, FMT="(T4,A10,I3,A6,I3,A1,F20.10)") &
3631 74 : " subsystem ", i_dens, ', spin', i_spin, ":", &
3632 196 : opt_embed%max_subsys_dens_diff(i_dens_start + i_spin - 1)
3633 : END DO
3634 : END DO
3635 :
3636 : END IF
3637 :
3638 48 : IF ((opt_embed%converged) .AND. (output_unit > 0)) THEN
3639 12 : WRITE (UNIT=output_unit, FMT="(/,T2,A)") REPEAT("*", 79)
3640 : WRITE (UNIT=output_unit, FMT="(T2,A,T25,A,T78,A)") &
3641 12 : "***", "EMBEDDING POTENTIAL OPTIMIZATION COMPLETED", "***"
3642 12 : WRITE (UNIT=output_unit, FMT="(T2,A)") REPEAT("*", 79)
3643 : END IF
3644 :
3645 48 : END SUBROUTINE conv_check_embed
3646 :
3647 : END MODULE optimize_embedding_potential
|