Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Utilities for rtp in combination with admm methods
10 : !> adapted routines from admm_method (author Manuel Guidon)
11 : !>
12 : !> \par History Use new "force only" overlap routine [07.2014,JGH]
13 : !> \author Florian Schiffmann
14 : ! **************************************************************************************************
15 : MODULE rtp_admm_methods
16 : USE admm_types, ONLY: admm_env_create,&
17 : admm_type,&
18 : get_admm_env
19 : USE cp_control_types, ONLY: admm_control_type,&
20 : dft_control_type
21 : USE cp_dbcsr_api, ONLY: &
22 : dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, &
23 : dbcsr_get_info, dbcsr_p_type, dbcsr_release, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
24 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
25 : copy_fm_to_dbcsr,&
26 : cp_dbcsr_plus_fm_fm_t
27 : USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale,&
28 : cp_fm_uplo_to_full
29 : USE cp_fm_cholesky, ONLY: cp_fm_cholesky_decompose,&
30 : cp_fm_cholesky_invert
31 : USE cp_fm_types, ONLY: cp_fm_create,&
32 : cp_fm_get_info,&
33 : cp_fm_release,&
34 : cp_fm_to_fm,&
35 : cp_fm_type
36 : USE hfx_admm_utils, ONLY: create_admm_xc_section
37 : USE input_constants, ONLY: do_admm_purify_none
38 : USE input_section_types, ONLY: section_vals_get_subs_vals,&
39 : section_vals_type
40 : USE kinds, ONLY: default_string_length,&
41 : dp
42 : USE mathconstants, ONLY: zero
43 : USE message_passing, ONLY: mp_para_env_type
44 : USE parallel_gemm_api, ONLY: parallel_gemm
45 : USE pw_types, ONLY: pw_c1d_gs_type,&
46 : pw_r3d_rs_type
47 : USE qs_collocate_density, ONLY: calculate_rho_elec
48 : USE qs_environment_types, ONLY: get_qs_env,&
49 : qs_environment_type,&
50 : set_qs_env
51 : USE qs_gapw_densities, ONLY: prepare_gapw_den
52 : USE qs_kind_types, ONLY: get_qs_kind_set,&
53 : qs_kind_type
54 : USE qs_ks_types, ONLY: qs_ks_env_type
55 : USE qs_mo_types, ONLY: get_mo_set,&
56 : mo_set_type
57 : USE qs_rho_atom_methods, ONLY: calculate_rho_atom_coeff
58 : USE qs_rho_types, ONLY: qs_rho_get,&
59 : qs_rho_set,&
60 : qs_rho_type
61 : USE rt_propagation_types, ONLY: get_rtp,&
62 : rt_prop_type
63 : USE task_list_types, ONLY: task_list_type
64 : #include "./base/base_uses.f90"
65 :
66 : IMPLICIT NONE
67 :
68 : PRIVATE
69 :
70 : ! *** Public subroutines ***
71 : PUBLIC :: rtp_admm_calc_rho_aux, rtp_admm_merge_ks_matrix
72 :
73 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rtp_admm_methods'
74 :
75 : CONTAINS
76 :
77 : ! **************************************************************************************************
78 : !> \brief Compute the ADMM density matrix in case of rtp (complex MO's)
79 : !>
80 : !> \param qs_env ...
81 : !> \par History
82 : ! **************************************************************************************************
83 114 : SUBROUTINE rtp_admm_calc_rho_aux(qs_env)
84 :
85 : TYPE(qs_environment_type), POINTER :: qs_env
86 :
87 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_calc_rho_aux'
88 :
89 : CHARACTER(LEN=default_string_length) :: basis_type
90 : INTEGER :: handle, ispin, nmo_aux, nspins
91 : LOGICAL :: gapw, s_mstruct_changed
92 114 : REAL(KIND=dp), DIMENSION(:), POINTER :: occ_num_aux, tot_rho_r_aux
93 : TYPE(admm_type), POINTER :: admm_env
94 114 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: rtp_coeff_aux_fit
95 114 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_p_aux, matrix_p_aux_im, &
96 114 : matrix_s_aux_fit, &
97 114 : matrix_s_aux_fit_vs_orb
98 : TYPE(dft_control_type), POINTER :: dft_control
99 114 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos, mos_aux_fit
100 : TYPE(mp_para_env_type), POINTER :: para_env
101 114 : TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER :: rho_g_aux
102 114 : TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r_aux
103 : TYPE(qs_ks_env_type), POINTER :: ks_env
104 : TYPE(qs_rho_type), POINTER :: rho, rho_aux_fit
105 : TYPE(rt_prop_type), POINTER :: rtp
106 : TYPE(task_list_type), POINTER :: task_list_aux_fit
107 :
108 114 : CALL timeset(routineN, handle)
109 114 : NULLIFY (admm_env, matrix_p_aux, matrix_p_aux_im, mos, &
110 114 : mos_aux_fit, para_env, matrix_s_aux_fit, matrix_s_aux_fit_vs_orb, rho, &
111 114 : ks_env, dft_control, tot_rho_r_aux, rho_r_aux, rho_g_aux, task_list_aux_fit)
112 :
113 : CALL get_qs_env(qs_env, &
114 : admm_env=admm_env, &
115 : ks_env=ks_env, &
116 : dft_control=dft_control, &
117 : para_env=para_env, &
118 : mos=mos, &
119 : rtp=rtp, &
120 : rho=rho, &
121 114 : s_mstruct_changed=s_mstruct_changed)
122 : CALL get_admm_env(admm_env, matrix_s_aux_fit=matrix_s_aux_fit, task_list_aux_fit=task_list_aux_fit, &
123 : matrix_s_aux_fit_vs_orb=matrix_s_aux_fit_vs_orb, mos_aux_fit=mos_aux_fit, &
124 114 : rho_aux_fit=rho_aux_fit)
125 114 : gapw = admm_env%do_gapw
126 :
127 114 : nspins = dft_control%nspins
128 :
129 114 : CALL get_rtp(rtp=rtp, admm_mos=rtp_coeff_aux_fit)
130 : CALL rtp_admm_fit_mo_coeffs(qs_env, admm_env, dft_control%admm_control, para_env, &
131 : matrix_s_aux_fit, matrix_s_aux_fit_vs_orb, &
132 : mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, &
133 114 : s_mstruct_changed)
134 :
135 266 : DO ispin = 1, nspins
136 : CALL qs_rho_get(rho_aux_fit, &
137 : rho_ao=matrix_p_aux, &
138 : rho_ao_im=matrix_p_aux_im, &
139 : rho_r=rho_r_aux, &
140 : rho_g=rho_g_aux, &
141 152 : tot_rho_r=tot_rho_r_aux)
142 :
143 152 : CALL get_mo_set(mos_aux_fit(ispin), occupation_numbers=occ_num_aux, nmo=nmo_aux)
144 :
145 : CALL rtp_admm_calculate_dm(admm_env, rtp_coeff_aux_fit, &
146 : matrix_p_aux(ispin)%matrix, &
147 : matrix_p_aux_im(ispin)%matrix, &
148 152 : occ_num_aux, ispin)
149 :
150 : !IF GAPW, only do the soft basis with PW
151 : basis_type = "AUX_FIT"
152 152 : IF (gapw) THEN
153 : basis_type = "AUX_FIT_SOFT"
154 60 : task_list_aux_fit => admm_env%admm_gapw_env%task_list
155 : END IF
156 :
157 : CALL calculate_rho_elec(matrix_p=matrix_p_aux(ispin)%matrix, &
158 : rho=rho_r_aux(ispin), &
159 : rho_gspace=rho_g_aux(ispin), &
160 : total_rho=tot_rho_r_aux(ispin), &
161 : ks_env=ks_env, soft_valid=.FALSE., &
162 : basis_type="AUX_FIT", &
163 152 : task_list_external=task_list_aux_fit)
164 :
165 : !IF GAPW, also need to atomic densities
166 418 : IF (gapw) THEN
167 : CALL calculate_rho_atom_coeff(qs_env, matrix_p_aux, &
168 : rho_atom_set=admm_env%admm_gapw_env%local_rho_set%rho_atom_set, &
169 : qs_kind_set=admm_env%admm_gapw_env%admm_kind_set, &
170 : oce=admm_env%admm_gapw_env%oce, sab=admm_env%sab_aux_fit, &
171 60 : para_env=para_env)
172 :
173 : CALL prepare_gapw_den(qs_env, local_rho_set=admm_env%admm_gapw_env%local_rho_set, &
174 60 : do_rho0=.FALSE., kind_set_external=admm_env%admm_gapw_env%admm_kind_set)
175 : END IF
176 : END DO
177 114 : CALL set_qs_env(qs_env, admm_env=admm_env)
178 114 : CALL qs_rho_set(rho_aux_fit, rho_r_valid=.TRUE., rho_g_valid=.TRUE.)
179 :
180 114 : CALL timestop(handle)
181 :
182 114 : END SUBROUTINE rtp_admm_calc_rho_aux
183 :
184 : ! **************************************************************************************************
185 : !> \brief ...
186 : !> \param admm_env ...
187 : !> \param rtp_coeff_aux_fit ...
188 : !> \param density_matrix_aux ...
189 : !> \param density_matrix_aux_im ...
190 : !> \param occupation ...
191 : !> \param ispin ...
192 : ! **************************************************************************************************
193 304 : SUBROUTINE rtp_admm_calculate_dm(admm_env, rtp_coeff_aux_fit, density_matrix_aux, &
194 152 : density_matrix_aux_im, occupation, ispin)
195 : TYPE(admm_type), POINTER :: admm_env
196 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: rtp_coeff_aux_fit
197 : TYPE(dbcsr_type), POINTER :: density_matrix_aux, density_matrix_aux_im
198 : REAL(KIND=dp), DIMENSION(:), INTENT(in) :: occupation
199 : INTEGER, INTENT(in) :: ispin
200 :
201 : CHARACTER(len=*), PARAMETER :: routineN = 'rtp_admm_calculate_dm'
202 :
203 : INTEGER :: handle
204 :
205 152 : CALL timeset(routineN, handle)
206 :
207 304 : SELECT CASE (admm_env%purification_method)
208 : CASE (do_admm_purify_none)
209 : CALL calculate_rtp_admm_density(density_matrix_aux, density_matrix_aux_im, &
210 152 : rtp_coeff_aux_fit, occupation, ispin)
211 : END SELECT
212 :
213 152 : CALL timestop(handle)
214 :
215 152 : END SUBROUTINE rtp_admm_calculate_dm
216 :
217 : ! **************************************************************************************************
218 : !> \brief ...
219 : !> \param qs_env ...
220 : !> \param admm_env ...
221 : !> \param admm_control ...
222 : !> \param para_env ...
223 : !> \param matrix_s_aux_fit ...
224 : !> \param matrix_s_mixed ...
225 : !> \param mos ...
226 : !> \param mos_aux_fit ...
227 : !> \param rtp ...
228 : !> \param rtp_coeff_aux_fit ...
229 : !> \param geometry_did_change ...
230 : ! **************************************************************************************************
231 228 : SUBROUTINE rtp_admm_fit_mo_coeffs(qs_env, admm_env, admm_control, para_env, matrix_s_aux_fit, matrix_s_mixed, &
232 114 : mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, geometry_did_change)
233 :
234 : TYPE(qs_environment_type), POINTER :: qs_env
235 : TYPE(admm_type), POINTER :: admm_env
236 : TYPE(admm_control_type), POINTER :: admm_control
237 : TYPE(mp_para_env_type), POINTER :: para_env
238 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s_aux_fit, matrix_s_mixed
239 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mos, mos_aux_fit
240 : TYPE(rt_prop_type), POINTER :: rtp
241 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: rtp_coeff_aux_fit
242 : LOGICAL, INTENT(IN) :: geometry_did_change
243 :
244 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_fit_mo_coeffs'
245 :
246 : INTEGER :: handle, nao_aux_fit, natoms
247 : LOGICAL :: recalc_S
248 114 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
249 : TYPE(section_vals_type), POINTER :: input, xc_section
250 :
251 114 : CALL timeset(routineN, handle)
252 :
253 114 : NULLIFY (xc_section, qs_kind_set)
254 :
255 114 : IF (.NOT. (ASSOCIATED(admm_env))) THEN
256 : ! setup admm environment
257 0 : CALL get_qs_env(qs_env, input=input, natom=natoms, qs_kind_set=qs_kind_set)
258 0 : CALL get_qs_kind_set(qs_kind_set, nsgf=nao_aux_fit, basis_type="AUX_FIT")
259 0 : CALL admm_env_create(admm_env, admm_control, mos, para_env, natoms, nao_aux_fit)
260 0 : xc_section => section_vals_get_subs_vals(input, "DFT%XC")
261 : CALL create_admm_xc_section(x_data=qs_env%x_data, xc_section=xc_section, &
262 0 : admm_env=admm_env)
263 : END IF
264 :
265 114 : recalc_S = geometry_did_change .OR. (rtp%iter == 0 .AND. (rtp%istep == rtp%i_start))
266 :
267 228 : SELECT CASE (admm_env%purification_method)
268 : CASE (do_admm_purify_none)
269 : CALL rtp_fit_mo_coeffs_none(qs_env, admm_env, para_env, matrix_s_aux_fit, matrix_s_mixed, &
270 114 : mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, recalc_S)
271 : END SELECT
272 :
273 114 : CALL timestop(handle)
274 :
275 114 : END SUBROUTINE rtp_admm_fit_mo_coeffs
276 : ! **************************************************************************************************
277 : !> \brief Calculates the MO coefficients for the auxiliary fitting basis set
278 : !> by minimizing int (psi_i - psi_aux_i)^2 using Lagrangian Multipliers
279 : !>
280 : !> \param qs_env ...
281 : !> \param admm_env The ADMM env
282 : !> \param para_env The parallel env
283 : !> \param matrix_s_aux_fit the overlap matrix of the auxiliary fitting basis set
284 : !> \param matrix_s_mixed the mixed overlap matrix of the auxiliary fitting basis
285 : !> set and the orbital basis set
286 : !> \param mos the MO's of the orbital basis set
287 : !> \param mos_aux_fit the MO's of the auxiliary fitting basis set
288 : !> \param rtp ...
289 : !> \param rtp_coeff_aux_fit ...
290 : !> \param geometry_did_change flag to indicate if the geomtry changed
291 : !> \par History
292 : !> 05.2008 created [Manuel Guidon]
293 : !> \author Manuel Guidon
294 : ! **************************************************************************************************
295 228 : SUBROUTINE rtp_fit_mo_coeffs_none(qs_env, admm_env, para_env, matrix_s_aux_fit, matrix_s_mixed, &
296 114 : mos, mos_aux_fit, rtp, rtp_coeff_aux_fit, geometry_did_change)
297 :
298 : TYPE(qs_environment_type), POINTER :: qs_env
299 : TYPE(admm_type), POINTER :: admm_env
300 : TYPE(mp_para_env_type), POINTER :: para_env
301 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s_aux_fit, matrix_s_mixed
302 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mos, mos_aux_fit
303 : TYPE(rt_prop_type), POINTER :: rtp
304 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: rtp_coeff_aux_fit
305 : LOGICAL, INTENT(IN) :: geometry_did_change
306 :
307 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_fit_mo_coeffs_none'
308 :
309 : INTEGER :: handle, ispin, nao_aux_fit, nao_orb, &
310 : natoms, nmo, nmo_mos, nspins
311 114 : REAL(KIND=dp), DIMENSION(:), POINTER :: occ_num, occ_num_aux
312 114 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: mos_new
313 : TYPE(cp_fm_type), POINTER :: mo_coeff, mo_coeff_aux_fit
314 : TYPE(dft_control_type), POINTER :: dft_control
315 114 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
316 : TYPE(section_vals_type), POINTER :: input, xc_section
317 :
318 114 : CALL timeset(routineN, handle)
319 :
320 114 : NULLIFY (dft_control, qs_kind_set)
321 :
322 114 : IF (.NOT. (ASSOCIATED(admm_env))) THEN
323 0 : CALL get_qs_env(qs_env, input=input, natom=natoms, dft_control=dft_control, qs_kind_set=qs_kind_set)
324 0 : CALL get_qs_kind_set(qs_kind_set, nsgf=nao_aux_fit, basis_type="AUX_FIT")
325 0 : CALL admm_env_create(admm_env, dft_control%admm_control, mos, para_env, natoms, nao_aux_fit)
326 0 : xc_section => section_vals_get_subs_vals(input, "DFT%XC")
327 : CALL create_admm_xc_section(x_data=qs_env%x_data, xc_section=xc_section, &
328 0 : admm_env=admm_env)
329 : END IF
330 :
331 114 : nao_aux_fit = admm_env%nao_aux_fit
332 114 : nao_orb = admm_env%nao_orb
333 114 : nspins = SIZE(mos)
334 :
335 : ! *** This part only depends on overlap matrices ==> needs only to be calculated if the geometry changed
336 :
337 114 : IF (geometry_did_change) THEN
338 30 : CALL copy_dbcsr_to_fm(matrix_s_aux_fit(1)%matrix, admm_env%S_inv)
339 30 : CALL cp_fm_uplo_to_full(admm_env%S_inv, admm_env%work_aux_aux)
340 30 : CALL cp_fm_to_fm(admm_env%S_inv, admm_env%S)
341 :
342 30 : CALL copy_dbcsr_to_fm(matrix_s_mixed(1)%matrix, admm_env%Q)
343 :
344 : !! Calculate S'_inverse
345 30 : CALL cp_fm_cholesky_decompose(admm_env%S_inv)
346 30 : CALL cp_fm_cholesky_invert(admm_env%S_inv)
347 : !! Symmetrize the guy
348 30 : CALL cp_fm_uplo_to_full(admm_env%S_inv, admm_env%work_aux_aux)
349 : !! Calculate A=S'^(-1)*P
350 : CALL parallel_gemm('N', 'N', nao_aux_fit, nao_orb, nao_aux_fit, &
351 : 1.0_dp, admm_env%S_inv, admm_env%Q, 0.0_dp, &
352 30 : admm_env%A)
353 : END IF
354 :
355 : ! *** Calculate the mo_coeffs for the fitting basis
356 266 : DO ispin = 1, nspins
357 152 : nmo = admm_env%nmo(ispin)
358 152 : IF (nmo == 0) CYCLE
359 : !! Lambda = C^(T)*B*C
360 152 : CALL get_rtp(rtp=rtp, mos_new=mos_new)
361 152 : CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, occupation_numbers=occ_num, nmo=nmo_mos)
362 : CALL get_mo_set(mos_aux_fit(ispin), mo_coeff=mo_coeff_aux_fit, &
363 152 : occupation_numbers=occ_num_aux)
364 :
365 : CALL parallel_gemm('N', 'N', nao_aux_fit, nmo, nao_orb, &
366 : 1.0_dp, admm_env%A, mos_new(2*ispin - 1), 0.0_dp, &
367 152 : rtp_coeff_aux_fit(2*ispin - 1))
368 : CALL parallel_gemm('N', 'N', nao_aux_fit, nmo, nao_orb, &
369 : 1.0_dp, admm_env%A, mos_new(2*ispin), 0.0_dp, &
370 152 : rtp_coeff_aux_fit(2*ispin))
371 :
372 418 : CALL cp_fm_to_fm(rtp_coeff_aux_fit(2*ispin - 1), mo_coeff_aux_fit)
373 : END DO
374 :
375 114 : CALL timestop(handle)
376 :
377 114 : END SUBROUTINE rtp_fit_mo_coeffs_none
378 :
379 : ! **************************************************************************************************
380 : !> \brief ...
381 : !> \param density_matrix_aux ...
382 : !> \param density_matrix_aux_im ...
383 : !> \param rtp_coeff_aux_fit ...
384 : !> \param occupation ...
385 : !> \param ispin ...
386 : ! **************************************************************************************************
387 456 : SUBROUTINE calculate_rtp_admm_density(density_matrix_aux, density_matrix_aux_im, &
388 152 : rtp_coeff_aux_fit, occupation, ispin)
389 :
390 : TYPE(dbcsr_type), POINTER :: density_matrix_aux, density_matrix_aux_im
391 : TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: rtp_coeff_aux_fit
392 : REAL(KIND=dp), DIMENSION(:), INTENT(in) :: occupation
393 : INTEGER, INTENT(in) :: ispin
394 :
395 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_rtp_admm_density'
396 : REAL(KIND=dp), PARAMETER :: zero = 0.0_dp
397 :
398 : INTEGER :: handle, im, ncol, re
399 : REAL(KIND=dp) :: alpha
400 : TYPE(cp_fm_type) :: fm_tmp
401 :
402 152 : CALL timeset(routineN, handle)
403 :
404 152 : re = 2*ispin - 1; im = 2*ispin
405 :
406 152 : CALL dbcsr_set(density_matrix_aux, zero)
407 152 : CALL cp_fm_get_info(rtp_coeff_aux_fit(re), ncol_global=ncol)
408 152 : alpha = occupation(1)
409 628 : IF (ALL(occupation == alpha)) THEN
410 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
411 : matrix_v=rtp_coeff_aux_fit(re), &
412 : ncol=ncol, &
413 108 : alpha=alpha)
414 :
415 : ! It is actually complex conjugate but i*i=-1 therefore it must be added
416 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
417 : matrix_v=rtp_coeff_aux_fit(im), &
418 : ncol=ncol, &
419 108 : alpha=alpha)
420 :
421 : ! compute the imaginary part of the dm
422 108 : CALL dbcsr_set(density_matrix_aux_im, zero)
423 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux_im, &
424 : matrix_v=rtp_coeff_aux_fit(im), &
425 : matrix_g=rtp_coeff_aux_fit(re), &
426 : ncol=ncol, &
427 : alpha=2.0_dp*alpha, &
428 108 : symmetry_mode=-1)
429 : ELSE
430 44 : CALL cp_fm_create(fm_tmp, rtp_coeff_aux_fit(1)%matrix_struct)
431 44 : CALL cp_fm_to_fm(rtp_coeff_aux_fit(re), fm_tmp)
432 44 : CALL cp_fm_column_scale(fm_tmp, occupation(1:ncol))
433 44 : alpha = 1.0_dp
434 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
435 : matrix_v=rtp_coeff_aux_fit(re), &
436 : matrix_g=fm_tmp, &
437 44 : ncol=ncol, alpha=alpha)
438 : ! It is actually complex conjugate but i*i=-1 therefore it must be added
439 44 : CALL cp_fm_to_fm(rtp_coeff_aux_fit(im), fm_tmp)
440 44 : CALL cp_fm_column_scale(fm_tmp, occupation(1:ncol))
441 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux, &
442 : matrix_v=rtp_coeff_aux_fit(im), &
443 : matrix_g=fm_tmp, &
444 44 : ncol=ncol, alpha=alpha)
445 : ! compute the imaginary part of the dm
446 44 : CALL dbcsr_set(density_matrix_aux_im, zero)
447 : CALL cp_dbcsr_plus_fm_fm_t(sparse_matrix=density_matrix_aux_im, &
448 : matrix_v=fm_tmp, &
449 : matrix_g=rtp_coeff_aux_fit(re), &
450 : ncol=ncol, alpha=2.0_dp*alpha, &
451 44 : symmetry_mode=-1)
452 44 : CALL cp_fm_release(fm_tmp)
453 : END IF
454 :
455 152 : CALL timestop(handle)
456 :
457 152 : END SUBROUTINE calculate_rtp_admm_density
458 :
459 : ! **************************************************************************************************
460 : !> \brief ...
461 : !> \param qs_env ...
462 : ! **************************************************************************************************
463 114 : SUBROUTINE rtp_admm_merge_ks_matrix(qs_env)
464 : TYPE(qs_environment_type), POINTER :: qs_env
465 :
466 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rtp_admm_merge_ks_matrix'
467 :
468 : INTEGER :: handle, ispin
469 : TYPE(admm_type), POINTER :: admm_env
470 114 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_ks_aux_fit, &
471 114 : matrix_ks_aux_fit_im, matrix_ks_im
472 : TYPE(dft_control_type), POINTER :: dft_control
473 :
474 114 : NULLIFY (admm_env, dft_control, matrix_ks, matrix_ks_im, matrix_ks_aux_fit, matrix_ks_aux_fit_im)
475 114 : CALL timeset(routineN, handle)
476 :
477 : CALL get_qs_env(qs_env, &
478 : admm_env=admm_env, &
479 : dft_control=dft_control, &
480 : matrix_ks=matrix_ks, &
481 114 : matrix_ks_im=matrix_ks_im)
482 114 : CALL get_admm_env(admm_env, matrix_ks_aux_fit=matrix_ks_aux_fit, matrix_ks_aux_fit_im=matrix_ks_aux_fit_im)
483 :
484 : !note: the GAPW contribution to ks_aux_fit taken care of in qs_ks_methods.F/update_admm_ks_atom
485 :
486 266 : DO ispin = 1, dft_control%nspins
487 :
488 114 : SELECT CASE (admm_env%purification_method)
489 : CASE (do_admm_purify_none)
490 : CALL rt_merge_ks_matrix_none(ispin, admm_env, &
491 152 : matrix_ks, matrix_ks_aux_fit)
492 : CALL rt_merge_ks_matrix_none(ispin, admm_env, &
493 304 : matrix_ks_im, matrix_ks_aux_fit_im)
494 : END SELECT
495 :
496 : END DO !spin loop
497 114 : CALL timestop(handle)
498 :
499 114 : END SUBROUTINE rtp_admm_merge_ks_matrix
500 :
501 : ! **************************************************************************************************
502 : !> \brief ...
503 : !> \param ispin ...
504 : !> \param admm_env ...
505 : !> \param matrix_ks ...
506 : !> \param matrix_ks_aux_fit ...
507 : ! **************************************************************************************************
508 304 : SUBROUTINE rt_merge_ks_matrix_none(ispin, admm_env, &
509 : matrix_ks, matrix_ks_aux_fit)
510 : INTEGER, INTENT(IN) :: ispin
511 : TYPE(admm_type), POINTER :: admm_env
512 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks, matrix_ks_aux_fit
513 :
514 : CHARACTER(LEN=*), PARAMETER :: routineN = 'rt_merge_ks_matrix_none'
515 :
516 : CHARACTER :: matrix_type_fit
517 : INTEGER :: handle, nao_aux_fit, nao_orb, nmo
518 : INTEGER, SAVE :: counter = 0
519 : TYPE(dbcsr_type) :: matrix_ks_nosym
520 : TYPE(dbcsr_type), POINTER :: matrix_k_tilde
521 :
522 304 : CALL timeset(routineN, handle)
523 :
524 304 : counter = counter + 1
525 304 : nao_aux_fit = admm_env%nao_aux_fit
526 304 : nao_orb = admm_env%nao_orb
527 304 : nmo = admm_env%nmo(ispin)
528 : CALL dbcsr_create(matrix_ks_nosym, template=matrix_ks_aux_fit(ispin)%matrix, &
529 304 : matrix_type=dbcsr_type_no_symmetry)
530 304 : CALL dbcsr_set(matrix_ks_nosym, 0.0_dp)
531 304 : CALL dbcsr_desymmetrize(matrix_ks_aux_fit(ispin)%matrix, matrix_ks_nosym)
532 :
533 304 : CALL copy_dbcsr_to_fm(matrix_ks_nosym, admm_env%K(ispin))
534 :
535 : !! K*A
536 : CALL parallel_gemm('N', 'N', nao_aux_fit, nao_orb, nao_aux_fit, &
537 : 1.0_dp, admm_env%K(ispin), admm_env%A, 0.0_dp, &
538 304 : admm_env%work_aux_orb)
539 : !! A^T*K*A
540 : CALL parallel_gemm('T', 'N', nao_orb, nao_orb, nao_aux_fit, &
541 : 1.0_dp, admm_env%A, admm_env%work_aux_orb, 0.0_dp, &
542 304 : admm_env%work_orb_orb)
543 :
544 304 : CALL dbcsr_get_info(matrix_ks_aux_fit(ispin)%matrix, matrix_type=matrix_type_fit)
545 :
546 : NULLIFY (matrix_k_tilde)
547 304 : ALLOCATE (matrix_k_tilde)
548 : CALL dbcsr_create(matrix_k_tilde, template=matrix_ks(ispin)%matrix, &
549 304 : name='MATRIX K_tilde', matrix_type=matrix_type_fit)
550 :
551 304 : CALL dbcsr_copy(matrix_k_tilde, matrix_ks(ispin)%matrix)
552 304 : CALL dbcsr_set(matrix_k_tilde, 0.0_dp)
553 304 : CALL copy_fm_to_dbcsr(admm_env%work_orb_orb, matrix_k_tilde, keep_sparsity=.TRUE.)
554 :
555 304 : CALL dbcsr_add(matrix_ks(ispin)%matrix, matrix_k_tilde, 1.0_dp, 1.0_dp)
556 :
557 304 : CALL dbcsr_deallocate_matrix(matrix_k_tilde)
558 304 : CALL dbcsr_release(matrix_ks_nosym)
559 :
560 304 : CALL timestop(handle)
561 :
562 304 : END SUBROUTINE rt_merge_ks_matrix_none
563 :
564 : END MODULE rtp_admm_methods
|