Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Localization methods such as 2x2 Jacobi rotations
10 : !> Steepest Decents
11 : !> Conjugate Gradient
12 : !> \par History
13 : !> Initial parallellization of jacobi (JVDV 07.2003)
14 : !> direct minimization using exponential parametrization (JVDV 09.2003)
15 : !> crazy rotations go fast (JVDV 10.2003)
16 : !> \author CJM (04.2003)
17 : ! **************************************************************************************************
18 : MODULE qs_localization_methods
19 : USE bibliography, ONLY: Schreder2024_2,&
20 : cite_reference
21 : USE cell_types, ONLY: cell_type
22 : USE cp_blacs_env, ONLY: cp_blacs_env_type
23 : USE cp_cfm_basic_linalg, ONLY: cp_cfm_column_scale,&
24 : cp_cfm_gemm,&
25 : cp_cfm_rot_cols,&
26 : cp_cfm_rot_rows,&
27 : cp_cfm_scale,&
28 : cp_cfm_scale_and_add,&
29 : cp_cfm_schur_product,&
30 : cp_cfm_trace
31 : USE cp_cfm_diag, ONLY: cp_cfm_heevd
32 : USE cp_cfm_types, ONLY: &
33 : cp_cfm_create, cp_cfm_get_element, cp_cfm_get_info, cp_cfm_get_submatrix, cp_cfm_release, &
34 : cp_cfm_set_all, cp_cfm_set_element, cp_cfm_set_submatrix, cp_cfm_to_cfm, cp_cfm_to_fm, &
35 : cp_cfm_type, cp_fm_to_cfm
36 : USE cp_dbcsr_api, ONLY: dbcsr_p_type
37 : USE cp_dbcsr_operations, ONLY: cp_dbcsr_sm_fm_multiply
38 : USE cp_external_control, ONLY: external_control
39 : USE cp_fm_basic_linalg, ONLY: cp_fm_frobenius_norm,&
40 : cp_fm_pdgeqpf,&
41 : cp_fm_pdorgqr,&
42 : cp_fm_scale,&
43 : cp_fm_scale_and_add,&
44 : cp_fm_trace,&
45 : cp_fm_transpose,&
46 : cp_fm_triangular_multiply
47 : USE cp_fm_cholesky, ONLY: cp_fm_cholesky_decompose
48 : USE cp_fm_diag, ONLY: choose_eigv_solver,&
49 : cp_fm_syevd
50 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
51 : cp_fm_struct_get,&
52 : cp_fm_struct_release,&
53 : cp_fm_struct_type
54 : USE cp_fm_types, ONLY: &
55 : cp_fm_create, cp_fm_get_element, cp_fm_get_info, cp_fm_get_submatrix, cp_fm_init_random, &
56 : cp_fm_maxabsrownorm, cp_fm_maxabsval, cp_fm_release, cp_fm_set_all, cp_fm_set_submatrix, &
57 : cp_fm_to_fm, cp_fm_to_fm_submat, cp_fm_type
58 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit,&
59 : cp_logger_get_default_unit_nr
60 : USE kahan_sum, ONLY: accurate_sum
61 : USE kinds, ONLY: dp
62 : USE machine, ONLY: m_flush,&
63 : m_walltime
64 : USE mathconstants, ONLY: gaussi,&
65 : pi,&
66 : twopi,&
67 : z_one,&
68 : z_zero
69 : USE matrix_exp, ONLY: exp_pade_real,&
70 : get_nsquare_norder
71 : USE message_passing, ONLY: mp_para_env_type
72 : USE parallel_gemm_api, ONLY: parallel_gemm
73 : #include "./base/base_uses.f90"
74 :
75 : IMPLICIT NONE
76 : PUBLIC :: initialize_weights, crazy_rotations, &
77 : direct_mini, rotate_orbitals, approx_l1_norm_sd, jacobi_rotations, scdm_qrfact, zij_matrix, &
78 : jacobi_cg_edf_ls, cardoso_souloumiac, cardoso_souloumiac_pipek
79 :
80 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_localization_methods'
81 :
82 : PRIVATE
83 :
84 : TYPE set_c_1d_type
85 : COMPLEX(KIND=dp), POINTER, DIMENSION(:) :: c_array => NULL()
86 : END TYPE set_c_1d_type
87 :
88 : TYPE set_c_2d_type
89 : COMPLEX(KIND=dp), POINTER, DIMENSION(:, :) :: c_array => NULL()
90 : END TYPE set_c_2d_type
91 :
92 : CONTAINS
93 : ! **************************************************************************************************
94 : !> \brief ...
95 : !> \param C ...
96 : !> \param iterations ...
97 : !> \param eps ...
98 : !> \param converged ...
99 : !> \param sweeps ...
100 : ! **************************************************************************************************
101 210 : SUBROUTINE approx_l1_norm_sd(C, iterations, eps, converged, sweeps)
102 : TYPE(cp_fm_type), INTENT(IN) :: C
103 : INTEGER, INTENT(IN) :: iterations
104 : REAL(KIND=dp), INTENT(IN) :: eps
105 : LOGICAL, INTENT(INOUT) :: converged
106 : INTEGER, INTENT(INOUT) :: sweeps
107 :
108 : CHARACTER(len=*), PARAMETER :: routineN = 'approx_l1_norm_sd'
109 : INTEGER, PARAMETER :: taylor_order = 100
110 : REAL(KIND=dp), PARAMETER :: alpha = 0.1_dp, f2_eps = 0.01_dp
111 :
112 : INTEGER :: handle, i, istep, k, n, ncol_local, &
113 : nrow_local, output_unit, p
114 : REAL(KIND=dp) :: expfactor, f2, f2old, gnorm, tnorm
115 : TYPE(cp_blacs_env_type), POINTER :: context
116 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_k_k
117 : TYPE(cp_fm_type) :: CTmp, G, Gp1, Gp2, U
118 : TYPE(mp_para_env_type), POINTER :: para_env
119 :
120 30 : CALL timeset(routineN, handle)
121 :
122 30 : NULLIFY (context, para_env, fm_struct_k_k)
123 :
124 30 : output_unit = cp_logger_get_default_io_unit()
125 :
126 : CALL cp_fm_struct_get(C%matrix_struct, nrow_global=n, ncol_global=k, &
127 : nrow_local=nrow_local, ncol_local=ncol_local, &
128 30 : para_env=para_env, context=context)
129 : CALL cp_fm_struct_create(fm_struct_k_k, para_env=para_env, context=context, &
130 30 : nrow_global=k, ncol_global=k)
131 30 : CALL cp_fm_create(CTmp, C%matrix_struct)
132 30 : CALL cp_fm_create(U, fm_struct_k_k)
133 30 : CALL cp_fm_create(G, fm_struct_k_k)
134 30 : CALL cp_fm_create(Gp1, fm_struct_k_k)
135 30 : CALL cp_fm_create(Gp2, fm_struct_k_k)
136 : !
137 : ! printing
138 30 : IF (output_unit > 0) THEN
139 15 : WRITE (output_unit, '(1X)')
140 15 : WRITE (output_unit, '(2X,A)') '-----------------------------------------------------------------------------'
141 15 : WRITE (output_unit, '(A,I5)') ' Nbr iterations =', iterations
142 15 : WRITE (output_unit, '(A,E10.2)') ' eps convergence =', eps
143 15 : WRITE (output_unit, '(A,I5)') ' Max Taylor order =', taylor_order
144 15 : WRITE (output_unit, '(A,E10.2)') ' f2 eps =', f2_eps
145 15 : WRITE (output_unit, '(A,E10.2)') ' alpha =', alpha
146 15 : WRITE (output_unit, '(A)') ' iteration approx_l1_norm g_norm rel_err'
147 : END IF
148 : !
149 30 : f2old = 0.0_dp
150 30 : converged = .FALSE.
151 : !
152 : ! Start the steepest descent
153 1480 : DO istep = 1, iterations
154 : !
155 : !-------------------------------------------------------------------
156 : ! compute f_2
157 : ! f_2(x)=(x^2+eps)^1/2
158 1470 : f2 = 0.0_dp
159 22748 : DO p = 1, ncol_local ! p
160 1100956 : DO i = 1, nrow_local ! i
161 1099486 : f2 = f2 + SQRT(C%local_data(i, p)**2 + f2_eps)
162 : END DO
163 : END DO
164 1470 : CALL C%matrix_struct%para_env%sum(f2)
165 : !-------------------------------------------------------------------
166 : ! compute the derivative of f_2
167 : ! f_2(x)=(x^2+eps)^1/2
168 22748 : DO p = 1, ncol_local ! p
169 1100956 : DO i = 1, nrow_local ! i
170 1099486 : CTmp%local_data(i, p) = C%local_data(i, p)/SQRT(C%local_data(i, p)**2 + f2_eps)
171 : END DO
172 : END DO
173 1470 : CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, CTmp, C, 0.0_dp, G)
174 : ! antisymmetrize
175 1470 : CALL cp_fm_transpose(G, U)
176 1470 : CALL cp_fm_scale_and_add(-0.5_dp, G, 0.5_dp, U)
177 : !
178 : !-------------------------------------------------------------------
179 : !
180 1470 : gnorm = cp_fm_frobenius_norm(G)
181 : !
182 : ! rescale for steepest descent
183 1470 : CALL cp_fm_scale(-alpha, G)
184 : !
185 : ! compute unitary transform
186 : ! zeroth order
187 1470 : CALL cp_fm_set_all(U, 0.0_dp, 1.0_dp)
188 : ! first order
189 1470 : expfactor = 1.0_dp
190 1470 : CALL cp_fm_scale_and_add(1.0_dp, U, expfactor, G)
191 1470 : tnorm = cp_fm_frobenius_norm(G)
192 1470 : IF (tnorm > 1.0E-10_dp) THEN
193 : ! other orders
194 1470 : CALL cp_fm_to_fm(G, Gp1)
195 4866 : DO i = 2, taylor_order
196 : ! new power of G
197 4866 : CALL parallel_gemm('N', 'N', k, k, k, 1.0_dp, G, Gp1, 0.0_dp, Gp2)
198 4866 : CALL cp_fm_to_fm(Gp2, Gp1)
199 : ! add to the taylor expansion so far
200 4866 : expfactor = expfactor/REAL(i, KIND=dp)
201 4866 : CALL cp_fm_scale_and_add(1.0_dp, U, expfactor, Gp1)
202 4866 : tnorm = cp_fm_frobenius_norm(Gp1)
203 4866 : IF (tnorm*expfactor < 1.0E-10_dp) EXIT
204 : END DO
205 : END IF
206 : !
207 : ! incrementaly rotate the MOs
208 1470 : CALL parallel_gemm('N', 'N', n, k, k, 1.0_dp, C, U, 0.0_dp, CTmp)
209 1470 : CALL cp_fm_to_fm(CTmp, C)
210 : !
211 : ! printing
212 1470 : IF (output_unit > 0) THEN
213 735 : WRITE (output_unit, '(10X,I4,E18.10,2E10.2)') istep, f2, gnorm, ABS((f2 - f2old)/f2)
214 : END IF
215 : !
216 : ! Are we done?
217 1470 : sweeps = istep
218 1470 : IF (ABS((f2 - f2old)/f2) <= eps .AND. istep > 1) THEN
219 20 : converged = .TRUE.
220 20 : EXIT
221 : END IF
222 1460 : f2old = f2
223 : END DO
224 : !
225 : ! here we should do one refine step to enforce C'*S*C=1 for any case
226 : !
227 : ! Print the final result
228 30 : IF (output_unit > 0) WRITE (output_unit, '(A,E16.10)') ' sparseness function f2 = ', f2
229 : ! deallocate
230 30 : CALL cp_fm_struct_release(fm_struct_k_k)
231 30 : CALL cp_fm_release(CTmp)
232 30 : CALL cp_fm_release(U)
233 30 : CALL cp_fm_release(G)
234 30 : CALL cp_fm_release(Gp1)
235 30 : CALL cp_fm_release(Gp2)
236 :
237 30 : CALL timestop(handle)
238 :
239 30 : END SUBROUTINE approx_l1_norm_sd
240 : ! **************************************************************************************************
241 : !> \brief ...
242 : !> \param cell ...
243 : !> \param weights ...
244 : ! **************************************************************************************************
245 504 : SUBROUTINE initialize_weights(cell, weights)
246 :
247 : TYPE(cell_type), POINTER :: cell
248 : REAL(KIND=dp), DIMENSION(:) :: weights
249 :
250 : REAL(KIND=dp), DIMENSION(3, 3) :: metric
251 :
252 504 : CPASSERT(ASSOCIATED(cell))
253 :
254 504 : metric = 0.0_dp
255 504 : CALL dgemm('T', 'N', 3, 3, 3, 1._dp, cell%hmat(:, :), 3, cell%hmat(:, :), 3, 0.0_dp, metric(:, :), 3)
256 :
257 504 : weights(1) = METRIC(1, 1) - METRIC(1, 2) - METRIC(1, 3)
258 504 : weights(2) = METRIC(2, 2) - METRIC(1, 2) - METRIC(2, 3)
259 504 : weights(3) = METRIC(3, 3) - METRIC(1, 3) - METRIC(2, 3)
260 504 : weights(4) = METRIC(1, 2)
261 504 : weights(5) = METRIC(1, 3)
262 504 : weights(6) = METRIC(2, 3)
263 :
264 504 : END SUBROUTINE initialize_weights
265 :
266 : ! **************************************************************************************************
267 : !> \brief wrapper for the jacobi routines, should be removed if jacobi_rot_para
268 : !> can deal with serial para_envs.
269 : !> \param weights ...
270 : !> \param zij ...
271 : !> \param vectors ...
272 : !> \param para_env ...
273 : !> \param max_iter ...
274 : !> \param eps_localization ...
275 : !> \param sweeps ...
276 : !> \param out_each ...
277 : !> \param target_time ...
278 : !> \param start_time ...
279 : !> \param restricted ...
280 : !> \par History
281 : !> \author Joost VandeVondele (02.2010)
282 : ! **************************************************************************************************
283 390 : SUBROUTINE jacobi_rotations(weights, zij, vectors, para_env, max_iter, &
284 : eps_localization, sweeps, out_each, target_time, start_time, restricted)
285 :
286 : REAL(KIND=dp), INTENT(IN) :: weights(:)
287 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
288 : TYPE(mp_para_env_type), POINTER :: para_env
289 : INTEGER, INTENT(IN) :: max_iter
290 : REAL(KIND=dp), INTENT(IN) :: eps_localization
291 : INTEGER :: sweeps
292 : INTEGER, INTENT(IN) :: out_each
293 : REAL(dp) :: target_time, start_time
294 : INTEGER :: restricted
295 :
296 390 : IF (para_env%num_pe == 1) THEN
297 : CALL jacobi_rotations_serial(weights, zij, vectors, max_iter, eps_localization, &
298 0 : sweeps, out_each, restricted=restricted)
299 : ELSE
300 : CALL jacobi_rot_para(weights, zij, vectors, para_env, max_iter, eps_localization, &
301 390 : sweeps, out_each, target_time, start_time, restricted=restricted)
302 : END IF
303 :
304 390 : END SUBROUTINE jacobi_rotations
305 :
306 : ! **************************************************************************************************
307 : !> \brief this routine, private to the module is a serial backup, till we have jacobi_rot_para to work in serial
308 : !> while the routine below works in parallel, it is too slow to be useful
309 : !> \param weights ...
310 : !> \param zij ...
311 : !> \param vectors ...
312 : !> \param max_iter ...
313 : !> \param eps_localization ...
314 : !> \param sweeps ...
315 : !> \param out_each ...
316 : !> \param restricted ...
317 : ! **************************************************************************************************
318 0 : SUBROUTINE jacobi_rotations_serial(weights, zij, vectors, max_iter, eps_localization, sweeps, &
319 : out_each, restricted)
320 : REAL(KIND=dp), INTENT(IN) :: weights(:)
321 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
322 : INTEGER, INTENT(IN) :: max_iter
323 : REAL(KIND=dp), INTENT(IN) :: eps_localization
324 : INTEGER :: sweeps
325 : INTEGER, INTENT(IN) :: out_each
326 : INTEGER :: restricted
327 :
328 : CHARACTER(len=*), PARAMETER :: routineN = 'jacobi_rotations_serial'
329 :
330 : COMPLEX(KIND=dp), POINTER :: mii(:), mij(:), mjj(:)
331 : INTEGER :: dim2, handle, idim, istate, jstate, &
332 : nstate, unit_nr
333 : REAL(KIND=dp) :: ct, st, t1, t2, theta, tolerance
334 : TYPE(cp_cfm_type) :: c_rmat
335 : TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:) :: c_zij
336 : TYPE(cp_fm_type) :: rmat
337 :
338 0 : CALL timeset(routineN, handle)
339 :
340 0 : dim2 = SIZE(zij, 2)
341 0 : ALLOCATE (c_zij(dim2))
342 : NULLIFY (mii, mij, mjj)
343 0 : ALLOCATE (mii(dim2), mij(dim2), mjj(dim2))
344 :
345 0 : CALL cp_fm_create(rmat, zij(1, 1)%matrix_struct)
346 0 : CALL cp_fm_set_all(rmat, 0._dp, 1._dp)
347 :
348 0 : CALL cp_cfm_create(c_rmat, zij(1, 1)%matrix_struct)
349 0 : CALL cp_cfm_set_all(c_rmat, (0._dp, 0._dp), (1._dp, 0._dp))
350 0 : DO idim = 1, dim2
351 0 : CALL cp_cfm_create(c_zij(idim), zij(1, 1)%matrix_struct)
352 : c_zij(idim)%local_data = CMPLX(zij(1, idim)%local_data, &
353 0 : zij(2, idim)%local_data, dp)
354 : END DO
355 :
356 0 : CALL cp_fm_get_info(rmat, nrow_global=nstate)
357 0 : tolerance = 1.0e10_dp
358 :
359 0 : sweeps = 0
360 0 : unit_nr = -1
361 0 : IF (rmat%matrix_struct%para_env%is_source()) THEN
362 0 : unit_nr = cp_logger_get_default_unit_nr()
363 0 : WRITE (unit_nr, '(T4,A )') " Localization by iterative Jacobi rotation"
364 : END IF
365 :
366 0 : IF (restricted > 0) THEN
367 0 : unit_nr = cp_logger_get_default_unit_nr()
368 0 : WRITE (unit_nr, '(T4,A,I2,A )') "JACOBI: for the ROKS method, the last ", restricted, " orbitals DO NOT ROTATE"
369 0 : nstate = nstate - restricted
370 : END IF
371 :
372 : ! do jacobi sweeps until converged
373 0 : DO WHILE (tolerance >= eps_localization .AND. sweeps < max_iter)
374 0 : sweeps = sweeps + 1
375 0 : t1 = m_walltime()
376 :
377 0 : DO istate = 1, nstate
378 0 : DO jstate = istate + 1, nstate
379 0 : DO idim = 1, dim2
380 0 : CALL cp_cfm_get_element(c_zij(idim), istate, istate, mii(idim))
381 0 : CALL cp_cfm_get_element(c_zij(idim), istate, jstate, mij(idim))
382 0 : CALL cp_cfm_get_element(c_zij(idim), jstate, jstate, mjj(idim))
383 : END DO
384 0 : CALL get_angle(mii, mjj, mij, weights, theta)
385 0 : st = SIN(theta)
386 0 : ct = COS(theta)
387 0 : CALL rotate_zij(istate, jstate, st, ct, c_zij)
388 :
389 0 : CALL rotate_rmat(istate, jstate, st, ct, c_rmat)
390 : END DO
391 : END DO
392 :
393 0 : CALL check_tolerance(c_zij, weights, tolerance)
394 :
395 0 : t2 = m_walltime()
396 0 : IF (unit_nr > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
397 : WRITE (unit_nr, '(T4,A,I7,T30,A,E12.4,T60,A,F8.3)') &
398 0 : "Iteration:", sweeps, "Tolerance:", tolerance, "Time:", t2 - t1
399 0 : CALL m_flush(unit_nr)
400 : END IF
401 :
402 : END DO
403 :
404 0 : DO idim = 1, dim2
405 0 : zij(1, idim)%local_data = REAL(c_zij(idim)%local_data, dp)
406 0 : zij(2, idim)%local_data = AIMAG(c_zij(idim)%local_data)
407 0 : CALL cp_cfm_release(c_zij(idim))
408 : END DO
409 0 : DEALLOCATE (c_zij)
410 0 : DEALLOCATE (mii, mij, mjj)
411 0 : rmat%local_data = REAL(c_rmat%local_data, dp)
412 :
413 0 : CALL rotate_orbitals(rmat, vectors)
414 :
415 0 : CALL cp_cfm_release(c_rmat)
416 0 : CALL cp_fm_release(rmat)
417 :
418 0 : CALL timestop(handle)
419 :
420 0 : END SUBROUTINE jacobi_rotations_serial
421 : ! **************************************************************************************************
422 : !> \brief very similar to jacobi_rotations_serial with some extra output options
423 : !> \param weights ...
424 : !> \param c_zij ...
425 : !> \param max_iter ...
426 : !> \param c_rmat ...
427 : !> \param eps_localization ...
428 : !> \param tol_out ...
429 : !> \param jsweeps ...
430 : !> \param out_each ...
431 : !> \param c_zij_out ...
432 : !> \param grad_final ...
433 : ! **************************************************************************************************
434 0 : SUBROUTINE jacobi_rotations_serial_1(weights, c_zij, max_iter, c_rmat, eps_localization, &
435 0 : tol_out, jsweeps, out_each, c_zij_out, grad_final)
436 : REAL(KIND=dp), INTENT(IN) :: weights(:)
437 : TYPE(cp_cfm_type), INTENT(IN) :: c_zij(:)
438 : INTEGER, INTENT(IN) :: max_iter
439 : TYPE(cp_cfm_type), INTENT(IN) :: c_rmat
440 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: eps_localization
441 : REAL(KIND=dp), INTENT(OUT), OPTIONAL :: tol_out
442 : INTEGER, INTENT(OUT), OPTIONAL :: jsweeps
443 : INTEGER, INTENT(IN), OPTIONAL :: out_each
444 : TYPE(cp_cfm_type), INTENT(IN), OPTIONAL :: c_zij_out(:)
445 : TYPE(cp_fm_type), INTENT(OUT), OPTIONAL, POINTER :: grad_final
446 :
447 : CHARACTER(len=*), PARAMETER :: routineN = 'jacobi_rotations_serial_1'
448 :
449 : COMPLEX(KIND=dp) :: mzii
450 : COMPLEX(KIND=dp), POINTER :: mii(:), mij(:), mjj(:)
451 : INTEGER :: dim2, handle, idim, istate, jstate, &
452 : nstate, sweeps, unit_nr
453 : REAL(KIND=dp) :: alpha, avg_spread_ii, ct, spread_ii, st, &
454 : sum_spread_ii, t1, t2, theta, tolerance
455 : TYPE(cp_cfm_type) :: c_rmat_local
456 : TYPE(cp_cfm_type), ALLOCATABLE :: c_zij_local(:)
457 :
458 0 : CALL timeset(routineN, handle)
459 :
460 0 : dim2 = SIZE(c_zij)
461 : NULLIFY (mii, mij, mjj)
462 0 : ALLOCATE (mii(dim2), mij(dim2), mjj(dim2))
463 :
464 0 : ALLOCATE (c_zij_local(dim2))
465 0 : CALL cp_cfm_create(c_rmat_local, c_rmat%matrix_struct)
466 0 : CALL cp_cfm_set_all(c_rmat_local, (0.0_dp, 0.0_dp), (1.0_dp, 0.0_dp))
467 0 : DO idim = 1, dim2
468 0 : CALL cp_cfm_create(c_zij_local(idim), c_zij(idim)%matrix_struct)
469 0 : c_zij_local(idim)%local_data = c_zij(idim)%local_data
470 : END DO
471 :
472 0 : CALL cp_cfm_get_info(c_rmat_local, nrow_global=nstate)
473 0 : tolerance = 1.0e10_dp
474 :
475 0 : IF (PRESENT(grad_final)) CALL cp_fm_set_all(grad_final, 0.0_dp)
476 :
477 0 : sweeps = 0
478 0 : IF (PRESENT(out_each)) THEN
479 0 : unit_nr = -1
480 0 : IF (c_rmat_local%matrix_struct%para_env%is_source()) THEN
481 0 : unit_nr = cp_logger_get_default_unit_nr()
482 : END IF
483 0 : alpha = 0.0_dp
484 0 : DO idim = 1, dim2
485 0 : alpha = alpha + weights(idim)
486 : END DO
487 : END IF
488 :
489 : ! do jacobi sweeps until converged
490 0 : DO WHILE (sweeps < max_iter)
491 0 : sweeps = sweeps + 1
492 0 : IF (PRESENT(eps_localization)) THEN
493 0 : IF (tolerance < eps_localization) EXIT
494 : END IF
495 0 : IF (PRESENT(out_each)) t1 = m_walltime()
496 :
497 0 : DO istate = 1, nstate
498 0 : DO jstate = istate + 1, nstate
499 0 : DO idim = 1, dim2
500 0 : CALL cp_cfm_get_element(c_zij_local(idim), istate, istate, mii(idim))
501 0 : CALL cp_cfm_get_element(c_zij_local(idim), istate, jstate, mij(idim))
502 0 : CALL cp_cfm_get_element(c_zij_local(idim), jstate, jstate, mjj(idim))
503 : END DO
504 0 : CALL get_angle(mii, mjj, mij, weights, theta)
505 0 : st = SIN(theta)
506 0 : ct = COS(theta)
507 0 : CALL rotate_zij(istate, jstate, st, ct, c_zij_local)
508 :
509 0 : CALL rotate_rmat(istate, jstate, st, ct, c_rmat_local)
510 : END DO
511 : END DO
512 :
513 0 : IF (PRESENT(grad_final)) THEN
514 0 : CALL check_tolerance(c_zij_local, weights, tolerance, grad=grad_final)
515 : ELSE
516 0 : CALL check_tolerance(c_zij_local, weights, tolerance)
517 : END IF
518 0 : IF (PRESENT(tol_out)) tol_out = tolerance
519 :
520 0 : IF (PRESENT(out_each)) THEN
521 0 : t2 = m_walltime()
522 0 : IF (unit_nr > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
523 0 : sum_spread_ii = 0.0_dp
524 0 : DO istate = 1, nstate
525 : spread_ii = 0.0_dp
526 0 : DO idim = 1, dim2
527 0 : CALL cp_cfm_get_element(c_zij_local(idim), istate, istate, mzii)
528 : spread_ii = spread_ii + weights(idim)* &
529 0 : ABS(mzii)**2/twopi/twopi
530 : END DO
531 0 : sum_spread_ii = sum_spread_ii + spread_ii
532 : END DO
533 0 : sum_spread_ii = alpha*nstate/twopi/twopi - sum_spread_ii
534 0 : avg_spread_ii = sum_spread_ii/nstate
535 : WRITE (unit_nr, '(T4,A,T26,A,T48,A,T64,A)') &
536 0 : "Iteration", "Avg. Spread_ii", "Tolerance", "Time"
537 : WRITE (unit_nr, '(T4,I7,T20,F20.10,T45,E12.4,T60,F8.3)') &
538 0 : sweeps, avg_spread_ii, tolerance, t2 - t1
539 0 : CALL m_flush(unit_nr)
540 : END IF
541 0 : IF (PRESENT(jsweeps)) jsweeps = sweeps
542 : END IF
543 :
544 : END DO
545 :
546 0 : IF (PRESENT(c_zij_out)) THEN
547 0 : DO idim = 1, dim2
548 0 : CALL cp_cfm_to_cfm(c_zij_local(idim), c_zij_out(idim))
549 : END DO
550 : END IF
551 0 : CALL cp_cfm_to_cfm(c_rmat_local, c_rmat)
552 :
553 0 : DEALLOCATE (mii, mij, mjj)
554 0 : DO idim = 1, dim2
555 0 : CALL cp_cfm_release(c_zij_local(idim))
556 : END DO
557 0 : DEALLOCATE (c_zij_local)
558 0 : CALL cp_cfm_release(c_rmat_local)
559 :
560 0 : CALL timestop(handle)
561 :
562 0 : END SUBROUTINE jacobi_rotations_serial_1
563 : ! **************************************************************************************************
564 : !> \brief combine jacobi rotations (serial) and conjugate gradient with golden section line search
565 : !> for partially occupied wannier functions
566 : !> \param para_env ...
567 : !> \param weights ...
568 : !> \param zij ...
569 : !> \param vectors ...
570 : !> \param max_iter ...
571 : !> \param eps_localization ...
572 : !> \param iter ...
573 : !> \param out_each ...
574 : !> \param nextra ...
575 : !> \param do_cg ...
576 : !> \param nmo ...
577 : !> \param vectors_2 ...
578 : !> \param mos_guess ...
579 : ! **************************************************************************************************
580 2 : SUBROUTINE jacobi_cg_edf_ls(para_env, weights, zij, vectors, max_iter, eps_localization, &
581 : iter, out_each, nextra, do_cg, nmo, vectors_2, mos_guess)
582 : TYPE(mp_para_env_type), POINTER :: para_env
583 : REAL(KIND=dp), INTENT(IN) :: weights(:)
584 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
585 : INTEGER, INTENT(IN) :: max_iter
586 : REAL(KIND=dp), INTENT(IN) :: eps_localization
587 : INTEGER :: iter
588 : INTEGER, INTENT(IN) :: out_each, nextra
589 : LOGICAL, INTENT(IN) :: do_cg
590 : INTEGER, INTENT(IN), OPTIONAL :: nmo
591 : TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: vectors_2, mos_guess
592 :
593 : CHARACTER(len=*), PARAMETER :: routineN = 'jacobi_cg_edf_ls'
594 : COMPLEX(KIND=dp), PARAMETER :: cone = (1.0_dp, 0.0_dp), &
595 : czero = (0.0_dp, 0.0_dp)
596 : REAL(KIND=dp), PARAMETER :: gold_sec = 0.3819_dp
597 :
598 : COMPLEX(KIND=dp) :: cnorm2_Gct, cnorm2_Gct_cross, mzii
599 2 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: tmp_cmat
600 2 : COMPLEX(KIND=dp), DIMENSION(:), POINTER :: arr_zii
601 2 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: matrix_zii
602 : INTEGER :: dim2, handle, icinit, idim, istate, line_search_count, line_searches, lsl, lsm, &
603 : lsr, miniter, nao, ndummy, nocc, norextra, northo, nstate, unit_nr
604 : INTEGER, DIMENSION(1) :: iloc
605 : LOGICAL :: do_cinit_mo, do_cinit_random, &
606 : do_U_guess_mo, new_direction
607 : REAL(KIND=dp) :: alpha, avg_spread_ii, beta, beta_pr, ds, ds_min, mintol, norm, norm2_Gct, &
608 : norm2_Gct_cross, norm2_old, spread_ii, spread_sum, sum_spread_ii, t1, tol, tolc, weight
609 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: sum_spread
610 2 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: tmp_mat, tmp_mat_1
611 : REAL(KIND=dp), DIMENSION(50) :: energy, pos
612 2 : REAL(KIND=dp), DIMENSION(:), POINTER :: tmp_arr
613 : TYPE(cp_blacs_env_type), POINTER :: context
614 : TYPE(cp_cfm_type) :: c_tilde, ctrans_lambda, Gct_old, &
615 : grad_ctilde, skc, tmp_cfm, tmp_cfm_1, &
616 : tmp_cfm_2, U, UL, V, VL, zdiag
617 2 : TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:) :: c_zij, zij_0
618 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
619 : TYPE(cp_fm_type) :: id_nextra, matrix_U, matrix_V, &
620 : matrix_V_all, rmat, tmp_fm, vectors_all
621 :
622 2 : CALL timeset(routineN, handle)
623 :
624 2 : dim2 = SIZE(zij, 2)
625 2 : NULLIFY (context)
626 2 : NULLIFY (matrix_zii, arr_zii)
627 2 : NULLIFY (tmp_fm_struct)
628 2 : NULLIFY (tmp_arr)
629 :
630 12 : ALLOCATE (c_zij(dim2))
631 :
632 2 : CALL cp_fm_get_info(zij(1, 1), nrow_global=nstate)
633 :
634 6 : ALLOCATE (sum_spread(nstate))
635 8 : ALLOCATE (matrix_zii(nstate, dim2))
636 266 : matrix_zii = czero
637 2 : sum_spread = 0.0_dp
638 :
639 2 : alpha = 0.0_dp
640 8 : DO idim = 1, dim2
641 6 : alpha = alpha + weights(idim)
642 6 : CALL cp_cfm_create(c_zij(idim), zij(1, 1)%matrix_struct)
643 : c_zij(idim)%local_data = CMPLX(zij(1, idim)%local_data, &
644 5813 : zij(2, idim)%local_data, dp)
645 : END DO
646 :
647 10 : ALLOCATE (zij_0(dim2))
648 :
649 2 : CALL cp_cfm_create(U, zij(1, 1)%matrix_struct)
650 2 : CALL cp_fm_create(matrix_U, zij(1, 1)%matrix_struct)
651 :
652 2 : CALL cp_cfm_set_all(U, czero, cone)
653 2 : CALL cp_fm_set_all(matrix_U, 0.0_dp, 1.0_dp)
654 :
655 2 : CALL cp_fm_get_info(vectors, nrow_global=nao)
656 2 : IF (nextra > 0) THEN
657 2 : IF (PRESENT(mos_guess)) THEN
658 2 : do_cinit_random = .FALSE.
659 2 : do_cinit_mo = .TRUE.
660 2 : CALL cp_fm_get_info(mos_guess, ncol_global=ndummy)
661 : ELSE
662 0 : do_cinit_random = .TRUE.
663 0 : do_cinit_mo = .FALSE.
664 0 : ndummy = nstate
665 : END IF
666 :
667 : IF (do_cinit_random) THEN
668 : icinit = 1
669 : do_U_guess_mo = .FALSE.
670 : ELSE IF (do_cinit_mo) THEN
671 2 : icinit = 2
672 2 : do_U_guess_mo = .TRUE.
673 : END IF
674 :
675 2 : nocc = nstate - nextra
676 2 : northo = nmo - nocc
677 2 : norextra = nmo - nstate
678 2 : CALL cp_fm_struct_get(zij(1, 1)%matrix_struct, context=context)
679 :
680 8 : ALLOCATE (tmp_cmat(nstate, nstate))
681 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, ncol_global=nmo, &
682 2 : para_env=para_env, context=context)
683 8 : DO idim = 1, dim2
684 6 : CALL cp_cfm_create(zij_0(idim), tmp_fm_struct)
685 6 : CALL cp_cfm_set_all(zij_0(idim), czero, cone)
686 6 : CALL cp_cfm_get_submatrix(c_zij(idim), tmp_cmat)
687 8 : CALL cp_cfm_set_submatrix(zij_0(idim), tmp_cmat)
688 : END DO
689 2 : CALL cp_fm_struct_release(tmp_fm_struct)
690 2 : DEALLOCATE (tmp_cmat)
691 :
692 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, ncol_global=nstate, &
693 2 : para_env=para_env, context=context)
694 2 : CALL cp_cfm_create(V, tmp_fm_struct)
695 2 : CALL cp_fm_create(matrix_V, tmp_fm_struct)
696 2 : CALL cp_cfm_create(zdiag, tmp_fm_struct)
697 2 : CALL cp_fm_create(rmat, tmp_fm_struct)
698 2 : CALL cp_fm_struct_release(tmp_fm_struct)
699 2 : CALL cp_cfm_set_all(V, czero, cone)
700 2 : CALL cp_fm_set_all(matrix_V, 0.0_dp, 1.0_dp)
701 :
702 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, ncol_global=ndummy, &
703 2 : para_env=para_env, context=context)
704 2 : CALL cp_fm_create(matrix_V_all, tmp_fm_struct)
705 2 : CALL cp_fm_struct_release(tmp_fm_struct)
706 2 : CALL cp_fm_set_all(matrix_V_all, 0._dp, 1._dp)
707 :
708 6 : ALLOCATE (arr_zii(nstate))
709 :
710 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=northo, ncol_global=nextra, &
711 2 : para_env=para_env, context=context)
712 2 : CALL cp_cfm_create(c_tilde, tmp_fm_struct)
713 2 : CALL cp_cfm_create(grad_ctilde, tmp_fm_struct)
714 2 : CALL cp_cfm_create(Gct_old, tmp_fm_struct)
715 2 : CALL cp_cfm_create(skc, tmp_fm_struct)
716 2 : CALL cp_fm_struct_release(tmp_fm_struct)
717 2 : CALL cp_cfm_set_all(c_tilde, czero)
718 2 : CALL cp_cfm_set_all(Gct_old, czero)
719 2 : CALL cp_cfm_set_all(skc, czero)
720 :
721 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=northo, ncol_global=nstate, &
722 2 : para_env=para_env, context=context)
723 2 : CALL cp_cfm_create(VL, tmp_fm_struct)
724 2 : CALL cp_cfm_set_all(VL, czero)
725 2 : CALL cp_fm_struct_release(tmp_fm_struct)
726 :
727 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nextra, ncol_global=nextra, &
728 2 : para_env=para_env, context=context)
729 2 : CALL cp_fm_create(id_nextra, tmp_fm_struct)
730 2 : CALL cp_cfm_create(ctrans_lambda, tmp_fm_struct)
731 2 : CALL cp_fm_struct_release(tmp_fm_struct)
732 2 : CALL cp_cfm_set_all(ctrans_lambda, czero)
733 2 : CALL cp_fm_set_all(id_nextra, 0.0_dp, 1.0_dp)
734 :
735 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nextra, ncol_global=nstate, &
736 2 : para_env=para_env, context=context)
737 2 : CALL cp_cfm_create(UL, tmp_fm_struct)
738 2 : CALL cp_fm_struct_release(tmp_fm_struct)
739 2 : CALL cp_cfm_set_all(UL, czero)
740 :
741 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nao, ncol_global=nmo, &
742 2 : para_env=para_env, context=context)
743 2 : CALL cp_fm_create(vectors_all, tmp_fm_struct)
744 2 : CALL cp_fm_struct_release(tmp_fm_struct)
745 8 : ALLOCATE (tmp_mat(nao, nstate))
746 2 : CALL cp_fm_get_submatrix(vectors, tmp_mat)
747 2 : CALL cp_fm_set_submatrix(vectors_all, tmp_mat, 1, 1, nao, nstate)
748 2 : DEALLOCATE (tmp_mat)
749 8 : ALLOCATE (tmp_mat(nao, norextra))
750 2 : CALL cp_fm_get_submatrix(vectors_2, tmp_mat)
751 2 : CALL cp_fm_set_submatrix(vectors_all, tmp_mat, 1, nstate + 1, nao, norextra)
752 2 : DEALLOCATE (tmp_mat)
753 :
754 : ! initialize c_tilde
755 14 : SELECT CASE (icinit)
756 : CASE (1) ! random coefficients
757 : !WRITE (*, *) "RANDOM INITIAL GUESS FOR C"
758 0 : CALL cp_fm_create(tmp_fm, c_tilde%matrix_struct)
759 0 : CALL cp_fm_init_random(tmp_fm, nextra)
760 0 : CALL ortho_vectors(tmp_fm)
761 0 : c_tilde%local_data = tmp_fm%local_data
762 0 : CALL cp_fm_release(tmp_fm)
763 0 : ALLOCATE (tmp_cmat(northo, nextra))
764 0 : CALL cp_cfm_get_submatrix(c_tilde, tmp_cmat)
765 0 : CALL cp_cfm_set_submatrix(V, tmp_cmat, nocc + 1, nocc + 1, northo, nextra)
766 0 : DEALLOCATE (tmp_cmat)
767 : CASE (2) ! MO based coeffs
768 2 : CALL parallel_gemm("T", "N", nmo, ndummy, nao, 1.0_dp, vectors_all, mos_guess, 0.0_dp, matrix_V_all)
769 6 : ALLOCATE (tmp_arr(nmo))
770 8 : ALLOCATE (tmp_mat(nmo, ndummy))
771 8 : ALLOCATE (tmp_mat_1(nmo, nstate))
772 : ! normalize matrix_V_all
773 2 : CALL cp_fm_get_submatrix(matrix_V_all, tmp_mat)
774 88 : DO istate = 1, ndummy
775 4558 : tmp_arr(:) = tmp_mat(:, istate)
776 4558 : norm = NORM2(tmp_arr)
777 4558 : tmp_arr(:) = tmp_arr(:)/norm
778 4560 : tmp_mat(:, istate) = tmp_arr(:)
779 : END DO
780 2 : CALL cp_fm_set_submatrix(matrix_V_all, tmp_mat)
781 2 : CALL cp_fm_get_submatrix(matrix_V_all, tmp_mat_1, 1, 1, nmo, nstate)
782 2 : CALL cp_fm_set_submatrix(matrix_V, tmp_mat_1)
783 2 : DEALLOCATE (tmp_arr, tmp_mat, tmp_mat_1)
784 2 : CALL cp_fm_to_cfm(msourcer=matrix_V, mtarget=V)
785 8 : ALLOCATE (tmp_mat(northo, ndummy))
786 8 : ALLOCATE (tmp_mat_1(northo, nextra))
787 2 : CALL cp_fm_get_submatrix(matrix_V_all, tmp_mat, nocc + 1, 1, northo, ndummy)
788 6 : ALLOCATE (tmp_arr(ndummy))
789 88 : tmp_arr = 0.0_dp
790 88 : DO istate = 1, ndummy
791 1034 : tmp_arr(istate) = NORM2(tmp_mat(:, istate))
792 : END DO
793 : ! find edfs
794 6 : DO istate = 1, nextra
795 180 : iloc = MAXLOC(tmp_arr)
796 48 : tmp_mat_1(:, istate) = tmp_mat(:, iloc(1))
797 6 : tmp_arr(iloc(1)) = 0.0_dp
798 : END DO
799 :
800 2 : DEALLOCATE (tmp_arr, tmp_mat)
801 :
802 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=northo, ncol_global=nextra, &
803 2 : para_env=para_env, context=context)
804 2 : CALL cp_fm_create(tmp_fm, tmp_fm_struct)
805 2 : CALL cp_fm_struct_release(tmp_fm_struct)
806 2 : CALL cp_fm_set_submatrix(tmp_fm, tmp_mat_1)
807 2 : DEALLOCATE (tmp_mat_1)
808 2 : CALL ortho_vectors(tmp_fm)
809 2 : CALL cp_fm_to_cfm(msourcer=tmp_fm, mtarget=c_tilde)
810 2 : CALL cp_fm_release(tmp_fm)
811 : ! initialize U
812 2 : IF (do_U_guess_mo) THEN
813 8 : ALLOCATE (tmp_cmat(nocc, nstate))
814 2 : CALL cp_cfm_get_submatrix(V, tmp_cmat, 1, 1, nocc, nstate)
815 2 : CALL cp_cfm_set_submatrix(U, tmp_cmat, 1, 1, nocc, nstate)
816 2 : DEALLOCATE (tmp_cmat)
817 8 : ALLOCATE (tmp_cmat(northo, nstate))
818 2 : CALL cp_cfm_get_submatrix(V, tmp_cmat, nocc + 1, 1, northo, nstate)
819 2 : CALL cp_cfm_set_submatrix(VL, tmp_cmat, 1, 1, northo, nstate)
820 2 : DEALLOCATE (tmp_cmat)
821 2 : CALL parallel_gemm("C", "N", nextra, nstate, northo, cone, c_tilde, VL, czero, UL)
822 8 : ALLOCATE (tmp_cmat(nextra, nstate))
823 2 : CALL cp_cfm_get_submatrix(UL, tmp_cmat, 1, 1, nextra, nstate)
824 2 : CALL cp_cfm_set_submatrix(U, tmp_cmat, nocc + 1, 1, nextra, nstate)
825 2 : DEALLOCATE (tmp_cmat)
826 2 : CALL cp_fm_create(tmp_fm, U%matrix_struct)
827 1937 : tmp_fm%local_data = REAL(U%local_data, KIND=dp)
828 2 : CALL ortho_vectors(tmp_fm)
829 2 : CALL cp_fm_to_cfm(msourcer=tmp_fm, mtarget=U)
830 2 : CALL cp_fm_release(tmp_fm)
831 4 : CALL cp_cfm_to_fm(U, matrix_U)
832 : END IF
833 : ! reevaluate V
834 8 : ALLOCATE (tmp_cmat(nocc, nstate))
835 2 : CALL cp_cfm_get_submatrix(U, tmp_cmat, 1, 1, nocc, nstate)
836 2 : CALL cp_cfm_set_submatrix(V, tmp_cmat, 1, 1, nocc, nstate)
837 2 : DEALLOCATE (tmp_cmat)
838 8 : ALLOCATE (tmp_cmat(nextra, nstate))
839 2 : CALL cp_cfm_get_submatrix(U, tmp_cmat, nocc + 1, 1, nextra, nstate)
840 2 : CALL cp_cfm_set_submatrix(UL, tmp_cmat, 1, 1, nextra, nstate)
841 2 : DEALLOCATE (tmp_cmat)
842 2 : CALL parallel_gemm("N", "N", northo, nstate, nextra, cone, c_tilde, UL, czero, VL)
843 8 : ALLOCATE (tmp_cmat(northo, nstate))
844 2 : CALL cp_cfm_get_submatrix(VL, tmp_cmat)
845 2 : CALL cp_cfm_set_submatrix(V, tmp_cmat, nocc + 1, 1, northo, nstate)
846 6 : DEALLOCATE (tmp_cmat)
847 : END SELECT
848 : ELSE
849 0 : DO idim = 1, dim2
850 0 : CALL cp_cfm_create(zij_0(idim), zij(1, 1)%matrix_struct)
851 0 : CALL cp_cfm_to_cfm(c_zij(idim), zij_0(idim))
852 : END DO
853 0 : CALL cp_fm_create(rmat, zij(1, 1)%matrix_struct)
854 0 : CALL cp_fm_set_all(rmat, 0._dp, 1._dp)
855 : END IF
856 :
857 2 : unit_nr = -1
858 2 : IF (rmat%matrix_struct%para_env%is_source()) THEN
859 1 : unit_nr = cp_logger_get_default_unit_nr()
860 1 : WRITE (unit_nr, '(T4,A )') " Localization by combined Jacobi rotations and Non-Linear Conjugate Gradient"
861 : END IF
862 :
863 2 : norm2_old = 1.0E30_dp
864 2 : ds_min = 1.0_dp
865 2 : new_direction = .TRUE.
866 2 : iter = 0
867 2 : line_searches = 0
868 2 : line_search_count = 0
869 2 : tol = 1.0E+20_dp
870 2 : mintol = 1.0E+10_dp
871 2 : miniter = 0
872 :
873 : !IF (nextra > 0) WRITE(*,*) 'random_guess, MO_guess, U_guess, conjugate_gradient: ', &
874 : ! do_cinit_random, do_cinit_mo, do_U_guess_mo, do_cg
875 :
876 : ! do conjugate gradient until converged
877 34 : DO WHILE (iter < max_iter)
878 34 : iter = iter + 1
879 : !WRITE(*,*) 'iter = ', iter
880 34 : t1 = m_walltime()
881 :
882 34 : IF (iter > 1) THEN
883 : ! comput U
884 32 : CALL cp_cfm_create(tmp_cfm, zij(1, 1)%matrix_struct)
885 32 : CALL cp_cfm_create(tmp_cfm_2, zij(1, 1)%matrix_struct)
886 32 : IF (para_env%num_pe == 1) THEN
887 0 : CALL jacobi_rotations_serial_1(weights, c_zij, 1, tmp_cfm_2, tol_out=tol)
888 : ELSE
889 32 : CALL jacobi_rot_para_1(weights, c_zij, para_env, 1, tmp_cfm_2, tol_out=tol)
890 : END IF
891 32 : CALL parallel_gemm('N', 'N', nstate, nstate, nstate, cone, U, tmp_cfm_2, czero, tmp_cfm)
892 32 : CALL cp_cfm_to_cfm(tmp_cfm, U)
893 32 : CALL cp_cfm_release(tmp_cfm)
894 32 : CALL cp_cfm_release(tmp_cfm_2)
895 : END IF
896 :
897 34 : IF (nextra > 0) THEN
898 136 : ALLOCATE (tmp_cmat(nextra, nstate))
899 34 : CALL cp_cfm_get_submatrix(U, tmp_cmat, nocc + 1, 1, nextra, nstate)
900 34 : CALL cp_cfm_set_submatrix(UL, tmp_cmat)
901 34 : DEALLOCATE (tmp_cmat)
902 34 : IF (iter > 1) THEN
903 : ! orthonormalize c_tilde
904 32 : CALL cp_fm_create(tmp_fm, c_tilde%matrix_struct)
905 448 : tmp_fm%local_data = REAL(c_tilde%local_data, KIND=dp)
906 32 : CALL ortho_vectors(tmp_fm)
907 32 : CALL cp_fm_to_cfm(msourcer=tmp_fm, mtarget=c_tilde)
908 32 : CALL cp_fm_release(tmp_fm)
909 :
910 128 : ALLOCATE (tmp_cmat(nocc, nstate))
911 32 : CALL cp_cfm_get_submatrix(U, tmp_cmat, 1, 1, nocc, nstate)
912 32 : CALL cp_cfm_set_submatrix(V, tmp_cmat, 1, 1, nocc, nstate)
913 32 : DEALLOCATE (tmp_cmat)
914 32 : CALL parallel_gemm("N", "N", northo, nstate, nextra, cone, c_tilde, UL, czero, VL)
915 128 : ALLOCATE (tmp_cmat(northo, nstate))
916 32 : CALL cp_cfm_get_submatrix(VL, tmp_cmat)
917 32 : CALL cp_cfm_set_submatrix(V, tmp_cmat, nocc + 1, 1, northo, nstate)
918 64 : DEALLOCATE (tmp_cmat)
919 : END IF
920 :
921 : ! reset if new_direction
922 34 : IF (new_direction .AND. MOD(line_searches, 20) == 5) THEN
923 0 : CALL cp_cfm_set_all(skc, czero)
924 0 : CALL cp_cfm_set_all(Gct_old, czero)
925 0 : norm2_old = 1.0E30_dp
926 : END IF
927 :
928 34 : CALL cp_cfm_create(tmp_cfm, V%matrix_struct)
929 34 : CALL cp_cfm_to_cfm(V, tmp_cfm)
930 34 : CALL cp_cfm_create(tmp_cfm_1, V%matrix_struct)
931 68 : ndummy = nmo
932 : ELSE
933 0 : CALL cp_cfm_create(tmp_cfm, zij(1, 1)%matrix_struct)
934 0 : CALL cp_cfm_to_cfm(U, tmp_cfm)
935 0 : CALL cp_cfm_create(tmp_cfm_1, zij(1, 1)%matrix_struct)
936 0 : ndummy = nstate
937 : END IF
938 : ! update z_ij
939 136 : DO idim = 1, dim2
940 : ! 'tmp_cfm_1 = zij_0*tmp_cfm'
941 : CALL parallel_gemm("N", "N", ndummy, nstate, ndummy, cone, zij_0(idim), &
942 102 : tmp_cfm, czero, tmp_cfm_1)
943 : ! 'c_zij = tmp_cfm_dagg*tmp_cfm_1'
944 : CALL parallel_gemm("C", "N", nstate, nstate, ndummy, cone, tmp_cfm, tmp_cfm_1, &
945 136 : czero, c_zij(idim))
946 : END DO
947 34 : CALL cp_cfm_release(tmp_cfm)
948 34 : CALL cp_cfm_release(tmp_cfm_1)
949 : ! compute spread
950 1496 : DO istate = 1, nstate
951 1462 : spread_ii = 0.0_dp
952 5848 : DO idim = 1, dim2
953 4386 : CALL cp_cfm_get_element(c_zij(idim), istate, istate, mzii)
954 : spread_ii = spread_ii + weights(idim)* &
955 4386 : ABS(mzii)**2/twopi/twopi
956 5848 : matrix_zii(istate, idim) = mzii
957 : END DO
958 : !WRITE(*,*) 'spread_ii', spread_ii
959 1496 : sum_spread(istate) = spread_ii
960 : END DO
961 34 : CALL c_zij(1)%matrix_struct%para_env%sum(spread_ii)
962 34 : spread_sum = accurate_sum(sum_spread)
963 :
964 34 : IF (nextra > 0) THEN
965 : ! update c_tilde
966 34 : CALL cp_cfm_set_all(zdiag, czero)
967 34 : CALL cp_cfm_set_all(grad_ctilde, czero)
968 34 : CALL cp_cfm_create(tmp_cfm, V%matrix_struct)
969 34 : CALL cp_cfm_set_all(tmp_cfm, czero)
970 34 : CALL cp_cfm_create(tmp_cfm_1, V%matrix_struct)
971 34 : CALL cp_cfm_set_all(tmp_cfm_1, czero)
972 136 : ALLOCATE (tmp_cmat(northo, nstate))
973 136 : DO idim = 1, dim2
974 102 : weight = weights(idim)
975 8874 : arr_zii = matrix_zii(:, idim)
976 : ! tmp_cfm = zij_0*V
977 : CALL parallel_gemm("N", "N", nmo, nstate, nmo, cone, &
978 102 : zij_0(idim), V, czero, tmp_cfm)
979 : ! tmp_cfm = tmp_cfm*diag_zij_dagg
980 4488 : CALL cp_cfm_column_scale(tmp_cfm, CONJG(arr_zii))
981 : ! tmp_cfm_1 = tmp_cfm*U_dagg
982 : CALL parallel_gemm("N", "C", nmo, nstate, nstate, cone, tmp_cfm, &
983 102 : U, czero, tmp_cfm_1)
984 102 : CALL cp_cfm_scale(weight, tmp_cfm_1)
985 : ! zdiag = zdiag + tmp_cfm_1'
986 102 : CALL cp_cfm_scale_and_add(cone, zdiag, cone, tmp_cfm_1)
987 :
988 : ! tmp_cfm = zij_0_dagg*V
989 : CALL parallel_gemm("C", "N", nmo, nstate, nmo, cone, &
990 102 : zij_0(idim), V, czero, tmp_cfm)
991 :
992 : ! tmp_cfm = tmp_cfm*diag_zij
993 102 : CALL cp_cfm_column_scale(tmp_cfm, arr_zii)
994 : ! tmp_cfm_1 = tmp_cfm*U_dagg
995 : CALL parallel_gemm("N", "C", nmo, nstate, nstate, cone, tmp_cfm, &
996 102 : U, czero, tmp_cfm_1)
997 102 : CALL cp_cfm_scale(weight, tmp_cfm_1)
998 : ! zdiag = zdiag + tmp_cfm_1'
999 136 : CALL cp_cfm_scale_and_add(cone, zdiag, cone, tmp_cfm_1)
1000 : END DO ! idim
1001 34 : CALL cp_cfm_release(tmp_cfm)
1002 34 : CALL cp_cfm_release(tmp_cfm_1)
1003 34 : DEALLOCATE (tmp_cmat)
1004 136 : ALLOCATE (tmp_cmat(northo, nextra))
1005 : CALL cp_cfm_get_submatrix(zdiag, tmp_cmat, nocc + 1, nocc + 1, &
1006 34 : northo, nextra, .FALSE.)
1007 : ! 'grad_ctilde'
1008 34 : CALL cp_cfm_set_submatrix(grad_ctilde, tmp_cmat)
1009 34 : DEALLOCATE (tmp_cmat)
1010 : ! ctrans_lambda = c_tilde_dagg*grad_ctilde
1011 34 : CALL parallel_gemm("C", "N", nextra, nextra, northo, cone, c_tilde, grad_ctilde, czero, ctrans_lambda)
1012 : !WRITE(*,*) "norm(ctrans_lambda) = ", cp_cfm_norm(ctrans_lambda, "F")
1013 : ! 'grad_ctilde = - c_tilde*ctrans_lambda + grad_ctilde'
1014 102 : CALL parallel_gemm("N", "N", northo, nextra, nextra, -cone, c_tilde, ctrans_lambda, cone, grad_ctilde)
1015 : END IF ! nextra > 0
1016 :
1017 : ! tolerance
1018 34 : IF (nextra > 0) THEN
1019 : tolc = 0.0_dp
1020 34 : CALL cp_fm_create(tmp_fm, grad_ctilde%matrix_struct)
1021 34 : CALL cp_cfm_to_fm(grad_ctilde, tmp_fm)
1022 34 : CALL cp_fm_maxabsval(tmp_fm, tolc)
1023 34 : CALL cp_fm_release(tmp_fm)
1024 : !WRITE(*,*) 'tolc = ', tolc
1025 34 : tol = tol + tolc
1026 : END IF
1027 : !WRITE(*,*) 'tol = ', tol
1028 :
1029 36 : IF (nextra > 0) THEN
1030 : !WRITE(*,*) 'new_direction: ', new_direction
1031 34 : IF (new_direction) THEN
1032 6 : line_searches = line_searches + 1
1033 6 : IF (mintol > tol) THEN
1034 4 : mintol = tol
1035 4 : miniter = iter
1036 : END IF
1037 :
1038 6 : IF (unit_nr > 0 .AND. MODULO(iter, out_each) == 0) THEN
1039 0 : sum_spread_ii = alpha*nstate/twopi/twopi - spread_sum
1040 0 : avg_spread_ii = sum_spread_ii/nstate
1041 : WRITE (unit_nr, '(T4,A,T26,A,T48,A)') &
1042 0 : "Iteration", "Avg. Spread_ii", "Tolerance"
1043 : WRITE (unit_nr, '(T4,I7,T20,F20.10,T45,E12.4)') &
1044 0 : iter, avg_spread_ii, tol
1045 0 : CALL m_flush(unit_nr)
1046 : END IF
1047 6 : IF (tol < eps_localization) EXIT
1048 :
1049 4 : IF (do_cg) THEN
1050 : cnorm2_Gct = czero
1051 : cnorm2_Gct_cross = czero
1052 4 : CALL cp_cfm_trace(grad_ctilde, Gct_old, cnorm2_Gct_cross)
1053 4 : norm2_Gct_cross = REAL(cnorm2_Gct_cross, KIND=dp)
1054 56 : Gct_old%local_data = grad_ctilde%local_data
1055 4 : CALL cp_cfm_trace(grad_ctilde, Gct_old, cnorm2_Gct)
1056 4 : norm2_Gct = REAL(cnorm2_Gct, KIND=dp)
1057 : ! compute beta_pr
1058 4 : beta_pr = (norm2_Gct - norm2_Gct_cross)/norm2_old
1059 4 : norm2_old = norm2_Gct
1060 4 : beta = MAX(0.0_dp, beta_pr)
1061 : !WRITE(*,*) 'beta = ', beta
1062 : ! compute skc / ska = beta * skc / ska + grad_ctilde / G
1063 4 : CALL cp_cfm_scale(beta, skc)
1064 4 : CALL cp_cfm_scale_and_add(cone, skc, cone, Gct_old)
1065 4 : CALL cp_cfm_trace(skc, Gct_old, cnorm2_Gct_cross)
1066 4 : norm2_Gct_cross = REAL(cnorm2_Gct_cross, KIND=dp)
1067 4 : IF (norm2_Gct_cross <= 0.0_dp) THEN ! back to steepest ascent
1068 0 : CALL cp_cfm_scale_and_add(czero, skc, cone, Gct_old)
1069 : END IF
1070 : ELSE
1071 0 : CALL cp_cfm_scale_and_add(czero, skc, cone, grad_ctilde)
1072 : END IF
1073 : line_search_count = 0
1074 : END IF
1075 :
1076 32 : line_search_count = line_search_count + 1
1077 : !WRITE(*,*) 'line_search_count = ', line_search_count
1078 32 : energy(line_search_count) = spread_sum
1079 :
1080 : ! gold line search
1081 32 : new_direction = .FALSE.
1082 32 : IF (line_search_count == 1) THEN
1083 4 : lsl = 1
1084 4 : lsr = 0
1085 4 : lsm = 1
1086 4 : pos(1) = 0.0_dp
1087 4 : pos(2) = ds_min/gold_sec
1088 4 : ds = pos(2)
1089 : ELSE
1090 28 : IF (line_search_count == 50) THEN
1091 0 : IF (ABS(energy(line_search_count) - energy(line_search_count - 1)) < 1.0E-4_dp) THEN
1092 0 : CPWARN("Line search failed to converge properly")
1093 0 : ds_min = 0.1_dp
1094 0 : new_direction = .TRUE.
1095 : ds = pos(line_search_count)
1096 0 : line_search_count = 0
1097 : ELSE
1098 0 : CPABORT("No. of line searches exceeds 50")
1099 : END IF
1100 : ELSE
1101 28 : IF (lsr == 0) THEN
1102 28 : IF (energy(line_search_count - 1) > energy(line_search_count)) THEN
1103 0 : lsr = line_search_count
1104 0 : pos(line_search_count + 1) = pos(lsm) + (pos(lsr) - pos(lsm))*gold_sec
1105 : ELSE
1106 28 : lsl = lsm
1107 28 : lsm = line_search_count
1108 28 : pos(line_search_count + 1) = pos(line_search_count)/gold_sec
1109 : END IF
1110 : ELSE
1111 0 : IF (pos(line_search_count) < pos(lsm)) THEN
1112 0 : IF (energy(line_search_count) > energy(lsm)) THEN
1113 : lsr = lsm
1114 : lsm = line_search_count
1115 : ELSE
1116 0 : lsl = line_search_count
1117 : END IF
1118 : ELSE
1119 0 : IF (energy(line_search_count) > energy(lsm)) THEN
1120 : lsl = lsm
1121 : lsm = line_search_count
1122 : ELSE
1123 0 : lsr = line_search_count
1124 : END IF
1125 : END IF
1126 0 : IF (pos(lsr) - pos(lsm) > pos(lsm) - pos(lsl)) THEN
1127 0 : pos(line_search_count + 1) = pos(lsm) + gold_sec*(pos(lsr) - pos(lsm))
1128 : ELSE
1129 0 : pos(line_search_count + 1) = pos(lsl) + gold_sec*(pos(lsm) - pos(lsl))
1130 : END IF
1131 0 : IF ((pos(lsr) - pos(lsl)) < 1.0E-3_dp*pos(lsr)) THEN
1132 0 : new_direction = .TRUE.
1133 : END IF
1134 : END IF ! lsr .eq. 0
1135 : END IF ! line_search_count .eq. 50
1136 : ! now go to the suggested point
1137 28 : ds = pos(line_search_count + 1) - pos(line_search_count)
1138 : !WRITE(*,*) 'lsl, lsr, lsm, ds = ', lsl, lsr, lsm, ds
1139 28 : IF ((ABS(ds) < 1.0E-10_dp) .AND. (lsl == 1)) THEN
1140 0 : new_direction = .TRUE.
1141 0 : ds_min = 0.5_dp/alpha
1142 28 : ELSE IF (ABS(ds) > 10.0_dp) THEN
1143 4 : new_direction = .TRUE.
1144 4 : ds_min = 0.5_dp/alpha
1145 : ELSE
1146 : ds_min = pos(line_search_count + 1)
1147 : END IF
1148 : END IF ! first step
1149 : ! 'c_tilde = c_tilde + d*skc'
1150 32 : CALL cp_cfm_scale(ds, skc)
1151 32 : CALL cp_cfm_scale_and_add(cone, c_tilde, cone, skc)
1152 : ELSE
1153 0 : IF (mintol > tol) THEN
1154 0 : mintol = tol
1155 0 : miniter = iter
1156 : END IF
1157 0 : IF (unit_nr > 0 .AND. MODULO(iter, out_each) == 0) THEN
1158 0 : sum_spread_ii = alpha*nstate/twopi/twopi - spread_sum
1159 0 : avg_spread_ii = sum_spread_ii/nstate
1160 : WRITE (unit_nr, '(T4,A,T26,A,T48,A)') &
1161 0 : "Iteration", "Avg. Spread_ii", "Tolerance"
1162 : WRITE (unit_nr, '(T4,I7,T20,F20.10,T45,E12.4)') &
1163 0 : iter, avg_spread_ii, tol
1164 0 : CALL m_flush(unit_nr)
1165 : END IF
1166 0 : IF (tol < eps_localization) EXIT
1167 : END IF ! nextra > 0
1168 :
1169 : END DO ! iteration
1170 :
1171 2 : IF ((unit_nr > 0) .AND. (iter == max_iter)) THEN
1172 0 : WRITE (unit_nr, '(T4,A,T4,A)') "Min. Itr.", "Min. Tol."
1173 0 : WRITE (unit_nr, '(T4,I7,T4,E12.4)') miniter, mintol
1174 0 : CALL m_flush(unit_nr)
1175 : END IF
1176 :
1177 2 : CALL cp_cfm_to_fm(U, matrix_U)
1178 :
1179 2 : IF (nextra > 0) THEN
1180 2324 : rmat%local_data = REAL(V%local_data, KIND=dp)
1181 2 : CALL rotate_orbitals_edf(rmat, vectors_all, vectors)
1182 :
1183 2 : CALL cp_cfm_release(c_tilde)
1184 2 : CALL cp_cfm_release(grad_ctilde)
1185 2 : CALL cp_cfm_release(Gct_old)
1186 2 : CALL cp_cfm_release(skc)
1187 2 : CALL cp_cfm_release(UL)
1188 2 : CALL cp_cfm_release(zdiag)
1189 2 : CALL cp_cfm_release(ctrans_lambda)
1190 2 : CALL cp_fm_release(id_nextra)
1191 2 : CALL cp_fm_release(vectors_all)
1192 2 : CALL cp_cfm_release(V)
1193 2 : CALL cp_fm_release(matrix_V)
1194 2 : CALL cp_fm_release(matrix_V_all)
1195 2 : CALL cp_cfm_release(VL)
1196 2 : DEALLOCATE (arr_zii)
1197 : ELSE
1198 0 : rmat%local_data = matrix_U%local_data
1199 0 : CALL rotate_orbitals(rmat, vectors)
1200 : END IF
1201 8 : DO idim = 1, dim2
1202 8 : CALL cp_cfm_release(zij_0(idim))
1203 : END DO
1204 2 : DEALLOCATE (zij_0)
1205 :
1206 8 : DO idim = 1, dim2
1207 5811 : zij(1, idim)%local_data = REAL(c_zij(idim)%local_data, dp)
1208 5811 : zij(2, idim)%local_data = AIMAG(c_zij(idim)%local_data)
1209 8 : CALL cp_cfm_release(c_zij(idim))
1210 : END DO
1211 2 : DEALLOCATE (c_zij)
1212 2 : CALL cp_fm_release(rmat)
1213 2 : CALL cp_cfm_release(U)
1214 2 : CALL cp_fm_release(matrix_U)
1215 2 : DEALLOCATE (matrix_zii, sum_spread)
1216 :
1217 2 : CALL timestop(handle)
1218 :
1219 10 : END SUBROUTINE jacobi_cg_edf_ls
1220 :
1221 : ! **************************************************************************************************
1222 : !> \brief ...
1223 : !> \param vmatrix ...
1224 : ! **************************************************************************************************
1225 108 : SUBROUTINE ortho_vectors(vmatrix)
1226 :
1227 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
1228 :
1229 : CHARACTER(LEN=*), PARAMETER :: routineN = 'ortho_vectors'
1230 :
1231 : INTEGER :: handle, n, ncol
1232 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
1233 : TYPE(cp_fm_type) :: overlap_vv
1234 :
1235 36 : CALL timeset(routineN, handle)
1236 :
1237 36 : NULLIFY (fm_struct_tmp)
1238 :
1239 36 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol)
1240 :
1241 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
1242 : para_env=vmatrix%matrix_struct%para_env, &
1243 36 : context=vmatrix%matrix_struct%context)
1244 36 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
1245 36 : CALL cp_fm_struct_release(fm_struct_tmp)
1246 :
1247 36 : CALL parallel_gemm('T', 'N', ncol, ncol, n, 1.0_dp, vmatrix, vmatrix, 0.0_dp, overlap_vv)
1248 36 : CALL cp_fm_cholesky_decompose(overlap_vv)
1249 36 : CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
1250 :
1251 36 : CALL cp_fm_release(overlap_vv)
1252 :
1253 36 : CALL timestop(handle)
1254 :
1255 36 : END SUBROUTINE ortho_vectors
1256 :
1257 : ! **************************************************************************************************
1258 : !> \brief ...
1259 : !> \param istate ...
1260 : !> \param jstate ...
1261 : !> \param st ...
1262 : !> \param ct ...
1263 : !> \param zij ...
1264 : ! **************************************************************************************************
1265 0 : SUBROUTINE rotate_zij(istate, jstate, st, ct, zij)
1266 : INTEGER, INTENT(IN) :: istate, jstate
1267 : REAL(KIND=dp), INTENT(IN) :: st, ct
1268 : TYPE(cp_cfm_type) :: zij(:)
1269 :
1270 : INTEGER :: id
1271 :
1272 : ! Locals
1273 :
1274 0 : DO id = 1, SIZE(zij, 1)
1275 0 : CALL cp_cfm_rot_cols(zij(id), istate, jstate, ct, st)
1276 0 : CALL cp_cfm_rot_rows(zij(id), istate, jstate, ct, st)
1277 : END DO
1278 :
1279 0 : END SUBROUTINE rotate_zij
1280 : ! **************************************************************************************************
1281 : !> \brief ...
1282 : !> \param istate ...
1283 : !> \param jstate ...
1284 : !> \param st ...
1285 : !> \param ct ...
1286 : !> \param rmat ...
1287 : ! **************************************************************************************************
1288 0 : SUBROUTINE rotate_rmat(istate, jstate, st, ct, rmat)
1289 : INTEGER, INTENT(IN) :: istate, jstate
1290 : REAL(KIND=dp), INTENT(IN) :: st, ct
1291 : TYPE(cp_cfm_type), INTENT(IN) :: rmat
1292 :
1293 0 : CALL cp_cfm_rot_cols(rmat, istate, jstate, ct, st)
1294 :
1295 0 : END SUBROUTINE rotate_rmat
1296 : ! **************************************************************************************************
1297 : !> \brief ...
1298 : !> \param mii ...
1299 : !> \param mjj ...
1300 : !> \param mij ...
1301 : !> \param weights ...
1302 : !> \param theta ...
1303 : !> \param grad_ij ...
1304 : !> \param step ...
1305 : ! **************************************************************************************************
1306 2342024 : SUBROUTINE get_angle(mii, mjj, mij, weights, theta, grad_ij, step)
1307 : COMPLEX(KIND=dp), POINTER :: mii(:), mjj(:), mij(:)
1308 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1309 : REAL(KIND=dp), INTENT(OUT) :: theta
1310 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: grad_ij, step
1311 :
1312 : COMPLEX(KIND=dp) :: z11, z12, z22
1313 : INTEGER :: dim_m, idim
1314 : REAL(KIND=dp) :: a12, b12, d2, ratio
1315 :
1316 2342024 : a12 = 0.0_dp
1317 2342024 : b12 = 0.0_dp
1318 2342024 : dim_m = SIZE(mii)
1319 9509066 : DO idim = 1, dim_m
1320 7167042 : z11 = mii(idim)
1321 7167042 : z22 = mjj(idim)
1322 7167042 : z12 = mij(idim)
1323 7167042 : a12 = a12 + weights(idim)*REAL(CONJG(z12)*(z11 - z22), KIND=dp)
1324 : b12 = b12 + weights(idim)*REAL((z12*CONJG(z12) - &
1325 9509066 : 0.25_dp*(z11 - z22)*(CONJG(z11) - CONJG(z22))), KIND=dp)
1326 : END DO
1327 2342024 : IF (ABS(b12) > 1.e-10_dp) THEN
1328 2342024 : ratio = -a12/b12
1329 2342024 : theta = 0.25_dp*ATAN(ratio)
1330 0 : ELSE IF (ABS(b12) < 1.e-10_dp) THEN
1331 0 : b12 = 0.0_dp
1332 0 : theta = 0.0_dp
1333 : ELSE
1334 0 : theta = 0.25_dp*pi
1335 : END IF
1336 2342024 : IF (PRESENT(grad_ij)) theta = theta + step*grad_ij
1337 : ! Check second derivative info
1338 2342024 : d2 = a12*SIN(4._dp*theta) - b12*COS(4._dp*theta)
1339 2342024 : IF (d2 <= 0._dp) THEN ! go to the maximum, not the minimum
1340 3322 : IF (theta > 0.0_dp) THEN ! make theta as small as possible
1341 1629 : theta = theta - 0.25_dp*pi
1342 : ELSE
1343 1693 : theta = theta + 0.25_dp*pi
1344 : END IF
1345 : END IF
1346 2342024 : END SUBROUTINE get_angle
1347 : ! **************************************************************************************************
1348 : !> \brief ...
1349 : !> \param zij ...
1350 : !> \param weights ...
1351 : !> \param tolerance ...
1352 : !> \param grad ...
1353 : ! **************************************************************************************************
1354 104 : SUBROUTINE check_tolerance(zij, weights, tolerance, grad)
1355 : TYPE(cp_cfm_type) :: zij(:)
1356 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1357 : REAL(KIND=dp), INTENT(OUT) :: tolerance
1358 : TYPE(cp_fm_type), INTENT(OUT), OPTIONAL :: grad
1359 :
1360 : CHARACTER(len=*), PARAMETER :: routineN = 'check_tolerance'
1361 :
1362 : INTEGER :: handle
1363 : TYPE(cp_fm_type) :: force
1364 :
1365 104 : CALL timeset(routineN, handle)
1366 :
1367 : ! compute gradient at t=0
1368 :
1369 104 : CALL cp_fm_create(force, zij(1)%matrix_struct)
1370 104 : CALL cp_fm_set_all(force, 0._dp)
1371 104 : CALL grad_at_0(zij, weights, force)
1372 104 : CALL cp_fm_maxabsval(force, tolerance)
1373 104 : IF (PRESENT(grad)) CALL cp_fm_to_fm(force, grad)
1374 104 : CALL cp_fm_release(force)
1375 :
1376 104 : CALL timestop(handle)
1377 :
1378 104 : END SUBROUTINE check_tolerance
1379 :
1380 : ! **************************************************************************************************
1381 : !> \brief ...
1382 : !> \param rmat ...
1383 : !> \param vectors ...
1384 : ! **************************************************************************************************
1385 1128 : SUBROUTINE rotate_orbitals(rmat, vectors)
1386 : TYPE(cp_fm_type), INTENT(IN) :: rmat, vectors
1387 :
1388 : INTEGER :: k, n
1389 : TYPE(cp_fm_type) :: wf
1390 :
1391 564 : CALL cp_fm_create(wf, vectors%matrix_struct)
1392 564 : CALL cp_fm_get_info(vectors, nrow_global=n, ncol_global=k)
1393 564 : CALL parallel_gemm("N", "N", n, k, k, 1.0_dp, vectors, rmat, 0.0_dp, wf)
1394 564 : CALL cp_fm_to_fm(wf, vectors)
1395 564 : CALL cp_fm_release(wf)
1396 564 : END SUBROUTINE rotate_orbitals
1397 :
1398 : ! **************************************************************************************************
1399 : !> \brief ...
1400 : !> \param rmat ...
1401 : !> \param vectors ...
1402 : ! **************************************************************************************************
1403 24 : SUBROUTINE rotate_orbitals_cfm(rmat, vectors)
1404 : TYPE(cp_cfm_type), INTENT(IN) :: rmat, vectors
1405 :
1406 : INTEGER :: k, n
1407 : TYPE(cp_cfm_type) :: wf
1408 :
1409 12 : CALL cp_cfm_create(wf, vectors%matrix_struct)
1410 12 : CALL cp_cfm_get_info(vectors, nrow_global=n, ncol_global=k)
1411 12 : CALL parallel_gemm("N", "N", n, k, k, z_one, vectors, rmat, z_zero, wf)
1412 12 : CALL cp_cfm_to_cfm(wf, vectors)
1413 12 : CALL cp_cfm_release(wf)
1414 12 : END SUBROUTINE rotate_orbitals_cfm
1415 :
1416 : ! **************************************************************************************************
1417 : !> \brief ...
1418 : !> \param rmat ...
1419 : !> \param vec_all ...
1420 : !> \param vectors ...
1421 : ! **************************************************************************************************
1422 6 : SUBROUTINE rotate_orbitals_edf(rmat, vec_all, vectors)
1423 : TYPE(cp_fm_type), INTENT(IN) :: rmat, vec_all, vectors
1424 :
1425 : INTEGER :: k, l, n
1426 : TYPE(cp_fm_type) :: wf
1427 :
1428 2 : CALL cp_fm_create(wf, vectors%matrix_struct)
1429 2 : CALL cp_fm_get_info(vec_all, nrow_global=n, ncol_global=k)
1430 2 : CALL cp_fm_get_info(rmat, ncol_global=l)
1431 :
1432 2 : CALL parallel_gemm("N", "N", n, l, k, 1.0_dp, vec_all, rmat, 0.0_dp, wf)
1433 2 : CALL cp_fm_to_fm(wf, vectors)
1434 2 : CALL cp_fm_release(wf)
1435 2 : END SUBROUTINE rotate_orbitals_edf
1436 : ! **************************************************************************************************
1437 : !> \brief ...
1438 : !> \param diag ...
1439 : !> \param weights ...
1440 : !> \param matrix ...
1441 : !> \param ndim ...
1442 : ! **************************************************************************************************
1443 154 : SUBROUTINE gradsq_at_0(diag, weights, matrix, ndim)
1444 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: diag
1445 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1446 : TYPE(cp_fm_type), INTENT(IN) :: matrix
1447 : INTEGER, INTENT(IN) :: ndim
1448 :
1449 : COMPLEX(KIND=dp) :: zii, zjj
1450 : INTEGER :: idim, istate, jstate, ncol_local, &
1451 : nrow_global, nrow_local
1452 154 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1453 : REAL(KIND=dp) :: gradsq_ij
1454 :
1455 : CALL cp_fm_get_info(matrix, nrow_local=nrow_local, &
1456 : ncol_local=ncol_local, nrow_global=nrow_global, &
1457 154 : row_indices=row_indices, col_indices=col_indices)
1458 :
1459 308 : DO istate = 1, nrow_local
1460 616 : DO jstate = 1, ncol_local
1461 : ! get real and imaginary parts
1462 308 : gradsq_ij = 0.0_dp
1463 2156 : DO idim = 1, ndim
1464 1848 : zii = diag(row_indices(istate), idim)
1465 1848 : zjj = diag(col_indices(jstate), idim)
1466 : gradsq_ij = gradsq_ij + weights(idim)* &
1467 2156 : 4.0_dp*REAL((CONJG(zii)*zii + CONJG(zjj)*zjj), KIND=dp)
1468 : END DO
1469 462 : matrix%local_data(istate, jstate) = gradsq_ij
1470 : END DO
1471 : END DO
1472 154 : END SUBROUTINE gradsq_at_0
1473 : ! **************************************************************************************************
1474 : !> \brief ...
1475 : !> \param matrix_p ...
1476 : !> \param weights ...
1477 : !> \param matrix ...
1478 : ! **************************************************************************************************
1479 104 : SUBROUTINE grad_at_0(matrix_p, weights, matrix)
1480 : TYPE(cp_cfm_type) :: matrix_p(:)
1481 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1482 : TYPE(cp_fm_type), INTENT(IN) :: matrix
1483 :
1484 : COMPLEX(KIND=dp) :: zii, zij, zjj
1485 104 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: diag
1486 : INTEGER :: dim_m, idim, istate, jstate, ncol_local, &
1487 : nrow_global, nrow_local
1488 104 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1489 : REAL(KIND=dp) :: grad_ij
1490 :
1491 104 : NULLIFY (diag)
1492 : CALL cp_fm_get_info(matrix, nrow_local=nrow_local, &
1493 : ncol_local=ncol_local, nrow_global=nrow_global, &
1494 104 : row_indices=row_indices, col_indices=col_indices)
1495 104 : dim_m = SIZE(matrix_p, 1)
1496 416 : ALLOCATE (diag(nrow_global, dim_m))
1497 :
1498 728 : DO idim = 1, dim_m
1499 23192 : DO istate = 1, nrow_global
1500 23088 : CALL cp_cfm_get_element(matrix_p(idim), istate, istate, diag(istate, idim))
1501 : END DO
1502 : END DO
1503 :
1504 1976 : DO istate = 1, nrow_local
1505 69368 : DO jstate = 1, ncol_local
1506 : ! get real and imaginary parts
1507 : grad_ij = 0.0_dp
1508 471744 : DO idim = 1, dim_m
1509 404352 : zii = diag(row_indices(istate), idim)
1510 404352 : zjj = diag(col_indices(jstate), idim)
1511 404352 : zij = matrix_p(idim)%local_data(istate, jstate)
1512 : grad_ij = grad_ij + weights(idim)* &
1513 471744 : REAL(4.0_dp*CONJG(zij)*(zjj - zii), dp)
1514 : END DO
1515 69264 : matrix%local_data(istate, jstate) = grad_ij
1516 : END DO
1517 : END DO
1518 104 : DEALLOCATE (diag)
1519 104 : END SUBROUTINE grad_at_0
1520 :
1521 : ! return energy and maximum gradient in the current point
1522 : ! **************************************************************************************************
1523 : !> \brief ...
1524 : !> \param weights ...
1525 : !> \param zij ...
1526 : !> \param tolerance ...
1527 : !> \param value ...
1528 : ! **************************************************************************************************
1529 4986 : SUBROUTINE check_tolerance_new(weights, zij, tolerance, value)
1530 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1531 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :)
1532 : REAL(KIND=dp) :: tolerance, value
1533 :
1534 : COMPLEX(KIND=dp) :: kii, kij, kjj
1535 4986 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: diag
1536 : INTEGER :: idim, istate, jstate, ncol_local, &
1537 : nrow_global, nrow_local
1538 4986 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1539 : REAL(KIND=dp) :: grad_ij, ra, rb
1540 :
1541 4986 : NULLIFY (diag)
1542 : CALL cp_fm_get_info(zij(1, 1), nrow_local=nrow_local, &
1543 : ncol_local=ncol_local, nrow_global=nrow_global, &
1544 4986 : row_indices=row_indices, col_indices=col_indices)
1545 19944 : ALLOCATE (diag(nrow_global, SIZE(zij, 2)))
1546 4986 : value = 0.0_dp
1547 20058 : DO idim = 1, SIZE(zij, 2)
1548 203172 : DO istate = 1, nrow_global
1549 183114 : CALL cp_fm_get_element(zij(1, idim), istate, istate, ra)
1550 183114 : CALL cp_fm_get_element(zij(2, idim), istate, istate, rb)
1551 183114 : diag(istate, idim) = CMPLX(ra, rb, dp)
1552 198186 : value = value + weights(idim) - weights(idim)*ABS(diag(istate, idim))**2
1553 : END DO
1554 : END DO
1555 4986 : tolerance = 0.0_dp
1556 35410 : DO istate = 1, nrow_local
1557 504826 : DO jstate = 1, ncol_local
1558 1879089 : grad_ij = 0.0_dp
1559 1879089 : DO idim = 1, SIZE(zij, 2)
1560 1409673 : kii = diag(row_indices(istate), idim)
1561 1409673 : kjj = diag(col_indices(jstate), idim)
1562 1409673 : ra = zij(1, idim)%local_data(istate, jstate)
1563 1409673 : rb = zij(2, idim)%local_data(istate, jstate)
1564 1409673 : kij = CMPLX(ra, rb, dp)
1565 : grad_ij = grad_ij + weights(idim)* &
1566 1879089 : REAL(4.0_dp*CONJG(kij)*(kjj - kii), dp)
1567 : END DO
1568 499840 : tolerance = MAX(ABS(grad_ij), tolerance)
1569 : END DO
1570 : END DO
1571 4986 : CALL zij(1, 1)%matrix_struct%para_env%max(tolerance)
1572 :
1573 4986 : DEALLOCATE (diag)
1574 :
1575 4986 : END SUBROUTINE check_tolerance_new
1576 :
1577 : ! **************************************************************************************************
1578 : !> \brief yet another crazy try, computes the angles needed to rotate the orbitals first
1579 : !> and rotates them all at the same time (hoping for the best of course)
1580 : !> \param weights ...
1581 : !> \param zij ...
1582 : !> \param vectors ...
1583 : !> \param max_iter ...
1584 : !> \param max_crazy_angle ...
1585 : !> \param crazy_scale ...
1586 : !> \param crazy_use_diag ...
1587 : !> \param eps_localization ...
1588 : !> \param iterations ...
1589 : !> \param converged ...
1590 : ! **************************************************************************************************
1591 136 : SUBROUTINE crazy_rotations(weights, zij, vectors, max_iter, max_crazy_angle, crazy_scale, crazy_use_diag, &
1592 : eps_localization, iterations, converged)
1593 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1594 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
1595 : INTEGER, INTENT(IN) :: max_iter
1596 : REAL(KIND=dp), INTENT(IN) :: max_crazy_angle
1597 : REAL(KIND=dp) :: crazy_scale
1598 : LOGICAL :: crazy_use_diag
1599 : REAL(KIND=dp), INTENT(IN) :: eps_localization
1600 : INTEGER :: iterations
1601 : LOGICAL, INTENT(out), OPTIONAL :: converged
1602 :
1603 : CHARACTER(len=*), PARAMETER :: routineN = 'crazy_rotations'
1604 : COMPLEX(KIND=dp), PARAMETER :: cone = (1.0_dp, 0.0_dp), &
1605 : czero = (0.0_dp, 0.0_dp)
1606 :
1607 : COMPLEX(KIND=dp), DIMENSION(:), POINTER :: evals_exp
1608 136 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: diag_z
1609 : COMPLEX(KIND=dp), POINTER :: mii(:), mij(:), mjj(:)
1610 : INTEGER :: dim2, handle, i, icol, idim, irow, &
1611 : method, ncol_global, ncol_local, &
1612 : norder, nrow_global, nrow_local, &
1613 : nsquare, unit_nr
1614 136 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1615 : LOGICAL :: do_emd
1616 : REAL(KIND=dp) :: eps_exp, limit_crazy_angle, maxeval, &
1617 : norm, ra, rb, theta, tolerance, value
1618 : REAL(KIND=dp), DIMENSION(:), POINTER :: evals
1619 : TYPE(cp_cfm_type) :: cmat_A, cmat_R, cmat_t1
1620 : TYPE(cp_fm_type) :: mat_R, mat_t, mat_theta, mat_U
1621 :
1622 136 : CALL timeset(routineN, handle)
1623 136 : NULLIFY (row_indices, col_indices)
1624 : CALL cp_fm_get_info(zij(1, 1), nrow_global=nrow_global, &
1625 : ncol_global=ncol_global, &
1626 : row_indices=row_indices, col_indices=col_indices, &
1627 136 : nrow_local=nrow_local, ncol_local=ncol_local)
1628 :
1629 136 : limit_crazy_angle = max_crazy_angle
1630 :
1631 136 : NULLIFY (diag_z, evals, evals_exp, mii, mij, mjj)
1632 136 : dim2 = SIZE(zij, 2)
1633 544 : ALLOCATE (diag_z(nrow_global, dim2))
1634 408 : ALLOCATE (evals(nrow_global))
1635 408 : ALLOCATE (evals_exp(nrow_global))
1636 :
1637 136 : CALL cp_cfm_create(cmat_A, zij(1, 1)%matrix_struct)
1638 136 : CALL cp_cfm_create(cmat_R, zij(1, 1)%matrix_struct)
1639 136 : CALL cp_cfm_create(cmat_t1, zij(1, 1)%matrix_struct)
1640 :
1641 136 : CALL cp_fm_create(mat_U, zij(1, 1)%matrix_struct)
1642 136 : CALL cp_fm_create(mat_t, zij(1, 1)%matrix_struct)
1643 136 : CALL cp_fm_create(mat_R, zij(1, 1)%matrix_struct)
1644 :
1645 136 : CALL cp_fm_create(mat_theta, zij(1, 1)%matrix_struct)
1646 :
1647 136 : CALL cp_fm_set_all(mat_R, 0.0_dp, 1.0_dp)
1648 136 : CALL cp_fm_set_all(mat_t, 0.0_dp)
1649 680 : ALLOCATE (mii(dim2), mij(dim2), mjj(dim2))
1650 550 : DO idim = 1, dim2
1651 414 : CALL cp_fm_scale_and_add(1.0_dp, mat_t, weights(idim), zij(1, idim))
1652 550 : CALL cp_fm_scale_and_add(1.0_dp, mat_t, weights(idim), zij(2, idim))
1653 : END DO
1654 136 : CALL cp_fm_syevd(mat_t, mat_U, evals)
1655 550 : DO idim = 1, dim2
1656 : ! rotate z's
1657 414 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, zij(1, idim), mat_U, 0.0_dp, mat_t)
1658 414 : CALL parallel_gemm('T', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_U, mat_t, 0.0_dp, zij(1, idim))
1659 414 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, zij(2, idim), mat_U, 0.0_dp, mat_t)
1660 550 : CALL parallel_gemm('T', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_U, mat_t, 0.0_dp, zij(2, idim))
1661 : END DO
1662 : ! collect rotation matrix
1663 136 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_R, mat_U, 0.0_dp, mat_t)
1664 136 : CALL cp_fm_to_fm(mat_t, mat_R)
1665 :
1666 136 : unit_nr = -1
1667 136 : IF (cmat_A%matrix_struct%para_env%is_source()) THEN
1668 68 : unit_nr = cp_logger_get_default_unit_nr()
1669 : WRITE (unit_nr, '(T2,A7,A6,1X,A20,A12,A12,A12)') &
1670 68 : "CRAZY| ", "Iter", "value ", "gradient", "Max. eval", "limit"
1671 : END IF
1672 :
1673 136 : iterations = 0
1674 136 : tolerance = 1.0_dp
1675 :
1676 : DO
1677 4986 : iterations = iterations + 1
1678 20058 : DO idim = 1, dim2
1679 203172 : DO i = 1, nrow_global
1680 183114 : CALL cp_fm_get_element(zij(1, idim), i, i, ra)
1681 183114 : CALL cp_fm_get_element(zij(2, idim), i, i, rb)
1682 198186 : diag_z(i, idim) = CMPLX(ra, rb, dp)
1683 : END DO
1684 : END DO
1685 35410 : DO irow = 1, nrow_local
1686 504826 : DO icol = 1, ncol_local
1687 1879089 : DO idim = 1, dim2
1688 1409673 : ra = zij(1, idim)%local_data(irow, icol)
1689 1409673 : rb = zij(2, idim)%local_data(irow, icol)
1690 1409673 : mij(idim) = CMPLX(ra, rb, dp)
1691 1409673 : mii(idim) = diag_z(row_indices(irow), idim)
1692 1879089 : mjj(idim) = diag_z(col_indices(icol), idim)
1693 : END DO
1694 499840 : IF (row_indices(irow) /= col_indices(icol)) THEN
1695 438992 : CALL get_angle(mii, mjj, mij, weights, theta)
1696 438992 : theta = crazy_scale*theta
1697 438992 : IF (theta > limit_crazy_angle) theta = limit_crazy_angle
1698 438992 : IF (theta < -limit_crazy_angle) theta = -limit_crazy_angle
1699 438992 : IF (crazy_use_diag) THEN
1700 0 : cmat_A%local_data(irow, icol) = -CMPLX(0.0_dp, theta, dp)
1701 : ELSE
1702 438992 : mat_theta%local_data(irow, icol) = -theta
1703 : END IF
1704 : ELSE
1705 30424 : IF (crazy_use_diag) THEN
1706 0 : cmat_A%local_data(irow, icol) = czero
1707 : ELSE
1708 30424 : mat_theta%local_data(irow, icol) = 0.0_dp
1709 : END IF
1710 : END IF
1711 : END DO
1712 : END DO
1713 :
1714 : ! construct rotation matrix U based on A using diagonalization
1715 : ! alternatively, exp based on repeated squaring could be faster
1716 4986 : IF (crazy_use_diag) THEN
1717 0 : CALL cp_cfm_heevd(cmat_A, cmat_R, evals)
1718 0 : maxeval = MAXVAL(ABS(evals))
1719 0 : evals_exp(:) = EXP((0.0_dp, -1.0_dp)*evals(:))
1720 0 : CALL cp_cfm_to_cfm(cmat_R, cmat_t1)
1721 0 : CALL cp_cfm_column_scale(cmat_t1, evals_exp)
1722 : CALL parallel_gemm('N', 'C', nrow_global, nrow_global, nrow_global, cone, &
1723 0 : cmat_t1, cmat_R, czero, cmat_A)
1724 0 : mat_U%local_data = REAL(cmat_A%local_data, KIND=dp) ! U is a real matrix
1725 : ELSE
1726 4986 : do_emd = .FALSE.
1727 4986 : method = 2
1728 4986 : eps_exp = 1.0_dp*EPSILON(eps_exp)
1729 4986 : CALL cp_fm_maxabsrownorm(mat_theta, norm)
1730 4986 : maxeval = norm ! an upper bound
1731 4986 : CALL get_nsquare_norder(norm, nsquare, norder, eps_exp, method, do_emd)
1732 4986 : CALL exp_pade_real(mat_U, mat_theta, nsquare, norder)
1733 : END IF
1734 :
1735 20058 : DO idim = 1, dim2
1736 : ! rotate z's
1737 15072 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, zij(1, idim), mat_U, 0.0_dp, mat_t)
1738 15072 : CALL parallel_gemm('T', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_U, mat_t, 0.0_dp, zij(1, idim))
1739 15072 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, zij(2, idim), mat_U, 0.0_dp, mat_t)
1740 20058 : CALL parallel_gemm('T', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_U, mat_t, 0.0_dp, zij(2, idim))
1741 : END DO
1742 : ! collect rotation matrix
1743 4986 : CALL parallel_gemm('N', 'N', nrow_global, nrow_global, nrow_global, 1.0_dp, mat_R, mat_U, 0.0_dp, mat_t)
1744 4986 : CALL cp_fm_to_fm(mat_t, mat_R)
1745 :
1746 4986 : CALL check_tolerance_new(weights, zij, tolerance, value)
1747 :
1748 4986 : IF (unit_nr > 0) THEN
1749 : WRITE (unit_nr, '(T2,A7,I6,1X,G20.15,E12.4,E12.4,E12.4)') &
1750 2493 : "CRAZY| ", iterations, value, tolerance, maxeval, limit_crazy_angle
1751 2493 : CALL m_flush(unit_nr)
1752 : END IF
1753 4986 : IF (tolerance < eps_localization .OR. iterations >= max_iter) EXIT
1754 : END DO
1755 :
1756 136 : IF (PRESENT(converged)) converged = (tolerance < eps_localization)
1757 :
1758 136 : CALL cp_cfm_release(cmat_A)
1759 136 : CALL cp_cfm_release(cmat_R)
1760 136 : CALL cp_cfm_release(cmat_T1)
1761 :
1762 136 : CALL cp_fm_release(mat_U)
1763 136 : CALL cp_fm_release(mat_T)
1764 136 : CALL cp_fm_release(mat_theta)
1765 :
1766 136 : CALL rotate_orbitals(mat_R, vectors)
1767 :
1768 136 : CALL cp_fm_release(mat_R)
1769 136 : DEALLOCATE (evals_exp, evals, diag_z)
1770 136 : DEALLOCATE (mii, mij, mjj)
1771 :
1772 136 : CALL timestop(handle)
1773 :
1774 272 : END SUBROUTINE crazy_rotations
1775 :
1776 : ! **************************************************************************************************
1777 : !> \brief use the exponential parametrization as described in to perform a direct mini
1778 : !> Gerd Berghold et al. PRB 61 (15), pag. 10040 (2000)
1779 : !> none of the input is modified for the time being, just finds the rotations
1780 : !> that minimizes, and throws it away afterwards :-)
1781 : !> apart from being expensive and not cleaned, this works fine
1782 : !> useful to try different spread functionals
1783 : !> \param weights ...
1784 : !> \param zij ...
1785 : !> \param vectors ...
1786 : !> \param max_iter ...
1787 : !> \param eps_localization ...
1788 : !> \param iterations ...
1789 : ! **************************************************************************************************
1790 2 : SUBROUTINE direct_mini(weights, zij, vectors, max_iter, eps_localization, iterations)
1791 : REAL(KIND=dp), INTENT(IN) :: weights(:)
1792 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
1793 : INTEGER, INTENT(IN) :: max_iter
1794 : REAL(KIND=dp), INTENT(IN) :: eps_localization
1795 : INTEGER :: iterations
1796 :
1797 : CHARACTER(len=*), PARAMETER :: routineN = 'direct_mini'
1798 : COMPLEX(KIND=dp), PARAMETER :: cone = (1.0_dp, 0.0_dp), &
1799 : czero = (0.0_dp, 0.0_dp)
1800 : REAL(KIND=dp), PARAMETER :: gold_sec = 0.3819_dp
1801 :
1802 : COMPLEX(KIND=dp) :: lk, ll, tmp
1803 2 : COMPLEX(KIND=dp), DIMENSION(:), POINTER :: evals_exp
1804 2 : COMPLEX(KIND=dp), DIMENSION(:, :), POINTER :: diag_z
1805 : INTEGER :: handle, i, icol, idim, irow, &
1806 : line_search_count, line_searches, lsl, &
1807 : lsm, lsr, n, ncol_local, ndim, &
1808 : nrow_local, output_unit
1809 2 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1810 : LOGICAL :: new_direction
1811 : REAL(KIND=dp) :: a, b, beta_pr, c, denom, ds, ds_min, fa, &
1812 : fb, fc, nom, normg, normg_cross, &
1813 : normg_old, npos, omega, tol, val, x0, &
1814 : x1, xa, xb, xc
1815 : REAL(KIND=dp), DIMENSION(150) :: energy, grad, pos
1816 2 : REAL(KIND=dp), DIMENSION(:), POINTER :: evals, fval, fvald
1817 : TYPE(cp_cfm_type) :: cmat_A, cmat_B, cmat_M, cmat_R, cmat_t1, &
1818 : cmat_t2, cmat_U
1819 2 : TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:) :: c_zij
1820 : TYPE(cp_fm_type) :: matrix_A, matrix_G, matrix_G_old, &
1821 : matrix_G_search, matrix_H, matrix_R, &
1822 : matrix_T
1823 :
1824 2 : NULLIFY (evals, evals_exp, diag_z, fval, fvald)
1825 :
1826 2 : CALL timeset(routineN, handle)
1827 2 : output_unit = cp_logger_get_default_io_unit()
1828 :
1829 2 : n = zij(1, 1)%matrix_struct%nrow_global
1830 2 : ndim = (SIZE(zij, 2))
1831 :
1832 2 : IF (output_unit > 0) THEN
1833 1 : WRITE (output_unit, '(T4,A )') "Localization by direct minimization of the functional; "
1834 1 : WRITE (output_unit, '(T5,2A13,A20,A20,A10 )') " Line search ", " Iteration ", " Functional ", " Tolerance ", " ds Min "
1835 : END IF
1836 :
1837 20 : ALLOCATE (evals(n), evals_exp(n), diag_z(n, ndim), fval(n), fvald(n))
1838 18 : ALLOCATE (c_zij(ndim))
1839 :
1840 : ! create the three complex matrices Z
1841 14 : DO idim = 1, ndim
1842 12 : CALL cp_cfm_create(c_zij(idim), zij(1, 1)%matrix_struct)
1843 : c_zij(idim)%local_data = CMPLX(zij(1, idim)%local_data, &
1844 62 : zij(2, idim)%local_data, dp)
1845 : END DO
1846 :
1847 2 : CALL cp_fm_create(matrix_A, zij(1, 1)%matrix_struct)
1848 2 : CALL cp_fm_create(matrix_G, zij(1, 1)%matrix_struct)
1849 2 : CALL cp_fm_create(matrix_T, zij(1, 1)%matrix_struct)
1850 2 : CALL cp_fm_create(matrix_H, zij(1, 1)%matrix_struct)
1851 2 : CALL cp_fm_create(matrix_G_search, zij(1, 1)%matrix_struct)
1852 2 : CALL cp_fm_create(matrix_G_old, zij(1, 1)%matrix_struct)
1853 2 : CALL cp_fm_create(matrix_R, zij(1, 1)%matrix_struct)
1854 2 : CALL cp_fm_set_all(matrix_R, 0.0_dp, 1.0_dp)
1855 :
1856 2 : CALL cp_fm_set_all(matrix_A, 0.0_dp)
1857 : ! CALL cp_fm_init_random ( matrix_A )
1858 :
1859 2 : CALL cp_cfm_create(cmat_A, zij(1, 1)%matrix_struct)
1860 2 : CALL cp_cfm_create(cmat_U, zij(1, 1)%matrix_struct)
1861 2 : CALL cp_cfm_create(cmat_R, zij(1, 1)%matrix_struct)
1862 2 : CALL cp_cfm_create(cmat_t1, zij(1, 1)%matrix_struct)
1863 2 : CALL cp_cfm_create(cmat_t2, zij(1, 1)%matrix_struct)
1864 2 : CALL cp_cfm_create(cmat_B, zij(1, 1)%matrix_struct)
1865 2 : CALL cp_cfm_create(cmat_M, zij(1, 1)%matrix_struct)
1866 :
1867 : CALL cp_cfm_get_info(cmat_B, nrow_local=nrow_local, ncol_local=ncol_local, &
1868 2 : row_indices=row_indices, col_indices=col_indices)
1869 :
1870 2 : CALL cp_fm_set_all(matrix_G_old, 0.0_dp)
1871 2 : CALL cp_fm_set_all(matrix_G_search, 0.0_dp)
1872 2 : normg_old = 1.0E30_dp
1873 2 : ds_min = 1.0_dp
1874 2 : new_direction = .TRUE.
1875 2 : Iterations = 0
1876 2 : line_searches = 0
1877 2 : line_search_count = 0
1878 154 : DO
1879 154 : iterations = iterations + 1
1880 : ! compute U,R,evals given A
1881 770 : cmat_A%local_data = CMPLX(0.0_dp, matrix_A%local_data, dp) ! cmat_A is hermitian, evals are reals
1882 154 : CALL cp_cfm_heevd(cmat_A, cmat_R, evals)
1883 770 : evals_exp(:) = EXP((0.0_dp, -1.0_dp)*evals(:))
1884 154 : CALL cp_cfm_to_cfm(cmat_R, cmat_t1)
1885 154 : CALL cp_cfm_column_scale(cmat_t1, evals_exp)
1886 154 : CALL parallel_gemm('N', 'C', n, n, n, cone, cmat_t1, cmat_R, czero, cmat_U)
1887 770 : cmat_U%local_data = REAL(cmat_U%local_data, KIND=dp) ! enforce numerics, U is a real matrix
1888 :
1889 154 : IF (new_direction .AND. MOD(line_searches, 20) == 5) THEN ! reset with A .eq. 0
1890 0 : DO idim = 1, ndim
1891 0 : CALL parallel_gemm('N', 'N', n, n, n, cone, c_zij(idim), cmat_U, czero, cmat_t1)
1892 0 : CALL parallel_gemm('C', 'N', n, n, n, cone, cmat_U, cmat_t1, czero, c_zij(idim))
1893 : END DO
1894 : ! collect rotation matrix
1895 0 : matrix_H%local_data = REAL(cmat_U%local_data, KIND=dp)
1896 0 : CALL parallel_gemm('N', 'N', n, n, n, 1.0_dp, matrix_R, matrix_H, 0.0_dp, matrix_T)
1897 0 : CALL cp_fm_to_fm(matrix_T, matrix_R)
1898 :
1899 0 : CALL cp_cfm_set_all(cmat_U, czero, cone)
1900 0 : CALL cp_cfm_set_all(cmat_R, czero, cone)
1901 0 : CALL cp_cfm_set_all(cmat_A, czero)
1902 0 : CALL cp_fm_set_all(matrix_A, 0.0_dp)
1903 0 : evals(:) = 0.0_dp
1904 0 : evals_exp(:) = EXP((0.0_dp, -1.0_dp)*evals(:))
1905 0 : CALL cp_fm_set_all(matrix_G_old, 0.0_dp)
1906 0 : CALL cp_fm_set_all(matrix_G_search, 0.0_dp)
1907 0 : normg_old = 1.0E30_dp
1908 : END IF
1909 :
1910 : ! compute Omega and M
1911 154 : CALL cp_cfm_set_all(cmat_M, czero)
1912 154 : omega = 0.0_dp
1913 1078 : DO idim = 1, ndim
1914 924 : CALL parallel_gemm('N', 'N', n, n, n, cone, c_zij(idim), cmat_U, czero, cmat_t1) ! t1=ZU
1915 924 : CALL parallel_gemm('C', 'N', n, n, n, cone, cmat_U, cmat_t1, czero, cmat_t2) ! t2=(U^T)ZU
1916 2772 : DO i = 1, n
1917 1848 : CALL cp_cfm_get_element(cmat_t2, i, i, diag_z(i, idim))
1918 : SELECT CASE (2) ! allows for selection of different spread functionals
1919 : CASE (1)
1920 : fval(i) = -weights(idim)*LOG(ABS(diag_z(i, idim))**2)
1921 : fvald(i) = -weights(idim)/(ABS(diag_z(i, idim))**2)
1922 : CASE (2) ! corresponds to the jacobi setup
1923 1848 : fval(i) = weights(idim) - weights(idim)*ABS(diag_z(i, idim))**2
1924 1848 : fvald(i) = -weights(idim)
1925 : END SELECT
1926 2772 : omega = omega + fval(i)
1927 : END DO
1928 2926 : DO icol = 1, ncol_local
1929 4620 : DO irow = 1, nrow_local
1930 1848 : tmp = cmat_t1%local_data(irow, icol)*CONJG(diag_z(col_indices(icol), idim))
1931 : cmat_M%local_data(irow, icol) = cmat_M%local_data(irow, icol) &
1932 3696 : + 4.0_dp*fvald(col_indices(icol))*REAL(tmp, KIND=dp)
1933 : END DO
1934 : END DO
1935 : END DO
1936 :
1937 : ! compute Hessian diagonal approximation for the preconditioner
1938 : IF (.TRUE.) THEN
1939 154 : CALL gradsq_at_0(diag_z, weights, matrix_H, ndim)
1940 : ELSE
1941 : CALL cp_fm_set_all(matrix_H, 1.0_dp)
1942 : END IF
1943 :
1944 : ! compute B
1945 462 : DO icol = 1, ncol_local
1946 770 : DO irow = 1, nrow_local
1947 308 : ll = (0.0_dp, -1.0_dp)*evals(row_indices(irow))
1948 308 : lk = (0.0_dp, -1.0_dp)*evals(col_indices(icol))
1949 616 : IF (ABS(ll - lk) < 0.5_dp) THEN ! use a series expansion to avoid loss of precision
1950 176 : tmp = 1.0_dp
1951 176 : cmat_B%local_data(irow, icol) = 0.0_dp
1952 2992 : DO i = 1, 16
1953 2816 : cmat_B%local_data(irow, icol) = cmat_B%local_data(irow, icol) + tmp
1954 2992 : tmp = tmp*(ll - lk)/(i + 1)
1955 : END DO
1956 176 : cmat_B%local_data(irow, icol) = cmat_B%local_data(irow, icol)*EXP(lk)
1957 : ELSE
1958 132 : cmat_B%local_data(irow, icol) = (EXP(lk) - EXP(ll))/(lk - ll)
1959 : END IF
1960 : END DO
1961 : END DO
1962 : ! compute gradient matrix_G
1963 :
1964 154 : CALL parallel_gemm('C', 'N', n, n, n, cone, cmat_M, cmat_R, czero, cmat_t1) ! t1=(M^T)(R^T)
1965 154 : CALL parallel_gemm('C', 'N', n, n, n, cone, cmat_R, cmat_t1, czero, cmat_t2) ! t2=(R)t1
1966 154 : CALL cp_cfm_schur_product(cmat_t2, cmat_B, cmat_t1)
1967 154 : CALL parallel_gemm('N', 'C', n, n, n, cone, cmat_t1, cmat_R, czero, cmat_t2)
1968 154 : CALL parallel_gemm('N', 'N', n, n, n, cone, cmat_R, cmat_t2, czero, cmat_t1)
1969 770 : matrix_G%local_data = REAL(cmat_t1%local_data, KIND=dp)
1970 154 : CALL cp_fm_transpose(matrix_G, matrix_T)
1971 154 : CALL cp_fm_scale_and_add(-1.0_dp, matrix_G, 1.0_dp, matrix_T)
1972 154 : CALL cp_fm_maxabsval(matrix_G, tol)
1973 :
1974 : ! from here on, minimizing technology
1975 154 : IF (new_direction) THEN
1976 : ! energy converged up to machine precision ?
1977 6 : line_searches = line_searches + 1
1978 6 : IF (output_unit > 0) THEN
1979 3 : WRITE (output_unit, '(T5,I10,T18,I10,T31,2F20.6,F10.3)') line_searches, Iterations, Omega, tol, ds_min
1980 3 : CALL m_flush(output_unit)
1981 : END IF
1982 6 : IF (tol < eps_localization .OR. iterations > max_iter) EXIT
1983 :
1984 : IF (.TRUE.) THEN ! do conjugate gradient CG
1985 4 : CALL cp_fm_trace(matrix_G, matrix_G_old, normg_cross)
1986 4 : normg_cross = normg_cross*0.5_dp ! takes into account the fact that A is antisymmetric
1987 : ! apply the preconditioner
1988 12 : DO icol = 1, ncol_local
1989 20 : DO irow = 1, nrow_local
1990 16 : matrix_G_old%local_data(irow, icol) = matrix_G%local_data(irow, icol)/matrix_H%local_data(irow, icol)
1991 : END DO
1992 : END DO
1993 4 : CALL cp_fm_trace(matrix_G, matrix_G_old, normg)
1994 4 : normg = normg*0.5_dp
1995 4 : beta_pr = (normg - normg_cross)/normg_old
1996 4 : normg_old = normg
1997 4 : beta_pr = MAX(beta_pr, 0.0_dp)
1998 4 : CALL cp_fm_scale_and_add(beta_pr, matrix_G_search, -1.0_dp, matrix_G_old)
1999 4 : CALL cp_fm_trace(matrix_G_search, matrix_G_old, normg_cross)
2000 4 : IF (normg_cross >= 0) THEN ! back to SD
2001 0 : IF (matrix_A%matrix_struct%para_env%is_source()) THEN
2002 0 : WRITE (cp_logger_get_default_unit_nr(), *) "!"
2003 : END IF
2004 0 : beta_pr = 0.0_dp
2005 0 : CALL cp_fm_scale_and_add(beta_pr, matrix_G_search, -1.0_dp, matrix_G_old)
2006 : END IF
2007 : ELSE ! SD
2008 : CALL cp_fm_scale_and_add(0.0_dp, matrix_G_search, -1.0_dp, matrix_G)
2009 : END IF
2010 : ! ds_min=1.0E-4_dp
2011 : line_search_count = 0
2012 : END IF
2013 152 : line_search_count = line_search_count + 1
2014 152 : energy(line_search_count) = Omega
2015 :
2016 : ! line search section
2017 : SELECT CASE (3)
2018 : CASE (1) ! two point line search
2019 : SELECT CASE (line_search_count)
2020 : CASE (1)
2021 : pos(1) = 0.0_dp
2022 : pos(2) = ds_min
2023 : CALL cp_fm_trace(matrix_G, matrix_G_search, grad(1))
2024 : grad(1) = grad(1)/2.0_dp
2025 : new_direction = .FALSE.
2026 : CASE (2)
2027 : new_direction = .TRUE.
2028 : x0 = pos(1) ! 0.0_dp
2029 : c = energy(1)
2030 : b = grad(1)
2031 : x1 = pos(2)
2032 : a = (energy(2) - b*x1 - c)/(x1**2)
2033 : IF (a <= 0.0_dp) a = 1.0E-15_dp
2034 : npos = -b/(2.0_dp*a)
2035 : val = a*npos**2 + b*npos + c
2036 : IF (val < energy(1) .AND. val <= energy(2)) THEN
2037 : ! we go to a minimum, but ...
2038 : ! we take a guard against too large steps
2039 : pos(3) = MIN(npos, MAXVAL(pos(1:2))*4.0_dp)
2040 : ELSE ! just take an extended step
2041 : pos(3) = MAXVAL(pos(1:2))*2.0_dp
2042 : END IF
2043 : END SELECT
2044 : CASE (2) ! 3 point line search
2045 : SELECT CASE (line_search_count)
2046 : CASE (1)
2047 : new_direction = .FALSE.
2048 : pos(1) = 0.0_dp
2049 : pos(2) = ds_min*0.8_dp
2050 : CASE (2)
2051 : new_direction = .FALSE.
2052 : IF (energy(2) > energy(1)) THEN
2053 : pos(3) = ds_min*0.7_dp
2054 : ELSE
2055 : pos(3) = ds_min*1.4_dp
2056 : END IF
2057 : CASE (3)
2058 : new_direction = .TRUE.
2059 : xa = pos(1)
2060 : xb = pos(2)
2061 : xc = pos(3)
2062 : fa = energy(1)
2063 : fb = energy(2)
2064 : fc = energy(3)
2065 : nom = (xb - xa)**2*(fb - fc) - (xb - xc)**2*(fb - fa)
2066 : denom = (xb - xa)*(fb - fc) - (xb - xc)*(fb - fa)
2067 : IF (ABS(denom) <= 1.0E-18_dp*MAX(ABS(fb - fc), ABS(fb - fa))) THEN
2068 : npos = xb
2069 : ELSE
2070 : npos = xb - 0.5_dp*nom/denom ! position of the stationary point
2071 : END IF
2072 : val = (npos - xa)*(npos - xb)*fc/((xc - xa)*(xc - xb)) + &
2073 : (npos - xb)*(npos - xc)*fa/((xa - xb)*(xa - xc)) + &
2074 : (npos - xc)*(npos - xa)*fb/((xb - xc)*(xb - xa))
2075 : IF (val < fa .AND. val <= fb .AND. val <= fc) THEN ! OK, we go to a minimum
2076 : ! we take a guard against too large steps
2077 : pos(4) = MAX(MAXVAL(pos(1:3))*0.01_dp, &
2078 : MIN(npos, MAXVAL(pos(1:3))*4.0_dp))
2079 : ELSE ! just take an extended step
2080 : pos(4) = MAXVAL(pos(1:3))*2.0_dp
2081 : END IF
2082 : END SELECT
2083 : CASE (3) ! golden section hunt
2084 152 : new_direction = .FALSE.
2085 152 : IF (line_search_count == 1) THEN
2086 4 : lsl = 1
2087 4 : lsr = 0
2088 4 : lsm = 1
2089 4 : pos(1) = 0.0_dp
2090 4 : pos(2) = ds_min/gold_sec
2091 : ELSE
2092 148 : IF (line_search_count == 150) CPABORT("Too many")
2093 148 : IF (lsr == 0) THEN
2094 28 : IF (energy(line_search_count - 1) < energy(line_search_count)) THEN
2095 4 : lsr = line_search_count
2096 4 : pos(line_search_count + 1) = pos(lsm) + (pos(lsr) - pos(lsm))*gold_sec
2097 : ELSE
2098 24 : lsl = lsm
2099 24 : lsm = line_search_count
2100 24 : pos(line_search_count + 1) = pos(line_search_count)/gold_sec
2101 : END IF
2102 : ELSE
2103 120 : IF (pos(line_search_count) < pos(lsm)) THEN
2104 38 : IF (energy(line_search_count) < energy(lsm)) THEN
2105 : lsr = lsm
2106 : lsm = line_search_count
2107 : ELSE
2108 28 : lsl = line_search_count
2109 : END IF
2110 : ELSE
2111 82 : IF (energy(line_search_count) < energy(lsm)) THEN
2112 : lsl = lsm
2113 : lsm = line_search_count
2114 : ELSE
2115 64 : lsr = line_search_count
2116 : END IF
2117 : END IF
2118 120 : IF (pos(lsr) - pos(lsm) > pos(lsm) - pos(lsl)) THEN
2119 78 : pos(line_search_count + 1) = pos(lsm) + gold_sec*(pos(lsr) - pos(lsm))
2120 : ELSE
2121 42 : pos(line_search_count + 1) = pos(lsl) + gold_sec*(pos(lsm) - pos(lsl))
2122 : END IF
2123 120 : IF ((pos(lsr) - pos(lsl)) < 1.0E-3_dp*pos(lsr)) THEN
2124 4 : new_direction = .TRUE.
2125 : END IF
2126 : END IF ! lsr .eq. 0
2127 : END IF ! first step
2128 : END SELECT
2129 : ! now go to the suggested point
2130 152 : ds_min = pos(line_search_count + 1)
2131 152 : ds = pos(line_search_count + 1) - pos(line_search_count)
2132 154 : CALL cp_fm_scale_and_add(1.0_dp, matrix_A, ds, matrix_G_search)
2133 : END DO
2134 :
2135 : ! collect rotation matrix
2136 10 : matrix_H%local_data = REAL(cmat_U%local_data, KIND=dp)
2137 2 : CALL parallel_gemm('N', 'N', n, n, n, 1.0_dp, matrix_R, matrix_H, 0.0_dp, matrix_T)
2138 2 : CALL cp_fm_to_fm(matrix_T, matrix_R)
2139 2 : CALL rotate_orbitals(matrix_R, vectors)
2140 2 : CALL cp_fm_release(matrix_R)
2141 :
2142 2 : CALL cp_fm_release(matrix_A)
2143 2 : CALL cp_fm_release(matrix_G)
2144 2 : CALL cp_fm_release(matrix_H)
2145 2 : CALL cp_fm_release(matrix_T)
2146 2 : CALL cp_fm_release(matrix_G_search)
2147 2 : CALL cp_fm_release(matrix_G_old)
2148 2 : CALL cp_cfm_release(cmat_A)
2149 2 : CALL cp_cfm_release(cmat_U)
2150 2 : CALL cp_cfm_release(cmat_R)
2151 2 : CALL cp_cfm_release(cmat_t1)
2152 2 : CALL cp_cfm_release(cmat_t2)
2153 2 : CALL cp_cfm_release(cmat_B)
2154 2 : CALL cp_cfm_release(cmat_M)
2155 :
2156 2 : DEALLOCATE (evals, evals_exp, fval, fvald)
2157 :
2158 14 : DO idim = 1, SIZE(c_zij)
2159 60 : zij(1, idim)%local_data = REAL(c_zij(idim)%local_data, dp)
2160 60 : zij(2, idim)%local_data = AIMAG(c_zij(idim)%local_data)
2161 14 : CALL cp_cfm_release(c_zij(idim))
2162 : END DO
2163 2 : DEALLOCATE (c_zij)
2164 2 : DEALLOCATE (diag_z)
2165 :
2166 2 : CALL timestop(handle)
2167 :
2168 6 : END SUBROUTINE direct_mini
2169 :
2170 : ! **************************************************************************************************
2171 : !> \brief Parallel algorithm for jacobi rotations
2172 : !> \param weights ...
2173 : !> \param zij ...
2174 : !> \param vectors ...
2175 : !> \param para_env ...
2176 : !> \param max_iter ...
2177 : !> \param eps_localization ...
2178 : !> \param sweeps ...
2179 : !> \param out_each ...
2180 : !> \param target_time ...
2181 : !> \param start_time ...
2182 : !> \param restricted ...
2183 : !> \par History
2184 : !> use allgather for improved performance
2185 : !> \author MI (11.2009)
2186 : ! **************************************************************************************************
2187 390 : SUBROUTINE jacobi_rot_para(weights, zij, vectors, para_env, max_iter, eps_localization, &
2188 : sweeps, out_each, target_time, start_time, restricted)
2189 :
2190 : REAL(KIND=dp), INTENT(IN) :: weights(:)
2191 : TYPE(cp_fm_type), INTENT(IN) :: zij(:, :), vectors
2192 : TYPE(mp_para_env_type), POINTER :: para_env
2193 : INTEGER, INTENT(IN) :: max_iter
2194 : REAL(KIND=dp), INTENT(IN) :: eps_localization
2195 : INTEGER :: sweeps
2196 : INTEGER, INTENT(IN) :: out_each
2197 : REAL(dp) :: target_time, start_time
2198 : INTEGER :: restricted
2199 :
2200 : CHARACTER(len=*), PARAMETER :: routineN = 'jacobi_rot_para'
2201 :
2202 : INTEGER :: dim2, handle, i, idim, ii, ilow1, ip, j, &
2203 : nblock, nblock_max, ns_me, nstate, &
2204 : output_unit
2205 390 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: ns_bound
2206 390 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: rotmat, z_ij_loc_im, z_ij_loc_re
2207 : REAL(KIND=dp) :: xstate
2208 : TYPE(cp_fm_type) :: rmat
2209 : TYPE(set_c_2d_type), DIMENSION(:), POINTER :: cz_ij_loc
2210 :
2211 390 : CALL timeset(routineN, handle)
2212 :
2213 390 : output_unit = cp_logger_get_default_io_unit()
2214 :
2215 : NULLIFY (cz_ij_loc)
2216 :
2217 390 : dim2 = SIZE(zij, 2)
2218 :
2219 390 : CALL cp_fm_create(rmat, zij(1, 1)%matrix_struct)
2220 390 : CALL cp_fm_set_all(rmat, 0._dp, 1._dp)
2221 :
2222 390 : CALL cp_fm_get_info(rmat, nrow_global=nstate)
2223 :
2224 390 : IF (restricted > 0) THEN
2225 0 : IF (output_unit > 0) THEN
2226 0 : WRITE (output_unit, '(T4,A,I2,A )') "JACOBI: for the ROKS method, the last ", restricted, " orbitals DO NOT ROTATE"
2227 : END IF
2228 0 : nstate = nstate - restricted
2229 : END IF
2230 :
2231 : ! Distribution of the states (XXXXX safe against more pe than states ??? XXXXX)
2232 390 : xstate = REAL(nstate, dp)/REAL(para_env%num_pe, dp)
2233 1560 : ALLOCATE (ns_bound(0:para_env%num_pe - 1, 2))
2234 1170 : DO ip = 1, para_env%num_pe
2235 780 : ns_bound(ip - 1, 1) = MIN(nstate, NINT(xstate*(ip - 1))) + 1
2236 1170 : ns_bound(ip - 1, 2) = MIN(nstate, NINT(xstate*ip))
2237 : END DO
2238 390 : nblock_max = 0
2239 1170 : DO ip = 0, para_env%num_pe - 1
2240 780 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2241 1170 : nblock_max = MAX(nblock_max, nblock)
2242 : END DO
2243 :
2244 : ! otbtain local part of the matrix (could be made faster, but is likely irrelevant).
2245 1560 : ALLOCATE (z_ij_loc_re(nstate, nblock_max))
2246 1170 : ALLOCATE (z_ij_loc_im(nstate, nblock_max))
2247 2364 : ALLOCATE (cz_ij_loc(dim2))
2248 1584 : DO idim = 1, dim2
2249 3972 : DO ip = 0, para_env%num_pe - 1
2250 2388 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2251 2388 : CALL cp_fm_get_submatrix(zij(1, idim), z_ij_loc_re, 1, ns_bound(ip, 1), nstate, nblock)
2252 2388 : CALL cp_fm_get_submatrix(zij(2, idim), z_ij_loc_im, 1, ns_bound(ip, 1), nstate, nblock)
2253 3582 : IF (para_env%mepos == ip) THEN
2254 4752 : ALLOCATE (cz_ij_loc(idim)%c_array(nstate, nblock))
2255 5034 : DO i = 1, nblock
2256 37866 : DO j = 1, nstate
2257 36672 : cz_ij_loc(idim)%c_array(j, i) = CMPLX(z_ij_loc_re(j, i), z_ij_loc_im(j, i), dp)
2258 : END DO
2259 : END DO
2260 : END IF
2261 : END DO ! ip
2262 : END DO
2263 390 : DEALLOCATE (z_ij_loc_re)
2264 390 : DEALLOCATE (z_ij_loc_im)
2265 :
2266 1560 : ALLOCATE (rotmat(nstate, 2*nblock_max))
2267 :
2268 : CALL jacobi_rot_para_core(weights, para_env, max_iter, sweeps, out_each, dim2, nstate, nblock_max, ns_bound, &
2269 : cz_ij_loc, rotmat, output_unit, eps_localization=eps_localization, &
2270 390 : target_time=target_time, start_time=start_time)
2271 :
2272 390 : ilow1 = ns_bound(para_env%mepos, 1)
2273 390 : ns_me = ns_bound(para_env%mepos, 2) - ns_bound(para_env%mepos, 1) + 1
2274 1170 : ALLOCATE (z_ij_loc_re(nstate, nblock_max))
2275 1170 : ALLOCATE (z_ij_loc_im(nstate, nblock_max))
2276 1584 : DO idim = 1, dim2
2277 3972 : DO ip = 0, para_env%num_pe - 1
2278 2388 : z_ij_loc_re = 0.0_dp
2279 2388 : z_ij_loc_im = 0.0_dp
2280 2388 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2281 2388 : IF (ip == para_env%mepos) THEN
2282 5034 : ns_me = nblock
2283 5034 : DO i = 1, ns_me
2284 36672 : ii = ilow1 + i - 1
2285 37866 : DO j = 1, nstate
2286 32832 : z_ij_loc_re(j, i) = REAL(cz_ij_loc(idim)%c_array(j, i), dp)
2287 36672 : z_ij_loc_im(j, i) = AIMAG(cz_ij_loc(idim)%c_array(j, i))
2288 : END DO
2289 : END DO
2290 : END IF
2291 2388 : CALL para_env%bcast(z_ij_loc_re, ip)
2292 2388 : CALL para_env%bcast(z_ij_loc_im, ip)
2293 2388 : CALL cp_fm_set_submatrix(zij(1, idim), z_ij_loc_re, 1, ns_bound(ip, 1), nstate, nblock)
2294 3582 : CALL cp_fm_set_submatrix(zij(2, idim), z_ij_loc_im, 1, ns_bound(ip, 1), nstate, nblock)
2295 : END DO ! ip
2296 : END DO
2297 :
2298 1170 : DO ip = 0, para_env%num_pe - 1
2299 780 : z_ij_loc_re = 0.0_dp
2300 780 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2301 780 : IF (ip == para_env%mepos) THEN
2302 1633 : ns_me = nblock
2303 1633 : DO i = 1, ns_me
2304 11780 : ii = ilow1 + i - 1
2305 12170 : DO j = 1, nstate
2306 11780 : z_ij_loc_re(j, i) = rotmat(j, i)
2307 : END DO
2308 : END DO
2309 : END IF
2310 780 : CALL para_env%bcast(z_ij_loc_re, ip)
2311 1170 : CALL cp_fm_set_submatrix(rmat, z_ij_loc_re, 1, ns_bound(ip, 1), nstate, nblock)
2312 : END DO
2313 :
2314 390 : DEALLOCATE (z_ij_loc_re)
2315 390 : DEALLOCATE (z_ij_loc_im)
2316 1584 : DO idim = 1, dim2
2317 1584 : DEALLOCATE (cz_ij_loc(idim)%c_array)
2318 : END DO
2319 390 : DEALLOCATE (cz_ij_loc)
2320 :
2321 390 : CALL para_env%sync()
2322 390 : CALL rotate_orbitals(rmat, vectors)
2323 390 : CALL cp_fm_release(rmat)
2324 :
2325 390 : DEALLOCATE (rotmat)
2326 390 : DEALLOCATE (ns_bound)
2327 :
2328 390 : CALL timestop(handle)
2329 :
2330 1170 : END SUBROUTINE jacobi_rot_para
2331 :
2332 : ! **************************************************************************************************
2333 : !> \brief almost identical to 'jacobi_rot_para' but with different inout variables
2334 : !> \param weights ...
2335 : !> \param czij ...
2336 : !> \param para_env ...
2337 : !> \param max_iter ...
2338 : !> \param rmat ...
2339 : !> \param tol_out ...
2340 : !> \author Soumya Ghosh (08/21)
2341 : ! **************************************************************************************************
2342 32 : SUBROUTINE jacobi_rot_para_1(weights, czij, para_env, max_iter, rmat, tol_out)
2343 :
2344 : REAL(KIND=dp), INTENT(IN) :: weights(:)
2345 : TYPE(cp_cfm_type), INTENT(IN) :: czij(:)
2346 : TYPE(mp_para_env_type), POINTER :: para_env
2347 : INTEGER, INTENT(IN) :: max_iter
2348 : TYPE(cp_cfm_type), INTENT(IN) :: rmat
2349 : REAL(dp), INTENT(OUT), OPTIONAL :: tol_out
2350 :
2351 : CHARACTER(len=*), PARAMETER :: routineN = 'jacobi_rot_para_1'
2352 :
2353 32 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: czij_array
2354 : INTEGER :: dim2, handle, i, idim, ii, ilow1, ip, j, &
2355 : nblock, nblock_max, ns_me, nstate, &
2356 : sweeps
2357 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: ns_bound
2358 32 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: rotmat, z_ij_loc_re
2359 : REAL(KIND=dp) :: xstate
2360 : TYPE(set_c_2d_type), DIMENSION(:), POINTER :: cz_ij_loc
2361 :
2362 32 : CALL timeset(routineN, handle)
2363 :
2364 32 : dim2 = SIZE(czij)
2365 :
2366 32 : CALL cp_cfm_set_all(rmat, CMPLX(0._dp, 0._dp, dp), CMPLX(1._dp, 0._dp, dp))
2367 :
2368 32 : CALL cp_cfm_get_info(rmat, nrow_global=nstate)
2369 :
2370 : ! Distribution of the states (XXXXX safe against more pe than states ??? XXXXX)
2371 32 : xstate = REAL(nstate, dp)/REAL(para_env%num_pe, dp)
2372 128 : ALLOCATE (ns_bound(0:para_env%num_pe - 1, 2))
2373 96 : DO ip = 1, para_env%num_pe
2374 64 : ns_bound(ip - 1, 1) = MIN(nstate, NINT(xstate*(ip - 1))) + 1
2375 96 : ns_bound(ip - 1, 2) = MIN(nstate, NINT(xstate*ip))
2376 : END DO
2377 32 : nblock_max = 0
2378 96 : DO ip = 0, para_env%num_pe - 1
2379 64 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2380 96 : nblock_max = MAX(nblock_max, nblock)
2381 : END DO
2382 :
2383 : ! otbtain local part of the matrix (could be made faster, but is likely irrelevant).
2384 128 : ALLOCATE (czij_array(nstate, nblock_max))
2385 192 : ALLOCATE (cz_ij_loc(dim2))
2386 128 : DO idim = 1, dim2
2387 320 : DO ip = 0, para_env%num_pe - 1
2388 192 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2389 : ! cfm --> allocatable
2390 192 : CALL cp_cfm_get_submatrix(czij(idim), czij_array, 1, ns_bound(ip, 1), nstate, nblock)
2391 288 : IF (para_env%mepos == ip) THEN
2392 96 : ns_me = nblock
2393 384 : ALLOCATE (cz_ij_loc(idim)%c_array(nstate, ns_me))
2394 2160 : DO i = 1, ns_me
2395 90912 : DO j = 1, nstate
2396 90816 : cz_ij_loc(idim)%c_array(j, i) = czij_array(j, i)
2397 : END DO
2398 : END DO
2399 : END IF
2400 : END DO ! ip
2401 : END DO
2402 32 : DEALLOCATE (czij_array)
2403 :
2404 128 : ALLOCATE (rotmat(nstate, 2*nblock_max))
2405 :
2406 : CALL jacobi_rot_para_core(weights, para_env, max_iter, sweeps, 1, dim2, nstate, nblock_max, ns_bound, &
2407 32 : cz_ij_loc, rotmat, 0, tol_out=tol_out)
2408 :
2409 32 : ilow1 = ns_bound(para_env%mepos, 1)
2410 32 : ns_me = ns_bound(para_env%mepos, 2) - ns_bound(para_env%mepos, 1) + 1
2411 128 : ALLOCATE (z_ij_loc_re(nstate, nblock_max))
2412 :
2413 96 : DO ip = 0, para_env%num_pe - 1
2414 64 : z_ij_loc_re = 0.0_dp
2415 64 : nblock = ns_bound(ip, 2) - ns_bound(ip, 1) + 1
2416 64 : IF (ip == para_env%mepos) THEN
2417 720 : ns_me = nblock
2418 720 : DO i = 1, ns_me
2419 30272 : ii = ilow1 + i - 1
2420 30304 : DO j = 1, nstate
2421 30272 : z_ij_loc_re(j, i) = rotmat(j, i)
2422 : END DO
2423 : END DO
2424 : END IF
2425 64 : CALL para_env%bcast(z_ij_loc_re, ip)
2426 62048 : CALL cp_cfm_set_submatrix(rmat, CMPLX(z_ij_loc_re, 0.0_dp, dp), 1, ns_bound(ip, 1), nstate, nblock)
2427 : END DO
2428 :
2429 32 : DEALLOCATE (z_ij_loc_re)
2430 128 : DO idim = 1, dim2
2431 128 : DEALLOCATE (cz_ij_loc(idim)%c_array)
2432 : END DO
2433 32 : DEALLOCATE (cz_ij_loc)
2434 :
2435 32 : CALL para_env%sync()
2436 :
2437 32 : DEALLOCATE (rotmat)
2438 32 : DEALLOCATE (ns_bound)
2439 :
2440 32 : CALL timestop(handle)
2441 :
2442 64 : END SUBROUTINE jacobi_rot_para_1
2443 :
2444 : ! **************************************************************************************************
2445 : !> \brief Parallel algorithm for jacobi rotations
2446 : !> \param weights ...
2447 : !> \param para_env ...
2448 : !> \param max_iter ...
2449 : !> \param sweeps ...
2450 : !> \param out_each ...
2451 : !> \param dim2 ...
2452 : !> \param nstate ...
2453 : !> \param nblock_max ...
2454 : !> \param ns_bound ...
2455 : !> \param cz_ij_loc ...
2456 : !> \param rotmat ...
2457 : !> \param output_unit ...
2458 : !> \param tol_out ...
2459 : !> \param eps_localization ...
2460 : !> \param target_time ...
2461 : !> \param start_time ...
2462 : !> \par History
2463 : !> split out to reuse with different input types
2464 : !> \author HF (05.2022)
2465 : ! **************************************************************************************************
2466 1266 : SUBROUTINE jacobi_rot_para_core(weights, para_env, max_iter, sweeps, out_each, dim2, nstate, nblock_max, &
2467 422 : ns_bound, cz_ij_loc, rotmat, output_unit, tol_out, eps_localization, target_time, start_time)
2468 :
2469 : REAL(KIND=dp), INTENT(IN) :: weights(:)
2470 : TYPE(mp_para_env_type), POINTER :: para_env
2471 : INTEGER, INTENT(IN) :: max_iter
2472 : INTEGER, INTENT(OUT) :: sweeps
2473 : INTEGER, INTENT(IN) :: out_each, dim2, nstate, nblock_max
2474 : INTEGER, DIMENSION(0:, :), INTENT(IN) :: ns_bound
2475 : TYPE(set_c_2d_type), DIMENSION(:), POINTER :: cz_ij_loc
2476 : REAL(dp), DIMENSION(:, :), INTENT(OUT) :: rotmat
2477 : INTEGER, INTENT(IN) :: output_unit
2478 : REAL(dp), INTENT(OUT), OPTIONAL :: tol_out
2479 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: eps_localization
2480 : REAL(dp), OPTIONAL :: target_time, start_time
2481 :
2482 : COMPLEX(KIND=dp) :: zi, zj
2483 422 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: c_array_me, c_array_partner
2484 : COMPLEX(KIND=dp), POINTER :: mii(:), mij(:), mjj(:)
2485 : INTEGER :: i, idim, ii, ik, il1, il2, il_recv, il_recv_partner, ilow1, ilow2, ip, ip_has_i, &
2486 : ip_partner, ip_recv_from, ip_recv_partner, ipair, iperm, istate, iu1, iu2, iup1, iup2, j, &
2487 : jj, jstate, k, kk, lsweep, n1, n2, npair, nperm, ns_me, ns_partner, ns_recv_from, &
2488 : ns_recv_partner
2489 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rcount, rdispl
2490 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: list_pair
2491 : LOGICAL :: should_stop
2492 422 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: gmat, rmat_loc, rmat_recv, rmat_send
2493 422 : REAL(dp), ALLOCATABLE, DIMENSION(:, :, :) :: rmat_recv_all
2494 : REAL(KIND=dp) :: ct, func, gmax, grad, ri, rj, st, t1, &
2495 : t2, theta, tolerance, zc, zr
2496 422 : TYPE(set_c_1d_type), DIMENSION(:), POINTER :: zdiag_all, zdiag_me
2497 422 : TYPE(set_c_2d_type), DIMENSION(:), POINTER :: xyz_mix, xyz_mix_ns
2498 :
2499 422 : NULLIFY (zdiag_all, zdiag_me)
2500 422 : NULLIFY (xyz_mix, xyz_mix_ns)
2501 : NULLIFY (mii, mij, mjj)
2502 :
2503 2110 : ALLOCATE (mii(dim2), mij(dim2), mjj(dim2))
2504 :
2505 1266 : ALLOCATE (rcount(para_env%num_pe))
2506 844 : ALLOCATE (rdispl(para_env%num_pe))
2507 :
2508 422 : tolerance = 1.0e10_dp
2509 422 : sweeps = 0
2510 :
2511 : ! number of processor pairs and number of permutations
2512 422 : npair = (para_env%num_pe + 1)/2
2513 422 : nperm = para_env%num_pe - MOD(para_env%num_pe + 1, 2)
2514 1266 : ALLOCATE (list_pair(2, npair))
2515 :
2516 : ! initialize rotation matrix
2517 87366 : rotmat = 0.0_dp
2518 2353 : DO i = ns_bound(para_env%mepos, 1), ns_bound(para_env%mepos, 2)
2519 1931 : ii = i - ns_bound(para_env%mepos, 1) + 1
2520 2353 : rotmat(i, ii) = 1.0_dp
2521 : END DO
2522 :
2523 2556 : ALLOCATE (xyz_mix(dim2))
2524 2134 : ALLOCATE (xyz_mix_ns(dim2))
2525 2556 : ALLOCATE (zdiag_me(dim2))
2526 2134 : ALLOCATE (zdiag_all(dim2))
2527 :
2528 422 : ns_me = ns_bound(para_env%mepos, 2) - ns_bound(para_env%mepos, 1) + 1
2529 422 : IF (ns_me /= 0) THEN
2530 2070 : ALLOCATE (c_array_me(nstate, ns_me, dim2))
2531 1680 : DO idim = 1, dim2
2532 5478 : ALLOCATE (xyz_mix_ns(idim)%c_array(nstate, ns_me))
2533 : END DO
2534 1656 : ALLOCATE (gmat(nstate, ns_me))
2535 : END IF
2536 :
2537 1712 : DO idim = 1, dim2
2538 3870 : ALLOCATE (zdiag_me(idim)%c_array(nblock_max))
2539 7542 : zdiag_me(idim)%c_array = z_zero
2540 3870 : ALLOCATE (zdiag_all(idim)%c_array(para_env%num_pe*nblock_max))
2541 14216 : zdiag_all(idim)%c_array = z_zero
2542 : END DO
2543 1688 : ALLOCATE (rmat_recv(nblock_max*2, nblock_max))
2544 1266 : ALLOCATE (rmat_send(nblock_max*2, nblock_max))
2545 :
2546 : ! buffer for message passing
2547 2110 : ALLOCATE (rmat_recv_all(nblock_max*2, nblock_max, 0:para_env%num_pe - 1))
2548 :
2549 422 : IF (output_unit > 0) THEN
2550 195 : WRITE (output_unit, '(T4,A )') " Localization by iterative distributed Jacobi rotation"
2551 195 : WRITE (output_unit, '(T20,A12,T32, A22,T60, A12,A8 )') "Iteration", "Functional", "Tolerance", " Time "
2552 : END IF
2553 :
2554 87474 : DO lsweep = 1, max_iter + 1
2555 87474 : sweeps = lsweep
2556 87474 : IF (sweeps == max_iter + 1) THEN
2557 158 : IF (output_unit > 0) THEN
2558 63 : WRITE (output_unit, *) ' LOCALIZATION! loop did not converge within the maximum number of iterations.'
2559 63 : WRITE (output_unit, *) ' Present Max. gradient = ', tolerance
2560 : END IF
2561 : EXIT
2562 : END IF
2563 87316 : t1 = m_walltime()
2564 :
2565 174632 : DO iperm = 1, nperm
2566 :
2567 : ! fix partners for this permutation, and get the number of states
2568 87316 : CALL eberlein(iperm, para_env, list_pair)
2569 87316 : ip_partner = -1
2570 87316 : ns_partner = 0
2571 87316 : DO ipair = 1, npair
2572 87316 : IF (list_pair(1, ipair) == para_env%mepos) THEN
2573 43658 : ip_partner = list_pair(2, ipair)
2574 43658 : EXIT
2575 43658 : ELSE IF (list_pair(2, ipair) == para_env%mepos) THEN
2576 43658 : ip_partner = list_pair(1, ipair)
2577 43658 : EXIT
2578 : END IF
2579 : END DO
2580 87316 : IF (ip_partner >= 0) THEN
2581 87316 : ns_partner = ns_bound(ip_partner, 2) - ns_bound(ip_partner, 1) + 1
2582 : ELSE
2583 : ns_partner = 0
2584 : END IF
2585 :
2586 : ! if there is a non-zero block connecting two partners, jacobi-sweep it.
2587 87316 : IF (ns_partner*ns_me /= 0) THEN
2588 :
2589 349200 : ALLOCATE (rmat_loc(ns_me + ns_partner, ns_me + ns_partner))
2590 87300 : rmat_loc = 0.0_dp
2591 701456 : DO i = 1, ns_me + ns_partner
2592 701456 : rmat_loc(i, i) = 1.0_dp
2593 : END DO
2594 :
2595 436500 : ALLOCATE (c_array_partner(nstate, ns_partner, dim2))
2596 :
2597 351300 : DO idim = 1, dim2
2598 1056000 : ALLOCATE (xyz_mix(idim)%c_array(ns_me + ns_partner, ns_me + ns_partner))
2599 1284915 : DO i = 1, ns_me
2600 7980156 : c_array_me(1:nstate, i, idim) = cz_ij_loc(idim)%c_array(1:nstate, i)
2601 : END DO
2602 : END DO
2603 :
2604 : CALL para_env%sendrecv(msgin=c_array_me, dest=ip_partner, &
2605 87300 : msgout=c_array_partner, source=ip_partner)
2606 :
2607 87300 : n1 = ns_me
2608 87300 : n2 = ns_partner
2609 87300 : ilow1 = ns_bound(para_env%mepos, 1)
2610 87300 : iup1 = ns_bound(para_env%mepos, 1) + n1 - 1
2611 87300 : ilow2 = ns_bound(ip_partner, 1)
2612 87300 : iup2 = ns_bound(ip_partner, 1) + n2 - 1
2613 87300 : IF (ns_bound(para_env%mepos, 1) < ns_bound(ip_partner, 1)) THEN
2614 43650 : il1 = 1
2615 : iu1 = n1
2616 43650 : iu1 = n1
2617 43650 : il2 = 1 + n1
2618 43650 : iu2 = n1 + n2
2619 : ELSE
2620 43650 : il1 = 1 + n2
2621 : iu1 = n1 + n2
2622 43650 : iu1 = n1 + n2
2623 43650 : il2 = 1
2624 43650 : iu2 = n2
2625 : END IF
2626 :
2627 351300 : DO idim = 1, dim2
2628 1197615 : DO i = 1, n1
2629 4386354 : xyz_mix(idim)%c_array(il1:iu1, il1 + i - 1) = c_array_me(ilow1:iup1, i, idim)
2630 4527417 : xyz_mix(idim)%c_array(il2:iu2, il1 + i - 1) = c_array_me(ilow2:iup2, i, idim)
2631 : END DO
2632 1284915 : DO i = 1, n2
2633 4386354 : xyz_mix(idim)%c_array(il2:iu2, il2 + i - 1) = c_array_partner(ilow2:iup2, i, idim)
2634 4527417 : xyz_mix(idim)%c_array(il1:iu1, il2 + i - 1) = c_array_partner(ilow1:iup1, i, idim)
2635 : END DO
2636 : END DO
2637 :
2638 701456 : DO istate = 1, n1 + n2
2639 2604488 : DO jstate = istate + 1, n1 + n2
2640 7751958 : DO idim = 1, dim2
2641 5848926 : mii(idim) = xyz_mix(idim)%c_array(istate, istate)
2642 5848926 : mij(idim) = xyz_mix(idim)%c_array(istate, jstate)
2643 7751958 : mjj(idim) = xyz_mix(idim)%c_array(jstate, jstate)
2644 : END DO
2645 1903032 : CALL get_angle(mii, mjj, mij, weights, theta)
2646 1903032 : st = SIN(theta)
2647 1903032 : ct = COS(theta)
2648 7751958 : DO idim = 1, dim2
2649 52347834 : DO i = 1, n1 + n2
2650 46498908 : zi = ct*xyz_mix(idim)%c_array(i, istate) + st*xyz_mix(idim)%c_array(i, jstate)
2651 46498908 : zj = -st*xyz_mix(idim)%c_array(i, istate) + ct*xyz_mix(idim)%c_array(i, jstate)
2652 46498908 : xyz_mix(idim)%c_array(i, istate) = zi
2653 52347834 : xyz_mix(idim)%c_array(i, jstate) = zj
2654 : END DO
2655 54250866 : DO i = 1, n1 + n2
2656 46498908 : zi = ct*xyz_mix(idim)%c_array(istate, i) + st*xyz_mix(idim)%c_array(jstate, i)
2657 46498908 : zj = -st*xyz_mix(idim)%c_array(istate, i) + ct*xyz_mix(idim)%c_array(jstate, i)
2658 46498908 : xyz_mix(idim)%c_array(istate, i) = zi
2659 52347834 : xyz_mix(idim)%c_array(jstate, i) = zj
2660 : END DO
2661 : END DO
2662 :
2663 17423024 : DO i = 1, n1 + n2
2664 14905836 : ri = ct*rmat_loc(i, istate) + st*rmat_loc(i, jstate)
2665 14905836 : rj = ct*rmat_loc(i, jstate) - st*rmat_loc(i, istate)
2666 14905836 : rmat_loc(i, istate) = ri
2667 16808868 : rmat_loc(i, jstate) = rj
2668 : END DO
2669 : END DO
2670 : END DO
2671 :
2672 87300 : k = nblock_max + 1
2673 : CALL para_env%sendrecv(rotmat(1:nstate, 1:ns_me), ip_partner, &
2674 5121676 : rotmat(1:nstate, k:k + n2 - 1), ip_partner)
2675 :
2676 87300 : IF (ilow1 < ilow2) THEN
2677 : ! no longer compiles in official sdgb:
2678 : ! probably inefficient:
2679 : CALL dgemm("N", "N", nstate, n1, n2, 1.0_dp, rotmat(1:, k:), nstate, rmat_loc(1 + n1:, 1:n1), &
2680 1476102 : n2, 0.0_dp, gmat(:, :), nstate)
2681 : CALL dgemm("N", "N", nstate, n1, n1, 1.0_dp, rotmat(1:, 1:), nstate, rmat_loc(1:, 1:), &
2682 43650 : n1 + n2, 1.0_dp, gmat(:, :), nstate)
2683 : ELSE
2684 : CALL dgemm("N", "N", nstate, n1, n2, 1.0_dp, rotmat(1:, k:), nstate, &
2685 43650 : rmat_loc(1:, n2 + 1:), n1 + n2, 0.0_dp, gmat(:, :), nstate)
2686 : ! no longer compiles in official sdgb:
2687 : ! probably inefficient:
2688 : CALL dgemm("N", "N", nstate, n1, n1, 1.0_dp, rotmat(1:, 1:), nstate, rmat_loc(n2 + 1:, n2 + 1:), &
2689 1151398 : n1, 1.0_dp, gmat(:, :), nstate)
2690 : END IF
2691 :
2692 87300 : CALL dcopy(nstate*n1, gmat(1, 1), 1, rotmat(1, 1), 1)
2693 :
2694 351300 : DO idim = 1, dim2
2695 1197615 : DO i = 1, n1
2696 7980156 : xyz_mix_ns(idim)%c_array(1:nstate, i) = z_zero
2697 : END DO
2698 :
2699 1197615 : DO istate = 1, n1
2700 7980156 : DO jstate = 1, nstate
2701 33924672 : DO i = 1, n2
2702 : xyz_mix_ns(idim)%c_array(jstate, istate) = &
2703 : xyz_mix_ns(idim)%c_array(jstate, istate) + &
2704 32991057 : c_array_partner(jstate, i, idim)*rmat_loc(il2 + i - 1, il1 + istate - 1)
2705 : END DO
2706 : END DO
2707 : END DO
2708 1284915 : DO istate = 1, n1
2709 7980156 : DO jstate = 1, nstate
2710 34789089 : DO i = 1, n1
2711 : xyz_mix_ns(idim)%c_array(jstate, istate) = xyz_mix_ns(idim)%c_array(jstate, istate) + &
2712 33855474 : c_array_me(jstate, i, idim)*rmat_loc(il1 + i - 1, il1 + istate - 1)
2713 : END DO
2714 : END DO
2715 : END DO
2716 : END DO ! idim
2717 :
2718 87300 : DEALLOCATE (c_array_partner)
2719 :
2720 : ELSE ! save my data
2721 64 : DO idim = 1, dim2
2722 88 : DO i = 1, ns_me
2723 120 : xyz_mix_ns(idim)%c_array(1:nstate, i) = cz_ij_loc(idim)%c_array(1:nstate, i)
2724 : END DO
2725 : END DO
2726 : END IF
2727 :
2728 351364 : DO idim = 1, dim2
2729 1285003 : DO i = 1, ns_me
2730 7980252 : cz_ij_loc(idim)%c_array(1:nstate, i) = z_zero
2731 : END DO
2732 : END DO
2733 :
2734 87316 : IF (ns_partner*ns_me /= 0) THEN
2735 : ! transpose rotation matrix rmat_loc
2736 701456 : DO i = 1, ns_me + ns_partner
2737 2604488 : DO j = i + 1, ns_me + ns_partner
2738 1903032 : ri = rmat_loc(i, j)
2739 1903032 : rmat_loc(i, j) = rmat_loc(j, i)
2740 2517188 : rmat_loc(j, i) = ri
2741 : END DO
2742 : END DO
2743 :
2744 : ! prepare for distribution
2745 394378 : DO i = 1, n1
2746 1519752 : rmat_send(1:n1, i) = rmat_loc(il1:iu1, il1 + i - 1)
2747 : END DO
2748 87300 : ik = nblock_max
2749 394378 : DO i = 1, n2
2750 1479114 : rmat_send(ik + 1:ik + n1, i) = rmat_loc(il1:iu1, il2 + i - 1)
2751 : END DO
2752 : ELSE
2753 16 : rmat_send = 0.0_dp
2754 : END IF
2755 :
2756 : ! collect data from all tasks (this takes some significant time)
2757 87316 : CALL para_env%allgather(rmat_send, rmat_recv_all)
2758 :
2759 : ! update blocks everywhere
2760 261948 : DO ip = 0, para_env%num_pe - 1
2761 :
2762 174632 : ip_recv_from = MOD(para_env%mepos - IP + para_env%num_pe, para_env%num_pe)
2763 6507920 : rmat_recv(:, :) = rmat_recv_all(:, :, ip_recv_from)
2764 :
2765 174632 : ns_recv_from = ns_bound(ip_recv_from, 2) - ns_bound(ip_recv_from, 1) + 1
2766 :
2767 261948 : IF (ns_me /= 0) THEN
2768 174616 : IF (ns_recv_from /= 0) THEN
2769 : !look for the partner of ip_recv_from
2770 174608 : ip_recv_partner = -1
2771 174608 : ns_recv_partner = 0
2772 174608 : DO ipair = 1, npair
2773 174608 : IF (list_pair(1, ipair) == ip_recv_from) THEN
2774 87308 : ip_recv_partner = list_pair(2, ipair)
2775 87308 : EXIT
2776 87300 : ELSE IF (list_pair(2, ipair) == ip_recv_from) THEN
2777 : ip_recv_partner = list_pair(1, ipair)
2778 : EXIT
2779 : END IF
2780 : END DO
2781 :
2782 174608 : IF (ip_recv_partner >= 0) THEN
2783 174608 : ns_recv_partner = ns_bound(ip_recv_partner, 2) - ns_bound(ip_recv_partner, 1) + 1
2784 : END IF
2785 174608 : IF (ns_recv_partner > 0) THEN
2786 174600 : il1 = ns_bound(para_env%mepos, 1)
2787 174600 : il_recv = ns_bound(ip_recv_from, 1)
2788 174600 : il_recv_partner = ns_bound(ip_recv_partner, 1)
2789 174600 : ik = nblock_max
2790 :
2791 702600 : DO idim = 1, dim2
2792 2395230 : DO i = 1, ns_recv_from
2793 1867230 : ii = il_recv + i - 1
2794 9177771 : DO j = 1, ns_me
2795 33855474 : jj = j
2796 35722704 : DO k = 1, ns_recv_from
2797 27072933 : kk = il_recv + k - 1
2798 : cz_ij_loc(idim)%c_array(ii, jj) = cz_ij_loc(idim)%c_array(ii, jj) + &
2799 33855474 : rmat_recv(i, k)*xyz_mix_ns(idim)%c_array(kk, j)
2800 : END DO
2801 : END DO
2802 : END DO
2803 2569830 : DO i = 1, ns_recv_from
2804 1867230 : ii = il_recv + i - 1
2805 9177771 : DO j = 1, ns_me
2806 32991057 : jj = j
2807 34858287 : DO k = 1, ns_recv_partner
2808 26208516 : kk = il_recv_partner + k - 1
2809 : cz_ij_loc(idim)%c_array(ii, jj) = cz_ij_loc(idim)%c_array(ii, jj) + &
2810 32991057 : rmat_recv(ik + i, k)*xyz_mix_ns(idim)%c_array(kk, j)
2811 : END DO
2812 : END DO
2813 : END DO
2814 : END DO ! idim
2815 : ELSE
2816 8 : il1 = ns_bound(para_env%mepos, 1)
2817 8 : il_recv = ns_bound(ip_recv_from, 1)
2818 32 : DO idim = 1, dim2
2819 56 : DO j = 1, ns_me
2820 48 : jj = j
2821 72 : DO i = 1, ns_recv_from
2822 24 : ii = il_recv + i - 1
2823 48 : cz_ij_loc(idim)%c_array(ii, jj) = xyz_mix_ns(idim)%c_array(ii, j)
2824 : END DO
2825 : END DO
2826 : END DO ! idim
2827 : END IF
2828 : END IF
2829 : END IF ! ns_me
2830 : END DO ! ip
2831 :
2832 174632 : IF (ns_partner*ns_me /= 0) THEN
2833 87300 : DEALLOCATE (rmat_loc)
2834 351300 : DO idim = 1, dim2
2835 351300 : DEALLOCATE (xyz_mix(idim)%c_array)
2836 : END DO
2837 : END IF
2838 :
2839 : END DO ! iperm
2840 :
2841 : ! calculate the max gradient
2842 351364 : DO idim = 1, dim2
2843 1197687 : DO i = ns_bound(para_env%mepos, 1), ns_bound(para_env%mepos, 2)
2844 933639 : ii = i - ns_bound(para_env%mepos, 1) + 1
2845 933639 : zdiag_me(idim)%c_array(ii) = cz_ij_loc(idim)%c_array(i, ii)
2846 1197687 : zdiag_me(idim)%c_array(ii) = cz_ij_loc(idim)%c_array(i, ii)
2847 : END DO
2848 792144 : rcount(:) = SIZE(zdiag_me(idim)%c_array)
2849 264048 : rdispl(1) = 0
2850 528096 : DO ip = 2, para_env%num_pe
2851 528096 : rdispl(ip) = rdispl(ip - 1) + rcount(ip - 1)
2852 : END DO
2853 : ! collect all the diagonal elements in a replicated 1d array
2854 3521164 : CALL para_env%allgatherv(zdiag_me(idim)%c_array, zdiag_all(idim)%c_array, rcount, rdispl)
2855 : END DO
2856 :
2857 87316 : gmax = 0.0_dp
2858 394402 : DO j = ns_bound(para_env%mepos, 1), ns_bound(para_env%mepos, 2)
2859 307086 : k = j - ns_bound(para_env%mepos, 1) + 1
2860 1345918 : DO i = 1, j - 1
2861 : ! find the location of the diagonal element (i,i)
2862 1095233 : DO ip = 0, para_env%num_pe - 1
2863 1095233 : IF (i >= ns_bound(ip, 1) .AND. i <= ns_bound(ip, 2)) THEN
2864 : ip_has_i = ip
2865 : EXIT
2866 : END IF
2867 : END DO
2868 951516 : ii = nblock_max*ip_has_i + i - ns_bound(ip_has_i, 1) + 1
2869 : ! mepos has the diagonal element (j,j), as well as the off diagonal (i,j)
2870 951516 : jj = nblock_max*para_env%mepos + j - ns_bound(para_env%mepos, 1) + 1
2871 951516 : grad = 0.0_dp
2872 3875979 : DO idim = 1, dim2
2873 2924463 : zi = zdiag_all(idim)%c_array(ii)
2874 2924463 : zj = zdiag_all(idim)%c_array(jj)
2875 3875979 : grad = grad + weights(idim)*REAL(4.0_dp*CONJG(cz_ij_loc(idim)%c_array(i, k))*(zj - zi), dp)
2876 : END DO
2877 1258602 : gmax = MAX(gmax, ABS(grad))
2878 : END DO
2879 : END DO
2880 :
2881 87316 : CALL para_env%max(gmax)
2882 87316 : tolerance = gmax
2883 87316 : IF (PRESENT(tol_out)) tol_out = tolerance
2884 :
2885 87316 : func = 0.0_dp
2886 394402 : DO i = ns_bound(para_env%mepos, 1), ns_bound(para_env%mepos, 2)
2887 307086 : k = i - ns_bound(para_env%mepos, 1) + 1
2888 1328041 : DO idim = 1, dim2
2889 933639 : zr = REAL(cz_ij_loc(idim)%c_array(i, k), dp)
2890 933639 : zc = AIMAG(cz_ij_loc(idim)%c_array(i, k))
2891 1240725 : func = func + weights(idim)*(1.0_dp - (zr*zr + zc*zc))/twopi/twopi
2892 : END DO
2893 : END DO
2894 87316 : CALL para_env%sum(func)
2895 87316 : t2 = m_walltime()
2896 :
2897 87316 : IF (output_unit > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
2898 444 : WRITE (output_unit, '(T20,I12,T35,F20.10,T60,E12.4,F8.3)') sweeps, func, tolerance, t2 - t1
2899 444 : CALL m_flush(output_unit)
2900 : END IF
2901 87316 : IF (PRESENT(eps_localization)) THEN
2902 87284 : IF (tolerance < eps_localization) EXIT
2903 : END IF
2904 87316 : IF (PRESENT(target_time) .AND. PRESENT(start_time)) THEN
2905 87020 : CALL external_control(should_stop, "LOC", target_time=target_time, start_time=start_time)
2906 87020 : IF (should_stop) EXIT
2907 : END IF
2908 :
2909 : END DO ! lsweep
2910 :
2911 : ! buffer for message passing
2912 422 : DEALLOCATE (rmat_recv_all)
2913 :
2914 422 : DEALLOCATE (rmat_recv)
2915 422 : DEALLOCATE (rmat_send)
2916 422 : IF (ns_me > 0) THEN
2917 414 : DEALLOCATE (c_array_me)
2918 : END IF
2919 1712 : DO idim = 1, dim2
2920 1290 : DEALLOCATE (zdiag_me(idim)%c_array)
2921 1712 : DEALLOCATE (zdiag_all(idim)%c_array)
2922 : END DO
2923 422 : DEALLOCATE (zdiag_me)
2924 422 : DEALLOCATE (zdiag_all)
2925 422 : DEALLOCATE (xyz_mix)
2926 1712 : DO idim = 1, dim2
2927 1712 : IF (ns_me /= 0) THEN
2928 1266 : DEALLOCATE (xyz_mix_ns(idim)%c_array)
2929 : END IF
2930 : END DO
2931 422 : DEALLOCATE (xyz_mix_ns)
2932 422 : IF (ns_me /= 0) THEN
2933 414 : DEALLOCATE (gmat)
2934 : END IF
2935 422 : DEALLOCATE (mii)
2936 422 : DEALLOCATE (mij)
2937 422 : DEALLOCATE (mjj)
2938 422 : DEALLOCATE (list_pair)
2939 :
2940 844 : END SUBROUTINE jacobi_rot_para_core
2941 :
2942 : ! **************************************************************************************************
2943 : !> \brief ...
2944 : !> \param iperm ...
2945 : !> \param para_env ...
2946 : !> \param list_pair ...
2947 : ! **************************************************************************************************
2948 87316 : SUBROUTINE eberlein(iperm, para_env, list_pair)
2949 : INTEGER, INTENT(IN) :: iperm
2950 : TYPE(mp_para_env_type), POINTER :: para_env
2951 : INTEGER, DIMENSION(:, :) :: list_pair
2952 :
2953 : INTEGER :: i, ii, jj, npair
2954 :
2955 87316 : npair = (para_env%num_pe + 1)/2
2956 87316 : IF (iperm == 1) THEN
2957 : !..set up initial ordering
2958 261948 : DO I = 0, para_env%num_pe - 1
2959 174632 : II = ((i + 1) + 1)/2
2960 174632 : JJ = MOD((i + 1) + 1, 2) + 1
2961 261948 : list_pair(JJ, II) = i
2962 : END DO
2963 87316 : IF (MOD(para_env%num_pe, 2) == 1) list_pair(2, npair) = -1
2964 0 : ELSE IF (MOD(iperm, 2) == 0) THEN
2965 : !..a type shift
2966 0 : jj = list_pair(1, npair)
2967 0 : DO I = npair, 3, -1
2968 0 : list_pair(1, I) = list_pair(1, I - 1)
2969 : END DO
2970 0 : list_pair(1, 2) = list_pair(2, 1)
2971 0 : list_pair(2, 1) = jj
2972 : ELSE
2973 : !..b type shift
2974 0 : jj = list_pair(2, 1)
2975 0 : DO I = 1, npair - 1
2976 0 : list_pair(2, I) = list_pair(2, I + 1)
2977 : END DO
2978 0 : list_pair(2, npair) = jj
2979 : END IF
2980 :
2981 87316 : END SUBROUTINE eberlein
2982 :
2983 : ! **************************************************************************************************
2984 : !> \brief ...
2985 : !> \param vectors ...
2986 : !> \param op_sm_set ...
2987 : !> \param zij_fm_set ...
2988 : ! **************************************************************************************************
2989 532 : SUBROUTINE zij_matrix(vectors, op_sm_set, zij_fm_set)
2990 :
2991 : TYPE(cp_fm_type), INTENT(IN) :: vectors
2992 : TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: op_sm_set
2993 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN) :: zij_fm_set
2994 :
2995 : CHARACTER(len=*), PARAMETER :: routineN = 'zij_matrix'
2996 :
2997 : INTEGER :: handle, i, j, nao, nmoloc
2998 : TYPE(cp_fm_type) :: opvec
2999 :
3000 532 : CALL timeset(routineN, handle)
3001 :
3002 : ! get rows and cols of the input
3003 532 : CALL cp_fm_get_info(vectors, nrow_global=nao, ncol_global=nmoloc)
3004 : ! replicate the input kind of matrix
3005 532 : CALL cp_fm_create(opvec, vectors%matrix_struct)
3006 :
3007 : ! Compute zij here
3008 2164 : DO i = 1, SIZE(zij_fm_set, 2)
3009 5428 : DO j = 1, SIZE(zij_fm_set, 1)
3010 3264 : CALL cp_fm_set_all(zij_fm_set(j, i), 0.0_dp)
3011 3264 : CALL cp_dbcsr_sm_fm_multiply(op_sm_set(j, i)%matrix, vectors, opvec, ncol=nmoloc)
3012 : CALL parallel_gemm("T", "N", nmoloc, nmoloc, nao, 1.0_dp, vectors, opvec, 0.0_dp, &
3013 4896 : zij_fm_set(j, i))
3014 : END DO
3015 : END DO
3016 :
3017 532 : CALL cp_fm_release(opvec)
3018 532 : CALL timestop(handle)
3019 :
3020 532 : END SUBROUTINE zij_matrix
3021 :
3022 : ! **************************************************************************************************
3023 : !> \brief ...
3024 : !> \param vectors ...
3025 : ! **************************************************************************************************
3026 38 : SUBROUTINE scdm_qrfact(vectors)
3027 :
3028 : TYPE(cp_fm_type), INTENT(IN) :: vectors
3029 :
3030 : CHARACTER(len=*), PARAMETER :: routineN = 'scdm_qrfact'
3031 :
3032 : INTEGER :: handle, ncolT, nrowT
3033 38 : REAL(KIND=dp), DIMENSION(:), POINTER :: tau
3034 : TYPE(cp_fm_struct_type), POINTER :: cstruct
3035 : TYPE(cp_fm_type) :: CTp, Qf, tmp
3036 :
3037 38 : CALL timeset(routineN, handle)
3038 :
3039 : ! Create Transpose of Coefficient Matrix vectors
3040 38 : nrowT = vectors%matrix_struct%ncol_global
3041 38 : ncolT = vectors%matrix_struct%nrow_global
3042 :
3043 : CALL cp_fm_struct_create(cstruct, template_fmstruct=vectors%matrix_struct, &
3044 38 : nrow_global=nrowT, ncol_global=ncolT)
3045 38 : CALL cp_fm_create(CTp, cstruct)
3046 38 : CALL cp_fm_struct_release(cstruct)
3047 :
3048 114 : ALLOCATE (tau(nrowT))
3049 :
3050 38 : CALL cp_fm_transpose(vectors, CTp)
3051 :
3052 : ! Get QR decomposition of CTs
3053 38 : CALL cp_fm_pdgeqpf(CTp, tau, nrowT, ncolT, 1, 1)
3054 :
3055 : ! Construction of Q from the scalapack output
3056 : CALL cp_fm_struct_create(cstruct, para_env=CTp%matrix_struct%para_env, &
3057 : context=CTp%matrix_struct%context, nrow_global=CTp%matrix_struct%nrow_global, &
3058 38 : ncol_global=CTp%matrix_struct%nrow_global)
3059 38 : CALL cp_fm_create(Qf, cstruct)
3060 38 : CALL cp_fm_struct_release(cstruct)
3061 38 : CALL cp_fm_to_fm_submat(CTp, Qf, nrowT, nrowT, 1, 1, 1, 1)
3062 :
3063 : ! Get Q
3064 38 : CALL cp_fm_pdorgqr(Qf, tau, nrowT, 1, 1)
3065 :
3066 : ! Transform original coefficient matrix vectors
3067 38 : CALL cp_fm_create(tmp, vectors%matrix_struct)
3068 38 : CALL cp_fm_set_all(tmp, 0.0_dp, 1.0_dp)
3069 38 : CALL cp_fm_to_fm(vectors, tmp)
3070 38 : CALL parallel_gemm('N', 'N', ncolT, nrowT, nrowT, 1.0_dp, tmp, Qf, 0.0_dp, vectors)
3071 :
3072 : ! Cleanup
3073 38 : CALL cp_fm_release(CTp)
3074 38 : CALL cp_fm_release(tmp)
3075 38 : CALL cp_fm_release(Qf)
3076 38 : DEALLOCATE (tau)
3077 :
3078 38 : CALL timestop(handle)
3079 :
3080 152 : END SUBROUTINE scdm_qrfact
3081 :
3082 : ! **************************************************************************************************
3083 : !> \brief Achieves minimisation of the spread functional by simultaneous diagonalisation with Jacobi
3084 : !> rotations as presented in Cardoso & Souloumiac, SIAM J. Matrix Anal. Appl., 17(1), 161.
3085 : !> Generalizes the Jacobi algorithm to complex matrices.
3086 : !> \param weights array of weights for calculating the total spread
3087 : !> \param zij spread operator matrices
3088 : !> \param max_iter maximum number iterations
3089 : !> \param eps_localization numerical tolerance
3090 : !> \param sweeps counts number of sweeps required
3091 : !> \param out_each how often to print info
3092 : !> \param vectors complex vectors to be localized
3093 : !> \par History
3094 : !> 2020-04 created [LS]
3095 : !> \author Lukas Schreder
3096 : ! **************************************************************************************************
3097 6 : SUBROUTINE cardoso_souloumiac(weights, zij, max_iter, eps_localization, sweeps, &
3098 : out_each, vectors)
3099 :
3100 : REAL(KIND=dp), INTENT(IN) :: weights(:)
3101 : TYPE(cp_cfm_type), INTENT(INOUT) :: zij(:, :)
3102 : INTEGER, INTENT(IN) :: max_iter
3103 : REAL(KIND=dp), INTENT(IN) :: eps_localization
3104 : INTEGER :: sweeps
3105 : INTEGER, INTENT(IN) :: out_each
3106 : TYPE(cp_cfm_type), POINTER :: vectors
3107 :
3108 : CHARACTER(len=*), PARAMETER :: routineN = 'cardoso_souloumiac'
3109 :
3110 : COMPLEX(KIND=dp) :: s
3111 6 : COMPLEX(KIND=dp), ALLOCATABLE :: mii(:), mij(:), mji(:), mjj(:)
3112 : INTEGER :: dim1, dim2, handle, idim, istate, jdim, &
3113 : jstate, nstate, unit_nr
3114 : REAL(KIND=dp) :: c, old_spread, spread, t1, t2, tolerance
3115 : TYPE(cp_cfm_type), POINTER :: c_rmat, c_zij(:)
3116 :
3117 6 : CALL timeset(routineN, handle)
3118 :
3119 6 : dim1 = SIZE(zij, 1)
3120 6 : dim2 = SIZE(zij, 2)
3121 :
3122 6 : NULLIFY (c_rmat, c_zij)
3123 84 : ALLOCATE (c_rmat, c_zij(dim1*dim2), mii(dim1*dim2), mij(dim1*dim2), mji(dim1*dim2), mjj(dim1*dim2))
3124 6 : CALL cp_cfm_create(c_rmat, zij(1, 1)%matrix_struct)
3125 6 : CALL cp_cfm_set_all(c_rmat, (0.0_dp, 0.0_dp), (1.0_dp, 0.0_dp)) ! start with the identity transformation
3126 24 : DO idim = 1, dim2
3127 60 : DO jdim = 1, dim1
3128 36 : CALL cp_cfm_create(c_zij((idim - 1)*dim1 + jdim), zij(jdim, idim)%matrix_struct)
3129 54 : CALL cp_cfm_to_cfm(zij(jdim, idim), c_zij((idim - 1)*dim1 + jdim))
3130 : END DO
3131 : END DO
3132 :
3133 6 : CALL cp_cfm_get_info(c_rmat, nrow_global=nstate)
3134 6 : tolerance = 1.0e10_dp
3135 6 : old_spread = 1.0e10_dp
3136 6 : sweeps = 0
3137 6 : unit_nr = -1
3138 6 : IF (c_rmat%matrix_struct%para_env%is_source()) THEN
3139 3 : unit_nr = cp_logger_get_default_unit_nr()
3140 : WRITE (unit_nr, "(T4,A )") " Localization by iterative Jacobi rotation using "// &
3141 3 : "Cardoso-Souloumiac angles"
3142 :
3143 : END IF
3144 :
3145 : ! Jacobi sweeps until converged
3146 58 : DO WHILE (tolerance >= eps_localization .AND. sweeps < max_iter)
3147 52 : sweeps = sweeps + 1
3148 52 : t1 = m_walltime()
3149 1924 : DO jstate = 1, nstate
3150 34684 : DO istate = jstate + 1, nstate
3151 229320 : DO idim = 1, dim1*dim2
3152 196560 : CALL cp_cfm_get_element(c_zij(idim), istate, istate, mii(idim))
3153 196560 : CALL cp_cfm_get_element(c_zij(idim), istate, jstate, mij(idim))
3154 196560 : CALL cp_cfm_get_element(c_zij(idim), jstate, istate, mji(idim))
3155 229320 : CALL cp_cfm_get_element(c_zij(idim), jstate, jstate, mjj(idim))
3156 : END DO
3157 32760 : CALL get_cardoso_angles(mii, mij, mji, mjj, c, s, vectors%matrix_struct)
3158 229320 : DO idim = 1, dim1*dim2
3159 196560 : CALL cp_cfm_rot_cols(c_zij(idim), istate, jstate, c, REAL(s))
3160 229320 : CALL cp_cfm_rot_rows(c_zij(idim), istate, jstate, c, REAL(s))
3161 : END DO
3162 67392 : CALL cp_cfm_rot_cols(c_rmat, istate, jstate, c, REAL(s))
3163 : END DO
3164 : END DO
3165 52 : CALL check_tolerance(c_zij, weights, spread)
3166 52 : CALL check_tolerance(c_zij, weights, tolerance)
3167 52 : tolerance = ABS(spread - old_spread)
3168 52 : old_spread = spread
3169 :
3170 52 : t2 = m_walltime()
3171 58 : IF (unit_nr > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
3172 : WRITE (unit_nr, "(T4,A,I7,A,E12.4,A,E12.4,A,F8.3)") &
3173 26 : "Iteration:", sweeps, "Functional", spread, "Tolerance:", tolerance, "Time:", t2 - t1
3174 26 : CALL m_flush(unit_nr)
3175 : END IF
3176 : END DO
3177 :
3178 24 : DO idim = 1, dim2
3179 : ! back to an interlaced matrix
3180 60 : DO jdim = 1, dim1
3181 36 : CALL cp_cfm_to_cfm(c_zij((idim - 1)*dim1 + jdim), zij(jdim, idim))
3182 54 : CALL cp_cfm_release(c_zij((idim - 1)*dim1 + jdim))
3183 : END DO
3184 : END DO
3185 :
3186 6 : CALL rotate_orbitals_cfm(c_rmat, vectors)
3187 :
3188 6 : DEALLOCATE (c_zij, mii, mij, mji, mjj)
3189 6 : CALL cp_cfm_release(c_rmat)
3190 6 : DEALLOCATE (c_rmat)
3191 :
3192 6 : CALL timestop(handle)
3193 :
3194 18 : END SUBROUTINE cardoso_souloumiac
3195 :
3196 : ! **************************************************************************************************
3197 : !> \brief Pipek-Mezey version of the Cardoso-Souloumiac PADE algorithm for complex-valued matrices.
3198 : !> \param zij spread operator matrices
3199 : !> \param vec complex vectors to be localised
3200 : !> \param sweeps counts number of sweeps required
3201 : !> \param max_iter maximum number iterations
3202 : !> \param eps numerical tolerance
3203 : !> \param out_each how often to print info
3204 : !> \par History
3205 : !> 2020-04 created [LS]
3206 : !> \author Lukas Schreder
3207 : ! **************************************************************************************************
3208 6 : SUBROUTINE cardoso_souloumiac_pipek(zij, vec, sweeps, max_iter, eps, out_each)
3209 :
3210 : TYPE(cp_cfm_type), POINTER :: zij(:, :), vec
3211 : INTEGER :: sweeps, max_iter
3212 : REAL(dp) :: eps
3213 : INTEGER :: out_each
3214 :
3215 : CHARACTER(*), PARAMETER :: routineN = 'cardoso_souloumiac_pipek'
3216 :
3217 : COMPLEX(dp) :: c_spread, s
3218 : COMPLEX(dp), POINTER :: qii(:), qij(:), qji(:), qjj(:)
3219 : INTEGER :: handle, i, j, k, n_dim, n_states, &
3220 : output_unit
3221 : REAL(dp) :: c, old_spread, spread, t1, t2, tol
3222 6 : TYPE(cp_cfm_type), POINTER :: c_zij(:), rmat
3223 :
3224 6 : CALL timeset(routineN, handle)
3225 :
3226 6 : CALL cite_reference(Schreder2024_2)
3227 :
3228 18 : n_dim = SIZE(zij)
3229 :
3230 6 : ALLOCATE (rmat)
3231 6 : CALL cp_cfm_create(rmat, zij(1, 1)%matrix_struct)
3232 :
3233 6 : CALL cp_cfm_set_all(rmat, (0.0_dp, 0.0_dp), (1.0_dp, 0.0_dp))
3234 120 : ALLOCATE (c_zij(n_dim), qii(n_dim), qij(n_dim), qji(n_dim), qjj(n_dim))
3235 :
3236 : ! build Qij matrix
3237 78 : DO k = 1, n_dim
3238 78 : c_zij(k) = zij(k, 1)
3239 : END DO
3240 :
3241 6 : CALL cp_cfm_get_info(c_zij(1), ncol_global=n_states)
3242 :
3243 6 : tol = 1.0e10_dp
3244 6 : c_spread = (0.0_dp, 0.0_dp)
3245 78 : DO k = 1, n_dim
3246 2382 : DO i = 1, n_states
3247 2304 : CALL cp_cfm_get_element(c_zij(k), i, i, s)
3248 2376 : c_spread = c_spread + s*s
3249 : END DO
3250 : END DO
3251 6 : spread = REAL(c_spread)
3252 6 : old_spread = spread
3253 :
3254 6 : sweeps = 0
3255 6 : output_unit = cp_logger_get_default_unit_nr()
3256 : WRITE (output_unit, "(T4,A )") " Localization by iterative Jacobi rotation using "// &
3257 6 : "Cardoso-Souloumiac angles"
3258 6 : WRITE (output_unit, "(T4,A )") " and Pipek-Mezey spread functional"
3259 :
3260 6 : IF (output_unit > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
3261 : WRITE (output_unit, "(T4,A,I7,A,E12.4,A,E12.4,A,F8.3)") &
3262 6 : "Iteration:", sweeps, " Functional", spread, " Tolerance:", tol, " Time:", 0.0_dp
3263 : END IF
3264 :
3265 36 : DO WHILE (tol >= eps .AND. sweeps < max_iter)
3266 30 : t1 = m_walltime()
3267 30 : sweeps = sweeps + 1
3268 :
3269 990 : DO i = 1, n_states
3270 15870 : DO j = i + 1, n_states
3271 193440 : DO k = 1, n_dim
3272 178560 : CALL cp_cfm_get_element(c_zij(k), i, i, qii(k))
3273 178560 : CALL cp_cfm_get_element(c_zij(k), i, j, qij(k))
3274 178560 : CALL cp_cfm_get_element(c_zij(k), j, i, qji(k))
3275 193440 : CALL cp_cfm_get_element(c_zij(k), j, j, qjj(k))
3276 : END DO
3277 14880 : CALL get_cardoso_angles(qii, qij, qji, qjj, c, s, vec%matrix_struct)
3278 193440 : DO k = 1, n_dim
3279 178560 : CALL cp_cfm_rot_cols(c_zij(k), i, j, c, REAL(s))
3280 193440 : CALL cp_cfm_rot_rows(c_zij(k), i, j, c, REAL(s))
3281 : END DO
3282 30720 : CALL cp_cfm_rot_cols(rmat, i, j, c, REAL(s))
3283 : END DO
3284 : END DO
3285 :
3286 30 : c_spread = (0.0_dp, 0.0_dp)
3287 990 : DO i = 1, n_states
3288 12510 : DO k = 1, n_dim
3289 11520 : CALL cp_cfm_get_element(c_zij(k), i, i, s)
3290 12480 : c_spread = c_spread + s*s
3291 : END DO
3292 : END DO
3293 30 : spread = REAL(c_spread)
3294 :
3295 30 : tol = ABS(spread - old_spread)
3296 30 : old_spread = spread
3297 30 : t2 = m_walltime()
3298 36 : IF (output_unit > 0 .AND. MODULO(sweeps, out_each) == 0) THEN
3299 : WRITE (output_unit, "(T4,A,I7,A,E12.4,A,E12.4,A,F8.3)") &
3300 30 : "Iteration:", sweeps, " Functional", spread, " Tolerance:", tol, " Time:", t2 - t1
3301 : END IF
3302 : END DO
3303 :
3304 6 : CALL rotate_orbitals_cfm(rmat, vec)
3305 :
3306 : ! c_zij(k) was assigned (shallow copy of zij(k,1)); do not release contents
3307 6 : DEALLOCATE (c_zij, qii, qij, qji, qjj)
3308 6 : CALL cp_cfm_release(rmat)
3309 6 : DEALLOCATE (rmat)
3310 :
3311 6 : CALL timestop(handle)
3312 :
3313 18 : END SUBROUTINE cardoso_souloumiac_pipek
3314 :
3315 : ! **************************************************************************************************
3316 : !> \brief calculates the Jacobi angles needed in serial Cardoso-Souloumiac diagonalisation
3317 : !> \param mii ...
3318 : !> \param mij ...
3319 : !> \param mji ...
3320 : !> \param mjj ...
3321 : !> \param c ...
3322 : !> \param s ...
3323 : !> \param tmp_fm_struct ...
3324 : !> \par History
3325 : !> 2020-04 created [LS]
3326 : !> \author Lukas Schreder
3327 : ! **************************************************************************************************
3328 47640 : SUBROUTINE get_cardoso_angles(mii, mij, mji, mjj, c, s, tmp_fm_struct)
3329 :
3330 : COMPLEX(KIND=dp), DIMENSION(:) :: mii, mij, mji, mjj
3331 : REAL(KIND=dp), INTENT(out) :: c
3332 : COMPLEX(KIND=dp), INTENT(out) :: s
3333 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
3334 :
3335 : INTEGER :: dim_m, i, i_max
3336 : REAL(KIND=dp) :: r, x, y, z
3337 : REAL(KIND=dp), DIMENSION(3) :: evals
3338 : TYPE(cp_cfm_type), POINTER :: c_Gmat, hmat
3339 : TYPE(cp_fm_struct_type), POINTER :: G_fm_struct, h_fm_struct
3340 : TYPE(cp_fm_type), POINTER :: evects, Gmat
3341 :
3342 47640 : dim_m = SIZE(mii)
3343 :
3344 : CALL cp_fm_struct_create(h_fm_struct, nrow_global=1, ncol_global=3, &
3345 47640 : template_fmstruct=tmp_fm_struct)
3346 : CALL cp_fm_struct_create(G_fm_struct, nrow_global=3, ncol_global=3, &
3347 47640 : template_fmstruct=tmp_fm_struct)
3348 47640 : ALLOCATE (hmat, c_Gmat, Gmat, evects)
3349 47640 : CALL cp_cfm_create(hmat, h_fm_struct)
3350 47640 : CALL cp_cfm_create(c_Gmat, G_fm_struct)
3351 47640 : CALL cp_cfm_set_all(c_Gmat, (0.0_dp, 0.0_dp), (0.0_dp, 0.0_dp))
3352 47640 : CALL cp_fm_create(Gmat, G_fm_struct)
3353 47640 : CALL cp_fm_create(evects, G_fm_struct)
3354 :
3355 422760 : DO i = 1, dim_m
3356 375120 : CALL cp_cfm_set_element(hmat, 1, 1, (mii(i) - mjj(i)))
3357 375120 : CALL cp_cfm_set_element(hmat, 1, 2, (mij(i) + mji(i)))
3358 375120 : CALL cp_cfm_set_element(hmat, 1, 3, (0.0_dp, 1.0_dp)*(mji(i) - mij(i)))
3359 422760 : CALL cp_cfm_gemm("C", "N", 3, 3, 1, (1.0_dp, 0.0_dp), hmat, hmat, (1.0_dp, 0.0_dp), c_Gmat)
3360 : END DO
3361 47640 : CALL cp_cfm_to_fm(c_Gmat, Gmat)
3362 :
3363 : ! find eigenvector with highest eigenvalue
3364 47640 : CALL choose_eigv_solver(Gmat, evects, evals)
3365 190560 : i_max = MAXLOC(evals, 1)
3366 47640 : CALL cp_fm_get_element(evects, 1, i_max, x)
3367 47640 : CALL cp_fm_get_element(evects, 2, i_max, y)
3368 47640 : CALL cp_fm_get_element(evects, 3, i_max, z)
3369 47640 : IF (x < 0) THEN
3370 47288 : x = -x
3371 47288 : y = -y
3372 47288 : z = -z
3373 : END IF
3374 :
3375 : ! calculate the angles
3376 47640 : r = SQRT(x**2 + y**2 + z**2) ! always 1
3377 47640 : c = SQRT((x + r)/(2*r)) ! always real
3378 47640 : s = (y - gaussi*z)/SQRT(2*r*(x + r)) ! always complex
3379 :
3380 47640 : CALL cp_fm_struct_release(h_fm_struct)
3381 47640 : CALL cp_fm_struct_release(G_fm_struct)
3382 47640 : CALL cp_cfm_release(hmat)
3383 47640 : CALL cp_cfm_release(c_Gmat)
3384 47640 : CALL cp_fm_release(Gmat)
3385 47640 : CALL cp_fm_release(evects)
3386 47640 : DEALLOCATE (hmat, c_Gmat, Gmat, evects)
3387 :
3388 47640 : END SUBROUTINE get_cardoso_angles
3389 :
3390 0 : END MODULE qs_localization_methods
|