Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Subroutines for ALMO SCF
10 : !> \par History
11 : !> 2011.06 created [Rustam Z Khaliullin]
12 : !> 2018.09 smearing support [Ruben Staub]
13 : !> \author Rustam Z Khaliullin
14 : ! **************************************************************************************************
15 : MODULE almo_scf_methods
16 : USE almo_scf_types, ONLY: almo_scf_env_type,&
17 : almo_scf_history_type
18 : USE bibliography, ONLY: Kolafa2004,&
19 : Kuhne2007,&
20 : cite_reference
21 : USE cp_blacs_env, ONLY: cp_blacs_env_type
22 : USE cp_dbcsr_api, ONLY: &
23 : dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_distribution_get, dbcsr_distribution_type, &
24 : dbcsr_filter, dbcsr_finalize, dbcsr_get_info, dbcsr_iterator_blocks_left, &
25 : dbcsr_iterator_next_block, dbcsr_iterator_readonly_start, dbcsr_iterator_start, &
26 : dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_put_block, dbcsr_release, &
27 : dbcsr_set, dbcsr_transposed, dbcsr_type, dbcsr_type_no_symmetry, dbcsr_type_symmetric, &
28 : dbcsr_work_create
29 : USE cp_dbcsr_cholesky, ONLY: cp_dbcsr_cholesky_decompose,&
30 : cp_dbcsr_cholesky_invert
31 : USE cp_dbcsr_contrib, ONLY: &
32 : dbcsr_add_on_diag, dbcsr_frobenius_norm, dbcsr_get_diag, dbcsr_init_random, dbcsr_print, &
33 : dbcsr_reserve_all_blocks, dbcsr_reserve_diag_blocks, dbcsr_scale_by_vector, dbcsr_set_diag
34 : USE cp_log_handling, ONLY: cp_get_default_logger,&
35 : cp_logger_get_default_unit_nr,&
36 : cp_logger_type
37 : USE domain_submatrix_methods, ONLY: &
38 : add_submatrices, construct_dbcsr_from_submatrices, construct_submatrices, &
39 : copy_submatrices, copy_submatrix_data, init_submatrices, multiply_submatrices, &
40 : print_submatrices, release_submatrices
41 : USE domain_submatrix_types, ONLY: domain_map_type,&
42 : domain_submatrix_type,&
43 : select_row,&
44 : select_row_col
45 : USE fermi_utils, ONLY: FermiFixed
46 : !! for smearing
47 : USE input_constants, ONLY: almo_domain_layout_molecular,&
48 : almo_mat_distr_atomic,&
49 : almo_scf_diag,&
50 : spd_inversion_dense_cholesky,&
51 : spd_inversion_ls_hotelling,&
52 : spd_inversion_ls_taylor
53 : USE iterate_matrix, ONLY: invert_Hotelling,&
54 : invert_Taylor,&
55 : matrix_sqrt_Newton_Schulz
56 : USE kinds, ONLY: dp
57 : USE mathlib, ONLY: binomial,&
58 : invmat_symm
59 : USE message_passing, ONLY: mp_comm_type,&
60 : mp_para_env_type
61 : USE util, ONLY: sort
62 : #include "./base/base_uses.f90"
63 :
64 : IMPLICIT NONE
65 :
66 : PRIVATE
67 :
68 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'almo_scf_methods'
69 :
70 : PUBLIC almo_scf_ks_to_ks_blk, almo_scf_p_blk_to_t_blk, &
71 : almo_scf_t_to_proj, almo_scf_ks_blk_to_tv_blk, &
72 : almo_scf_ks_xx_to_tv_xx, almo_scf_t_rescaling, &
73 : apply_projector, get_overlap, &
74 : generator_to_unitary, &
75 : orthogonalize_mos, &
76 : pseudo_invert_diagonal_blk, construct_test, &
77 : construct_domain_preconditioner, &
78 : apply_domain_operators, &
79 : construct_domain_s_inv, &
80 : construct_domain_s_sqrt, &
81 : distribute_domains, &
82 : almo_scf_ks_to_ks_xx, &
83 : construct_domain_r_down, &
84 : xalmo_initial_guess, &
85 : fill_matrix_with_ones
86 :
87 : CONTAINS
88 :
89 : ! **************************************************************************************************
90 : !> \brief Fill all matrix blocks with 1.0_dp
91 : !> \param matrix ...
92 : !> \par History
93 : !> 2019.09 created [Rustam Z Khaliullin]
94 : !> \author Rustam Z Khaliullin
95 : ! **************************************************************************************************
96 0 : SUBROUTINE fill_matrix_with_ones(matrix)
97 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix
98 :
99 0 : CALL dbcsr_reserve_all_blocks(matrix)
100 0 : CALL dbcsr_set(matrix, 1.0_dp)
101 0 : END SUBROUTINE fill_matrix_with_ones
102 :
103 : ! **************************************************************************************************
104 : !> \brief builds projected KS matrices for the overlapping domains
105 : !> also computes the DIIS error vector as a by-product
106 : !> \param almo_scf_env ...
107 : !> \par History
108 : !> 2013.03 created [Rustam Z Khaliullin]
109 : !> \author Rustam Z Khaliullin
110 : ! **************************************************************************************************
111 2 : SUBROUTINE almo_scf_ks_to_ks_xx(almo_scf_env)
112 :
113 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
114 :
115 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_to_ks_xx'
116 :
117 : INTEGER :: handle, ispin, ndomains
118 : REAL(KIND=dp) :: eps_multiply
119 : TYPE(dbcsr_type) :: matrix_tmp1, matrix_tmp2, matrix_tmp3, matrix_tmp4, matrix_tmp5, &
120 : matrix_tmp6, matrix_tmp7, matrix_tmp8, matrix_tmp9
121 : TYPE(domain_submatrix_type), ALLOCATABLE, &
122 2 : DIMENSION(:) :: subm_tmp1, subm_tmp2, subm_tmp3
123 :
124 2 : CALL timeset(routineN, handle)
125 :
126 2 : eps_multiply = almo_scf_env%eps_filter
127 :
128 4 : DO ispin = 1, almo_scf_env%nspins
129 :
130 2 : CALL dbcsr_get_info(almo_scf_env%quench_t(ispin), nblkcols_total=ndomains)
131 :
132 : ! 0. Create KS_xx
133 : CALL construct_submatrices( &
134 : almo_scf_env%matrix_ks(ispin), &
135 : almo_scf_env%domain_ks_xx(:, ispin), &
136 : almo_scf_env%quench_t(ispin), &
137 : almo_scf_env%domain_map(ispin), &
138 : almo_scf_env%cpu_of_domain, &
139 2 : select_row_col)
140 :
141 : !!!!! RZK-warning MAKE SURE THAT YOU NEED BLOCKS OUTSIDE QUENCH_T
142 : !!!!! FOR ALL NO-MATRICES NOT COMPUTING THEM CAN SAVE LOTS OF TIME
143 :
144 : ! 1. TMP1=KS.T
145 : ! Cost: NOn
146 : !matrix_tmp1 = create NxO, full
147 : CALL dbcsr_create(matrix_tmp1, &
148 2 : template=almo_scf_env%matrix_t(ispin))
149 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks(ispin), &
150 : almo_scf_env%matrix_t(ispin), &
151 : 0.0_dp, matrix_tmp1, &
152 2 : filter_eps=eps_multiply)
153 :
154 : ! 2. TMP2=TMP1.SigInv=KS.T.SigInv
155 : ! Cost: NOO
156 : !matrix_tmp2 = create NxO, full
157 : CALL dbcsr_create(matrix_tmp2, &
158 2 : template=almo_scf_env%matrix_t(ispin))
159 : CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
160 : almo_scf_env%matrix_sigma_inv(ispin), &
161 : 0.0_dp, matrix_tmp2, &
162 2 : filter_eps=eps_multiply)
163 :
164 : ! 3. TMP1=S.T
165 : ! Cost: NOn
166 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s(1), &
167 : almo_scf_env%matrix_t(ispin), &
168 : 0.0_dp, matrix_tmp1, &
169 2 : filter_eps=eps_multiply)
170 :
171 : ! 4. TMP4=TMP2.tr(TMP1)=KS.T.SigInv.tr(T).S
172 : ! Cost: NNO
173 : !matrix_tmp4 = create NxN
174 : CALL dbcsr_create(matrix_tmp4, &
175 : template=almo_scf_env%matrix_s(1), &
176 2 : matrix_type=dbcsr_type_no_symmetry)
177 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp2, &
178 : matrix_tmp1, &
179 : 0.0_dp, matrix_tmp4, &
180 2 : filter_eps=eps_multiply)
181 :
182 : ! 5. KS_xx=KS_xx-TMP4_xx-tr(TMP4_xx)
183 16 : ALLOCATE (subm_tmp1(ndomains))
184 2 : CALL init_submatrices(subm_tmp1)
185 : CALL construct_submatrices( &
186 : matrix_tmp4, &
187 : subm_tmp1, &
188 : almo_scf_env%quench_t(ispin), &
189 : almo_scf_env%domain_map(ispin), &
190 : almo_scf_env%cpu_of_domain, &
191 2 : select_row_col)
192 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
193 2 : -1.0_dp, subm_tmp1, 'N')
194 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
195 2 : -1.0_dp, subm_tmp1, 'T')
196 :
197 : ! 6. TMP3=tr(TMP4).T=S.T.SigInv.tr(T).KS.T
198 : ! Cost: NOn
199 : !matrix_tmp3 = create NxO, full
200 : CALL dbcsr_create(matrix_tmp3, &
201 : template=almo_scf_env%matrix_t(ispin), &
202 2 : matrix_type=dbcsr_type_no_symmetry)
203 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
204 : matrix_tmp4, &
205 : almo_scf_env%matrix_t(ispin), &
206 : 0.0_dp, matrix_tmp3, &
207 2 : filter_eps=eps_multiply)
208 2 : CALL dbcsr_release(matrix_tmp4)
209 :
210 : ! 8. TMP6=TMP3.SigInv=S.T.SigInv.tr(T).KS.T.SigInv
211 : ! Cost: NOO
212 : !matrix_tmp6 = create NxO, full
213 : CALL dbcsr_create(matrix_tmp6, &
214 : template=almo_scf_env%matrix_t(ispin), &
215 2 : matrix_type=dbcsr_type_no_symmetry)
216 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
217 : matrix_tmp3, &
218 : almo_scf_env%matrix_sigma_inv(ispin), &
219 : 0.0_dp, matrix_tmp6, &
220 2 : filter_eps=eps_multiply)
221 :
222 : ! 8A. Use intermediate matrices to evaluate the gradient/error
223 : ! Err=(TMP2-TMP6)_q=(KS.T.SigInv-S.T.SigInv.tr(T).KS.T.SigInv)_q
224 : ! error vector in AO-MO basis
225 : CALL dbcsr_copy(almo_scf_env%matrix_err_xx(ispin), &
226 2 : almo_scf_env%quench_t(ispin))
227 : CALL dbcsr_copy(almo_scf_env%matrix_err_xx(ispin), &
228 2 : matrix_tmp2, keep_sparsity=.TRUE.)
229 : CALL dbcsr_create(matrix_tmp4, &
230 : template=almo_scf_env%matrix_t(ispin), &
231 2 : matrix_type=dbcsr_type_no_symmetry)
232 : CALL dbcsr_copy(matrix_tmp4, &
233 2 : almo_scf_env%quench_t(ispin))
234 : CALL dbcsr_copy(matrix_tmp4, &
235 2 : matrix_tmp6, keep_sparsity=.TRUE.)
236 : CALL dbcsr_add(almo_scf_env%matrix_err_xx(ispin), &
237 2 : matrix_tmp4, 1.0_dp, -1.0_dp)
238 2 : CALL dbcsr_release(matrix_tmp4)
239 : !
240 : ! error vector in AO-AO basis
241 : ! RZK-warning tmp4 can be created using the sparsity pattern,
242 : ! then retain_sparsity can be used to perform the multiply
243 : ! this will save some time
244 : CALL dbcsr_copy(matrix_tmp3, &
245 2 : matrix_tmp2)
246 : CALL dbcsr_add(matrix_tmp3, &
247 2 : matrix_tmp6, 1.0_dp, -1.0_dp)
248 : CALL dbcsr_create(matrix_tmp4, &
249 : template=almo_scf_env%matrix_s(1), &
250 2 : matrix_type=dbcsr_type_no_symmetry)
251 : CALL dbcsr_multiply("N", "T", 1.0_dp, &
252 : matrix_tmp3, &
253 : almo_scf_env%matrix_t(ispin), &
254 : 0.0_dp, matrix_tmp4, &
255 2 : filter_eps=eps_multiply)
256 : CALL construct_submatrices( &
257 : matrix_tmp4, &
258 : almo_scf_env%domain_err(:, ispin), &
259 : almo_scf_env%quench_t(ispin), &
260 : almo_scf_env%domain_map(ispin), &
261 : almo_scf_env%cpu_of_domain, &
262 2 : select_row_col)
263 2 : CALL dbcsr_release(matrix_tmp4)
264 : ! domain_err submatrices are in down-up representation
265 : ! bring them into the orthogonalized basis
266 14 : ALLOCATE (subm_tmp2(ndomains))
267 2 : CALL init_submatrices(subm_tmp2)
268 : CALL multiply_submatrices('N', 'N', 1.0_dp, &
269 : almo_scf_env%domain_err(:, ispin), &
270 2 : almo_scf_env%domain_s_sqrt(:, ispin), 0.0_dp, subm_tmp2)
271 : CALL multiply_submatrices('N', 'N', 1.0_dp, &
272 : almo_scf_env%domain_s_sqrt_inv(:, ispin), &
273 2 : subm_tmp2, 0.0_dp, almo_scf_env%domain_err(:, ispin))
274 :
275 : ! 9. TMP5=TMP6.tr(TMP1)=S.T.SigInv.tr(T).KS.T.SigInv.tr(T).S
276 : ! Cost: NNO
277 : ! matrix_tmp5 = create NxN, full
278 : ! RZK-warning tmp5 can be created using the sparsity pattern,
279 : ! then retain_sparsity can be used to perform the multiply
280 : ! this will save some time
281 : CALL dbcsr_create(matrix_tmp5, &
282 : template=almo_scf_env%matrix_s(1), &
283 2 : matrix_type=dbcsr_type_no_symmetry)
284 : CALL dbcsr_multiply("N", "T", 1.0_dp, &
285 : matrix_tmp6, &
286 : matrix_tmp1, &
287 : 0.0_dp, matrix_tmp5, &
288 2 : filter_eps=eps_multiply)
289 :
290 : ! 10. KS_xx=KS_xx+TMP5_xx
291 : CALL construct_submatrices( &
292 : matrix_tmp5, &
293 : subm_tmp1, &
294 : almo_scf_env%quench_t(ispin), &
295 : almo_scf_env%domain_map(ispin), &
296 : almo_scf_env%cpu_of_domain, &
297 2 : select_row_col)
298 2 : CALL dbcsr_release(matrix_tmp5)
299 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
300 2 : 1.0_dp, subm_tmp1, 'N')
301 :
302 : ! 11. KS_xx=KS_xx + [S.T]_xx.[SigInv.tr(T).KS.(1-T.SigInv.tr(T).S)]_xx + transposed
303 14 : ALLOCATE (subm_tmp3(ndomains))
304 2 : CALL init_submatrices(subm_tmp3)
305 : CALL construct_submatrices( &
306 : matrix_tmp2, &
307 : subm_tmp2, &
308 : almo_scf_env%quench_t(ispin), &
309 : almo_scf_env%domain_map(ispin), &
310 : almo_scf_env%cpu_of_domain, &
311 2 : select_row)
312 : CALL construct_submatrices( &
313 : matrix_tmp6, &
314 : subm_tmp3, &
315 : almo_scf_env%quench_t(ispin), &
316 : almo_scf_env%domain_map(ispin), &
317 : almo_scf_env%cpu_of_domain, &
318 2 : select_row)
319 2 : CALL dbcsr_release(matrix_tmp6)
320 : CALL add_submatrices(1.0_dp, subm_tmp2, &
321 2 : -1.0_dp, subm_tmp3, 'N')
322 : CALL construct_submatrices( &
323 : matrix_tmp1, &
324 : subm_tmp3, &
325 : almo_scf_env%quench_t(ispin), &
326 : almo_scf_env%domain_map(ispin), &
327 : almo_scf_env%cpu_of_domain, &
328 2 : select_row)
329 : CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
330 2 : subm_tmp3, 0.0_dp, subm_tmp1)
331 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
332 2 : 1.0_dp, subm_tmp1, 'N')
333 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
334 2 : 1.0_dp, subm_tmp1, 'T')
335 :
336 : ! 12. TMP7=tr(T).KS.T.SigInv
337 : CALL dbcsr_create(matrix_tmp7, &
338 : template=almo_scf_env%matrix_sigma_blk(ispin), &
339 2 : matrix_type=dbcsr_type_no_symmetry)
340 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
341 : almo_scf_env%matrix_t(ispin), &
342 : matrix_tmp2, &
343 : 0.0_dp, matrix_tmp7, &
344 2 : filter_eps=eps_multiply)
345 :
346 : ! 13. TMP8=[SigInv.tr(T).KS.T.SigInv]_xx
347 : CALL dbcsr_create(matrix_tmp8, &
348 : template=almo_scf_env%matrix_sigma_blk(ispin), &
349 2 : matrix_type=dbcsr_type_symmetric)
350 2 : CALL dbcsr_copy(matrix_tmp8, almo_scf_env%matrix_sigma_blk(ispin))
351 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
352 : almo_scf_env%matrix_sigma_inv(ispin), &
353 : matrix_tmp7, &
354 : 0.0_dp, matrix_tmp8, &
355 : retain_sparsity=.TRUE., &
356 2 : filter_eps=eps_multiply)
357 2 : CALL dbcsr_release(matrix_tmp7)
358 :
359 : ! 13. TMP9=[S.T]_xx
360 : CALL dbcsr_create(matrix_tmp9, &
361 : template=almo_scf_env%matrix_t(ispin), &
362 2 : matrix_type=dbcsr_type_no_symmetry)
363 2 : CALL dbcsr_copy(matrix_tmp9, almo_scf_env%quench_t(ispin))
364 2 : CALL dbcsr_copy(matrix_tmp9, matrix_tmp1, keep_sparsity=.TRUE.)
365 :
366 : ! 14. TMP3=TMP9.TMP8=[S.T]_xx.[SigInv.tr(T).KS.T.SigInv]_xx
367 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
368 : matrix_tmp9, &
369 : matrix_tmp8, &
370 : 0.0_dp, matrix_tmp3, &
371 2 : filter_eps=eps_multiply)
372 2 : CALL dbcsr_release(matrix_tmp8)
373 2 : CALL dbcsr_release(matrix_tmp9)
374 :
375 : ! 15. KS_xx=KS_xx+[S.T]_xx.[SigInv.tr(T).KS.T.SigInv]_xx.[tr(T).S]_xx
376 : CALL construct_submatrices( &
377 : matrix_tmp3, &
378 : subm_tmp2, &
379 : almo_scf_env%quench_t(ispin), &
380 : almo_scf_env%domain_map(ispin), &
381 : almo_scf_env%cpu_of_domain, &
382 2 : select_row)
383 : CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
384 2 : subm_tmp3, 0.0_dp, subm_tmp1)
385 : CALL add_submatrices(1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
386 2 : 1.0_dp, subm_tmp1, 'N')
387 :
388 : !!!!!!! use intermediate matrices to get the error vector !!!!!!!
389 : !!!!!!! make sure s_blk_sqrt and its inverse exist (i.e. we use diag algorithm)
390 : !CPPrecondition(almo_scf_env%almo_update_algorithm.eq.almo_scf_diag,cp_failure_level,routineP,failure)
391 : !! tmp_err = (1-S.T_blk.SigInv.tr(T_blk)).F.T_blk.SigInv
392 : !CALL dbcsr_init(matrix_tmp_err)
393 : !CALL dbcsr_create(matrix_tmp_err,&
394 : ! template=almo_scf_env%matrix_t(ispin))
395 : !CALL dbcsr_copy(matrix_tmp_err,&
396 : ! matrix_tmp2)
397 : !CALL dbcsr_add(matrix_tmp_err,matrix_tmp3,&
398 : ! 1.0_dp,-1.0_dp)
399 : !! err_blk = tmp_err.tr(T_blk)
400 : !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
401 : ! almo_scf_env%matrix_s_blk_sqrt(1))
402 : !CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp_err,&
403 : ! almo_scf_env%matrix_t(ispin),&
404 : ! 0.0_dp, almo_scf_env%matrix_err_blk(ispin),&
405 : ! retain_sparsity=.TRUE.,&
406 : ! filter_eps=eps_multiply)
407 : !CALL dbcsr_release(matrix_tmp_err)
408 : !! bring to the orthogonal basis
409 : !! err_blk = (S_blk^-1/2).err_blk.(S_blk^1/2)
410 : !CALL dbcsr_init(matrix_tmp_err)
411 : !CALL dbcsr_create(matrix_tmp_err,&
412 : ! template=almo_scf_env%matrix_err_blk(ispin))
413 : !CALL dbcsr_multiply("N", "N", 1.0_dp,&
414 : ! almo_scf_env%matrix_err_blk(ispin),&
415 : ! almo_scf_env%matrix_s_blk_sqrt(1),&
416 : ! 0.0_dp, matrix_tmp_err,&
417 : ! filter_eps=eps_multiply)
418 : !CALL dbcsr_multiply("N", "N", 1.0_dp,&
419 : ! almo_scf_env%matrix_s_blk_sqrt_inv(1),&
420 : ! matrix_tmp_err,&
421 : ! 0.0_dp, almo_scf_env%matrix_err_blk(ispin),&
422 : ! filter_eps=eps_multiply)
423 : !! subtract transpose
424 : !CALL dbcsr_transposed(matrix_tmp_err,&
425 : ! almo_scf_env%matrix_err_blk(ispin))
426 : !CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin),&
427 : ! matrix_tmp_err,&
428 : ! 1.0_dp,-1.0_dp)
429 : !CALL dbcsr_release(matrix_tmp_err)
430 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
431 :
432 2 : CALL release_submatrices(subm_tmp3)
433 2 : CALL release_submatrices(subm_tmp2)
434 2 : CALL release_submatrices(subm_tmp1)
435 12 : DEALLOCATE (subm_tmp3)
436 12 : DEALLOCATE (subm_tmp2)
437 12 : DEALLOCATE (subm_tmp1)
438 2 : CALL dbcsr_release(matrix_tmp3)
439 2 : CALL dbcsr_release(matrix_tmp2)
440 6 : CALL dbcsr_release(matrix_tmp1)
441 :
442 : END DO ! spins
443 :
444 2 : CALL timestop(handle)
445 :
446 4 : END SUBROUTINE almo_scf_ks_to_ks_xx
447 :
448 : ! **************************************************************************************************
449 : !> \brief computes the projected KS from the total KS matrix
450 : !> also computes the DIIS error vector as a by-product
451 : !> \param almo_scf_env ...
452 : !> \par History
453 : !> 2011.06 created [Rustam Z Khaliullin]
454 : !> \author Rustam Z Khaliullin
455 : ! **************************************************************************************************
456 424 : SUBROUTINE almo_scf_ks_to_ks_blk(almo_scf_env)
457 :
458 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
459 :
460 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_to_ks_blk'
461 :
462 : INTEGER :: handle, ispin
463 : REAL(KIND=dp) :: eps_multiply
464 : TYPE(dbcsr_type) :: matrix_tmp1, matrix_tmp2, matrix_tmp3, matrix_tmp4, matrix_tmp5, &
465 : matrix_tmp6, matrix_tmp7, matrix_tmp8, matrix_tmp9, matrix_tmp_err
466 :
467 424 : CALL timeset(routineN, handle)
468 :
469 424 : eps_multiply = almo_scf_env%eps_filter
470 :
471 848 : DO ispin = 1, almo_scf_env%nspins
472 :
473 : ! 1. TMP1=KS.T_blk
474 : ! Cost: NOn
475 : !matrix_tmp1 = create NxO, full
476 : CALL dbcsr_create(matrix_tmp1, &
477 424 : template=almo_scf_env%matrix_t(ispin))
478 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks(ispin), &
479 : almo_scf_env%matrix_t_blk(ispin), &
480 : 0.0_dp, matrix_tmp1, &
481 424 : filter_eps=eps_multiply)
482 : ! 2. TMP2=TMP1.SigInv=KS.T_blk.SigInv
483 : ! Cost: NOO
484 : !matrix_tmp2 = create NxO, full
485 : CALL dbcsr_create(matrix_tmp2, &
486 424 : template=almo_scf_env%matrix_t(ispin))
487 : CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
488 : almo_scf_env%matrix_sigma_inv(ispin), &
489 : 0.0_dp, matrix_tmp2, &
490 424 : filter_eps=eps_multiply)
491 :
492 : !!!!!! use intermediate matrices to get the error vector !!!!!!!
493 : !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
494 : ! almo_scf_env%matrix_t_blk(ispin))
495 : !CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin),&
496 : ! matrix_tmp2,&
497 : ! keep_sparsity=.TRUE.)
498 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
499 :
500 : ! 3. TMP1=S.T_blk
501 : ! Cost: NOn
502 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s(1), &
503 : almo_scf_env%matrix_t_blk(ispin), &
504 : 0.0_dp, matrix_tmp1, &
505 424 : filter_eps=eps_multiply)
506 :
507 : ! 4. TMP4_blk=TMP2.tr(TMP1)=KS.T_blk.SigInv.tr(T_blk).S
508 : ! Cost: NnO
509 : !matrix_tmp4 = create NxN, blk
510 : CALL dbcsr_create(matrix_tmp4, &
511 : template=almo_scf_env%matrix_s_blk(1), &
512 424 : matrix_type=dbcsr_type_no_symmetry)
513 424 : CALL dbcsr_copy(matrix_tmp4, almo_scf_env%matrix_s_blk(1))
514 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp2, &
515 : matrix_tmp1, &
516 : 0.0_dp, matrix_tmp4, &
517 : retain_sparsity=.TRUE., &
518 424 : filter_eps=eps_multiply)
519 :
520 : ! 5. KS_blk=KS_blk-TMP4_blk
521 : CALL dbcsr_copy(almo_scf_env%matrix_ks_blk(ispin), &
522 424 : almo_scf_env%matrix_ks(ispin), keep_sparsity=.TRUE.)
523 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), &
524 : matrix_tmp4, &
525 424 : 1.0_dp, -1.0_dp)
526 :
527 : ! 6. TMP5_blk=tr(TMP4_blk)
528 : ! KS_blk=KS_blk-tr(TMP4_blk)
529 : !matrix_tmp5 = create NxN, blk
530 : CALL dbcsr_create(matrix_tmp5, &
531 : template=almo_scf_env%matrix_s_blk(1), &
532 424 : matrix_type=dbcsr_type_no_symmetry)
533 424 : CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
534 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
535 424 : 1.0_dp, -1.0_dp)
536 :
537 : ! 7. TMP3=tr(T_blk).TMP2=tr(T_blk).KS.T_blk.SigInv
538 : ! Cost: OOn
539 : !matrix_tmp3 = create OxO, full
540 : CALL dbcsr_create(matrix_tmp3, &
541 : template=almo_scf_env%matrix_sigma_inv(ispin), &
542 424 : matrix_type=dbcsr_type_no_symmetry)
543 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
544 : almo_scf_env%matrix_t_blk(ispin), &
545 : matrix_tmp2, &
546 : 0.0_dp, matrix_tmp3, &
547 424 : filter_eps=eps_multiply)
548 :
549 : ! 8. TMP6=SigInv.TMP3=SigInv.tr(T_blk).KS.T_blk.SigInv
550 : ! Cost: OOO
551 : !matrix_tmp6 = create OxO, full
552 : CALL dbcsr_create(matrix_tmp6, &
553 : template=almo_scf_env%matrix_sigma_inv(ispin), &
554 424 : matrix_type=dbcsr_type_no_symmetry)
555 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
556 : almo_scf_env%matrix_sigma_inv(ispin), &
557 : matrix_tmp3, &
558 : 0.0_dp, matrix_tmp6, &
559 424 : filter_eps=eps_multiply)
560 :
561 : ! 9. TMP3=TMP1.TMP6=S.T_blk.SigInv.tr(T_blk).KS.T_blk.SigInv
562 : ! Cost: NOO
563 : !matrix_tmp3 = re-create NxO, full
564 424 : CALL dbcsr_release(matrix_tmp3)
565 : CALL dbcsr_create(matrix_tmp3, &
566 424 : template=almo_scf_env%matrix_t(ispin))
567 : CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp1, &
568 : matrix_tmp6, &
569 : 0.0_dp, matrix_tmp3, &
570 424 : filter_eps=eps_multiply)
571 :
572 : !!!!!! use intermediate matrices to get the error vector !!!!!!!
573 : !CALL dbcsr_init(matrix_tmp_err)
574 : !CALL dbcsr_create(matrix_tmp_err,&
575 : ! template=almo_scf_env%matrix_t_blk(ispin))
576 : !CALL dbcsr_copy(matrix_tmp_err,&
577 : ! almo_scf_env%matrix_t_blk(ispin))
578 : !CALL dbcsr_copy(matrix_tmp_err,matrix_tmp3,&
579 : ! keep_sparsity=.TRUE.)
580 : !CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin),matrix_tmp_err,&
581 : ! 1.0_dp,-1.0_dp)
582 : !CALL dbcsr_release(matrix_tmp_err)
583 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
584 :
585 : !!!!!! use intermediate matrices to get the error vector !!!!!!!
586 : !!!!!! make sure s_blk_sqrt and its inverse exist (i.e. we use diag algorithm)
587 424 : CPASSERT(almo_scf_env%almo_update_algorithm .EQ. almo_scf_diag)
588 : ! tmp_err = (1-S.T_blk.SigInv.tr(T_blk)).F.T_blk.SigInv
589 : CALL dbcsr_create(matrix_tmp_err, &
590 424 : template=almo_scf_env%matrix_t_blk(ispin))
591 : CALL dbcsr_copy(matrix_tmp_err, &
592 424 : matrix_tmp2)
593 : CALL dbcsr_add(matrix_tmp_err, matrix_tmp3, &
594 424 : 1.0_dp, -1.0_dp)
595 : ! err_blk = tmp_err.tr(T_blk)
596 : CALL dbcsr_copy(almo_scf_env%matrix_err_blk(ispin), &
597 424 : almo_scf_env%matrix_s_blk_sqrt(1))
598 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp_err, &
599 : almo_scf_env%matrix_t_blk(ispin), &
600 : 0.0_dp, almo_scf_env%matrix_err_blk(ispin), &
601 : retain_sparsity=.TRUE., &
602 424 : filter_eps=eps_multiply)
603 424 : CALL dbcsr_release(matrix_tmp_err)
604 : ! bring to the orthogonal basis
605 : ! err_blk = (S_blk^-1/2).err_blk.(S_blk^1/2)
606 : CALL dbcsr_create(matrix_tmp_err, &
607 424 : template=almo_scf_env%matrix_err_blk(ispin))
608 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
609 : almo_scf_env%matrix_err_blk(ispin), &
610 : almo_scf_env%matrix_s_blk_sqrt(1), &
611 : 0.0_dp, matrix_tmp_err, &
612 424 : filter_eps=eps_multiply)
613 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
614 : almo_scf_env%matrix_s_blk_sqrt_inv(1), &
615 : matrix_tmp_err, &
616 : 0.0_dp, almo_scf_env%matrix_err_blk(ispin), &
617 424 : filter_eps=eps_multiply)
618 :
619 : ! subtract transpose
620 : CALL dbcsr_transposed(matrix_tmp_err, &
621 424 : almo_scf_env%matrix_err_blk(ispin))
622 : CALL dbcsr_add(almo_scf_env%matrix_err_blk(ispin), &
623 : matrix_tmp_err, &
624 424 : 1.0_dp, -1.0_dp)
625 424 : CALL dbcsr_release(matrix_tmp_err)
626 : !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
627 :
628 : ! later we will need only the blk version of TMP6
629 : ! create it here and release TMP6
630 : !matrix_tmp9 = create OxO, blk
631 : !matrix_tmp9 = copy data from matrix_tmp6, retain sparsity
632 : !matrix_tmp6 = release
633 : CALL dbcsr_create(matrix_tmp9, &
634 : template=almo_scf_env%matrix_sigma_blk(ispin), &
635 424 : matrix_type=dbcsr_type_no_symmetry)
636 424 : CALL dbcsr_copy(matrix_tmp9, almo_scf_env%matrix_sigma_blk(ispin))
637 424 : CALL dbcsr_copy(matrix_tmp9, matrix_tmp6, keep_sparsity=.TRUE.)
638 424 : CALL dbcsr_release(matrix_tmp6)
639 :
640 : !10. KS_blk=KS_blk+TMP3.tr(TMP1)=
641 : ! =KS_blk+S.T_blk.SigInv.tr.(T_blk).KS.T_blk.SigInv.tr(T_blk).S
642 : ! Cost: NnO
643 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp3, &
644 : matrix_tmp1, &
645 : 1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
646 : retain_sparsity=.TRUE., &
647 424 : filter_eps=eps_multiply)
648 :
649 : ! 11. TMP4_blk=TMP7_blk.tr(TMP8_blk)
650 : ! Cost: Nnn
651 : !matrix_tmp7 = create NxO, blk
652 : !matrix_tmp7 = copy data from matrix_tmp3, retain sparsity
653 : !matrix_tmp3 = release
654 : !matrix_tmp8 = create NxO, blk
655 : !matrix_tmp8 = copy data from matrix_tmp1, retain sparsity
656 : !matrix_tmp1 = release
657 : CALL dbcsr_create(matrix_tmp7, &
658 424 : template=almo_scf_env%matrix_t_blk(ispin))
659 : ! transfer only the ALMO blocks from tmp3 into tmp7:
660 : ! first, copy t_blk into tmp7 to transfer the blk structure,
661 : ! then copy tmp3 into tmp7 with retain_sparsity
662 424 : CALL dbcsr_copy(matrix_tmp7, almo_scf_env%matrix_t_blk(ispin))
663 424 : CALL dbcsr_copy(matrix_tmp7, matrix_tmp3, keep_sparsity=.TRUE.)
664 424 : CALL dbcsr_release(matrix_tmp3)
665 : ! do the same for tmp1->tmp8
666 : CALL dbcsr_create(matrix_tmp8, &
667 424 : template=almo_scf_env%matrix_t_blk(ispin))
668 424 : CALL dbcsr_copy(matrix_tmp8, almo_scf_env%matrix_t_blk(ispin))
669 424 : CALL dbcsr_copy(matrix_tmp8, matrix_tmp1, keep_sparsity=.TRUE.)
670 424 : CALL dbcsr_release(matrix_tmp1)
671 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
672 : matrix_tmp8, &
673 : 0.0_dp, matrix_tmp4, &
674 : filter_eps=eps_multiply, &
675 424 : retain_sparsity=.TRUE.)
676 :
677 : ! 12. KS_blk=KS_blk-TMP4_blk
678 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp4, &
679 424 : 1.0_dp, -1.0_dp)
680 :
681 : ! 13. TMP5_blk=tr(TMP5_blk)
682 : ! KS_blk=KS_blk-tr(TMP4_blk)
683 424 : CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
684 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
685 424 : 1.0_dp, -1.0_dp)
686 :
687 : ! 14. TMP4_blk=TMP7_blk.tr(TMP8_blk)
688 : ! Cost: Nnn
689 424 : CALL dbcsr_copy(matrix_tmp7, matrix_tmp2, keep_sparsity=.TRUE.)
690 424 : CALL dbcsr_release(matrix_tmp2)
691 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
692 : matrix_tmp8, &
693 : 0.0_dp, matrix_tmp4, &
694 : retain_sparsity=.TRUE., &
695 424 : filter_eps=eps_multiply)
696 : ! 15. KS_blk=KS_blk+TMP4_blk
697 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp4, &
698 424 : 1.0_dp, 1.0_dp)
699 :
700 : ! 16. KS_blk=KS_blk+tr(TMP4_blk)
701 424 : CALL dbcsr_transposed(matrix_tmp5, matrix_tmp4)
702 424 : CALL dbcsr_release(matrix_tmp4)
703 : CALL dbcsr_add(almo_scf_env%matrix_ks_blk(ispin), matrix_tmp5, &
704 424 : 1.0_dp, 1.0_dp)
705 424 : CALL dbcsr_release(matrix_tmp5)
706 :
707 : ! 17. TMP10_blk=TMP8_blk.TMP9_blk
708 : ! Cost: Noo
709 : CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_tmp8, &
710 : matrix_tmp9, &
711 : 0.0_dp, matrix_tmp7, &
712 : retain_sparsity=.TRUE., &
713 424 : filter_eps=eps_multiply)
714 424 : CALL dbcsr_release(matrix_tmp9)
715 :
716 : ! 18. KS_blk=TMP7_blk.tr(TMP8_blk)
717 : ! Cost: Nno
718 : CALL dbcsr_multiply("N", "T", 1.0_dp, matrix_tmp7, &
719 : matrix_tmp8, &
720 : 1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
721 : retain_sparsity=.TRUE., &
722 424 : filter_eps=eps_multiply)
723 424 : CALL dbcsr_release(matrix_tmp7)
724 848 : CALL dbcsr_release(matrix_tmp8)
725 :
726 : END DO ! spins
727 :
728 424 : CALL timestop(handle)
729 :
730 424 : END SUBROUTINE almo_scf_ks_to_ks_blk
731 :
732 : ! **************************************************************************************************
733 : !> \brief ALMOs by diagonalizing the KS domain submatrices
734 : !> computes both the occupied and virtual orbitals
735 : !> \param almo_scf_env ...
736 : !> \par History
737 : !> 2013.03 created [Rustam Z Khaliullin]
738 : !> 2018.09 smearing support [Ruben Staub]
739 : !> \author Rustam Z Khaliullin
740 : ! **************************************************************************************************
741 2 : SUBROUTINE almo_scf_ks_xx_to_tv_xx(almo_scf_env)
742 :
743 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
744 :
745 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_xx_to_tv_xx'
746 :
747 : INTEGER :: handle, iblock_size, idomain, info, &
748 : ispin, lwork, ndomains
749 2 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, work
750 2 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: data_copy
751 : TYPE(domain_submatrix_type), ALLOCATABLE, &
752 2 : DIMENSION(:) :: subm_ks_xx_orthog, subm_t, subm_tmp
753 :
754 2 : CALL timeset(routineN, handle)
755 :
756 2 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular .AND. &
757 : almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
758 0 : CPABORT("a domain must be located entirely on a CPU")
759 : END IF
760 :
761 2 : ndomains = almo_scf_env%ndomains
762 16 : ALLOCATE (subm_tmp(ndomains))
763 14 : ALLOCATE (subm_ks_xx_orthog(ndomains))
764 14 : ALLOCATE (subm_t(ndomains))
765 :
766 4 : DO ispin = 1, almo_scf_env%nspins
767 :
768 2 : CALL init_submatrices(subm_tmp)
769 2 : CALL init_submatrices(subm_ks_xx_orthog)
770 :
771 : ! TRY: project out T0-occupied space for each domain
772 : ! F=(1-R_du).F.(1-tr(R_du))
773 : !CALL copy_submatrices(almo_scf_env%domain_ks_xx(:,ispin),&
774 : ! subm_ks_xx_orthog,copy_data=.TRUE.)
775 : !CALL multiply_submatrices('N','N',1.0_dp,&
776 : ! almo_scf_env%domain_r_down_up(:,ispin),&
777 : ! almo_scf_env%domain_ks_xx(:,ispin),0.0_dp,subm_tmp)
778 : !CALL add_submatrices(1.0_dp,subm_ks_xx_orthog,-1.0_dp,subm_tmp,'N')
779 : !CALL add_submatrices(1.0_dp,subm_ks_xx_orthog,-1.0_dp,subm_tmp,'T')
780 : !!CALL multiply_submatrices('N','T',1.0_dp,subm_tmp,&
781 : !! almo_scf_env%domain_r_down_up(:,ispin),&
782 : !! 1.0_dp,subm_ks_xx_orthog)
783 :
784 : ! convert blocks to the orthogonal basis set
785 : ! TRY: replace one multiply
786 : !CALL multiply_submatrices('N','N',1.0_dp,subm_ks_xx_orthog,&
787 : ! almo_scf_env%domain_s_sqrt_inv(:,ispin),0.0_dp,subm_tmp)
788 : CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_ks_xx(:, ispin), &
789 2 : almo_scf_env%domain_s_sqrt_inv(:, ispin), 0.0_dp, subm_tmp)
790 : CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_s_sqrt_inv(:, ispin), &
791 2 : subm_tmp, 0.0_dp, subm_ks_xx_orthog)
792 2 : CALL release_submatrices(subm_tmp)
793 :
794 : ! create temporary matrices for occupied and virtual orbitals
795 : ! represented in the orthogonalized basis set
796 2 : CALL init_submatrices(subm_t)
797 :
798 : ! loop over domains - perform diagonalization
799 12 : DO idomain = 1, ndomains
800 :
801 : ! check if the submatrix exists
802 12 : IF (subm_ks_xx_orthog(idomain)%domain .GT. 0) THEN
803 :
804 5 : iblock_size = subm_ks_xx_orthog(idomain)%nrows
805 :
806 : ! Prepare data
807 15 : ALLOCATE (eigenvalues(iblock_size))
808 20 : ALLOCATE (data_copy(iblock_size, iblock_size))
809 31607 : data_copy(:, :) = subm_ks_xx_orthog(idomain)%mdata(:, :)
810 :
811 : ! Query the optimal workspace for dsyev
812 5 : LWORK = -1
813 5 : ALLOCATE (WORK(MAX(1, LWORK)))
814 5 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
815 5 : LWORK = INT(WORK(1))
816 5 : DEALLOCATE (WORK)
817 :
818 : ! Allocate the workspace and solve the eigenproblem
819 15 : ALLOCATE (WORK(MAX(1, LWORK)))
820 5 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
821 5 : IF (INFO .NE. 0) CPABORT("DSYEV failed")
822 :
823 : ! Copy occupied eigenvectors
824 5 : IF (almo_scf_env%domain_t(idomain, ispin)%ncols .NE. &
825 : almo_scf_env%nocc_of_domain(idomain, ispin)) THEN
826 0 : CPABORT("wrong domain structure")
827 : END IF
828 : CALL copy_submatrices(almo_scf_env%domain_t(idomain, ispin), &
829 5 : subm_t(idomain), .FALSE.)
830 : CALL copy_submatrix_data(data_copy(:, 1:almo_scf_env%nocc_of_domain(idomain, ispin)), &
831 5 : subm_t(idomain))
832 : !! Copy occupied eigenvalues if smearing requested
833 5 : IF (almo_scf_env%smear) THEN
834 : almo_scf_env%mo_energies(1 + SUM(almo_scf_env%nocc_of_domain(:idomain - 1, ispin)) &
835 : :SUM(almo_scf_env%nocc_of_domain(:idomain, ispin)), ispin) &
836 0 : = eigenvalues(1:almo_scf_env%nocc_of_domain(idomain, ispin))
837 : END IF
838 :
839 5 : DEALLOCATE (WORK)
840 5 : DEALLOCATE (data_copy)
841 5 : DEALLOCATE (eigenvalues)
842 :
843 : END IF ! submatrix for the domain exists
844 :
845 : END DO ! loop over domains
846 :
847 2 : CALL release_submatrices(subm_ks_xx_orthog)
848 :
849 : ! convert orbitals to the AO basis set (from orthogonalized AOs)
850 : CALL multiply_submatrices('N', 'N', 1.0_dp, almo_scf_env%domain_s_sqrt_inv(:, ispin), &
851 2 : subm_t, 0.0_dp, almo_scf_env%domain_t(:, ispin))
852 2 : CALL release_submatrices(subm_t)
853 :
854 : ! convert domain orbitals to a dbcsr matrix
855 : CALL construct_dbcsr_from_submatrices( &
856 : almo_scf_env%matrix_t(ispin), &
857 : almo_scf_env%domain_t(:, ispin), &
858 2 : almo_scf_env%quench_t(ispin))
859 : CALL dbcsr_filter(almo_scf_env%matrix_t(ispin), &
860 4 : almo_scf_env%eps_filter)
861 :
862 : ! TRY: add T0 component
863 : !!CALL dbcsr_add(almo_scf_env%matrix_t(ispin),&
864 : !! almo_scf_env%matrix_t_blk(ispin),1.0_dp,1.0_dp)
865 :
866 : END DO ! spins
867 :
868 12 : DEALLOCATE (subm_tmp)
869 12 : DEALLOCATE (subm_ks_xx_orthog)
870 12 : DEALLOCATE (subm_t)
871 :
872 2 : CALL timestop(handle)
873 :
874 4 : END SUBROUTINE almo_scf_ks_xx_to_tv_xx
875 :
876 : ! **************************************************************************************************
877 : !> \brief computes ALMOs by diagonalizing the projected blocked KS matrix
878 : !> uses the diagonalization code for blocks
879 : !> computes both the occupied and virtual orbitals
880 : !> \param almo_scf_env ...
881 : !> \par History
882 : !> 2011.07 created [Rustam Z Khaliullin]
883 : !> 2018.09 smearing support [Ruben Staub]
884 : !> \author Rustam Z Khaliullin
885 : ! **************************************************************************************************
886 348 : SUBROUTINE almo_scf_ks_blk_to_tv_blk(almo_scf_env)
887 :
888 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
889 :
890 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_ks_blk_to_tv_blk'
891 :
892 : INTEGER :: handle, iblock_col, iblock_row, &
893 : iblock_size, info, ispin, lwork, &
894 : nocc_of_block, nvirt_of_block, orbital
895 : LOGICAL :: block_needed
896 348 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, work
897 348 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: data_copy, new_block
898 348 : REAL(kind=dp), DIMENSION(:, :), POINTER :: data_p
899 : TYPE(dbcsr_iterator_type) :: iter
900 : TYPE(dbcsr_type) :: matrix_ks_blk_orthog, &
901 : matrix_t_blk_orthog, matrix_tmp, &
902 : matrix_v_blk_orthog
903 :
904 348 : CALL timeset(routineN, handle)
905 :
906 348 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular .AND. &
907 : almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
908 0 : CPABORT("a domain must be located entirely on a CPU")
909 : END IF
910 :
911 696 : DO ispin = 1, almo_scf_env%nspins
912 :
913 : CALL dbcsr_create(matrix_tmp, template=almo_scf_env%matrix_ks_blk(ispin), &
914 348 : matrix_type=dbcsr_type_no_symmetry)
915 : CALL dbcsr_create(matrix_ks_blk_orthog, template=almo_scf_env%matrix_ks_blk(ispin), &
916 348 : matrix_type=dbcsr_type_no_symmetry)
917 :
918 : ! convert blocks to the orthogonal basis set
919 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_ks_blk(ispin), &
920 : almo_scf_env%matrix_s_blk_sqrt_inv(1), 0.0_dp, matrix_tmp, &
921 348 : filter_eps=almo_scf_env%eps_filter)
922 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
923 : matrix_tmp, 0.0_dp, matrix_ks_blk_orthog, &
924 348 : filter_eps=almo_scf_env%eps_filter)
925 :
926 348 : CALL dbcsr_release(matrix_tmp)
927 :
928 : ! create temporary matrices for occupied and virtual orbitals
929 : ! represented in the orthogonalized AOs basis set
930 348 : CALL dbcsr_create(matrix_t_blk_orthog, template=almo_scf_env%matrix_t_blk(ispin))
931 348 : CALL dbcsr_create(matrix_v_blk_orthog, template=almo_scf_env%matrix_v_full_blk(ispin))
932 348 : CALL dbcsr_work_create(matrix_t_blk_orthog, work_mutable=.TRUE.)
933 348 : CALL dbcsr_work_create(matrix_v_blk_orthog, work_mutable=.TRUE.)
934 :
935 348 : CALL dbcsr_work_create(almo_scf_env%matrix_eoo(ispin), work_mutable=.TRUE.)
936 348 : CALL dbcsr_work_create(almo_scf_env%matrix_evv_full(ispin), work_mutable=.TRUE.)
937 :
938 348 : CALL dbcsr_iterator_start(iter, matrix_ks_blk_orthog)
939 :
940 1624 : DO WHILE (dbcsr_iterator_blocks_left(iter))
941 1276 : CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
942 :
943 1276 : IF (iblock_row .NE. iblock_col) THEN
944 0 : CPABORT("off-diagonal block found")
945 : END IF
946 :
947 1276 : block_needed = .TRUE.
948 1276 : IF (almo_scf_env%nocc_of_domain(iblock_col, ispin) .EQ. 0 .AND. &
949 : almo_scf_env%nvirt_of_domain(iblock_col, ispin) .EQ. 0) THEN
950 : block_needed = .FALSE.
951 : END IF
952 :
953 348 : IF (block_needed) THEN
954 :
955 : ! Prepare data
956 3828 : ALLOCATE (eigenvalues(iblock_size))
957 5104 : ALLOCATE (data_copy(iblock_size, iblock_size))
958 382688 : data_copy(:, :) = data_p(:, :)
959 :
960 : ! Query the optimal workspace for dsyev
961 1276 : LWORK = -1
962 1276 : ALLOCATE (WORK(MAX(1, LWORK)))
963 1276 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
964 1276 : LWORK = INT(WORK(1))
965 1276 : DEALLOCATE (WORK)
966 :
967 : ! Allocate the workspace and solve the eigenproblem
968 3828 : ALLOCATE (WORK(MAX(1, LWORK)))
969 1276 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
970 1276 : IF (INFO .NE. 0) CPABORT("DSYEV failed")
971 :
972 : !!! RZK-warning !!!
973 : !!! IT IS EXTREMELY IMPORTANT THAT THE DIAGONAL BLOCKS OF THE !!!
974 : !!! FOLLOWING MATRICES ARE LOCATED ON THE SAME NODES WITH !!!
975 : !!! THE CORRESPONDING DIAGONAL BLOCKS OF THE FOCK MATRIX: !!!
976 : !!! T, V, E_o, E_v
977 :
978 : ! copy eigenvectors into two dbcsr matrices - occupied and virtuals
979 1276 : nocc_of_block = almo_scf_env%nocc_of_domain(iblock_col, ispin)
980 1276 : IF (nocc_of_block .GT. 0) THEN
981 : CALL dbcsr_put_block(matrix_t_blk_orthog, iblock_row, iblock_col, &
982 1252 : block=data_copy(:, 1:nocc_of_block))
983 : ! copy eigenvalues into diagonal dbcsr matrix - Eoo
984 5008 : ALLOCATE (new_block(nocc_of_block, nocc_of_block))
985 32156 : new_block(:, :) = 0.0_dp
986 6358 : DO orbital = 1, nocc_of_block
987 6358 : new_block(orbital, orbital) = eigenvalues(orbital)
988 : END DO
989 1252 : CALL dbcsr_put_block(almo_scf_env%matrix_eoo(ispin), iblock_row, iblock_col, new_block)
990 1252 : DEALLOCATE (new_block)
991 : !! Retrieve occupied MOs energies for smearing purpose, if requested
992 : !! RS-WARNING: Hack to retrieve the occupied energies, since matrix_eoo seems to be ill-defined
993 : !! for multiprocessing (any idea for fix?)
994 : !! RS-WARNING: This section is not suitable for parallel run !!!
995 : !! (but usually fails less than retrieving the diagonal of matrix_eoo)
996 : !! RS-WARNING: This method will likely keep the energies of the initial guess if run in parallel
997 : !! (which is still a reasonable smearing in most cases...)
998 1252 : IF (almo_scf_env%smear) THEN
999 292 : DO orbital = 1, nocc_of_block
1000 : almo_scf_env%mo_energies(SUM(almo_scf_env%nocc_of_domain(:iblock_row - 1, ispin)) + orbital, &
1001 348 : ispin) = eigenvalues(orbital)
1002 : END DO
1003 : END IF
1004 : END IF
1005 :
1006 : ! now virtuals
1007 1276 : nvirt_of_block = almo_scf_env%nvirt_of_domain(iblock_col, ispin)
1008 1276 : IF (nvirt_of_block .GT. 0) THEN
1009 : CALL dbcsr_put_block(matrix_v_blk_orthog, iblock_row, iblock_col, &
1010 1276 : block=data_copy(:, (nocc_of_block + 1):(nocc_of_block + nvirt_of_block)))
1011 : ! virtual energies
1012 5104 : ALLOCATE (new_block(nvirt_of_block, nvirt_of_block))
1013 235160 : new_block(:, :) = 0.0_dp
1014 13896 : DO orbital = 1, nvirt_of_block
1015 13896 : new_block(orbital, orbital) = eigenvalues(nocc_of_block + orbital)
1016 : END DO
1017 1276 : CALL dbcsr_put_block(almo_scf_env%matrix_evv_full(ispin), iblock_row, iblock_col, new_block)
1018 1276 : DEALLOCATE (new_block)
1019 : END IF
1020 :
1021 1276 : DEALLOCATE (WORK)
1022 1276 : DEALLOCATE (data_copy)
1023 1276 : DEALLOCATE (eigenvalues)
1024 :
1025 : END IF
1026 :
1027 : END DO
1028 348 : CALL dbcsr_iterator_stop(iter)
1029 :
1030 348 : CALL dbcsr_finalize(matrix_t_blk_orthog)
1031 348 : CALL dbcsr_finalize(matrix_v_blk_orthog)
1032 348 : CALL dbcsr_finalize(almo_scf_env%matrix_eoo(ispin))
1033 348 : CALL dbcsr_finalize(almo_scf_env%matrix_evv_full(ispin))
1034 :
1035 : !! RS-WARNING: When matrix_eoo will be well-defined with multiprocessing,
1036 : !! the following should be the preferred way to retrieve the occupied energies:
1037 : !! Retrieve occupied MOs energies for smearing purpose, if requested
1038 : !! IF (almo_scf_env%smear) THEN
1039 : !! CALL dbcsr_get_diag(almo_scf_env%matrix_eoo(ispin), almo_scf_env%mo_energies(:, ispin))
1040 : !! END IF
1041 :
1042 348 : CALL dbcsr_filter(matrix_t_blk_orthog, almo_scf_env%eps_filter)
1043 348 : CALL dbcsr_filter(matrix_v_blk_orthog, almo_scf_env%eps_filter)
1044 :
1045 348 : CALL dbcsr_release(matrix_ks_blk_orthog)
1046 :
1047 : ! convert orbitals to the AO basis set (from orthogonalized AOs)
1048 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
1049 : matrix_t_blk_orthog, 0.0_dp, almo_scf_env%matrix_t_blk(ispin), &
1050 348 : filter_eps=almo_scf_env%eps_filter)
1051 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk_sqrt_inv(1), &
1052 : matrix_v_blk_orthog, 0.0_dp, almo_scf_env%matrix_v_full_blk(ispin), &
1053 348 : filter_eps=almo_scf_env%eps_filter)
1054 :
1055 348 : CALL dbcsr_release(matrix_t_blk_orthog)
1056 1044 : CALL dbcsr_release(matrix_v_blk_orthog)
1057 :
1058 : END DO ! spins
1059 :
1060 348 : CALL timestop(handle)
1061 :
1062 696 : END SUBROUTINE almo_scf_ks_blk_to_tv_blk
1063 :
1064 : ! **************************************************************************************************
1065 : !> \brief inverts block-diagonal blocks of a dbcsr_matrix
1066 : !> \param matrix_in ...
1067 : !> \param matrix_out ...
1068 : !> \param nocc ...
1069 : !> \par History
1070 : !> 2012.05 created [Rustam Z Khaliullin]
1071 : !> \author Rustam Z Khaliullin
1072 : ! **************************************************************************************************
1073 82 : SUBROUTINE pseudo_invert_diagonal_blk(matrix_in, matrix_out, nocc)
1074 :
1075 : TYPE(dbcsr_type), INTENT(IN) :: matrix_in
1076 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_out
1077 : INTEGER, DIMENSION(:) :: nocc
1078 :
1079 : CHARACTER(LEN=*), PARAMETER :: routineN = 'pseudo_invert_diagonal_blk'
1080 :
1081 : INTEGER :: handle, iblock_col, iblock_row, &
1082 : iblock_size, methodID
1083 82 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: data_copy
1084 82 : REAL(kind=dp), DIMENSION(:, :), POINTER :: data_p
1085 : TYPE(dbcsr_iterator_type) :: iter
1086 :
1087 82 : CALL timeset(routineN, handle)
1088 :
1089 82 : CALL dbcsr_create(matrix_out, template=matrix_in)
1090 82 : CALL dbcsr_work_create(matrix_out, work_mutable=.TRUE.)
1091 :
1092 82 : CALL dbcsr_iterator_readonly_start(iter, matrix_in)
1093 :
1094 423 : DO WHILE (dbcsr_iterator_blocks_left(iter))
1095 :
1096 341 : CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
1097 :
1098 423 : IF (iblock_row == iblock_col) THEN
1099 :
1100 : ! Prepare data
1101 1276 : ALLOCATE (data_copy(iblock_size, iblock_size))
1102 : !data_copy(:,:)=data_p(:,:)
1103 :
1104 : ! 0. Cholesky factorization
1105 : ! 1. Diagonalization
1106 319 : methodID = 1
1107 : CALL pseudo_invert_matrix(data_p, data_copy, iblock_size, &
1108 : methodID, &
1109 : range1=nocc(iblock_row), range2=nocc(iblock_row), &
1110 : !range1_thr,range2_thr,&
1111 319 : shift=1.0E-5_dp)
1112 : !!! IT IS EXTREMELY IMPORTANT THAT THE BLOCKS OF THE "OUT" !!!
1113 : !!! MATRIX ARE DISTRIBUTED AS THE BLOCKS OF THE "IN" MATRIX !!!
1114 :
1115 319 : CALL dbcsr_put_block(matrix_out, iblock_row, iblock_col, data_copy)
1116 319 : DEALLOCATE (data_copy)
1117 : END IF
1118 :
1119 : END DO
1120 82 : CALL dbcsr_iterator_stop(iter)
1121 :
1122 82 : CALL dbcsr_finalize(matrix_out)
1123 :
1124 82 : CALL timestop(handle)
1125 :
1126 164 : END SUBROUTINE pseudo_invert_diagonal_blk
1127 :
1128 : ! **************************************************************************************************
1129 : !> \brief computes occupied ALMOs from the superimposed atomic density blocks
1130 : !> \param almo_scf_env ...
1131 : !> \param ionic ...
1132 : !> \par History
1133 : !> 2011.06 created [Rustam Z Khaliullin]
1134 : !> \author Rustam Z Khaliullin
1135 : ! **************************************************************************************************
1136 60 : SUBROUTINE almo_scf_p_blk_to_t_blk(almo_scf_env, ionic)
1137 :
1138 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
1139 : LOGICAL, INTENT(IN) :: ionic
1140 :
1141 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_p_blk_to_t_blk'
1142 :
1143 : INTEGER :: handle, iblock_col, iblock_row, &
1144 : iblock_size, info, ispin, lwork, &
1145 : nocc_of_block, unit_nr
1146 : LOGICAL :: block_needed
1147 60 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, work
1148 60 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: data_copy
1149 60 : REAL(kind=dp), DIMENSION(:, :), POINTER :: data_p
1150 : TYPE(cp_logger_type), POINTER :: logger
1151 : TYPE(dbcsr_iterator_type) :: iter
1152 : TYPE(dbcsr_type) :: matrix_t_blk_tmp
1153 :
1154 60 : CALL timeset(routineN, handle)
1155 :
1156 : ! get a useful unit_nr
1157 60 : logger => cp_get_default_logger()
1158 60 : IF (logger%para_env%is_source()) THEN
1159 30 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
1160 : ELSE
1161 : unit_nr = -1
1162 : END IF
1163 :
1164 120 : DO ispin = 1, almo_scf_env%nspins
1165 :
1166 120 : IF (ionic) THEN
1167 :
1168 : ! create a temporary matrix to keep the eigenvectors
1169 : CALL dbcsr_create(matrix_t_blk_tmp, &
1170 0 : template=almo_scf_env%matrix_t_blk(ispin))
1171 : CALL dbcsr_work_create(matrix_t_blk_tmp, &
1172 0 : work_mutable=.TRUE.)
1173 :
1174 0 : CALL dbcsr_iterator_start(iter, almo_scf_env%matrix_p_blk(ispin))
1175 0 : DO WHILE (dbcsr_iterator_blocks_left(iter))
1176 0 : CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, data_p, row_size=iblock_size)
1177 :
1178 0 : block_needed = .FALSE.
1179 :
1180 0 : IF (iblock_row == iblock_col) THEN
1181 : block_needed = .TRUE.
1182 : END IF
1183 :
1184 : IF (.NOT. block_needed) THEN
1185 0 : CPABORT("off-diag block found")
1186 : END IF
1187 :
1188 : ! Prepare data
1189 0 : ALLOCATE (eigenvalues(iblock_size))
1190 0 : ALLOCATE (data_copy(iblock_size, iblock_size))
1191 0 : data_copy(:, :) = data_p(:, :)
1192 :
1193 : ! Query the optimal workspace for dsyev
1194 0 : LWORK = -1
1195 0 : ALLOCATE (WORK(MAX(1, LWORK)))
1196 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, &
1197 0 : WORK, LWORK, INFO)
1198 0 : LWORK = INT(WORK(1))
1199 0 : DEALLOCATE (WORK)
1200 :
1201 : ! Allocate the workspace and solve the eigenproblem
1202 0 : ALLOCATE (WORK(MAX(1, LWORK)))
1203 0 : CALL dsyev('V', 'L', iblock_size, data_copy, iblock_size, eigenvalues, WORK, LWORK, INFO)
1204 0 : IF (INFO .NE. 0) THEN
1205 0 : IF (unit_nr > 0) THEN
1206 0 : WRITE (unit_nr, *) 'BLOCK = ', iblock_row
1207 0 : WRITE (unit_nr, *) 'INFO =', INFO
1208 0 : WRITE (unit_nr, *) data_p(:, :)
1209 : END IF
1210 0 : CPABORT("DSYEV failed")
1211 : END IF
1212 :
1213 : !!! IT IS EXTREMELY IMPORTANT THAT THE DIAGONAL BLOCKS OF THE !!!
1214 : !!! P AND T MATRICES ARE LOCATED ON THE SAME NODES !!!
1215 :
1216 : ! copy eigenvectors into two dbcsr matrices - occupied and virtuals
1217 0 : nocc_of_block = almo_scf_env%nocc_of_domain(iblock_col, ispin)
1218 0 : CPASSERT(nocc_of_block > 0)
1219 : CALL dbcsr_put_block(matrix_t_blk_tmp, iblock_row, iblock_col, &
1220 0 : block=data_copy(:, iblock_size - nocc_of_block + 1:))
1221 0 : DEALLOCATE (WORK)
1222 0 : DEALLOCATE (data_copy)
1223 0 : DEALLOCATE (eigenvalues)
1224 :
1225 : END DO
1226 0 : CALL dbcsr_iterator_stop(iter)
1227 :
1228 0 : CALL dbcsr_finalize(matrix_t_blk_tmp)
1229 : CALL dbcsr_filter(matrix_t_blk_tmp, &
1230 0 : almo_scf_env%eps_filter)
1231 : CALL dbcsr_copy(almo_scf_env%matrix_t_blk(ispin), &
1232 0 : matrix_t_blk_tmp)
1233 0 : CALL dbcsr_release(matrix_t_blk_tmp)
1234 :
1235 : ELSE
1236 :
1237 : !! generate a random set of ALMOs
1238 : !! matrix_t_blk should already be initiated to the proper domain structure
1239 : CALL dbcsr_init_random(almo_scf_env%matrix_t_blk(ispin), &
1240 60 : keep_sparsity=.TRUE.)
1241 :
1242 : CALL dbcsr_create(matrix_t_blk_tmp, &
1243 : template=almo_scf_env%matrix_t_blk(ispin), &
1244 60 : matrix_type=dbcsr_type_no_symmetry)
1245 :
1246 : ! use current ALMOs in matrix_t_blk and project them onto the blocked dm
1247 : ! compute T_new = R_blk S_blk T_random
1248 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_s_blk(1), &
1249 : almo_scf_env%matrix_t_blk(ispin), &
1250 : 0.0_dp, matrix_t_blk_tmp, &
1251 60 : filter_eps=almo_scf_env%eps_filter)
1252 :
1253 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1254 : almo_scf_env%matrix_p_blk(ispin), matrix_t_blk_tmp, &
1255 : 0.0_dp, almo_scf_env%matrix_t_blk(ispin), &
1256 60 : filter_eps=almo_scf_env%eps_filter)
1257 :
1258 60 : CALL dbcsr_release(matrix_t_blk_tmp)
1259 :
1260 : END IF
1261 :
1262 : END DO
1263 :
1264 60 : CALL timestop(handle)
1265 :
1266 120 : END SUBROUTINE almo_scf_p_blk_to_t_blk
1267 :
1268 : ! **************************************************************************************************
1269 : !> \brief Apply an occupation-rescaling trick to ALMOs for smearing.
1270 : !> Partially occupied orbitals are considered full and rescaled by SQRT(occupation_number)
1271 : !> (this was designed to be used with smearing only)
1272 : !> \param matrix_t ...
1273 : !> \param mo_energies ...
1274 : !> \param mu_of_domain ...
1275 : !> \param real_ne_of_domain ...
1276 : !> \param spin_kTS ...
1277 : !> \param smear_e_temp ...
1278 : !> \param ndomains ...
1279 : !> \param nocc_of_domain ...
1280 : !> \par History
1281 : !> 2018.09 created [Ruben Staub]
1282 : !> \author Ruben Staub
1283 : ! **************************************************************************************************
1284 40 : SUBROUTINE almo_scf_t_rescaling(matrix_t, mo_energies, mu_of_domain, real_ne_of_domain, &
1285 20 : spin_kTS, smear_e_temp, ndomains, nocc_of_domain)
1286 :
1287 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_t
1288 : REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: mo_energies
1289 : REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: mu_of_domain, real_ne_of_domain
1290 : REAL(KIND=dp), INTENT(INOUT) :: spin_kTS
1291 : REAL(KIND=dp), INTENT(IN) :: smear_e_temp
1292 : INTEGER, INTENT(IN) :: ndomains
1293 : INTEGER, DIMENSION(:), INTENT(IN) :: nocc_of_domain
1294 :
1295 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_t_rescaling'
1296 :
1297 : INTEGER :: handle, idomain, neigenval_used, nmo
1298 : REAL(KIND=dp) :: kTS
1299 20 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: occupation_numbers, rescaling_factors
1300 :
1301 20 : CALL timeset(routineN, handle)
1302 :
1303 : !!
1304 : !! Initialization
1305 : !!
1306 20 : nmo = SIZE(mo_energies)
1307 60 : ALLOCATE (occupation_numbers(nmo))
1308 40 : ALLOCATE (rescaling_factors(nmo))
1309 :
1310 : !!
1311 : !! Set occupation numbers for smearing
1312 : !!
1313 : !! occupation numbers are obtained using Fermi-Dirac smearing with orbital energies stored in mo_energies
1314 : !! nocc_of_domain is the number of partially occupied orbitals, while real_ne_of_domain is the real number of electrons
1315 20 : neigenval_used = 0 !! this is used as an offset to copy sub-arrays
1316 :
1317 : !! Reset electronic entropy term
1318 20 : spin_kTS = 0.0_dp
1319 :
1320 : !! Apply Fermi-Dirac smearing for each domain and store associated occupations for the whole system
1321 60 : DO idomain = 1, ndomains
1322 : CALL FermiFixed(occupation_numbers(1 + neigenval_used:nocc_of_domain(idomain) + neigenval_used), &
1323 : mu_of_domain(idomain), &
1324 : kTS, &
1325 : mo_energies(1 + neigenval_used:nocc_of_domain(idomain) + neigenval_used), &
1326 : real_ne_of_domain(idomain), &
1327 : smear_e_temp, &
1328 40 : 1.0_dp) !! Warning, maxocc is set to 1 since we don't want to interfere with the spin_factor rescaling
1329 40 : spin_kTS = spin_kTS + kTS !! Add up electronic entropy contributions
1330 60 : neigenval_used = neigenval_used + nocc_of_domain(idomain) !! Update eigenvalues index offset
1331 : END DO
1332 700 : rescaling_factors(:) = SQRT(occupation_numbers) !! scale = sqrt(occupation_number)
1333 :
1334 : !!
1335 : !! Rescaling electronic entropy contribution by spin_factor (deprecated)
1336 : !! (currently, entropy is rescaled by spin_factor with the density matrix)
1337 : !!
1338 : !!IF (almo_scf_env%nspins == 1) THEN
1339 : !! spin_kTS = spin_kTS*2.0_dp
1340 : !!END IF
1341 :
1342 : !!
1343 : !! Rescaling of T (i.e. ALMOs)
1344 : !!
1345 20 : CALL dbcsr_scale_by_vector(matrix_t, rescaling_factors, side='right') !! Apply occupation-rescaling trick
1346 :
1347 : !!
1348 : !! Debug tools (for debug purpose only)
1349 : !!
1350 : !! WRITE (*,*) "occupations", occupation_numbers(:) !! debug
1351 : !! WRITE (*,*) "eigenvalues", mo_energies(:) !! debug
1352 : !! WRITE (*,*) "kTS (spin_factor excluded) = ", spin_kTS !! debug
1353 :
1354 : !!
1355 : !! Cleaning up before exit
1356 : !!
1357 20 : DEALLOCATE (occupation_numbers)
1358 20 : DEALLOCATE (rescaling_factors)
1359 :
1360 20 : CALL timestop(handle)
1361 :
1362 20 : END SUBROUTINE almo_scf_t_rescaling
1363 :
1364 : ! **************************************************************************************************
1365 : !> \brief Computes the overlap matrix of MO orbitals
1366 : !> \param bra ...
1367 : !> \param ket ...
1368 : !> \param overlap ...
1369 : !> \param metric ...
1370 : !> \param retain_overlap_sparsity ...
1371 : !> \param eps_filter ...
1372 : !> \param smear ...
1373 : !> \par History
1374 : !> 2011.08 created [Rustam Z Khaliullin]
1375 : !> 2018.09 smearing support [Ruben Staub]
1376 : !> \author Rustam Z Khaliullin
1377 : ! **************************************************************************************************
1378 378 : SUBROUTINE get_overlap(bra, ket, overlap, metric, retain_overlap_sparsity, &
1379 : eps_filter, smear)
1380 :
1381 : TYPE(dbcsr_type), INTENT(IN) :: bra, ket
1382 : TYPE(dbcsr_type), INTENT(INOUT) :: overlap
1383 : TYPE(dbcsr_type), INTENT(IN) :: metric
1384 : LOGICAL, INTENT(IN), OPTIONAL :: retain_overlap_sparsity
1385 : REAL(KIND=dp) :: eps_filter
1386 : LOGICAL, INTENT(IN), OPTIONAL :: smear
1387 :
1388 : CHARACTER(LEN=*), PARAMETER :: routineN = 'get_overlap'
1389 :
1390 : INTEGER :: dim0, handle
1391 : LOGICAL :: local_retain_sparsity, smearing
1392 378 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: diag_correction
1393 : TYPE(dbcsr_type) :: tmp
1394 :
1395 378 : CALL timeset(routineN, handle)
1396 :
1397 378 : IF (.NOT. PRESENT(retain_overlap_sparsity)) THEN
1398 0 : local_retain_sparsity = .FALSE.
1399 : ELSE
1400 378 : local_retain_sparsity = retain_overlap_sparsity
1401 : END IF
1402 :
1403 378 : IF (.NOT. PRESENT(smear)) THEN
1404 : smearing = .FALSE.
1405 : ELSE
1406 378 : smearing = smear
1407 : END IF
1408 :
1409 : CALL dbcsr_create(tmp, template=ket, &
1410 378 : matrix_type=dbcsr_type_no_symmetry)
1411 :
1412 : ! TMP=metric*ket
1413 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1414 : metric, ket, 0.0_dp, tmp, &
1415 378 : filter_eps=eps_filter)
1416 :
1417 : ! OVERLAP=tr(bra)*TMP
1418 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
1419 : bra, tmp, 0.0_dp, overlap, &
1420 : retain_sparsity=local_retain_sparsity, &
1421 378 : filter_eps=eps_filter)
1422 :
1423 378 : CALL dbcsr_release(tmp)
1424 :
1425 : !! If smearing ALMO is requested, apply correction of the occupation-rescaling trick
1426 : !! (i.e. converting rescaled orbitals into selfish orbitals)
1427 : !! (i.e. the diagonal blocks of the rescaled overlap must remain unscaled)
1428 : !! Since we have here orthonormal MOs within a fragment, diagonal blocks are identity matrices
1429 : !! Therefore, one only need to restore the diagonal to 1
1430 : !! RS-WARNING: Assume orthonormal MOs within a fragment
1431 378 : IF (smearing) THEN
1432 4 : CALL dbcsr_get_info(overlap, nfullrows_total=dim0)
1433 12 : ALLOCATE (diag_correction(dim0))
1434 132 : diag_correction = 1.0_dp
1435 4 : CALL dbcsr_set_diag(overlap, diag_correction)
1436 8 : DEALLOCATE (diag_correction)
1437 : END IF
1438 :
1439 378 : CALL timestop(handle)
1440 :
1441 756 : END SUBROUTINE get_overlap
1442 :
1443 : ! **************************************************************************************************
1444 : !> \brief orthogonalize MOs
1445 : !> \param ket ...
1446 : !> \param overlap ...
1447 : !> \param metric ...
1448 : !> \param retain_locality ...
1449 : !> \param only_normalize ...
1450 : !> \param nocc_of_domain ...
1451 : !> \param eps_filter ...
1452 : !> \param order_lanczos ...
1453 : !> \param eps_lanczos ...
1454 : !> \param max_iter_lanczos ...
1455 : !> \param overlap_sqrti ...
1456 : !> \param smear ...
1457 : !> \par History
1458 : !> 2012.03 created [Rustam Z Khaliullin]
1459 : !> 2018.09 smearing support [Ruben Staub]
1460 : !> \author Rustam Z Khaliullin
1461 : ! **************************************************************************************************
1462 378 : SUBROUTINE orthogonalize_mos(ket, overlap, metric, retain_locality, only_normalize, &
1463 378 : nocc_of_domain, eps_filter, order_lanczos, eps_lanczos, &
1464 : max_iter_lanczos, overlap_sqrti, smear)
1465 :
1466 : TYPE(dbcsr_type), INTENT(INOUT) :: ket, overlap
1467 : TYPE(dbcsr_type), INTENT(IN) :: metric
1468 : LOGICAL, INTENT(IN) :: retain_locality, only_normalize
1469 : INTEGER, DIMENSION(:), INTENT(IN) :: nocc_of_domain
1470 : REAL(KIND=dp) :: eps_filter
1471 : INTEGER, INTENT(IN) :: order_lanczos
1472 : REAL(KIND=dp), INTENT(IN) :: eps_lanczos
1473 : INTEGER, INTENT(IN) :: max_iter_lanczos
1474 : TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL :: overlap_sqrti
1475 : LOGICAL, INTENT(IN), OPTIONAL :: smear
1476 :
1477 : CHARACTER(LEN=*), PARAMETER :: routineN = 'orthogonalize_mos'
1478 :
1479 : INTEGER :: dim0, handle
1480 : LOGICAL :: smearing
1481 378 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: diagonal
1482 : TYPE(dbcsr_type) :: matrix_sigma_blk_sqrt, &
1483 : matrix_sigma_blk_sqrt_inv, &
1484 : matrix_t_blk_tmp
1485 :
1486 378 : CALL timeset(routineN, handle)
1487 :
1488 378 : IF (.NOT. PRESENT(smear)) THEN
1489 284 : smearing = .FALSE.
1490 : ELSE
1491 94 : smearing = smear
1492 : END IF
1493 :
1494 : ! create block-diagonal sparsity pattern for the overlap
1495 : ! in case retain_locality is set to true
1496 : ! RZK-warning this will fail if distribution blocks are smaller than domains!!!
1497 378 : CALL dbcsr_set(overlap, 0.0_dp)
1498 378 : CALL dbcsr_add_on_diag(overlap, 1.0_dp)
1499 378 : CALL dbcsr_filter(overlap, eps_filter)
1500 :
1501 : CALL get_overlap(ket, ket, overlap, metric, retain_locality, &
1502 378 : eps_filter, smear=smearing)
1503 :
1504 378 : IF (only_normalize) THEN
1505 :
1506 0 : CALL dbcsr_get_info(overlap, nfullrows_total=dim0)
1507 0 : ALLOCATE (diagonal(dim0))
1508 0 : CALL dbcsr_get_diag(overlap, diagonal)
1509 0 : CALL dbcsr_set(overlap, 0.0_dp)
1510 0 : CALL dbcsr_set_diag(overlap, diagonal)
1511 0 : DEALLOCATE (diagonal)
1512 0 : CALL dbcsr_filter(overlap, eps_filter)
1513 :
1514 : END IF
1515 :
1516 : CALL dbcsr_create(matrix_sigma_blk_sqrt, template=overlap, &
1517 378 : matrix_type=dbcsr_type_no_symmetry)
1518 : CALL dbcsr_create(matrix_sigma_blk_sqrt_inv, template=overlap, &
1519 378 : matrix_type=dbcsr_type_no_symmetry)
1520 :
1521 : ! compute sqrt and sqrt_inv of the blocked MO overlap
1522 378 : CALL set_zero_electron_blocks_in_mo_mo_matrix(overlap, nocc_of_domain, 1.0_dp)
1523 : CALL matrix_sqrt_Newton_Schulz(matrix_sigma_blk_sqrt, matrix_sigma_blk_sqrt_inv, &
1524 : overlap, threshold=eps_filter, &
1525 : order=order_lanczos, &
1526 : eps_lanczos=eps_lanczos, &
1527 378 : max_iter_lanczos=max_iter_lanczos)
1528 378 : CALL set_zero_electron_blocks_in_mo_mo_matrix(overlap, nocc_of_domain, 0.0_dp)
1529 : !CALL set_zero_electron_blocks_in_mo_mo_matrix(matrix_sigma_blk_sqrt,nocc_of_domain,0.0_dp)
1530 378 : CALL set_zero_electron_blocks_in_mo_mo_matrix(matrix_sigma_blk_sqrt_inv, nocc_of_domain, 0.0_dp)
1531 :
1532 : CALL dbcsr_create(matrix_t_blk_tmp, &
1533 : template=ket, &
1534 378 : matrix_type=dbcsr_type_no_symmetry)
1535 :
1536 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1537 : ket, &
1538 : matrix_sigma_blk_sqrt_inv, &
1539 : 0.0_dp, matrix_t_blk_tmp, &
1540 378 : filter_eps=eps_filter)
1541 :
1542 : ! update the orbitals with the orthonormalized MOs
1543 378 : CALL dbcsr_copy(ket, matrix_t_blk_tmp)
1544 :
1545 : ! return overlap SQRT_INV if necessary
1546 378 : IF (PRESENT(overlap_sqrti)) THEN
1547 : CALL dbcsr_copy(overlap_sqrti, &
1548 0 : matrix_sigma_blk_sqrt_inv)
1549 : END IF
1550 :
1551 378 : CALL dbcsr_release(matrix_t_blk_tmp)
1552 378 : CALL dbcsr_release(matrix_sigma_blk_sqrt)
1553 378 : CALL dbcsr_release(matrix_sigma_blk_sqrt_inv)
1554 :
1555 378 : CALL timestop(handle)
1556 :
1557 756 : END SUBROUTINE orthogonalize_mos
1558 :
1559 : ! **************************************************************************************************
1560 : !> \brief computes the idempotent density matrix from MOs
1561 : !> MOs can be either orthogonal or non-orthogonal
1562 : !> \param t ...
1563 : !> \param p ...
1564 : !> \param eps_filter ...
1565 : !> \param orthog_orbs ...
1566 : !> \param nocc_of_domain ...
1567 : !> \param s ...
1568 : !> \param sigma ...
1569 : !> \param sigma_inv ...
1570 : !> \param use_guess ...
1571 : !> \param smear ...
1572 : !> \param algorithm to inver sigma: 0 - Hotelling (linear), 1 - Cholesky (cubic, low prefactor)
1573 : !> \param para_env ...
1574 : !> \param blacs_env ...
1575 : !> \param eps_lanczos ...
1576 : !> \param max_iter_lanczos ...
1577 : !> \param inverse_accelerator ...
1578 : !> \param inv_eps_factor ...
1579 : !> \par History
1580 : !> 2011.07 created [Rustam Z Khaliullin]
1581 : !> 2018.09 smearing support [Ruben Staub]
1582 : !> \author Rustam Z Khaliullin
1583 : ! **************************************************************************************************
1584 1948 : SUBROUTINE almo_scf_t_to_proj(t, p, eps_filter, orthog_orbs, nocc_of_domain, s, sigma, sigma_inv, &
1585 : use_guess, smear, algorithm, para_env, blacs_env, eps_lanczos, &
1586 : max_iter_lanczos, inverse_accelerator, inv_eps_factor)
1587 :
1588 : TYPE(dbcsr_type), INTENT(IN) :: t
1589 : TYPE(dbcsr_type), INTENT(INOUT) :: p
1590 : REAL(KIND=dp), INTENT(IN) :: eps_filter
1591 : LOGICAL, INTENT(IN) :: orthog_orbs
1592 : INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: nocc_of_domain
1593 : TYPE(dbcsr_type), INTENT(IN), OPTIONAL :: s
1594 : TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL :: sigma, sigma_inv
1595 : LOGICAL, INTENT(IN), OPTIONAL :: use_guess, smear
1596 : INTEGER, INTENT(IN), OPTIONAL :: algorithm
1597 : TYPE(mp_para_env_type), OPTIONAL, POINTER :: para_env
1598 : TYPE(cp_blacs_env_type), OPTIONAL, POINTER :: blacs_env
1599 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: eps_lanczos
1600 : INTEGER, INTENT(IN), OPTIONAL :: max_iter_lanczos, inverse_accelerator
1601 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: inv_eps_factor
1602 :
1603 : CHARACTER(LEN=*), PARAMETER :: routineN = 'almo_scf_t_to_proj'
1604 :
1605 : INTEGER :: dim0, handle, my_accelerator, &
1606 : my_algorithm
1607 : LOGICAL :: smearing, use_sigma_inv_guess
1608 : REAL(KIND=dp) :: my_inv_eps_factor
1609 1948 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: diag_correction
1610 : TYPE(dbcsr_type) :: t_tmp
1611 :
1612 1948 : CALL timeset(routineN, handle)
1613 :
1614 : ! make sure that S, sigma and sigma_inv are present for non-orthogonal orbitals
1615 1948 : IF (.NOT. orthog_orbs) THEN
1616 : IF ((.NOT. PRESENT(s)) .OR. (.NOT. PRESENT(sigma)) .OR. &
1617 1948 : (.NOT. PRESENT(sigma_inv)) .OR. (.NOT. PRESENT(nocc_of_domain))) THEN
1618 0 : CPABORT("Nonorthogonal orbitals need more input")
1619 : END IF
1620 : END IF
1621 :
1622 1948 : my_algorithm = 0
1623 1948 : IF (PRESENT(algorithm)) my_algorithm = algorithm
1624 :
1625 1948 : IF (my_algorithm == 1 .AND. (.NOT. PRESENT(para_env) .OR. .NOT. PRESENT(blacs_env))) &
1626 0 : CPABORT("PARA and BLACS env are necessary for cholesky algorithm")
1627 :
1628 1948 : use_sigma_inv_guess = .FALSE.
1629 1948 : IF (PRESENT(use_guess)) THEN
1630 1948 : use_sigma_inv_guess = use_guess
1631 : END IF
1632 :
1633 1948 : IF (.NOT. PRESENT(smear)) THEN
1634 : smearing = .FALSE.
1635 : ELSE
1636 466 : smearing = smear
1637 : END IF
1638 :
1639 1948 : my_accelerator = 1
1640 1948 : IF (PRESENT(inverse_accelerator)) my_accelerator = inverse_accelerator
1641 :
1642 1948 : my_inv_eps_factor = 10.0_dp
1643 1948 : IF (PRESENT(inv_eps_factor)) my_inv_eps_factor = inv_eps_factor
1644 :
1645 1948 : IF (orthog_orbs) THEN
1646 :
1647 : CALL dbcsr_multiply("N", "T", 1.0_dp, t, t, &
1648 0 : 0.0_dp, p, filter_eps=eps_filter)
1649 :
1650 : ELSE
1651 :
1652 1948 : CALL dbcsr_create(t_tmp, template=t)
1653 :
1654 : ! TMP=S.T
1655 : CALL dbcsr_multiply("N", "N", 1.0_dp, s, t, 0.0_dp, t_tmp, &
1656 1948 : filter_eps=eps_filter)
1657 :
1658 : ! Sig=tr(T).TMP - get MO overlap
1659 : CALL dbcsr_multiply("T", "N", 1.0_dp, t, t_tmp, 0.0_dp, sigma, &
1660 1948 : filter_eps=eps_filter)
1661 :
1662 : !! If smearing ALMO is requested, apply correction of the occupation-rescaling trick
1663 : !! (i.e. converting rescaled orbitals into selfish orbitals)
1664 : !! (i.e. the diagonal blocks of the rescaled overlap must remain unscaled)
1665 : !! Since we have here orthonormal MOs within a fragment, diagonal blocks are identity matrices
1666 : !! Therefore, one only need to restore the diagonal to 1
1667 : !! RS-WARNING: Assume orthonormal MOs within a fragment
1668 1948 : IF (smearing) THEN
1669 20 : CALL dbcsr_get_info(sigma, nfullrows_total=dim0)
1670 60 : ALLOCATE (diag_correction(dim0))
1671 700 : diag_correction = 1.0_dp
1672 20 : CALL dbcsr_set_diag(sigma, diag_correction)
1673 40 : DEALLOCATE (diag_correction)
1674 : END IF
1675 :
1676 : ! invert MO overlap
1677 1948 : CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma, nocc_of_domain, 1.0_dp)
1678 26 : SELECT CASE (my_algorithm)
1679 : CASE (spd_inversion_ls_taylor)
1680 :
1681 : CALL invert_Taylor( &
1682 : matrix_inverse=sigma_inv, &
1683 : matrix=sigma, &
1684 : use_inv_as_guess=use_sigma_inv_guess, &
1685 : threshold=eps_filter*my_inv_eps_factor, &
1686 : filter_eps=eps_filter, &
1687 : !accelerator_order=my_accelerator, &
1688 : !eps_lanczos=eps_lanczos, &
1689 : !max_iter_lanczos=max_iter_lanczos, &
1690 26 : silent=.FALSE.)
1691 :
1692 : CASE (spd_inversion_ls_hotelling)
1693 :
1694 : CALL invert_Hotelling( &
1695 : matrix_inverse=sigma_inv, &
1696 : matrix=sigma, &
1697 : use_inv_as_guess=use_sigma_inv_guess, &
1698 : threshold=eps_filter*my_inv_eps_factor, &
1699 : filter_eps=eps_filter, &
1700 : accelerator_order=my_accelerator, &
1701 : eps_lanczos=eps_lanczos, &
1702 : max_iter_lanczos=max_iter_lanczos, &
1703 1436 : silent=.FALSE.)
1704 :
1705 : CASE (spd_inversion_dense_cholesky)
1706 :
1707 : ! invert using cholesky
1708 486 : CALL dbcsr_copy(sigma_inv, sigma)
1709 : CALL cp_dbcsr_cholesky_decompose(sigma_inv, &
1710 : para_env=para_env, &
1711 486 : blacs_env=blacs_env)
1712 : CALL cp_dbcsr_cholesky_invert(sigma_inv, &
1713 : para_env=para_env, &
1714 : blacs_env=blacs_env, &
1715 486 : uplo_to_full=.TRUE.)
1716 486 : CALL dbcsr_filter(sigma_inv, eps_filter)
1717 : CASE DEFAULT
1718 1948 : CPABORT("Illegal MO overalp inversion algorithm")
1719 : END SELECT
1720 1948 : CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma, nocc_of_domain, 0.0_dp)
1721 1948 : CALL set_zero_electron_blocks_in_mo_mo_matrix(sigma_inv, nocc_of_domain, 0.0_dp)
1722 :
1723 : ! TMP=T.SigInv
1724 : CALL dbcsr_multiply("N", "N", 1.0_dp, t, sigma_inv, 0.0_dp, t_tmp, &
1725 1948 : filter_eps=eps_filter)
1726 :
1727 : ! P=TMP.tr(T_blk)
1728 : CALL dbcsr_multiply("N", "T", 1.0_dp, t_tmp, t, 0.0_dp, p, &
1729 1948 : filter_eps=eps_filter)
1730 :
1731 1948 : CALL dbcsr_release(t_tmp)
1732 :
1733 : END IF
1734 :
1735 1948 : CALL timestop(handle)
1736 :
1737 3896 : END SUBROUTINE almo_scf_t_to_proj
1738 :
1739 : ! **************************************************************************************************
1740 : !> \brief self-explanatory
1741 : !> \param matrix ...
1742 : !> \param nocc_of_domain ...
1743 : !> \param value ...
1744 : !> \param
1745 : !> \par History
1746 : !> 2016.12 created [Rustam Z Khaliullin]
1747 : !> \author Rustam Z Khaliullin
1748 : ! **************************************************************************************************
1749 6978 : SUBROUTINE set_zero_electron_blocks_in_mo_mo_matrix(matrix, nocc_of_domain, value)
1750 :
1751 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix
1752 : INTEGER, DIMENSION(:), INTENT(IN) :: nocc_of_domain
1753 : REAL(KIND=dp), INTENT(IN) :: value
1754 :
1755 : INTEGER :: col, row
1756 6978 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: block
1757 : TYPE(dbcsr_iterator_type) :: iter
1758 :
1759 6978 : CALL dbcsr_reserve_diag_blocks(matrix)
1760 :
1761 6978 : CALL dbcsr_iterator_start(iter, matrix)
1762 81742 : DO WHILE (dbcsr_iterator_blocks_left(iter))
1763 74764 : CALL dbcsr_iterator_next_block(iter, row, col, block)
1764 81742 : IF (row == col .AND. nocc_of_domain(row) == 0) THEN
1765 3816 : block(1, 1) = value
1766 : END IF
1767 : END DO
1768 6978 : CALL dbcsr_iterator_stop(iter)
1769 :
1770 6978 : END SUBROUTINE set_zero_electron_blocks_in_mo_mo_matrix
1771 :
1772 : ! **************************************************************************************************
1773 : !> \brief applies projector to the orbitals
1774 : !> |psi_out> = P |psi_in> OR |psi_out> = (1-P) |psi_in>,
1775 : !> where P = |psi_proj> (<psi_proj|psi_roj>)^{-1} <psi_proj|
1776 : !> \param psi_in ...
1777 : !> \param psi_out ...
1778 : !> \param psi_projector ...
1779 : !> \param metric ...
1780 : !> \param project_out ...
1781 : !> \param psi_projector_orthogonal ...
1782 : !> \param proj_in_template ...
1783 : !> \param eps_filter ...
1784 : !> \param sig_inv_projector ...
1785 : !> \param sig_inv_template ...
1786 : !> \par History
1787 : !> 2011.10 created [Rustam Z Khaliullin]
1788 : !> \author Rustam Z Khaliullin
1789 : ! **************************************************************************************************
1790 0 : SUBROUTINE apply_projector(psi_in, psi_out, psi_projector, metric, project_out, &
1791 : psi_projector_orthogonal, proj_in_template, eps_filter, sig_inv_projector, &
1792 : sig_inv_template)
1793 :
1794 : TYPE(dbcsr_type), INTENT(IN) :: psi_in
1795 : TYPE(dbcsr_type), INTENT(INOUT) :: psi_out
1796 : TYPE(dbcsr_type), INTENT(IN) :: psi_projector, metric
1797 : LOGICAL, INTENT(IN) :: project_out, psi_projector_orthogonal
1798 : TYPE(dbcsr_type), INTENT(IN) :: proj_in_template
1799 : REAL(KIND=dp), INTENT(IN) :: eps_filter
1800 : TYPE(dbcsr_type), INTENT(IN), OPTIONAL :: sig_inv_projector, sig_inv_template
1801 :
1802 : CHARACTER(LEN=*), PARAMETER :: routineN = 'apply_projector'
1803 :
1804 : INTEGER :: handle
1805 : TYPE(dbcsr_type) :: tmp_no, tmp_ov, tmp_ov2, tmp_sig, &
1806 : tmp_sig_inv
1807 :
1808 0 : CALL timeset(routineN, handle)
1809 :
1810 : ! =S*PSI_proj
1811 0 : CALL dbcsr_create(tmp_no, template=psi_projector)
1812 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1813 : metric, psi_projector, &
1814 : 0.0_dp, tmp_no, &
1815 0 : filter_eps=eps_filter)
1816 :
1817 : ! =tr(S.PSI_proj)*PSI_in
1818 0 : CALL dbcsr_create(tmp_ov, template=proj_in_template)
1819 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
1820 : tmp_no, psi_in, &
1821 : 0.0_dp, tmp_ov, &
1822 0 : filter_eps=eps_filter)
1823 :
1824 0 : IF (.NOT. psi_projector_orthogonal) THEN
1825 : ! =SigInv_proj*Sigma_OV
1826 : CALL dbcsr_create(tmp_ov2, &
1827 0 : template=proj_in_template)
1828 0 : IF (PRESENT(sig_inv_projector)) THEN
1829 : CALL dbcsr_create(tmp_sig_inv, &
1830 0 : template=sig_inv_projector)
1831 0 : CALL dbcsr_copy(tmp_sig_inv, sig_inv_projector)
1832 : ELSE
1833 0 : IF (.NOT. PRESENT(sig_inv_template)) THEN
1834 0 : CPABORT("PROGRAMMING ERROR: provide either template or sig_inv")
1835 : END IF
1836 : ! compute inverse overlap of the projector orbitals
1837 : CALL dbcsr_create(tmp_sig, &
1838 : template=sig_inv_template, &
1839 0 : matrix_type=dbcsr_type_no_symmetry)
1840 : CALL dbcsr_multiply("T", "N", 1.0_dp, &
1841 : psi_projector, tmp_no, 0.0_dp, tmp_sig, &
1842 0 : filter_eps=eps_filter)
1843 : CALL dbcsr_create(tmp_sig_inv, &
1844 : template=sig_inv_template, &
1845 0 : matrix_type=dbcsr_type_no_symmetry)
1846 : CALL invert_Hotelling(tmp_sig_inv, tmp_sig, &
1847 0 : threshold=eps_filter)
1848 0 : CALL dbcsr_release(tmp_sig)
1849 : END IF
1850 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1851 : tmp_sig_inv, tmp_ov, 0.0_dp, tmp_ov2, &
1852 0 : filter_eps=eps_filter)
1853 0 : CALL dbcsr_release(tmp_sig_inv)
1854 0 : CALL dbcsr_copy(tmp_ov, tmp_ov2)
1855 0 : CALL dbcsr_release(tmp_ov2)
1856 : END IF
1857 0 : CALL dbcsr_release(tmp_no)
1858 :
1859 : ! =PSI_proj*TMP_OV
1860 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
1861 : psi_projector, tmp_ov, 0.0_dp, psi_out, &
1862 0 : filter_eps=eps_filter)
1863 0 : CALL dbcsr_release(tmp_ov)
1864 :
1865 : ! V_out=V_in-V_out
1866 0 : IF (project_out) THEN
1867 0 : CALL dbcsr_add(psi_out, psi_in, -1.0_dp, +1.0_dp)
1868 : END IF
1869 :
1870 0 : CALL timestop(handle)
1871 :
1872 0 : END SUBROUTINE apply_projector
1873 :
1874 : !! **************************************************************************************************
1875 : !!> \brief projects the occupied space out from the provided orbitals
1876 : !!> \par History
1877 : !!> 2011.07 created [Rustam Z Khaliullin]
1878 : !!> \author Rustam Z Khaliullin
1879 : !! **************************************************************************************************
1880 : ! SUBROUTINE almo_scf_p_out_from_v(v_in,v_out,ov_template,ispin,almo_scf_env)
1881 : !
1882 : ! TYPE(dbcsr_type), INTENT(IN) :: v_in, ov_template
1883 : ! TYPE(dbcsr_type), INTENT(INOUT) :: v_out
1884 : ! INTEGER, INTENT(IN) :: ispin
1885 : ! TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
1886 : !
1887 : ! CHARACTER(LEN=*), PARAMETER :: &
1888 : ! routineN = 'almo_scf_p_out_from_v', &
1889 : ! routineP = moduleN//':'//routineN
1890 : !
1891 : ! TYPE(dbcsr_type) :: tmp_on, tmp_ov, tmp_ov2
1892 : ! INTEGER :: handle
1893 : ! LOGICAL :: failure
1894 : !
1895 : ! CALL timeset(routineN,handle)
1896 : !
1897 : ! ! =tr(T_blk)*S
1898 : ! CALL dbcsr_init(tmp_on)
1899 : ! CALL dbcsr_create(tmp_on,&
1900 : ! template=almo_scf_env%matrix_t_tr(ispin))
1901 : ! CALL dbcsr_multiply("T","N",1.0_dp,&
1902 : ! almo_scf_env%matrix_t_blk(ispin),&
1903 : ! almo_scf_env%matrix_s(1),&
1904 : ! 0.0_dp,tmp_on,&
1905 : ! filter_eps=almo_scf_env%eps_filter)
1906 : !
1907 : ! ! =tr(T_blk).S*V_in
1908 : ! CALL dbcsr_init(tmp_ov)
1909 : ! CALL dbcsr_create(tmp_ov,template=ov_template)
1910 : ! CALL dbcsr_multiply("N","N",1.0_dp,&
1911 : ! tmp_on,v_in,0.0_dp,tmp_ov,&
1912 : ! filter_eps=almo_scf_env%eps_filter)
1913 : ! CALL dbcsr_release(tmp_on)
1914 : !
1915 : ! ! =SigmaInv*Sigma_OV
1916 : ! CALL dbcsr_init(tmp_ov2)
1917 : ! CALL dbcsr_create(tmp_ov2,template=ov_template)
1918 : ! CALL dbcsr_multiply("N","N",1.0_dp,&
1919 : ! almo_scf_env%matrix_sigma_inv(ispin),&
1920 : ! tmp_ov,0.0_dp,tmp_ov2,&
1921 : ! filter_eps=almo_scf_env%eps_filter)
1922 : ! CALL dbcsr_release(tmp_ov)
1923 : !
1924 : ! ! =T_blk*SigmaInv.Sigma_OV
1925 : ! CALL dbcsr_multiply("N","N",1.0_dp,&
1926 : ! almo_scf_env%matrix_t_blk(ispin),&
1927 : ! tmp_ov2,0.0_dp,v_out,&
1928 : ! filter_eps=almo_scf_env%eps_filter)
1929 : ! CALL dbcsr_release(tmp_ov2)
1930 : !
1931 : ! ! V_out=V_in-V_out=
1932 : ! CALL dbcsr_add(v_out,v_in,-1.0_dp,+1.0_dp)
1933 : !
1934 : ! CALL timestop(handle)
1935 : !
1936 : ! END SUBROUTINE almo_scf_p_out_from_v
1937 :
1938 : ! **************************************************************************************************
1939 : !> \brief computes a unitary matrix from an arbitrary "generator" matrix
1940 : !> U = ( 1 - X + tr(X) ) ( 1 + X - tr(X) )^(-1)
1941 : !> \param X ...
1942 : !> \param U ...
1943 : !> \param eps_filter ...
1944 : !> \par History
1945 : !> 2011.08 created [Rustam Z Khaliullin]
1946 : !> \author Rustam Z Khaliullin
1947 : ! **************************************************************************************************
1948 0 : SUBROUTINE generator_to_unitary(X, U, eps_filter)
1949 :
1950 : TYPE(dbcsr_type), INTENT(IN) :: X
1951 : TYPE(dbcsr_type), INTENT(INOUT) :: U
1952 : REAL(KIND=dp), INTENT(IN) :: eps_filter
1953 :
1954 : CHARACTER(LEN=*), PARAMETER :: routineN = 'generator_to_unitary'
1955 :
1956 : INTEGER :: handle, unit_nr
1957 : LOGICAL :: safe_mode
1958 : REAL(KIND=dp) :: frob_matrix, frob_matrix_base
1959 : TYPE(cp_logger_type), POINTER :: logger
1960 : TYPE(dbcsr_type) :: delta, t1, t2, tmp1
1961 :
1962 0 : CALL timeset(routineN, handle)
1963 :
1964 0 : safe_mode = .TRUE.
1965 :
1966 : ! get a useful output_unit
1967 0 : logger => cp_get_default_logger()
1968 0 : IF (logger%para_env%is_source()) THEN
1969 0 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
1970 : ELSE
1971 : unit_nr = -1
1972 : END IF
1973 :
1974 : CALL dbcsr_create(t1, template=X, &
1975 0 : matrix_type=dbcsr_type_no_symmetry)
1976 : CALL dbcsr_create(t2, template=X, &
1977 0 : matrix_type=dbcsr_type_no_symmetry)
1978 :
1979 : ! create antisymmetric Delta = -X + tr(X)
1980 : CALL dbcsr_create(delta, template=X, &
1981 0 : matrix_type=dbcsr_type_no_symmetry)
1982 0 : CALL dbcsr_transposed(delta, X)
1983 : ! check that transposed is added correctly
1984 0 : CALL dbcsr_add(delta, X, 1.0_dp, -1.0_dp)
1985 :
1986 : ! compute (1 - Delta)^(-1)
1987 0 : CALL dbcsr_add_on_diag(t1, 1.0_dp)
1988 0 : CALL dbcsr_add(t1, delta, 1.0_dp, -1.0_dp)
1989 0 : CALL invert_Hotelling(t2, t1, threshold=eps_filter)
1990 :
1991 : IF (safe_mode) THEN
1992 :
1993 : CALL dbcsr_create(tmp1, template=X, &
1994 0 : matrix_type=dbcsr_type_no_symmetry)
1995 : CALL dbcsr_multiply("N", "N", 1.0_dp, t2, t1, 0.0_dp, tmp1, &
1996 0 : filter_eps=eps_filter)
1997 0 : frob_matrix_base = dbcsr_frobenius_norm(tmp1)
1998 0 : CALL dbcsr_add_on_diag(tmp1, -1.0_dp)
1999 0 : frob_matrix = dbcsr_frobenius_norm(tmp1)
2000 0 : IF (unit_nr > 0) WRITE (unit_nr, *) "Error for (inv(A)*A-I)", frob_matrix/frob_matrix_base
2001 0 : CALL dbcsr_release(tmp1)
2002 : END IF
2003 :
2004 : CALL dbcsr_multiply("N", "N", 1.0_dp, delta, t2, 0.0_dp, U, &
2005 0 : filter_eps=eps_filter)
2006 0 : CALL dbcsr_add(U, t2, 1.0_dp, 1.0_dp)
2007 :
2008 : IF (safe_mode) THEN
2009 :
2010 : CALL dbcsr_create(tmp1, template=X, &
2011 0 : matrix_type=dbcsr_type_no_symmetry)
2012 : CALL dbcsr_multiply("T", "N", 1.0_dp, U, U, 0.0_dp, tmp1, &
2013 0 : filter_eps=eps_filter)
2014 0 : frob_matrix_base = dbcsr_frobenius_norm(tmp1)
2015 0 : CALL dbcsr_add_on_diag(tmp1, -1.0_dp)
2016 0 : frob_matrix = dbcsr_frobenius_norm(tmp1)
2017 0 : IF (unit_nr > 0) WRITE (unit_nr, *) "Error for (trn(U)*U-I)", frob_matrix/frob_matrix_base
2018 0 : CALL dbcsr_release(tmp1)
2019 : END IF
2020 :
2021 0 : CALL timestop(handle)
2022 :
2023 0 : END SUBROUTINE generator_to_unitary
2024 :
2025 : ! **************************************************************************************************
2026 : !> \brief Parallel code for domain specific operations (my_action)
2027 : !> 0. out = op1 * in
2028 : !> 1. out = in - op2 * op1 * in
2029 : !> \param matrix_in ...
2030 : !> \param matrix_out ...
2031 : !> \param operator1 ...
2032 : !> \param operator2 ...
2033 : !> \param dpattern ...
2034 : !> \param map ...
2035 : !> \param node_of_domain ...
2036 : !> \param my_action ...
2037 : !> \param filter_eps ...
2038 : !> \param matrix_trimmer ...
2039 : !> \param use_trimmer ...
2040 : !> \par History
2041 : !> 2013.01 created [Rustam Z. Khaliullin]
2042 : !> \author Rustam Z. Khaliullin
2043 : ! **************************************************************************************************
2044 2394 : SUBROUTINE apply_domain_operators(matrix_in, matrix_out, operator1, operator2, &
2045 2394 : dpattern, map, node_of_domain, my_action, filter_eps, matrix_trimmer, use_trimmer)
2046 :
2047 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_in, matrix_out
2048 : TYPE(domain_submatrix_type), DIMENSION(:), &
2049 : INTENT(IN) :: operator1
2050 : TYPE(domain_submatrix_type), DIMENSION(:), &
2051 : INTENT(IN), OPTIONAL :: operator2
2052 : TYPE(dbcsr_type), INTENT(IN) :: dpattern
2053 : TYPE(domain_map_type), INTENT(IN) :: map
2054 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
2055 : INTEGER, INTENT(IN) :: my_action
2056 : REAL(KIND=dp) :: filter_eps
2057 : TYPE(dbcsr_type), INTENT(IN), OPTIONAL :: matrix_trimmer
2058 : LOGICAL, INTENT(IN), OPTIONAL :: use_trimmer
2059 :
2060 : CHARACTER(len=*), PARAMETER :: routineN = 'apply_domain_operators'
2061 :
2062 : INTEGER :: handle, ndomains
2063 : LOGICAL :: matrix_trimmer_required, my_use_trimmer, &
2064 : operator2_required
2065 : TYPE(domain_submatrix_type), ALLOCATABLE, &
2066 2394 : DIMENSION(:) :: subm_in, subm_out, subm_temp
2067 :
2068 2394 : CALL timeset(routineN, handle)
2069 :
2070 2394 : my_use_trimmer = .FALSE.
2071 2394 : IF (PRESENT(use_trimmer)) THEN
2072 612 : my_use_trimmer = use_trimmer
2073 : END IF
2074 :
2075 2394 : operator2_required = .FALSE.
2076 2394 : matrix_trimmer_required = .FALSE.
2077 :
2078 2394 : IF (my_action .EQ. 1) operator2_required = .TRUE.
2079 :
2080 2394 : IF (my_use_trimmer) THEN
2081 0 : matrix_trimmer_required = .TRUE.
2082 0 : CPABORT("TRIMMED PROJECTOR DISABLED!")
2083 : END IF
2084 :
2085 2394 : IF (.NOT. PRESENT(operator2) .AND. operator2_required) THEN
2086 0 : CPABORT("SECOND OPERATOR IS REQUIRED")
2087 : END IF
2088 2394 : IF (.NOT. PRESENT(matrix_trimmer) .AND. matrix_trimmer_required) THEN
2089 0 : CPABORT("TRIMMER MATRIX IS REQUIRED")
2090 : END IF
2091 :
2092 2394 : CALL dbcsr_get_info(dpattern, nblkcols_total=ndomains)
2093 :
2094 22832 : ALLOCATE (subm_in(ndomains))
2095 22832 : ALLOCATE (subm_temp(ndomains))
2096 22832 : ALLOCATE (subm_out(ndomains))
2097 : !!!TRIM ALLOCATE(subm_trimmer(ndomains))
2098 2394 : CALL init_submatrices(subm_in)
2099 2394 : CALL init_submatrices(subm_temp)
2100 2394 : CALL init_submatrices(subm_out)
2101 :
2102 : CALL construct_submatrices(matrix_in, subm_in, &
2103 2394 : dpattern, map, node_of_domain, select_row)
2104 :
2105 : !!!TRIM IF (matrix_trimmer_required) THEN
2106 : !!!TRIM CALL construct_submatrices(matrix_trimmer,subm_trimmer,&
2107 : !!!TRIM dpattern,map,node_of_domain,select_row)
2108 : !!!TRIM ENDIF
2109 :
2110 2394 : IF (my_action .EQ. 0) THEN
2111 : ! for example, apply preconditioner
2112 : CALL multiply_submatrices('N', 'N', 1.0_dp, operator1, &
2113 1552 : subm_in, 0.0_dp, subm_out)
2114 842 : ELSE IF (my_action .EQ. 1) THEN
2115 : ! use for projectors
2116 842 : CALL copy_submatrices(subm_in, subm_out, .TRUE.)
2117 : CALL multiply_submatrices('N', 'N', 1.0_dp, operator1, &
2118 842 : subm_in, 0.0_dp, subm_temp)
2119 : CALL multiply_submatrices('N', 'N', -1.0_dp, operator2, &
2120 842 : subm_temp, 1.0_dp, subm_out)
2121 : ELSE
2122 0 : CPABORT("ILLEGAL ACTION")
2123 : END IF
2124 :
2125 2394 : CALL construct_dbcsr_from_submatrices(matrix_out, subm_out, dpattern)
2126 2394 : CALL dbcsr_filter(matrix_out, filter_eps)
2127 :
2128 2394 : CALL release_submatrices(subm_out)
2129 2394 : CALL release_submatrices(subm_temp)
2130 2394 : CALL release_submatrices(subm_in)
2131 :
2132 18044 : DEALLOCATE (subm_out)
2133 18044 : DEALLOCATE (subm_temp)
2134 18044 : DEALLOCATE (subm_in)
2135 :
2136 2394 : CALL timestop(handle)
2137 :
2138 4788 : END SUBROUTINE apply_domain_operators
2139 :
2140 : ! **************************************************************************************************
2141 : !> \brief Constructs preconditioners for each domain
2142 : !> -1. projected preconditioner
2143 : !> 0. simple preconditioner
2144 : !> \param matrix_main ...
2145 : !> \param subm_s_inv ...
2146 : !> \param subm_s_inv_half ...
2147 : !> \param subm_s_half ...
2148 : !> \param subm_r_down ...
2149 : !> \param matrix_trimmer ...
2150 : !> \param dpattern ...
2151 : !> \param map ...
2152 : !> \param node_of_domain ...
2153 : !> \param preconditioner ...
2154 : !> \param bad_modes_projector_down ...
2155 : !> \param use_trimmer ...
2156 : !> \param eps_zero_eigenvalues ...
2157 : !> \param my_action ...
2158 : !> \param skip_inversion ...
2159 : !> \par History
2160 : !> 2013.01 created [Rustam Z. Khaliullin]
2161 : !> \author Rustam Z. Khaliullin
2162 : ! **************************************************************************************************
2163 550 : SUBROUTINE construct_domain_preconditioner(matrix_main, subm_s_inv, &
2164 550 : subm_s_inv_half, subm_s_half, &
2165 550 : subm_r_down, matrix_trimmer, &
2166 550 : dpattern, map, node_of_domain, &
2167 550 : preconditioner, &
2168 550 : bad_modes_projector_down, &
2169 : use_trimmer, &
2170 : eps_zero_eigenvalues, &
2171 : my_action, skip_inversion)
2172 :
2173 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_main
2174 : TYPE(domain_submatrix_type), DIMENSION(:), &
2175 : INTENT(IN), OPTIONAL :: subm_s_inv, subm_s_inv_half, &
2176 : subm_s_half, subm_r_down
2177 : TYPE(dbcsr_type), INTENT(IN), OPTIONAL :: matrix_trimmer
2178 : TYPE(dbcsr_type), INTENT(IN) :: dpattern
2179 : TYPE(domain_map_type), INTENT(IN) :: map
2180 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
2181 : TYPE(domain_submatrix_type), DIMENSION(:), &
2182 : INTENT(INOUT) :: preconditioner
2183 : TYPE(domain_submatrix_type), DIMENSION(:), &
2184 : INTENT(INOUT), OPTIONAL :: bad_modes_projector_down
2185 : LOGICAL, INTENT(IN), OPTIONAL :: use_trimmer
2186 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: eps_zero_eigenvalues
2187 : INTEGER, INTENT(IN) :: my_action
2188 : LOGICAL, INTENT(IN), OPTIONAL :: skip_inversion
2189 :
2190 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_preconditioner'
2191 :
2192 : INTEGER :: handle, idomain, index1_end, &
2193 : index1_start, n_domain_mos, naos, &
2194 : nblkrows_tot, ndomains, neighbor, row
2195 550 : INTEGER, DIMENSION(:), POINTER :: nmos
2196 : LOGICAL :: eps_zero_eigenvalues_required, matrix_r_required, matrix_s_half_required, &
2197 : matrix_s_inv_half_required, matrix_s_inv_required, matrix_trimmer_required, &
2198 : my_skip_inversion, my_use_trimmer
2199 550 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: Minv, proj_array
2200 : TYPE(domain_submatrix_type), ALLOCATABLE, &
2201 550 : DIMENSION(:) :: subm_main, subm_tmp, subm_tmp2
2202 :
2203 550 : CALL timeset(routineN, handle)
2204 :
2205 550 : my_use_trimmer = .FALSE.
2206 550 : IF (PRESENT(use_trimmer)) THEN
2207 550 : my_use_trimmer = use_trimmer
2208 : END IF
2209 :
2210 550 : my_skip_inversion = .FALSE.
2211 550 : IF (PRESENT(skip_inversion)) THEN
2212 550 : my_skip_inversion = skip_inversion
2213 : END IF
2214 :
2215 550 : matrix_s_inv_half_required = .FALSE.
2216 550 : matrix_s_half_required = .FALSE.
2217 550 : eps_zero_eigenvalues_required = .FALSE.
2218 550 : matrix_s_inv_required = .FALSE.
2219 550 : matrix_trimmer_required = .FALSE.
2220 550 : matrix_r_required = .FALSE.
2221 :
2222 550 : IF (my_action .EQ. -1) matrix_s_inv_required = .TRUE.
2223 : IF (my_action .EQ. -1) matrix_r_required = .TRUE.
2224 550 : IF (my_use_trimmer) THEN
2225 0 : matrix_trimmer_required = .TRUE.
2226 0 : CPABORT("TRIMMED PRECONDITIONER DISABLED!")
2227 : END IF
2228 : ! tie the following optional arguments together to prevent bad calls
2229 550 : IF (PRESENT(bad_modes_projector_down)) THEN
2230 18 : matrix_s_inv_half_required = .TRUE.
2231 18 : matrix_s_half_required = .TRUE.
2232 18 : eps_zero_eigenvalues_required = .TRUE.
2233 : END IF
2234 :
2235 : ! check if all required optional arguments are provided
2236 550 : IF (.NOT. PRESENT(subm_s_inv_half) .AND. matrix_s_inv_half_required) THEN
2237 0 : CPABORT("S_inv_half SUBMATRICES ARE REQUIRED")
2238 : END IF
2239 550 : IF (.NOT. PRESENT(subm_s_half) .AND. matrix_s_half_required) THEN
2240 0 : CPABORT("S_half SUBMATRICES ARE REQUIRED")
2241 : END IF
2242 550 : IF (.NOT. PRESENT(eps_zero_eigenvalues) .AND. eps_zero_eigenvalues_required) THEN
2243 0 : CPABORT("EPS_ZERO_EIGENVALUES IS REQUIRED")
2244 : END IF
2245 550 : IF (.NOT. PRESENT(subm_s_inv) .AND. matrix_s_inv_required) THEN
2246 0 : CPABORT("S_inv SUBMATRICES ARE REQUIRED")
2247 : END IF
2248 550 : IF (.NOT. PRESENT(subm_r_down) .AND. matrix_r_required) THEN
2249 0 : CPABORT("R SUBMATRICES ARE REQUIRED")
2250 : END IF
2251 550 : IF (.NOT. PRESENT(matrix_trimmer) .AND. matrix_trimmer_required) THEN
2252 0 : CPABORT("TRIMMER MATRIX IS REQUIRED")
2253 : END IF
2254 :
2255 : CALL dbcsr_get_info(dpattern, &
2256 : nblkcols_total=ndomains, &
2257 : nblkrows_total=nblkrows_tot, &
2258 550 : col_blk_size=nmos)
2259 :
2260 4516 : ALLOCATE (subm_main(ndomains))
2261 550 : CALL init_submatrices(subm_main)
2262 : !!!TRIM ALLOCATE(subm_trimmer(ndomains))
2263 :
2264 : CALL construct_submatrices(matrix_main, subm_main, &
2265 550 : dpattern, map, node_of_domain, select_row_col)
2266 :
2267 : !!!TRIM IF (matrix_trimmer_required) THEN
2268 : !!!TRIM CALL construct_submatrices(matrix_trimmer,subm_trimmer,&
2269 : !!!TRIM dpattern,map,node_of_domain,select_row)
2270 : !!!TRIM ENDIF
2271 :
2272 550 : IF (my_action .EQ. -1) THEN
2273 : ! project out the local occupied space
2274 : !tmp=MATMUL(subm_r(idomain)%mdata,Minv)
2275 : !Minv=MATMUL(tmp,subm_main(idomain)%mdata)
2276 : !subm_main(idomain)%mdata=subm_main(idomain)%mdata-&
2277 : ! Minv-TRANSPOSE(Minv)+MATMUL(Minv,TRANSPOSE(tmp))
2278 222 : ALLOCATE (subm_tmp(ndomains))
2279 222 : ALLOCATE (subm_tmp2(ndomains))
2280 26 : CALL init_submatrices(subm_tmp)
2281 26 : CALL init_submatrices(subm_tmp2)
2282 : CALL multiply_submatrices('N', 'N', 1.0_dp, subm_r_down, &
2283 26 : subm_s_inv, 0.0_dp, subm_tmp)
2284 : CALL multiply_submatrices('N', 'N', 1.0_dp, subm_tmp, &
2285 26 : subm_main, 0.0_dp, subm_tmp2)
2286 26 : CALL add_submatrices(1.0_dp, subm_main, -1.0_dp, subm_tmp2, 'N')
2287 26 : CALL add_submatrices(1.0_dp, subm_main, -1.0_dp, subm_tmp2, 'T')
2288 : CALL multiply_submatrices('N', 'T', 1.0_dp, subm_tmp2, &
2289 26 : subm_tmp, 1.0_dp, subm_main)
2290 26 : CALL release_submatrices(subm_tmp)
2291 26 : CALL release_submatrices(subm_tmp2)
2292 196 : DEALLOCATE (subm_tmp2)
2293 196 : DEALLOCATE (subm_tmp)
2294 : END IF
2295 :
2296 550 : IF (my_skip_inversion) THEN
2297 316 : CALL copy_submatrices(subm_main, preconditioner, .TRUE.)
2298 : ELSE
2299 : ! loop over domains - perform inversion
2300 1284 : DO idomain = 1, ndomains
2301 :
2302 : ! check if the submatrix exists
2303 1284 : IF (subm_main(idomain)%domain .GT. 0) THEN
2304 :
2305 : ! find sizes of MO submatrices
2306 525 : IF (idomain .EQ. 1) THEN
2307 : index1_start = 1
2308 : ELSE
2309 408 : index1_start = map%index1(idomain - 1)
2310 : END IF
2311 525 : index1_end = map%index1(idomain) - 1
2312 :
2313 525 : n_domain_mos = 0
2314 2320 : DO row = index1_start, index1_end
2315 1795 : neighbor = map%pairs(row, 1)
2316 2320 : n_domain_mos = n_domain_mos + nmos(neighbor)
2317 : END DO
2318 :
2319 525 : naos = subm_main(idomain)%nrows
2320 : !WRITE(*,*) "Domain, mo_self_and_neig, ao_domain: ", idomain, n_domain_mos, naos
2321 :
2322 2100 : ALLOCATE (Minv(naos, naos))
2323 :
2324 : !!!TRIM IF (my_use_trimmer) THEN
2325 : !!!TRIM ! THIS IS SUPER EXPENSIVE (ELIMINATE)
2326 : !!!TRIM ! trim the main matrix before inverting
2327 : !!!TRIM ! assume that the trimmer columns are different (i.e. the main matrix is different for each MO)
2328 : !!!TRIM allocate(tmp(naos,nmos(idomain)))
2329 : !!!TRIM DO ii=1, nmos(idomain)
2330 : !!!TRIM ! transform the main matrix using the trimmer for the current MO
2331 : !!!TRIM DO jj=1, naos
2332 : !!!TRIM DO kk=1, naos
2333 : !!!TRIM Mstore(jj,kk)=sumb_main(idomain)%mdata(jj,kk)*&
2334 : !!!TRIM subm_trimmer(idomain)%mdata(jj,ii)*&
2335 : !!!TRIM subm_trimmer(idomain)%mdata(kk,ii)
2336 : !!!TRIM ENDDO
2337 : !!!TRIM ENDDO
2338 : !!!TRIM ! invert the main matrix (exclude some eigenvalues, shift some)
2339 : !!!TRIM CALL pseudo_invert_matrix(A=Mstore,Ainv=Minv,N=naos,method=1,&
2340 : !!!TRIM !range1_thr=1.0E-9_dp,range2_thr=1.0E-9_dp,&
2341 : !!!TRIM shift=1.0E-5_dp,&
2342 : !!!TRIM range1=nmos(idomain),range2=nmos(idomain),&
2343 : !!!TRIM
2344 : !!!TRIM ! apply the inverted matrix
2345 : !!!TRIM ! RZK-warning this is only possible when the preconditioner is applied
2346 : !!!TRIM tmp(:,ii)=MATMUL(Minv,subm_in(idomain)%mdata(:,ii))
2347 : !!!TRIM ENDDO
2348 : !!!TRIM subm_out=MATMUL(tmp,sigma)
2349 : !!!TRIM deallocate(tmp)
2350 : !!!TRIM ELSE
2351 :
2352 525 : IF (PRESENT(bad_modes_projector_down)) THEN
2353 180 : ALLOCATE (proj_array(naos, naos))
2354 : CALL pseudo_invert_matrix(A=subm_main(idomain)%mdata, Ainv=Minv, N=naos, method=1, &
2355 : range1=nmos(idomain), range2=n_domain_mos, &
2356 : range1_thr=eps_zero_eigenvalues, &
2357 : bad_modes_projector_down=proj_array, &
2358 : s_inv_half=subm_s_inv_half(idomain)%mdata, &
2359 : s_half=subm_s_half(idomain)%mdata &
2360 60 : )
2361 : ELSE
2362 : CALL pseudo_invert_matrix(A=subm_main(idomain)%mdata, Ainv=Minv, N=naos, method=1, &
2363 465 : range1=nmos(idomain), range2=n_domain_mos)
2364 : END IF
2365 : !!!TRIM ENDIF
2366 :
2367 525 : CALL copy_submatrices(subm_main(idomain), preconditioner(idomain), .FALSE.)
2368 525 : CALL copy_submatrix_data(Minv, preconditioner(idomain))
2369 525 : DEALLOCATE (Minv)
2370 :
2371 525 : IF (PRESENT(bad_modes_projector_down)) THEN
2372 60 : CALL copy_submatrices(subm_main(idomain), bad_modes_projector_down(idomain), .FALSE.)
2373 60 : CALL copy_submatrix_data(proj_array, bad_modes_projector_down(idomain))
2374 60 : DEALLOCATE (proj_array)
2375 : END IF
2376 :
2377 : END IF ! submatrix for the domain exists
2378 :
2379 : END DO ! loop over domains
2380 :
2381 : END IF
2382 :
2383 550 : CALL release_submatrices(subm_main)
2384 3416 : DEALLOCATE (subm_main)
2385 : !DEALLOCATE(subm_s)
2386 : !DEALLOCATE(subm_r)
2387 :
2388 : !IF (matrix_r_required) THEN
2389 : ! CALL dbcsr_release(m_tmp_no_1)
2390 : ! CALL dbcsr_release(m_tmp_no_2)
2391 : ! CALL dbcsr_release(matrix_r)
2392 : !ENDIF
2393 :
2394 550 : CALL timestop(handle)
2395 :
2396 1650 : END SUBROUTINE construct_domain_preconditioner
2397 :
2398 : ! **************************************************************************************************
2399 : !> \brief Constructs S^(+1/2) and S^(-1/2) submatrices for each domain
2400 : !> \param matrix_s ...
2401 : !> \param subm_s_sqrt ...
2402 : !> \param subm_s_sqrt_inv ...
2403 : !> \param dpattern ...
2404 : !> \param map ...
2405 : !> \param node_of_domain ...
2406 : !> \par History
2407 : !> 2013.03 created [Rustam Z. Khaliullin]
2408 : !> \author Rustam Z. Khaliullin
2409 : ! **************************************************************************************************
2410 40 : SUBROUTINE construct_domain_s_sqrt(matrix_s, subm_s_sqrt, subm_s_sqrt_inv, &
2411 40 : dpattern, map, node_of_domain)
2412 :
2413 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_s
2414 : TYPE(domain_submatrix_type), DIMENSION(:), &
2415 : INTENT(INOUT) :: subm_s_sqrt, subm_s_sqrt_inv
2416 : TYPE(dbcsr_type), INTENT(IN) :: dpattern
2417 : TYPE(domain_map_type), INTENT(IN) :: map
2418 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
2419 :
2420 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_s_sqrt'
2421 :
2422 : INTEGER :: handle, idomain, naos, ndomains
2423 40 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: Ssqrt, Ssqrtinv
2424 : TYPE(domain_submatrix_type), ALLOCATABLE, &
2425 : DIMENSION(:) :: subm_s
2426 :
2427 40 : CALL timeset(routineN, handle)
2428 :
2429 40 : CALL dbcsr_get_info(dpattern, nblkcols_total=ndomains)
2430 40 : CPASSERT(SIZE(subm_s_sqrt) .EQ. ndomains)
2431 40 : CPASSERT(SIZE(subm_s_sqrt_inv) .EQ. ndomains)
2432 376 : ALLOCATE (subm_s(ndomains))
2433 40 : CALL init_submatrices(subm_s)
2434 :
2435 : CALL construct_submatrices(matrix_s, subm_s, &
2436 40 : dpattern, map, node_of_domain, select_row_col)
2437 :
2438 : ! loop over domains - perform inversion
2439 296 : DO idomain = 1, ndomains
2440 :
2441 : ! check if the submatrix exists
2442 296 : IF (subm_s(idomain)%domain .GT. 0) THEN
2443 :
2444 128 : naos = subm_s(idomain)%nrows
2445 :
2446 512 : ALLOCATE (Ssqrt(naos, naos))
2447 512 : ALLOCATE (Ssqrtinv(naos, naos))
2448 :
2449 : CALL matrix_sqrt(A=subm_s(idomain)%mdata, Asqrt=Ssqrt, Asqrtinv=Ssqrtinv, &
2450 128 : N=naos)
2451 :
2452 128 : CALL copy_submatrices(subm_s(idomain), subm_s_sqrt(idomain), .FALSE.)
2453 128 : CALL copy_submatrix_data(Ssqrt, subm_s_sqrt(idomain))
2454 :
2455 128 : CALL copy_submatrices(subm_s(idomain), subm_s_sqrt_inv(idomain), .FALSE.)
2456 128 : CALL copy_submatrix_data(Ssqrtinv, subm_s_sqrt_inv(idomain))
2457 :
2458 128 : DEALLOCATE (Ssqrtinv)
2459 128 : DEALLOCATE (Ssqrt)
2460 :
2461 : END IF ! submatrix for the domain exists
2462 :
2463 : END DO ! loop over domains
2464 :
2465 40 : CALL release_submatrices(subm_s)
2466 296 : DEALLOCATE (subm_s)
2467 :
2468 40 : CALL timestop(handle)
2469 :
2470 80 : END SUBROUTINE construct_domain_s_sqrt
2471 :
2472 : ! **************************************************************************************************
2473 : !> \brief Constructs S_inv block for each domain
2474 : !> \param matrix_s ...
2475 : !> \param subm_s_inv ...
2476 : !> \param dpattern ...
2477 : !> \param map ...
2478 : !> \param node_of_domain ...
2479 : !> \par History
2480 : !> 2013.02 created [Rustam Z. Khaliullin]
2481 : !> \author Rustam Z. Khaliullin
2482 : ! **************************************************************************************************
2483 54 : SUBROUTINE construct_domain_s_inv(matrix_s, subm_s_inv, dpattern, map, &
2484 54 : node_of_domain)
2485 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_s
2486 : TYPE(domain_submatrix_type), DIMENSION(:), &
2487 : INTENT(INOUT) :: subm_s_inv
2488 : TYPE(dbcsr_type), INTENT(IN) :: dpattern
2489 : TYPE(domain_map_type), INTENT(IN) :: map
2490 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
2491 :
2492 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_s_inv'
2493 :
2494 : INTEGER :: handle, idomain, naos, ndomains
2495 54 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: Sinv
2496 : TYPE(domain_submatrix_type), ALLOCATABLE, &
2497 : DIMENSION(:) :: subm_s
2498 :
2499 54 : CALL timeset(routineN, handle)
2500 :
2501 54 : CALL dbcsr_get_info(dpattern, nblkcols_total=ndomains)
2502 :
2503 54 : CPASSERT(SIZE(subm_s_inv) .EQ. ndomains)
2504 520 : ALLOCATE (subm_s(ndomains))
2505 54 : CALL init_submatrices(subm_s)
2506 :
2507 : CALL construct_submatrices(matrix_s, subm_s, &
2508 54 : dpattern, map, node_of_domain, select_row_col)
2509 :
2510 : ! loop over domains - perform inversion
2511 412 : DO idomain = 1, ndomains
2512 :
2513 : ! check if the submatrix exists
2514 412 : IF (subm_s(idomain)%domain .GT. 0) THEN
2515 :
2516 179 : naos = subm_s(idomain)%nrows
2517 :
2518 716 : ALLOCATE (Sinv(naos, naos))
2519 :
2520 : CALL pseudo_invert_matrix(A=subm_s(idomain)%mdata, Ainv=Sinv, N=naos, &
2521 179 : method=0)
2522 :
2523 179 : CALL copy_submatrices(subm_s(idomain), subm_s_inv(idomain), .FALSE.)
2524 179 : CALL copy_submatrix_data(Sinv, subm_s_inv(idomain))
2525 :
2526 179 : DEALLOCATE (Sinv)
2527 :
2528 : END IF ! submatrix for the domain exists
2529 :
2530 : END DO ! loop over domains
2531 :
2532 54 : CALL release_submatrices(subm_s)
2533 412 : DEALLOCATE (subm_s)
2534 :
2535 54 : CALL timestop(handle)
2536 :
2537 108 : END SUBROUTINE construct_domain_s_inv
2538 :
2539 : ! **************************************************************************************************
2540 : !> \brief Constructs subblocks of the covariant-covariant projectors (i.e. DM without spin factor)
2541 : !> \param matrix_t ...
2542 : !> \param matrix_sigma_inv ...
2543 : !> \param matrix_s ...
2544 : !> \param subm_r_down ...
2545 : !> \param dpattern ...
2546 : !> \param map ...
2547 : !> \param node_of_domain ...
2548 : !> \param filter_eps ...
2549 : !> \par History
2550 : !> 2013.02 created [Rustam Z. Khaliullin]
2551 : !> \author Rustam Z. Khaliullin
2552 : ! **************************************************************************************************
2553 72 : SUBROUTINE construct_domain_r_down(matrix_t, matrix_sigma_inv, matrix_s, &
2554 24 : subm_r_down, dpattern, map, node_of_domain, filter_eps)
2555 :
2556 : TYPE(dbcsr_type), INTENT(IN) :: matrix_t, matrix_sigma_inv, matrix_s
2557 : TYPE(domain_submatrix_type), DIMENSION(:), &
2558 : INTENT(INOUT) :: subm_r_down
2559 : TYPE(dbcsr_type), INTENT(IN) :: dpattern
2560 : TYPE(domain_map_type), INTENT(IN) :: map
2561 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
2562 : REAL(KIND=dp) :: filter_eps
2563 :
2564 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_domain_r_down'
2565 :
2566 : INTEGER :: handle, ndomains
2567 : TYPE(dbcsr_type) :: m_tmp_no_1, m_tmp_no_2, matrix_r
2568 :
2569 24 : CALL timeset(routineN, handle)
2570 :
2571 : ! compute the density matrix in the COVARIANT representation
2572 : CALL dbcsr_create(matrix_r, &
2573 : template=matrix_s, &
2574 24 : matrix_type=dbcsr_type_symmetric)
2575 : CALL dbcsr_create(m_tmp_no_1, &
2576 : template=matrix_t, &
2577 24 : matrix_type=dbcsr_type_no_symmetry)
2578 : CALL dbcsr_create(m_tmp_no_2, &
2579 : template=matrix_t, &
2580 24 : matrix_type=dbcsr_type_no_symmetry)
2581 :
2582 : CALL dbcsr_multiply("N", "N", 1.0_dp, matrix_s, matrix_t, &
2583 24 : 0.0_dp, m_tmp_no_1, filter_eps=filter_eps)
2584 : CALL dbcsr_multiply("N", "N", 1.0_dp, m_tmp_no_1, matrix_sigma_inv, &
2585 24 : 0.0_dp, m_tmp_no_2, filter_eps=filter_eps)
2586 : CALL dbcsr_multiply("N", "T", 1.0_dp, m_tmp_no_2, m_tmp_no_1, &
2587 24 : 0.0_dp, matrix_r, filter_eps=filter_eps)
2588 :
2589 24 : CALL dbcsr_release(m_tmp_no_1)
2590 24 : CALL dbcsr_release(m_tmp_no_2)
2591 :
2592 24 : CALL dbcsr_get_info(dpattern, nblkcols_total=ndomains)
2593 24 : CPASSERT(SIZE(subm_r_down) .EQ. ndomains)
2594 :
2595 : CALL construct_submatrices(matrix_r, subm_r_down, &
2596 24 : dpattern, map, node_of_domain, select_row_col)
2597 :
2598 24 : CALL dbcsr_release(matrix_r)
2599 :
2600 24 : CALL timestop(handle)
2601 :
2602 24 : END SUBROUTINE construct_domain_r_down
2603 :
2604 : ! **************************************************************************************************
2605 : !> \brief Finds the square root of a matrix and its inverse
2606 : !> \param A ...
2607 : !> \param Asqrt ...
2608 : !> \param Asqrtinv ...
2609 : !> \param N ...
2610 : !> \par History
2611 : !> 2013.03 created [Rustam Z. Khaliullin]
2612 : !> \author Rustam Z. Khaliullin
2613 : ! **************************************************************************************************
2614 128 : SUBROUTINE matrix_sqrt(A, Asqrt, Asqrtinv, N)
2615 :
2616 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: A
2617 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: Asqrt, Asqrtinv
2618 : INTEGER, INTENT(IN) :: N
2619 :
2620 : CHARACTER(len=*), PARAMETER :: routineN = 'matrix_sqrt'
2621 :
2622 : INTEGER :: handle, INFO, jj, LWORK, unit_nr
2623 128 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, WORK
2624 128 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: test, testN
2625 : TYPE(cp_logger_type), POINTER :: logger
2626 :
2627 128 : CALL timeset(routineN, handle)
2628 :
2629 585400 : Asqrtinv = A
2630 128 : INFO = 0
2631 :
2632 : ! get a useful unit_nr
2633 128 : logger => cp_get_default_logger()
2634 128 : IF (logger%para_env%is_source()) THEN
2635 65 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
2636 : ELSE
2637 : unit_nr = -1
2638 : END IF
2639 :
2640 : !CALL dpotrf('L', N, Ainv, N, INFO )
2641 : !IF( INFO.NE.0 ) THEN
2642 : ! CPErrorMessage(cp_failure_level,routineP,"DPOTRF failed")
2643 : ! CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
2644 : !END IF
2645 : !CALL dpotri('L', N, Ainv, N, INFO )
2646 : !IF( INFO.NE.0 ) THEN
2647 : ! CPErrorMessage(cp_failure_level,routineP,"DPOTRI failed")
2648 : ! CPPrecondition(.FALSE.,cp_failure_level,routineP,failure)
2649 : !END IF
2650 : !! complete the matrix
2651 : !DO ii=1,N
2652 : ! DO jj=ii+1,N
2653 : ! Ainv(ii,jj)=Ainv(jj,ii)
2654 : ! ENDDO
2655 : ! !WRITE(*,'(100F13.9)') Ainv(ii,:)
2656 : !ENDDO
2657 :
2658 : ! diagonalize first
2659 384 : ALLOCATE (eigenvalues(N))
2660 : ! Query the optimal workspace for dsyev
2661 128 : LWORK = -1
2662 128 : ALLOCATE (WORK(MAX(1, LWORK)))
2663 128 : CALL dsyev('V', 'L', N, Asqrtinv, N, eigenvalues, WORK, LWORK, INFO)
2664 128 : LWORK = INT(WORK(1))
2665 128 : DEALLOCATE (WORK)
2666 : ! Allocate the workspace and solve the eigenproblem
2667 384 : ALLOCATE (WORK(MAX(1, LWORK)))
2668 128 : CALL dsyev('V', 'L', N, Asqrtinv, N, eigenvalues, WORK, LWORK, INFO)
2669 128 : IF (INFO .NE. 0) THEN
2670 0 : IF (unit_nr > 0) WRITE (unit_nr, *) 'DSYEV ERROR MESSAGE: ', INFO
2671 0 : CPABORT("DSYEV failed")
2672 : END IF
2673 128 : DEALLOCATE (WORK)
2674 :
2675 : ! take functions of eigenvalues and use eigenvectors to compute the matrix function
2676 : ! first sqrt
2677 512 : ALLOCATE (test(N, N))
2678 6242 : DO jj = 1, N
2679 585400 : test(jj, :) = Asqrtinv(:, jj)*SQRT(eigenvalues(jj))
2680 : END DO
2681 384 : ALLOCATE (testN(N, N))
2682 899950 : testN(:, :) = MATMUL(Asqrtinv, test)
2683 585400 : Asqrt = testN
2684 : ! now, sqrt_inv
2685 6242 : DO jj = 1, N
2686 585400 : test(jj, :) = Asqrtinv(:, jj)/SQRT(eigenvalues(jj))
2687 : END DO
2688 899950 : testN(:, :) = MATMUL(Asqrtinv, test)
2689 585400 : Asqrtinv = testN
2690 128 : DEALLOCATE (test, testN)
2691 :
2692 128 : DEALLOCATE (eigenvalues)
2693 :
2694 : !!! ! compute the error
2695 : !!! allocate(test(N,N))
2696 : !!! test=MATMUL(Ainv,A)
2697 : !!! DO ii=1,N
2698 : !!! test(ii,ii)=test(ii,ii)-1.0_dp
2699 : !!! ENDDO
2700 : !!! test_error=0.0_dp
2701 : !!! DO ii=1,N
2702 : !!! DO jj=1,N
2703 : !!! test_error=test_error+test(jj,ii)*test(jj,ii)
2704 : !!! ENDDO
2705 : !!! ENDDO
2706 : !!! WRITE(*,*) "Inversion error: ", SQRT(test_error)
2707 : !!! deallocate(test)
2708 :
2709 128 : CALL timestop(handle)
2710 :
2711 128 : END SUBROUTINE matrix_sqrt
2712 :
2713 : ! **************************************************************************************************
2714 : !> \brief Inverts a matrix using a requested method
2715 : !> 0. Cholesky factorization
2716 : !> 1. Diagonalization
2717 : !> \param A ...
2718 : !> \param Ainv ...
2719 : !> \param N ...
2720 : !> \param method ...
2721 : !> \param range1 ...
2722 : !> \param range2 ...
2723 : !> \param range1_thr ...
2724 : !> \param shift ...
2725 : !> \param bad_modes_projector_down ...
2726 : !> \param s_inv_half ...
2727 : !> \param s_half ...
2728 : !> \par History
2729 : !> 2012.04 created [Rustam Z. Khaliullin]
2730 : !> \author Rustam Z. Khaliullin
2731 : ! **************************************************************************************************
2732 1023 : SUBROUTINE pseudo_invert_matrix(A, Ainv, N, method, range1, range2, range1_thr, &
2733 2046 : shift, bad_modes_projector_down, s_inv_half, s_half)
2734 :
2735 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: A
2736 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: Ainv
2737 : INTEGER, INTENT(IN) :: N, method
2738 : INTEGER, INTENT(IN), OPTIONAL :: range1, range2
2739 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: range1_thr, shift
2740 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT), &
2741 : OPTIONAL :: bad_modes_projector_down
2742 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
2743 : OPTIONAL :: s_inv_half, s_half
2744 :
2745 : CHARACTER(len=*), PARAMETER :: routineN = 'pseudo_invert_matrix'
2746 :
2747 : INTEGER :: handle, INFO, jj, LWORK, range1_eiv, &
2748 : range2_eiv, range3_eiv, unit_nr
2749 : LOGICAL :: use_both, use_ranges_only, use_thr_only
2750 : REAL(KIND=dp) :: my_shift
2751 1023 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, WORK
2752 1023 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: temp1, temp2, temp3, temp4
2753 : TYPE(cp_logger_type), POINTER :: logger
2754 :
2755 1023 : CALL timeset(routineN, handle)
2756 :
2757 : ! get a useful unit_nr
2758 1023 : logger => cp_get_default_logger()
2759 1023 : IF (logger%para_env%is_source()) THEN
2760 514 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
2761 : ELSE
2762 : unit_nr = -1
2763 : END IF
2764 :
2765 1023 : IF (method .EQ. 1) THEN
2766 :
2767 844 : IF ((PRESENT(range1) .AND. (.NOT. PRESENT(range2))) .OR. (PRESENT(range2) .AND. (.NOT. PRESENT(range1)))) THEN
2768 0 : CPABORT("range1 and range2 must be provided together")
2769 : END IF
2770 :
2771 844 : IF (PRESENT(range1) .AND. PRESENT(range1_thr)) THEN
2772 : use_both = .TRUE.
2773 : use_thr_only = .FALSE.
2774 : use_ranges_only = .FALSE.
2775 : ELSE
2776 784 : use_both = .FALSE.
2777 :
2778 784 : IF (PRESENT(range1)) THEN
2779 : use_ranges_only = .TRUE.
2780 : ELSE
2781 0 : use_ranges_only = .FALSE.
2782 : END IF
2783 :
2784 784 : IF (PRESENT(range1_thr)) THEN
2785 : use_thr_only = .TRUE.
2786 : ELSE
2787 784 : use_thr_only = .FALSE.
2788 : END IF
2789 :
2790 : END IF
2791 :
2792 844 : IF ((PRESENT(s_half) .AND. (.NOT. PRESENT(s_inv_half))) .OR. (PRESENT(s_inv_half) .AND. (.NOT. PRESENT(s_half)))) THEN
2793 0 : CPABORT("Domain overlap matrix missing")
2794 : END IF
2795 : END IF
2796 :
2797 1023 : my_shift = 0.0_dp
2798 1023 : IF (PRESENT(shift)) THEN
2799 319 : my_shift = shift
2800 : END IF
2801 :
2802 2592719 : Ainv = A
2803 1023 : INFO = 0
2804 :
2805 179 : SELECT CASE (method)
2806 : CASE (0) ! Inversion via cholesky factorization
2807 179 : CALL invmat_symm(Ainv)
2808 : CASE (1)
2809 :
2810 : ! diagonalize first
2811 2532 : ALLOCATE (eigenvalues(N))
2812 3376 : ALLOCATE (temp1(N, N))
2813 2532 : ALLOCATE (temp4(N, N))
2814 844 : IF (PRESENT(s_inv_half)) THEN
2815 60 : CALL dsymm('L', 'U', N, N, 1.0_dp, s_inv_half, N, A, N, 0.0_dp, temp1, N)
2816 60 : CALL dsymm('R', 'U', N, N, 1.0_dp, s_inv_half, N, temp1, N, 0.0_dp, Ainv, N)
2817 : END IF
2818 : ! Query the optimal workspace for dsyev
2819 844 : LWORK = -1
2820 844 : ALLOCATE (WORK(MAX(1, LWORK)))
2821 844 : CALL dsyev('V', 'L', N, Ainv, N, eigenvalues, WORK, LWORK, INFO)
2822 :
2823 844 : LWORK = INT(WORK(1))
2824 844 : DEALLOCATE (WORK)
2825 : ! Allocate the workspace and solve the eigenproblem
2826 2532 : ALLOCATE (WORK(MAX(1, LWORK)))
2827 844 : CALL dsyev('V', 'L', N, Ainv, N, eigenvalues, WORK, LWORK, INFO)
2828 :
2829 844 : IF (INFO .NE. 0) THEN
2830 0 : IF (unit_nr > 0) WRITE (unit_nr, *) 'EIGENSYSTEM ERROR MESSAGE: ', INFO
2831 0 : CPABORT("Eigenproblem routine failed")
2832 : END IF
2833 844 : DEALLOCATE (WORK)
2834 :
2835 : !WRITE(*,*) "EIGENVALS: "
2836 : !WRITE(*,'(4F13.9)') eigenvalues(:)
2837 :
2838 : ! invert eigenvalues and use eigenvectors to compute pseudo Ainv
2839 : ! project out near-zero eigenvalue modes
2840 2532 : ALLOCATE (temp2(N, N))
2841 964 : IF (PRESENT(bad_modes_projector_down)) ALLOCATE (temp3(N, N))
2842 2015494 : temp2(1:N, 1:N) = Ainv(1:N, 1:N)
2843 :
2844 844 : range1_eiv = 0
2845 844 : range2_eiv = 0
2846 844 : range3_eiv = 0
2847 :
2848 844 : IF (use_both) THEN
2849 1116 : DO jj = 1, N
2850 1116 : IF ((jj .LE. range2) .AND. (eigenvalues(jj) .LT. range1_thr)) THEN
2851 9274 : temp1(jj, :) = temp2(:, jj)*0.0_dp
2852 9274 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
2853 454 : range1_eiv = range1_eiv + 1
2854 : ELSE
2855 17528 : temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
2856 17528 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
2857 602 : range2_eiv = range2_eiv + 1
2858 : END IF
2859 : END DO
2860 : ELSE
2861 784 : IF (use_ranges_only) THEN
2862 34678 : DO jj = 1, N
2863 34678 : IF (jj .LE. range1) THEN
2864 152199 : temp1(jj, :) = temp2(:, jj)*0.0_dp
2865 3173 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
2866 3173 : range1_eiv = range1_eiv + 1
2867 30721 : ELSE IF (jj .LE. range2) THEN
2868 256093 : temp1(jj, :) = temp2(:, jj)*1.0_dp
2869 4129 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
2870 4129 : range2_eiv = range2_eiv + 1
2871 : ELSE
2872 1579556 : temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
2873 26592 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
2874 26592 : range3_eiv = range3_eiv + 1
2875 : END IF
2876 : END DO
2877 0 : ELSE IF (use_thr_only) THEN
2878 0 : DO jj = 1, N
2879 0 : IF (eigenvalues(jj) .LT. range1_thr) THEN
2880 0 : temp1(jj, :) = temp2(:, jj)*0.0_dp
2881 0 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*1.0_dp
2882 0 : range1_eiv = range1_eiv + 1
2883 : ELSE
2884 0 : temp1(jj, :) = temp2(:, jj)/(eigenvalues(jj) + my_shift)
2885 0 : IF (PRESENT(bad_modes_projector_down)) temp3(jj, :) = Ainv(:, jj)*0.0_dp
2886 0 : range2_eiv = range2_eiv + 1
2887 : END IF
2888 : END DO
2889 : ELSE ! no ranges, no thresholds
2890 0 : CPABORT("Invert using Cholesky. It would be faster.")
2891 : END IF
2892 : END IF
2893 : !WRITE(*,*) ' EIV RANGES: ', range1_eiv, range2_eiv, range3_eiv
2894 844 : IF (PRESENT(bad_modes_projector_down)) THEN
2895 60 : IF (PRESENT(s_half)) THEN
2896 60 : CALL dsymm('L', 'U', N, N, 1.0_dp, s_half, N, temp2, N, 0.0_dp, Ainv, N)
2897 60 : CALL dsymm('R', 'U', N, N, 1.0_dp, s_half, N, temp3, N, 0.0_dp, temp4, N)
2898 60 : CALL dgemm('N', 'N', N, N, N, 1.0_dp, Ainv, N, temp4, N, 0.0_dp, bad_modes_projector_down, N)
2899 : ELSE
2900 0 : CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp2, N, temp3, N, 0.0_dp, bad_modes_projector_down, N)
2901 : END IF
2902 : END IF
2903 :
2904 844 : IF (PRESENT(s_inv_half)) THEN
2905 60 : CALL dsymm('L', 'U', N, N, 1.0_dp, s_inv_half, N, temp2, N, 0.0_dp, temp4, N)
2906 60 : CALL dsymm('R', 'U', N, N, 1.0_dp, s_inv_half, N, temp1, N, 0.0_dp, temp2, N)
2907 60 : CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp4, N, temp2, N, 0.0_dp, Ainv, N)
2908 : ELSE
2909 784 : CALL dgemm('N', 'N', N, N, N, 1.0_dp, temp2, N, temp1, N, 0.0_dp, Ainv, N)
2910 : END IF
2911 844 : DEALLOCATE (temp1, temp2, temp4)
2912 844 : IF (PRESENT(bad_modes_projector_down)) DEALLOCATE (temp3)
2913 844 : DEALLOCATE (eigenvalues)
2914 :
2915 : CASE DEFAULT
2916 :
2917 1023 : CPABORT("Illegal method selected for matrix inversion")
2918 :
2919 : END SELECT
2920 :
2921 : !! compute the inversion error
2922 : !allocate(temp1(N,N))
2923 : !temp1=MATMUL(Ainv,A)
2924 : !DO ii=1,N
2925 : ! temp1(ii,ii)=temp1(ii,ii)-1.0_dp
2926 : !ENDDO
2927 : !temp1_error=0.0_dp
2928 : !DO ii=1,N
2929 : ! DO jj=1,N
2930 : ! temp1_error=temp1_error+temp1(jj,ii)*temp1(jj,ii)
2931 : ! ENDDO
2932 : !ENDDO
2933 : !WRITE(*,*) "Inversion error: ", SQRT(temp1_error)
2934 : !deallocate(temp1)
2935 :
2936 1023 : CALL timestop(handle)
2937 :
2938 1023 : END SUBROUTINE pseudo_invert_matrix
2939 :
2940 : ! **************************************************************************************************
2941 : !> \brief Find matrix power using diagonalization
2942 : !> \param A ...
2943 : !> \param Apow ...
2944 : !> \param power ...
2945 : !> \param N ...
2946 : !> \param range1 ...
2947 : !> \param range1_thr ...
2948 : !> \param shift ...
2949 : !> \par History
2950 : !> 2012.04 created [Rustam Z. Khaliullin]
2951 : !> \author Rustam Z. Khaliullin
2952 : ! **************************************************************************************************
2953 0 : SUBROUTINE pseudo_matrix_power(A, Apow, power, N, range1, range1_thr, shift)
2954 :
2955 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: A
2956 : REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT) :: Apow
2957 : REAL(KIND=dp), INTENT(IN) :: power
2958 : INTEGER, INTENT(IN) :: N
2959 : INTEGER, INTENT(IN), OPTIONAL :: range1
2960 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: range1_thr, shift
2961 :
2962 : CHARACTER(len=*), PARAMETER :: routineN = 'pseudo_matrix_power'
2963 :
2964 : INTEGER :: handle, INFO, jj, LWORK, range1_eiv, &
2965 : range2_eiv, unit_nr
2966 : LOGICAL :: use_both, use_ranges, use_thr
2967 : REAL(KIND=dp) :: my_shift
2968 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigenvalues, WORK
2969 0 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: temp1, temp2
2970 : TYPE(cp_logger_type), POINTER :: logger
2971 :
2972 0 : CALL timeset(routineN, handle)
2973 :
2974 : ! get a useful unit_nr
2975 0 : logger => cp_get_default_logger()
2976 0 : IF (logger%para_env%is_source()) THEN
2977 0 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
2978 : ELSE
2979 : unit_nr = -1
2980 : END IF
2981 :
2982 0 : IF (PRESENT(range1) .AND. PRESENT(range1_thr)) THEN
2983 : use_both = .TRUE.
2984 : ELSE
2985 0 : use_both = .FALSE.
2986 0 : IF (PRESENT(range1)) THEN
2987 : use_ranges = .TRUE.
2988 : ELSE
2989 0 : use_ranges = .FALSE.
2990 0 : IF (PRESENT(range1_thr)) THEN
2991 : use_thr = .TRUE.
2992 : ELSE
2993 0 : use_thr = .FALSE.
2994 : END IF
2995 : END IF
2996 : END IF
2997 :
2998 0 : my_shift = 0.0_dp
2999 0 : IF (PRESENT(shift)) THEN
3000 0 : my_shift = shift
3001 : END IF
3002 :
3003 0 : Apow = A
3004 0 : INFO = 0
3005 :
3006 : ! diagonalize first
3007 0 : ALLOCATE (eigenvalues(N))
3008 0 : ALLOCATE (temp1(N, N))
3009 :
3010 : ! Query the optimal workspace for dsyev
3011 0 : LWORK = -1
3012 0 : ALLOCATE (WORK(MAX(1, LWORK)))
3013 0 : CALL dsyev('V', 'L', N, Apow, N, eigenvalues, WORK, LWORK, INFO)
3014 :
3015 0 : LWORK = INT(WORK(1))
3016 0 : DEALLOCATE (WORK)
3017 : ! Allocate the workspace and solve the eigenproblem
3018 0 : ALLOCATE (WORK(MAX(1, LWORK)))
3019 0 : CALL dsyev('V', 'L', N, Apow, N, eigenvalues, WORK, LWORK, INFO)
3020 :
3021 0 : IF (INFO .NE. 0) THEN
3022 0 : IF (unit_nr > 0) WRITE (unit_nr, *) 'EIGENSYSTEM ERROR MESSAGE: ', INFO
3023 0 : CPABORT("Eigenproblem routine failed")
3024 : END IF
3025 0 : DEALLOCATE (WORK)
3026 :
3027 : !WRITE(*,*) "EIGENVALS: "
3028 : !WRITE(*,'(4F13.9)') eigenvalues(:)
3029 :
3030 : ! invert eigenvalues and use eigenvectors to compute pseudo Ainv
3031 : ! project out near-zero eigenvalue modes
3032 0 : ALLOCATE (temp2(N, N))
3033 :
3034 0 : temp2(1:N, 1:N) = Apow(1:N, 1:N)
3035 :
3036 0 : range1_eiv = 0
3037 0 : range2_eiv = 0
3038 :
3039 0 : IF (use_both) THEN
3040 0 : DO jj = 1, N
3041 0 : IF ((jj .LE. range1) .AND. (eigenvalues(jj) .LT. range1_thr)) THEN
3042 0 : temp1(jj, :) = temp2(:, jj)*0.0_dp
3043 0 : range1_eiv = range1_eiv + 1
3044 : ELSE
3045 0 : temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
3046 : END IF
3047 : END DO
3048 : ELSE
3049 0 : IF (use_ranges) THEN
3050 0 : DO jj = 1, N
3051 0 : IF (jj .LE. range1) THEN
3052 0 : temp1(jj, :) = temp2(:, jj)*0.0_dp
3053 0 : range1_eiv = range1_eiv + 1
3054 : ELSE
3055 0 : temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
3056 : END IF
3057 : END DO
3058 : ELSE
3059 0 : IF (use_thr) THEN
3060 0 : DO jj = 1, N
3061 0 : IF (eigenvalues(jj) .LT. range1_thr) THEN
3062 0 : temp1(jj, :) = temp2(:, jj)*0.0_dp
3063 :
3064 0 : range1_eiv = range1_eiv + 1
3065 : ELSE
3066 0 : temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
3067 : END IF
3068 : END DO
3069 : ELSE
3070 0 : DO jj = 1, N
3071 0 : temp1(jj, :) = temp2(:, jj)*((eigenvalues(jj) + my_shift)**power)
3072 : END DO
3073 : END IF
3074 : END IF
3075 : END IF
3076 : !WRITE(*,*) ' EIV RANGES: ', range1_eiv, range2_eiv, range3_eiv
3077 0 : Apow = MATMUL(temp2, temp1)
3078 0 : DEALLOCATE (temp1, temp2)
3079 0 : DEALLOCATE (eigenvalues)
3080 :
3081 0 : CALL timestop(handle)
3082 :
3083 0 : END SUBROUTINE pseudo_matrix_power
3084 :
3085 : ! **************************************************************************************************
3086 : !> \brief Load balancing of the submatrix computations
3087 : !> \param almo_scf_env ...
3088 : !> \par History
3089 : !> 2013.02 created [Rustam Z. Khaliullin]
3090 : !> \author Rustam Z. Khaliullin
3091 : ! **************************************************************************************************
3092 116 : SUBROUTINE distribute_domains(almo_scf_env)
3093 :
3094 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
3095 :
3096 : CHARACTER(len=*), PARAMETER :: routineN = 'distribute_domains'
3097 :
3098 : INTEGER :: handle, idomain, least_loaded, nao, &
3099 : ncpus, ndomains
3100 116 : INTEGER, ALLOCATABLE, DIMENSION(:) :: index0
3101 116 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: cpu_load, domain_load
3102 : TYPE(dbcsr_distribution_type) :: dist
3103 :
3104 116 : CALL timeset(routineN, handle)
3105 :
3106 116 : ndomains = almo_scf_env%ndomains
3107 116 : CALL dbcsr_get_info(almo_scf_env%matrix_s(1), distribution=dist)
3108 116 : CALL dbcsr_distribution_get(dist, numnodes=ncpus)
3109 :
3110 348 : ALLOCATE (domain_load(ndomains))
3111 926 : DO idomain = 1, ndomains
3112 810 : nao = almo_scf_env%nbasis_of_domain(idomain)
3113 926 : domain_load(idomain) = (nao*nao*nao)*1.0_dp
3114 : END DO
3115 :
3116 348 : ALLOCATE (index0(ndomains))
3117 :
3118 116 : CALL sort(domain_load, ndomains, index0)
3119 :
3120 348 : ALLOCATE (cpu_load(ncpus))
3121 348 : cpu_load(:) = 0.0_dp
3122 :
3123 926 : DO idomain = 1, ndomains
3124 3240 : least_loaded = MINLOC(cpu_load, 1)
3125 810 : cpu_load(least_loaded) = cpu_load(least_loaded) + domain_load(idomain)
3126 926 : almo_scf_env%cpu_of_domain(index0(idomain)) = least_loaded - 1
3127 : END DO
3128 :
3129 116 : DEALLOCATE (cpu_load)
3130 116 : DEALLOCATE (index0)
3131 116 : DEALLOCATE (domain_load)
3132 :
3133 116 : CALL timestop(handle)
3134 :
3135 116 : END SUBROUTINE distribute_domains
3136 :
3137 : ! **************************************************************************************************
3138 : !> \brief Tests construction and release of domain submatrices
3139 : !> \param matrix_no ...
3140 : !> \param dpattern ...
3141 : !> \param map ...
3142 : !> \param node_of_domain ...
3143 : !> \par History
3144 : !> 2013.01 created [Rustam Z. Khaliullin]
3145 : !> \author Rustam Z. Khaliullin
3146 : ! **************************************************************************************************
3147 0 : SUBROUTINE construct_test(matrix_no, dpattern, map, node_of_domain)
3148 :
3149 : TYPE(dbcsr_type), INTENT(INOUT) :: matrix_no, dpattern
3150 : TYPE(domain_map_type), INTENT(IN) :: map
3151 : INTEGER, DIMENSION(:), INTENT(IN) :: node_of_domain
3152 :
3153 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_test'
3154 :
3155 : INTEGER :: handle, ndomains
3156 : TYPE(dbcsr_type) :: copy1
3157 : TYPE(domain_submatrix_type), ALLOCATABLE, &
3158 0 : DIMENSION(:) :: subm_nn, subm_no
3159 : TYPE(mp_comm_type) :: group
3160 :
3161 0 : CALL timeset(routineN, handle)
3162 :
3163 0 : CALL dbcsr_get_info(dpattern, group=group, nblkcols_total=ndomains)
3164 :
3165 0 : ALLOCATE (subm_no(ndomains), subm_nn(ndomains))
3166 0 : CALL init_submatrices(subm_no)
3167 0 : CALL init_submatrices(subm_nn)
3168 :
3169 : !CALL dbcsr_print(matrix_nn)
3170 : !CALL construct_submatrices(matrix_nn,subm_nn,dpattern,map,select_row_col)
3171 : !CALL print_submatrices(subm_nn,Group)
3172 :
3173 : !CALL dbcsr_print(matrix_no)
3174 0 : CALL construct_submatrices(matrix_no, subm_no, dpattern, map, node_of_domain, select_row)
3175 0 : CALL print_submatrices(subm_no, group)
3176 :
3177 0 : CALL dbcsr_create(copy1, template=matrix_no)
3178 0 : CALL dbcsr_copy(copy1, matrix_no)
3179 0 : CALL dbcsr_print(copy1)
3180 0 : CALL construct_dbcsr_from_submatrices(copy1, subm_no, dpattern)
3181 0 : CALL dbcsr_print(copy1)
3182 0 : CALL dbcsr_release(copy1)
3183 :
3184 0 : CALL release_submatrices(subm_no)
3185 0 : CALL release_submatrices(subm_nn)
3186 0 : DEALLOCATE (subm_no, subm_nn)
3187 :
3188 0 : CALL timestop(handle)
3189 :
3190 0 : END SUBROUTINE construct_test
3191 :
3192 : ! **************************************************************************************************
3193 : !> \brief create the initial guess for XALMOs
3194 : !> \param m_guess ...
3195 : !> \param m_t_in ...
3196 : !> \param m_t0 ...
3197 : !> \param m_quench_t ...
3198 : !> \param m_overlap ...
3199 : !> \param m_sigma_tmpl ...
3200 : !> \param nspins ...
3201 : !> \param xalmo_history ...
3202 : !> \param assume_t0_q0x ...
3203 : !> \param optimize_theta ...
3204 : !> \param envelope_amplitude ...
3205 : !> \param eps_filter ...
3206 : !> \param order_lanczos ...
3207 : !> \param eps_lanczos ...
3208 : !> \param max_iter_lanczos ...
3209 : !> \param nocc_of_domain ...
3210 : !> \par History
3211 : !> 2016.11 created [Rustam Z Khaliullin]
3212 : !> \author Rustam Z Khaliullin
3213 : ! **************************************************************************************************
3214 104 : SUBROUTINE xalmo_initial_guess(m_guess, m_t_in, m_t0, m_quench_t, &
3215 104 : m_overlap, m_sigma_tmpl, nspins, xalmo_history, assume_t0_q0x, &
3216 : optimize_theta, envelope_amplitude, eps_filter, order_lanczos, eps_lanczos, &
3217 104 : max_iter_lanczos, nocc_of_domain)
3218 :
3219 : TYPE(dbcsr_type), DIMENSION(:), INTENT(INOUT) :: m_guess
3220 : TYPE(dbcsr_type), DIMENSION(:), INTENT(IN) :: m_t_in, m_t0, m_quench_t
3221 : TYPE(dbcsr_type), INTENT(IN) :: m_overlap
3222 : TYPE(dbcsr_type), DIMENSION(:), INTENT(IN) :: m_sigma_tmpl
3223 : INTEGER, INTENT(IN) :: nspins
3224 : TYPE(almo_scf_history_type), INTENT(IN) :: xalmo_history
3225 : LOGICAL, INTENT(IN) :: assume_t0_q0x, optimize_theta
3226 : REAL(KIND=dp), INTENT(IN) :: envelope_amplitude, eps_filter
3227 : INTEGER, INTENT(IN) :: order_lanczos
3228 : REAL(KIND=dp), INTENT(IN) :: eps_lanczos
3229 : INTEGER, INTENT(IN) :: max_iter_lanczos
3230 : INTEGER, DIMENSION(:, :), INTENT(IN) :: nocc_of_domain
3231 :
3232 : CHARACTER(len=*), PARAMETER :: routineN = 'xalmo_initial_guess'
3233 :
3234 : INTEGER :: handle, iaspc, ispin, istore, naspc, &
3235 : unit_nr
3236 : LOGICAL :: aspc_guess
3237 : REAL(KIND=dp) :: alpha
3238 : TYPE(cp_logger_type), POINTER :: logger
3239 : TYPE(dbcsr_type) :: m_extrapolated, m_sigma_tmp
3240 :
3241 104 : CALL timeset(routineN, handle)
3242 :
3243 : ! get a useful output_unit
3244 104 : logger => cp_get_default_logger()
3245 104 : IF (logger%para_env%is_source()) THEN
3246 52 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
3247 : ELSE
3248 : unit_nr = -1
3249 : END IF
3250 :
3251 104 : IF (optimize_theta) THEN
3252 0 : CPWARN("unused option")
3253 : ! just not to trigger unused variable
3254 0 : alpha = envelope_amplitude
3255 : END IF
3256 :
3257 : ! if extrapolation order is zero then the standard guess is used
3258 : ! ... the number of stored history points will remain zero if extrapolation order is zero
3259 104 : IF (xalmo_history%istore == 0) THEN
3260 : aspc_guess = .FALSE.
3261 : ELSE
3262 : aspc_guess = .TRUE.
3263 : END IF
3264 :
3265 : ! create initial guess
3266 : IF (.NOT. aspc_guess) THEN
3267 :
3268 124 : DO ispin = 1, nspins
3269 :
3270 : ! zero initial guess for the delocalization amplitudes
3271 : ! or the supplied guess for orbitals
3272 124 : IF (assume_t0_q0x) THEN
3273 30 : CALL dbcsr_set(m_guess(ispin), 0.0_dp)
3274 : ELSE
3275 : ! copy coefficients to m_guess
3276 32 : CALL dbcsr_copy(m_guess(ispin), m_t_in(ispin))
3277 : END IF
3278 :
3279 : END DO !ispins
3280 :
3281 : ELSE !aspc_guess
3282 :
3283 42 : CALL cite_reference(Kolafa2004)
3284 42 : CALL cite_reference(Kuhne2007)
3285 :
3286 42 : naspc = MIN(xalmo_history%istore, xalmo_history%nstore)
3287 42 : IF (unit_nr > 0) THEN
3288 : WRITE (unit_nr, FMT="(/,T2,A,/,/,T3,A,I0)") &
3289 21 : "Parameters for the always stable predictor-corrector (ASPC) method:", &
3290 42 : "ASPC order: ", naspc
3291 : END IF
3292 :
3293 84 : DO ispin = 1, nspins
3294 :
3295 : CALL dbcsr_create(m_extrapolated, &
3296 42 : template=m_quench_t(ispin), matrix_type=dbcsr_type_no_symmetry)
3297 : CALL dbcsr_create(m_sigma_tmp, &
3298 42 : template=m_sigma_tmpl(ispin), matrix_type=dbcsr_type_no_symmetry)
3299 :
3300 : ! set to zero before accumulation
3301 42 : CALL dbcsr_set(m_guess(ispin), 0.0_dp)
3302 :
3303 : ! extrapolation
3304 124 : DO iaspc = 1, naspc
3305 :
3306 82 : istore = MOD(xalmo_history%istore - iaspc, xalmo_history%nstore) + 1
3307 : alpha = (-1.0_dp)**(iaspc + 1)*REAL(iaspc, KIND=dp)* &
3308 82 : binomial(2*naspc, naspc - iaspc)/binomial(2*naspc - 2, naspc - 1)
3309 82 : IF (unit_nr > 0) THEN
3310 : WRITE (unit_nr, FMT="(T3,A2,I0,A4,F10.6)") &
3311 41 : "B(", iaspc, ") = ", alpha
3312 : END IF
3313 :
3314 : ! m_extrapolated - initialize the correct sparsity pattern
3315 : ! it must be kept throughout extrapolation
3316 82 : CALL dbcsr_copy(m_extrapolated, m_quench_t(ispin))
3317 :
3318 : ! project t0 onto the previous DMs
3319 : ! note that t0 is projected instead of any other matrix (e.g.
3320 : ! t_SCF from the prev step or random t)
3321 : ! this is done to keep orbitals phase (i.e. sign) the same as in
3322 : ! t0. if this is not done then subtracting t0 on the next step
3323 : ! will produce a terrible guess and extrapolation will fail
3324 : CALL dbcsr_multiply("N", "N", 1.0_dp, &
3325 : xalmo_history%matrix_p_up_down(ispin, istore), &
3326 : m_t0(ispin), &
3327 : 0.0_dp, m_extrapolated, &
3328 82 : retain_sparsity=.TRUE.)
3329 : ! normalize MOs
3330 : CALL orthogonalize_mos(ket=m_extrapolated, &
3331 : overlap=m_sigma_tmp, &
3332 : metric=m_overlap, &
3333 : retain_locality=.TRUE., &
3334 : only_normalize=.FALSE., &
3335 : nocc_of_domain=nocc_of_domain(:, ispin), &
3336 : eps_filter=eps_filter, &
3337 : order_lanczos=order_lanczos, &
3338 : eps_lanczos=eps_lanczos, &
3339 82 : max_iter_lanczos=max_iter_lanczos)
3340 :
3341 : ! now accumulate. correct sparsity is ensured
3342 : CALL dbcsr_add(m_guess(ispin), m_extrapolated, &
3343 124 : 1.0_dp, (1.0_dp*alpha)/naspc)
3344 :
3345 : END DO !iaspc
3346 :
3347 42 : CALL dbcsr_release(m_extrapolated)
3348 :
3349 : ! normalize MOs
3350 : CALL orthogonalize_mos(ket=m_guess(ispin), &
3351 : overlap=m_sigma_tmp, &
3352 : metric=m_overlap, &
3353 : retain_locality=.TRUE., &
3354 : only_normalize=.FALSE., &
3355 : nocc_of_domain=nocc_of_domain(:, ispin), &
3356 : eps_filter=eps_filter, &
3357 : order_lanczos=order_lanczos, &
3358 : eps_lanczos=eps_lanczos, &
3359 42 : max_iter_lanczos=max_iter_lanczos)
3360 :
3361 42 : CALL dbcsr_release(m_sigma_tmp)
3362 :
3363 : ! project the t0 space out from the extrapolated state
3364 : ! this can be done outside this subroutine
3365 84 : IF (assume_t0_q0x) THEN
3366 : CALL dbcsr_add(m_guess(ispin), m_t0(ispin), &
3367 12 : 1.0_dp, -1.0_dp)
3368 : END IF !assume_t0_q0x
3369 :
3370 : END DO !ispin
3371 :
3372 : END IF !aspc_guess?
3373 :
3374 104 : CALL timestop(handle)
3375 :
3376 104 : END SUBROUTINE xalmo_initial_guess
3377 :
3378 : END MODULE almo_scf_methods
3379 :
|