(git:0a7030e)
Loading...
Searching...
No Matches
bse_util.F
Go to the documentation of this file.
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 Auxiliary routines for GW + Bethe-Salpeter for computing electronic excitations
10!> \par History
11!> 11.2023 created [Maximilian Graml]
12! **************************************************************************************************
15 USE cell_types, ONLY: cell_type
18 USE cp_dbcsr_api, ONLY: dbcsr_create,&
21 dbcsr_set,&
22 dbcsr_type_symmetric
34 USE cp_fm_types, ONLY: cp_fm_create,&
51 USE kinds, ONLY: default_path_length,&
52 dp,&
53 int_8
56 USE mo_window, ONLY: mo_window_type
63 USE physcon, ONLY: evolt
64 USE pw_env_types, ONLY: pw_env_get,&
67 USE pw_pool_types, ONLY: pw_pool_p_type,&
69 USE pw_types, ONLY: pw_c1d_gs_type,&
75 USE qs_mo_types, ONLY: get_mo_set,&
82 USE util, ONLY: sort,&
84#include "./base/base_uses.f90"
85
86 IMPLICIT NONE
87
88 PRIVATE
89
90 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'bse_util'
91
98
99CONTAINS
100
101! **************************************************************************************************
102!> \brief Multiplies B-matrix (RI-3c-Integrals) with W (screening) to obtain \bar{B}
103!> \param fm_mat_S_ij_bse ...
104!> \param fm_mat_S_ia_bse ...
105!> \param fm_mat_S_bar_ia_bse ...
106!> \param fm_mat_S_bar_ij_bse ...
107!> \param fm_mat_Q_static_bse_gemm ...
108!> \param dimen_RI ...
109!> \param homo ...
110!> \param virtual ...
111! **************************************************************************************************
112 SUBROUTINE mult_b_with_w(fm_mat_S_ij_bse, fm_mat_S_ia_bse, fm_mat_S_bar_ia_bse, &
113 fm_mat_S_bar_ij_bse, fm_mat_Q_static_bse_gemm, &
114 dimen_RI, homo, virtual)
115
116 TYPE(cp_fm_type), INTENT(IN) :: fm_mat_s_ij_bse, fm_mat_s_ia_bse
117 TYPE(cp_fm_type), INTENT(OUT) :: fm_mat_s_bar_ia_bse, fm_mat_s_bar_ij_bse
118 TYPE(cp_fm_type), INTENT(IN) :: fm_mat_q_static_bse_gemm
119 INTEGER, INTENT(IN) :: dimen_ri, homo, virtual
120
121 CHARACTER(LEN=*), PARAMETER :: routinen = 'mult_B_with_W'
122
123 INTEGER :: handle, i_global, iib, info_chol, &
124 j_global, jjb, ncol_local, nrow_local
125 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
126 TYPE(cp_fm_type) :: fm_work
127
128 CALL timeset(routinen, handle)
129
130 CALL cp_fm_create(fm_mat_s_bar_ia_bse, fm_mat_s_ia_bse%matrix_struct)
131 CALL cp_fm_set_all(fm_mat_s_bar_ia_bse, 0.0_dp)
132
133 CALL cp_fm_create(fm_mat_s_bar_ij_bse, fm_mat_s_ij_bse%matrix_struct)
134 CALL cp_fm_set_all(fm_mat_s_bar_ij_bse, 0.0_dp)
135
136 CALL cp_fm_create(fm_work, fm_mat_q_static_bse_gemm%matrix_struct)
137 CALL cp_fm_set_all(fm_work, 0.0_dp)
138
139 ! get info of fm_mat_Q_static_bse and compute ((1+Q(0))^-1-1)
140 CALL cp_fm_get_info(matrix=fm_mat_q_static_bse_gemm, &
141 nrow_local=nrow_local, &
142 ncol_local=ncol_local, &
143 row_indices=row_indices, &
144 col_indices=col_indices)
145
146 DO jjb = 1, ncol_local
147 j_global = col_indices(jjb)
148 DO iib = 1, nrow_local
149 i_global = row_indices(iib)
150 IF (j_global == i_global .AND. i_global <= dimen_ri) THEN
151 fm_mat_q_static_bse_gemm%local_data(iib, jjb) = fm_mat_q_static_bse_gemm%local_data(iib, jjb) + 1.0_dp
152 END IF
153 END DO
154 END DO
155
156 ! calculate Trace(Log(Matrix)) as Log(DET(Matrix)) via cholesky decomposition
157 CALL cp_fm_cholesky_decompose(matrix=fm_mat_q_static_bse_gemm, n=dimen_ri, info_out=info_chol)
158
159 IF (info_chol /= 0) THEN
160 CALL cp_abort(__location__, 'Cholesky decomposition failed for static polarization in BSE')
161 END IF
162
163 ! calculate [1+Q(i0)]^-1
164 CALL cp_fm_cholesky_invert(fm_mat_q_static_bse_gemm)
165
166 ! symmetrize the result
167 CALL cp_fm_uplo_to_full(fm_mat_q_static_bse_gemm, fm_work)
168
169 CALL parallel_gemm(transa="N", transb="N", m=dimen_ri, n=homo**2, k=dimen_ri, alpha=1.0_dp, &
170 matrix_a=fm_mat_q_static_bse_gemm, matrix_b=fm_mat_s_ij_bse, beta=0.0_dp, &
171 matrix_c=fm_mat_s_bar_ij_bse)
172
173 ! fm_mat_S_bar_ia_bse has a different blacs_env as fm_mat_S_ij_bse since we take
174 ! fm_mat_S_ia_bse from RPA. Therefore, we also need a different fm_mat_Q_static_bse_gemm
175 CALL parallel_gemm(transa="N", transb="N", m=dimen_ri, n=homo*virtual, k=dimen_ri, alpha=1.0_dp, &
176 matrix_a=fm_mat_q_static_bse_gemm, matrix_b=fm_mat_s_ia_bse, beta=0.0_dp, &
177 matrix_c=fm_mat_s_bar_ia_bse)
178
179 CALL cp_fm_release(fm_work)
180
181 CALL timestop(handle)
182
183 END SUBROUTINE mult_b_with_w
184
185! **************************************************************************************************
186!> \brief Adds and reorders full matrices with a combined index structure, e.g. adding W_ij,ab
187!> to A_ia, jb which needs MPI communication.
188!> \param fm_out ...
189!> \param fm_in ...
190!> \param beta ...
191!> \param nrow_secidx_in ...
192!> \param ncol_secidx_in ...
193!> \param nrow_secidx_out ...
194!> \param ncol_secidx_out ...
195!> \param unit_nr ...
196!> \param reordering ...
197!> \param mp2_env ...
198!> \param row_offset ...
199!> \param col_offset ...
200! **************************************************************************************************
201 SUBROUTINE fm_general_add_bse(fm_out, fm_in, beta, nrow_secidx_in, ncol_secidx_in, &
202 nrow_secidx_out, ncol_secidx_out, unit_nr, reordering, mp2_env, &
203 row_offset, col_offset)
204
205 TYPE(cp_fm_type), INTENT(INOUT) :: fm_out
206 TYPE(cp_fm_type), INTENT(IN) :: fm_in
207 REAL(kind=dp) :: beta
208 INTEGER, INTENT(IN) :: nrow_secidx_in, ncol_secidx_in, &
209 nrow_secidx_out, ncol_secidx_out
210 INTEGER :: unit_nr
211 INTEGER, DIMENSION(4) :: reordering
212 TYPE(mp2_type), INTENT(IN) :: mp2_env
213 INTEGER, INTENT(IN), OPTIONAL :: row_offset, col_offset
214
215 CHARACTER(LEN=*), PARAMETER :: routinen = 'fm_general_add_bse'
216
217 INTEGER :: col_idx_loc, dummy, handle, handle2, i_entry_rec, idx_col_out, idx_row_out, ii, &
218 iproc, jj, my_col_offset, my_row_offset, ncol_block_in, ncol_block_out, ncol_local_in, &
219 ncol_local_out, nprocs, nrow_block_in, nrow_block_out, nrow_local_in, nrow_local_out, &
220 proc_send, row_idx_loc, send_pcol, send_prow
221 INTEGER, ALLOCATABLE, DIMENSION(:) :: entry_counter, num_entries_rec, &
222 num_entries_send
223 INTEGER, DIMENSION(4) :: indices_in
224 INTEGER, DIMENSION(:), POINTER :: col_indices_in, col_indices_out, &
225 row_indices_in, row_indices_out
226 TYPE(integ_mat_buffer_type), ALLOCATABLE, &
227 DIMENSION(:) :: buffer_rec, buffer_send
228 TYPE(mp_para_env_type), POINTER :: para_env_out
229 TYPE(mp_request_type), DIMENSION(:, :), POINTER :: req_array
230
231! Offsets place the reshuffled block into a sub-block of fm_out (open-shell joint matrix);
232! both default 0, recovering the closed-shell single-block placement bit-identically.
233
234 my_row_offset = 0
235 my_col_offset = 0
236 IF (PRESENT(row_offset)) my_row_offset = row_offset
237 IF (PRESENT(col_offset)) my_col_offset = col_offset
238
239 CALL timeset(routinen, handle)
240 CALL timeset(routinen//"_1_setup", handle2)
241
242 para_env_out => fm_out%matrix_struct%para_env
243 ! A_iajb
244 ! We start by moving data from local parts of W_ijab to the full matrix A_iajb using buffers
245 CALL cp_fm_get_info(matrix=fm_out, &
246 nrow_local=nrow_local_out, &
247 ncol_local=ncol_local_out, &
248 row_indices=row_indices_out, &
249 col_indices=col_indices_out, &
250 nrow_block=nrow_block_out, &
251 ncol_block=ncol_block_out)
252
253 ALLOCATE (num_entries_rec(0:para_env_out%num_pe - 1))
254 ALLOCATE (num_entries_send(0:para_env_out%num_pe - 1))
255
256 num_entries_rec(:) = 0
257 num_entries_send(:) = 0
258
259 dummy = 0
260
261 CALL cp_fm_get_info(matrix=fm_in, &
262 nrow_local=nrow_local_in, &
263 ncol_local=ncol_local_in, &
264 row_indices=row_indices_in, &
265 col_indices=col_indices_in, &
266 nrow_block=nrow_block_in, &
267 ncol_block=ncol_block_in)
268
269 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
270 WRITE (unit_nr, '(T2,A10,T13,A14,A10,T71,I10)') 'BSE|DEBUG|', 'Row number of ', fm_out%name, &
271 fm_out%matrix_struct%nrow_global
272 WRITE (unit_nr, '(T2,A10,T13,A17,A10,T71,I10)') 'BSE|DEBUG|', 'Column number of ', fm_out%name, &
273 fm_out%matrix_struct%ncol_global
274
275 WRITE (unit_nr, '(T2,A10,T13,A18,A10,T71,I10)') 'BSE|DEBUG|', 'Row block size of ', fm_out%name, nrow_block_out
276 WRITE (unit_nr, '(T2,A10,T13,A21,A10,T71,I10)') 'BSE|DEBUG|', 'Column block size of ', fm_out%name, ncol_block_out
277
278 WRITE (unit_nr, '(T2,A10,T13,A14,A10,T71,I10)') 'BSE|DEBUG|', 'Row number of ', fm_in%name, &
279 fm_in%matrix_struct%nrow_global
280 WRITE (unit_nr, '(T2,A10,T13,A17,A10,T71,I10)') 'BSE|DEBUG|', 'Column number of ', fm_in%name, &
281 fm_in%matrix_struct%ncol_global
282
283 WRITE (unit_nr, '(T2,A10,T13,A18,A10,T71,I10)') 'BSE|DEBUG|', 'Row block size of ', fm_in%name, nrow_block_in
284 WRITE (unit_nr, '(T2,A10,T13,A21,A10,T71,I10)') 'BSE|DEBUG|', 'Column block size of ', fm_in%name, ncol_block_in
285 END IF
286
287 ! Use scalapack wrapper to find process index in fm_out
288 ! To that end, we obtain the global index in fm_out from the level indices
289 indices_in(:) = 0
290 DO row_idx_loc = 1, nrow_local_in
291 indices_in(1) = (row_indices_in(row_idx_loc) - 1)/nrow_secidx_in + 1
292 indices_in(2) = mod(row_indices_in(row_idx_loc) - 1, nrow_secidx_in) + 1
293 DO col_idx_loc = 1, ncol_local_in
294 indices_in(3) = (col_indices_in(col_idx_loc) - 1)/ncol_secidx_in + 1
295 indices_in(4) = mod(col_indices_in(col_idx_loc) - 1, ncol_secidx_in) + 1
296
297 idx_row_out = my_row_offset + indices_in(reordering(2)) + (indices_in(reordering(1)) - 1)*nrow_secidx_out
298 idx_col_out = my_col_offset + indices_in(reordering(4)) + (indices_in(reordering(3)) - 1)*ncol_secidx_out
299
300 send_prow = fm_out%matrix_struct%g2p_row(idx_row_out)
301 send_pcol = fm_out%matrix_struct%g2p_col(idx_col_out)
302
303 proc_send = fm_out%matrix_struct%context%blacs2mpi(send_prow, send_pcol)
304
305 num_entries_send(proc_send) = num_entries_send(proc_send) + 1
306
307 END DO
308 END DO
309
310 CALL timestop(handle2)
311
312 CALL timeset(routinen//"_2_comm_entry_nums", handle2)
313 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
314 WRITE (unit_nr, '(T2,A10,T13,A27)') 'BSE|DEBUG|', 'Communicating entry numbers'
315 END IF
316
317 CALL para_env_out%alltoall(num_entries_send, num_entries_rec, 1)
318
319 CALL timestop(handle2)
320
321 CALL timeset(routinen//"_3_alloc_buffer", handle2)
322 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
323 WRITE (unit_nr, '(T2,A10,T13,A18)') 'BSE|DEBUG|', 'Allocating buffers'
324 END IF
325
326 ! Buffers for entries and their indices
327 ALLOCATE (buffer_rec(0:para_env_out%num_pe - 1))
328 ALLOCATE (buffer_send(0:para_env_out%num_pe - 1))
329
330 ! allocate data message and corresponding indices
331 DO iproc = 0, para_env_out%num_pe - 1
332
333 ALLOCATE (buffer_rec(iproc)%msg(num_entries_rec(iproc)))
334 buffer_rec(iproc)%msg = 0.0_dp
335
336 END DO
337
338 DO iproc = 0, para_env_out%num_pe - 1
339
340 ALLOCATE (buffer_send(iproc)%msg(num_entries_send(iproc)))
341 buffer_send(iproc)%msg = 0.0_dp
342
343 END DO
344
345 DO iproc = 0, para_env_out%num_pe - 1
346
347 ALLOCATE (buffer_rec(iproc)%indx(num_entries_rec(iproc), 2))
348 buffer_rec(iproc)%indx = 0
349
350 END DO
351
352 DO iproc = 0, para_env_out%num_pe - 1
353
354 ALLOCATE (buffer_send(iproc)%indx(num_entries_send(iproc), 2))
355 buffer_send(iproc)%indx = 0
356
357 END DO
358
359 CALL timestop(handle2)
360
361 CALL timeset(routinen//"_4_buf_from_fmin_"//fm_out%name, handle2)
362 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
363 WRITE (unit_nr, '(T2,A10,T13,A18,A10,A13)') 'BSE|DEBUG|', 'Writing data from ', fm_in%name, ' into buffers'
364 END IF
365
366 ALLOCATE (entry_counter(0:para_env_out%num_pe - 1))
367 entry_counter(:) = 0
368
369 ! Now we can write the actual data and indices to the send-buffer
370 DO row_idx_loc = 1, nrow_local_in
371 indices_in(1) = (row_indices_in(row_idx_loc) - 1)/nrow_secidx_in + 1
372 indices_in(2) = mod(row_indices_in(row_idx_loc) - 1, nrow_secidx_in) + 1
373 DO col_idx_loc = 1, ncol_local_in
374 indices_in(3) = (col_indices_in(col_idx_loc) - 1)/ncol_secidx_in + 1
375 indices_in(4) = mod(col_indices_in(col_idx_loc) - 1, ncol_secidx_in) + 1
376
377 idx_row_out = my_row_offset + indices_in(reordering(2)) + (indices_in(reordering(1)) - 1)*nrow_secidx_out
378 idx_col_out = my_col_offset + indices_in(reordering(4)) + (indices_in(reordering(3)) - 1)*ncol_secidx_out
379
380 send_prow = fm_out%matrix_struct%g2p_row(idx_row_out)
381 send_pcol = fm_out%matrix_struct%g2p_col(idx_col_out)
382
383 proc_send = fm_out%matrix_struct%context%blacs2mpi(send_prow, send_pcol)
384 entry_counter(proc_send) = entry_counter(proc_send) + 1
385
386 buffer_send(proc_send)%msg(entry_counter(proc_send)) = &
387 fm_in%local_data(row_idx_loc, col_idx_loc)
388
389 buffer_send(proc_send)%indx(entry_counter(proc_send), 1) = idx_row_out
390 buffer_send(proc_send)%indx(entry_counter(proc_send), 2) = idx_col_out
391
392 END DO
393 END DO
394
395 ALLOCATE (req_array(1:para_env_out%num_pe, 4))
396
397 CALL timestop(handle2)
398
399 CALL timeset(routinen//"_5_comm_buffer", handle2)
400 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
401 WRITE (unit_nr, '(T2,A10,T13,A21)') 'BSE|DEBUG|', 'Communicating buffers'
402 END IF
403
404 ! communicate the buffer
405 CALL communicate_buffer(para_env_out, num_entries_rec, num_entries_send, buffer_rec, &
406 buffer_send, req_array)
407
408 CALL timestop(handle2)
409
410 CALL timeset(routinen//"_6_buffer_to_fmout"//fm_out%name, handle2)
411 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
412 WRITE (unit_nr, '(T2,A10,T13,A24,A10)') 'BSE|DEBUG|', 'Writing from buffers to ', fm_out%name
413 END IF
414
415 ! fill fm_out with the entries from buffer_rec, i.e. buffer_rec are parts of fm_in
416 nprocs = para_env_out%num_pe
417
418!$OMP PARALLEL DO DEFAULT(NONE) &
419!$OMP SHARED(fm_out, nprocs, num_entries_rec, buffer_rec, beta) &
420!$OMP PRIVATE(iproc, i_entry_rec, ii, jj)
421 DO iproc = 0, nprocs - 1
422 DO i_entry_rec = 1, num_entries_rec(iproc)
423 ii = fm_out%matrix_struct%g2l_row(buffer_rec(iproc)%indx(i_entry_rec, 1))
424 jj = fm_out%matrix_struct%g2l_col(buffer_rec(iproc)%indx(i_entry_rec, 2))
425
426 fm_out%local_data(ii, jj) = fm_out%local_data(ii, jj) + beta*buffer_rec(iproc)%msg(i_entry_rec)
427 END DO
428 END DO
429!$OMP END PARALLEL DO
430
431 CALL timestop(handle2)
432
433 CALL timeset(routinen//"_7_cleanup", handle2)
434 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
435 WRITE (unit_nr, '(T2,A10,T13,A41)') 'BSE|DEBUG|', 'Starting cleanup of communication buffers'
436 END IF
437
438 !Clean up all the arrays from the communication process
439 DO iproc = 0, para_env_out%num_pe - 1
440 DEALLOCATE (buffer_rec(iproc)%msg)
441 DEALLOCATE (buffer_rec(iproc)%indx)
442 DEALLOCATE (buffer_send(iproc)%msg)
443 DEALLOCATE (buffer_send(iproc)%indx)
444 END DO
445 DEALLOCATE (buffer_rec, buffer_send)
446 DEALLOCATE (req_array)
447 DEALLOCATE (entry_counter)
448 DEALLOCATE (num_entries_rec, num_entries_send)
449
450 CALL timestop(handle2)
451 CALL timestop(handle)
452
453 END SUBROUTINE fm_general_add_bse
454
455! **************************************************************************************************
456!> \brief Routine for truncating a full matrix as given by the energy cutoffs in the input file.
457!> Logic: Matrices have some dimension dimen_RI x nrow_in*ncol_in for the incoming (untruncated) matrix
458!> and dimen_RI x nrow_out*ncol_out for the truncated matrix. The truncation is done by resorting the indices
459!> via parallel communication.
460!> \param fm_out ...
461!> \param fm_in ...
462!> \param ncol_in ...
463!> \param nrow_out ...
464!> \param ncol_out ...
465!> \param unit_nr ...
466!> \param mp2_env ...
467!> \param nrow_offset ...
468!> \param ncol_offset ...
469! **************************************************************************************************
470 SUBROUTINE truncate_fm(fm_out, fm_in, ncol_in, &
471 nrow_out, ncol_out, unit_nr, mp2_env, &
472 nrow_offset, ncol_offset)
473
474 TYPE(cp_fm_type), INTENT(INOUT) :: fm_out
475 TYPE(cp_fm_type), INTENT(IN) :: fm_in
476 INTEGER :: ncol_in, nrow_out, ncol_out, unit_nr
477 TYPE(mp2_type), INTENT(INOUT) :: mp2_env
478 INTEGER, INTENT(IN), OPTIONAL :: nrow_offset, ncol_offset
479
480 CHARACTER(LEN=*), PARAMETER :: routinen = 'truncate_fm'
481
482 INTEGER :: col_idx_loc, dummy, handle, handle2, i_entry_rec, idx_col_first, idx_col_in, &
483 idx_col_out, idx_col_sec, idx_row_in, ii, iproc, jj, ncol_block_in, ncol_block_out, &
484 ncol_local_in, ncol_local_out, nprocs, nrow_block_in, nrow_block_out, nrow_local_in, &
485 nrow_local_out, proc_send, row_idx_loc, send_pcol, send_prow
486 INTEGER, ALLOCATABLE, DIMENSION(:) :: entry_counter, num_entries_rec, &
487 num_entries_send
488 INTEGER, DIMENSION(:), POINTER :: col_indices_in, col_indices_out, &
489 row_indices_in, row_indices_out
490 LOGICAL :: correct_ncol, correct_nrow
491 TYPE(integ_mat_buffer_type), ALLOCATABLE, &
492 DIMENSION(:) :: buffer_rec, buffer_send
493 TYPE(mp_para_env_type), POINTER :: para_env_out
494 TYPE(mp_request_type), DIMENSION(:, :), POINTER :: req_array
495
496 CALL timeset(routinen, handle)
497 CALL timeset(routinen//"_1_setup", handle2)
498
499 correct_nrow = .false.
500 correct_ncol = .false.
501 !In case of truncation in the occupied space, we need to correct the interval of indices
502 IF (PRESENT(nrow_offset)) THEN
503 correct_nrow = .true.
504 END IF
505 IF (PRESENT(ncol_offset)) THEN
506 correct_ncol = .true.
507 END IF
508
509 para_env_out => fm_out%matrix_struct%para_env
510
511 CALL cp_fm_get_info(matrix=fm_out, &
512 nrow_local=nrow_local_out, &
513 ncol_local=ncol_local_out, &
514 row_indices=row_indices_out, &
515 col_indices=col_indices_out, &
516 nrow_block=nrow_block_out, &
517 ncol_block=ncol_block_out)
518
519 ALLOCATE (num_entries_rec(0:para_env_out%num_pe - 1))
520 ALLOCATE (num_entries_send(0:para_env_out%num_pe - 1))
521
522 num_entries_rec(:) = 0
523 num_entries_send(:) = 0
524
525 dummy = 0
526
527 CALL cp_fm_get_info(matrix=fm_in, &
528 nrow_local=nrow_local_in, &
529 ncol_local=ncol_local_in, &
530 row_indices=row_indices_in, &
531 col_indices=col_indices_in, &
532 nrow_block=nrow_block_in, &
533 ncol_block=ncol_block_in)
534
535 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
536 WRITE (unit_nr, '(T2,A10,T13,A14,A10,T71,I10)') 'BSE|DEBUG|', 'Row number of ', fm_out%name, &
537 fm_out%matrix_struct%nrow_global
538 WRITE (unit_nr, '(T2,A10,T13,A17,A10,T71,I10)') 'BSE|DEBUG|', 'Column number of ', fm_out%name, &
539 fm_out%matrix_struct%ncol_global
540
541 WRITE (unit_nr, '(T2,A10,T13,A18,A10,T71,I10)') 'BSE|DEBUG|', 'Row block size of ', fm_out%name, nrow_block_out
542 WRITE (unit_nr, '(T2,A10,T13,A21,A10,T71,I10)') 'BSE|DEBUG|', 'Column block size of ', fm_out%name, ncol_block_out
543
544 WRITE (unit_nr, '(T2,A10,T13,A14,A10,T71,I10)') 'BSE|DEBUG|', 'Row number of ', fm_in%name, &
545 fm_in%matrix_struct%nrow_global
546 WRITE (unit_nr, '(T2,A10,T13,A17,A10,T71,I10)') 'BSE|DEBUG|', 'Column number of ', fm_in%name, &
547 fm_in%matrix_struct%ncol_global
548
549 WRITE (unit_nr, '(T2,A10,T13,A18,A10,T71,I10)') 'BSE|DEBUG|', 'Row block size of ', fm_in%name, nrow_block_in
550 WRITE (unit_nr, '(T2,A10,T13,A21,A10,T71,I10)') 'BSE|DEBUG|', 'Column block size of ', fm_in%name, ncol_block_in
551 END IF
552
553 ! We find global indices in S with nrow_in and ncol_in for truncation
554 DO col_idx_loc = 1, ncol_local_in
555 idx_col_in = col_indices_in(col_idx_loc)
556
557 idx_col_first = (idx_col_in - 1)/ncol_in + 1
558 idx_col_sec = mod(idx_col_in - 1, ncol_in) + 1
559
560 ! If occupied orbitals are included, these have to be handled differently
561 ! due to their reversed indexing
562 IF (correct_nrow) THEN
563 idx_col_first = idx_col_first - nrow_offset + 1
564 IF (idx_col_first <= 0) cycle
565 ELSE
566 IF (idx_col_first > nrow_out) EXIT
567 END IF
568 IF (correct_ncol) THEN
569 idx_col_sec = idx_col_sec - ncol_offset + 1
570 IF (idx_col_sec <= 0) cycle
571 ELSE
572 IF (idx_col_sec > ncol_out) cycle
573 END IF
574
575 idx_col_out = idx_col_sec + (idx_col_first - 1)*ncol_out
576
577 DO row_idx_loc = 1, nrow_local_in
578 idx_row_in = row_indices_in(row_idx_loc)
579
580 send_prow = fm_out%matrix_struct%g2p_row(idx_row_in)
581 send_pcol = fm_out%matrix_struct%g2p_col(idx_col_out)
582
583 proc_send = fm_out%matrix_struct%context%blacs2mpi(send_prow, send_pcol)
584
585 num_entries_send(proc_send) = num_entries_send(proc_send) + 1
586
587 END DO
588 END DO
589
590 CALL timestop(handle2)
591
592 CALL timeset(routinen//"_2_comm_entry_nums", handle2)
593 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
594 WRITE (unit_nr, '(T2,A10,T13,A27)') 'BSE|DEBUG|', 'Communicating entry numbers'
595 END IF
596
597 CALL para_env_out%alltoall(num_entries_send, num_entries_rec, 1)
598
599 CALL timestop(handle2)
600
601 CALL timeset(routinen//"_3_alloc_buffer", handle2)
602 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
603 WRITE (unit_nr, '(T2,A10,T13,A18)') 'BSE|DEBUG|', 'Allocating buffers'
604 END IF
605
606 ! Buffers for entries and their indices
607 ALLOCATE (buffer_rec(0:para_env_out%num_pe - 1))
608 ALLOCATE (buffer_send(0:para_env_out%num_pe - 1))
609
610 ! allocate data message and corresponding indices
611 DO iproc = 0, para_env_out%num_pe - 1
612
613 ALLOCATE (buffer_rec(iproc)%msg(num_entries_rec(iproc)))
614 buffer_rec(iproc)%msg = 0.0_dp
615
616 END DO
617
618 DO iproc = 0, para_env_out%num_pe - 1
619
620 ALLOCATE (buffer_send(iproc)%msg(num_entries_send(iproc)))
621 buffer_send(iproc)%msg = 0.0_dp
622
623 END DO
624
625 DO iproc = 0, para_env_out%num_pe - 1
626
627 ALLOCATE (buffer_rec(iproc)%indx(num_entries_rec(iproc), 2))
628 buffer_rec(iproc)%indx = 0
629
630 END DO
631
632 DO iproc = 0, para_env_out%num_pe - 1
633
634 ALLOCATE (buffer_send(iproc)%indx(num_entries_send(iproc), 2))
635 buffer_send(iproc)%indx = 0
636
637 END DO
638
639 CALL timestop(handle2)
640
641 CALL timeset(routinen//"_4_buf_from_fmin_"//fm_out%name, handle2)
642 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
643 WRITE (unit_nr, '(T2,A10,T13,A18,A10,A13)') 'BSE|DEBUG|', 'Writing data from ', fm_in%name, ' into buffers'
644 END IF
645
646 ALLOCATE (entry_counter(0:para_env_out%num_pe - 1))
647 entry_counter(:) = 0
648
649 ! Now we can write the actual data and indices to the send-buffer
650 DO col_idx_loc = 1, ncol_local_in
651 idx_col_in = col_indices_in(col_idx_loc)
652
653 idx_col_first = (idx_col_in - 1)/ncol_in + 1
654 idx_col_sec = mod(idx_col_in - 1, ncol_in) + 1
655
656 ! If occupied orbitals are included, these have to be handled differently
657 ! due to their reversed indexing
658 IF (correct_nrow) THEN
659 idx_col_first = idx_col_first - nrow_offset + 1
660 IF (idx_col_first <= 0) cycle
661 ELSE
662 IF (idx_col_first > nrow_out) EXIT
663 END IF
664 IF (correct_ncol) THEN
665 idx_col_sec = idx_col_sec - ncol_offset + 1
666 IF (idx_col_sec <= 0) cycle
667 ELSE
668 IF (idx_col_sec > ncol_out) cycle
669 END IF
670
671 idx_col_out = idx_col_sec + (idx_col_first - 1)*ncol_out
672
673 DO row_idx_loc = 1, nrow_local_in
674 idx_row_in = row_indices_in(row_idx_loc)
675
676 send_prow = fm_out%matrix_struct%g2p_row(idx_row_in)
677
678 send_pcol = fm_out%matrix_struct%g2p_col(idx_col_out)
679
680 proc_send = fm_out%matrix_struct%context%blacs2mpi(send_prow, send_pcol)
681 entry_counter(proc_send) = entry_counter(proc_send) + 1
682
683 buffer_send(proc_send)%msg(entry_counter(proc_send)) = &
684 fm_in%local_data(row_idx_loc, col_idx_loc)
685 !No need to create row_out, since it is identical to incoming
686 !We dont change the RI index for any fm_mat_XX_BSE
687 buffer_send(proc_send)%indx(entry_counter(proc_send), 1) = idx_row_in
688 buffer_send(proc_send)%indx(entry_counter(proc_send), 2) = idx_col_out
689
690 END DO
691 END DO
692
693 ALLOCATE (req_array(1:para_env_out%num_pe, 4))
694
695 CALL timestop(handle2)
696
697 CALL timeset(routinen//"_5_comm_buffer", handle2)
698 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
699 WRITE (unit_nr, '(T2,A10,T13,A21)') 'BSE|DEBUG|', 'Communicating buffers'
700 END IF
701
702 ! communicate the buffer
703 CALL communicate_buffer(para_env_out, num_entries_rec, num_entries_send, buffer_rec, &
704 buffer_send, req_array)
705
706 CALL timestop(handle2)
707
708 CALL timeset(routinen//"_6_buffer_to_fmout"//fm_out%name, handle2)
709 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
710 WRITE (unit_nr, '(T2,A10,T13,A24,A10)') 'BSE|DEBUG|', 'Writing from buffers to ', fm_out%name
711 END IF
712
713 ! fill fm_out with the entries from buffer_rec, i.e. buffer_rec are parts of fm_in
714 nprocs = para_env_out%num_pe
715
716!$OMP PARALLEL DO DEFAULT(NONE) &
717!$OMP SHARED(fm_out, nprocs, num_entries_rec, buffer_rec) &
718!$OMP PRIVATE(iproc, i_entry_rec, ii, jj)
719 DO iproc = 0, nprocs - 1
720 DO i_entry_rec = 1, num_entries_rec(iproc)
721 ii = fm_out%matrix_struct%g2l_row(buffer_rec(iproc)%indx(i_entry_rec, 1))
722 jj = fm_out%matrix_struct%g2l_col(buffer_rec(iproc)%indx(i_entry_rec, 2))
723
724 fm_out%local_data(ii, jj) = fm_out%local_data(ii, jj) + buffer_rec(iproc)%msg(i_entry_rec)
725 END DO
726 END DO
727!$OMP END PARALLEL DO
728
729 CALL timestop(handle2)
730
731 CALL timeset(routinen//"_7_cleanup", handle2)
732 IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
733 WRITE (unit_nr, '(T2,A10,T13,A41)') 'BSE|DEBUG|', 'Starting cleanup of communication buffers'
734 END IF
735
736 !Clean up all the arrays from the communication process
737 DO iproc = 0, para_env_out%num_pe - 1
738 DEALLOCATE (buffer_rec(iproc)%msg)
739 DEALLOCATE (buffer_rec(iproc)%indx)
740 DEALLOCATE (buffer_send(iproc)%msg)
741 DEALLOCATE (buffer_send(iproc)%indx)
742 END DO
743 DEALLOCATE (buffer_rec, buffer_send)
744 DEALLOCATE (req_array)
745 DEALLOCATE (entry_counter)
746 DEALLOCATE (num_entries_rec, num_entries_send)
747
748 CALL timestop(handle2)
749 CALL timestop(handle)
750
751 END SUBROUTINE truncate_fm
752
753! **************************************************************************************************
754!> \brief ...
755!> \param fm_mat_S_bar_ia_bse ...
756!> \param fm_mat_S_bar_ij_bse ...
757!> \param fm_mat_S_trunc ...
758!> \param fm_mat_S_ij_trunc ...
759!> \param fm_mat_S_ab_trunc ...
760!> \param fm_mat_Q_static_bse_gemm ...
761!> \param mp2_env ...
762! **************************************************************************************************
763 SUBROUTINE deallocate_matrices_bse(fm_mat_S_bar_ia_bse, fm_mat_S_bar_ij_bse, &
764 fm_mat_S_trunc, fm_mat_S_ij_trunc, fm_mat_S_ab_trunc, &
765 fm_mat_Q_static_bse_gemm, mp2_env)
766
767 TYPE(cp_fm_type), INTENT(INOUT) :: fm_mat_s_bar_ia_bse, fm_mat_s_bar_ij_bse, fm_mat_s_trunc, &
768 fm_mat_s_ij_trunc, fm_mat_s_ab_trunc, fm_mat_q_static_bse_gemm
769 TYPE(mp2_type) :: mp2_env
770
771 CHARACTER(LEN=*), PARAMETER :: routinen = 'deallocate_matrices_bse'
772
773 INTEGER :: handle
774
775 CALL timeset(routinen, handle)
776
777 CALL cp_fm_release(fm_mat_s_bar_ia_bse)
778 CALL cp_fm_release(fm_mat_s_bar_ij_bse)
779 CALL cp_fm_release(fm_mat_s_trunc)
780 CALL cp_fm_release(fm_mat_s_ij_trunc)
781 CALL cp_fm_release(fm_mat_s_ab_trunc)
782 CALL cp_fm_release(fm_mat_q_static_bse_gemm)
783 IF (mp2_env%bse%do_nto_analysis) THEN
784 DEALLOCATE (mp2_env%bse%bse_nto_state_list_final)
785 END IF
786
787 CALL timestop(handle)
788
789 END SUBROUTINE deallocate_matrices_bse
790
791! **************************************************************************************************
792!> \brief Routine for computing the coefficients of the eigenvectors of the BSE matrix from a
793!> multiplication with the eigenvalues
794!> \param fm_work ...
795!> \param eig_vals ...
796!> \param beta ...
797!> \param gamma ...
798!> \param do_transpose ...
799! **************************************************************************************************
800 SUBROUTINE comp_eigvec_coeff_bse(fm_work, eig_vals, beta, gamma, do_transpose)
801
802 TYPE(cp_fm_type), INTENT(INOUT) :: fm_work
803 REAL(kind=dp), ALLOCATABLE, DIMENSION(:), &
804 INTENT(IN) :: eig_vals
805 REAL(kind=dp), INTENT(IN) :: beta
806 REAL(kind=dp), INTENT(IN), OPTIONAL :: gamma
807 LOGICAL, INTENT(IN), OPTIONAL :: do_transpose
808
809 CHARACTER(LEN=*), PARAMETER :: routinen = 'comp_eigvec_coeff_BSE'
810
811 INTEGER :: handle, i_row_global, ii, j_col_global, &
812 jj, ncol_local, nrow_local
813 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
814 LOGICAL :: my_do_transpose
815 REAL(kind=dp) :: coeff, my_gamma
816
817 CALL timeset(routinen, handle)
818
819 IF (PRESENT(gamma)) THEN
820 my_gamma = gamma
821 ELSE
822 my_gamma = 2.0_dp
823 END IF
824
825 IF (PRESENT(do_transpose)) THEN
826 my_do_transpose = do_transpose
827 ELSE
828 my_do_transpose = .false.
829 END IF
830
831 CALL cp_fm_get_info(matrix=fm_work, &
832 nrow_local=nrow_local, &
833 ncol_local=ncol_local, &
834 row_indices=row_indices, &
835 col_indices=col_indices)
836
837 IF (my_do_transpose) THEN
838 DO jj = 1, ncol_local
839 j_col_global = col_indices(jj)
840 DO ii = 1, nrow_local
841 coeff = (eig_vals(j_col_global)**beta)/my_gamma
842 fm_work%local_data(ii, jj) = fm_work%local_data(ii, jj)*coeff
843 END DO
844 END DO
845 ELSE
846 DO jj = 1, ncol_local
847 DO ii = 1, nrow_local
848 i_row_global = row_indices(ii)
849 coeff = (eig_vals(i_row_global)**beta)/my_gamma
850 fm_work%local_data(ii, jj) = fm_work%local_data(ii, jj)*coeff
851 END DO
852 END DO
853 END IF
854
855 CALL timestop(handle)
856
857 END SUBROUTINE comp_eigvec_coeff_bse
858
859! **************************************************************************************************
860!> \brief Sorts excitation entries by ascending primary index, reordering the secondary index,
861!> the eigenvector coefficients and - open shell - the spin index alongside
862!> \param idx_prim Primary index of each entry; sorted in place and used as the sort key
863!> \param idx_sec Secondary index of each entry, reordered to follow idx_prim
864!> \param eigvec_entries Eigenvector coefficients of each entry, reordered to follow idx_prim
865!> \param idx_spin Optional spin index of each entry (open shell), reordered to follow idx_prim
866! **************************************************************************************************
867 SUBROUTINE sort_excitations(idx_prim, idx_sec, eigvec_entries, idx_spin)
868
869 INTEGER, ALLOCATABLE, DIMENSION(:) :: idx_prim, idx_sec
870 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigvec_entries
871 INTEGER, ALLOCATABLE, DIMENSION(:), OPTIONAL :: idx_spin
872
873 CHARACTER(LEN=*), PARAMETER :: routinen = 'sort_excitations'
874
875 INTEGER :: handle, ii, kk, num_entries, num_mults
876 INTEGER, ALLOCATABLE, DIMENSION(:) :: idx_prim_work, idx_sec_work, &
877 idx_spin_work, tmp_index
878 LOGICAL :: unique_entries
879 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigvec_entries_work
880
881 CALL timeset(routinen, handle)
882
883 num_entries = SIZE(idx_prim)
884
885 ALLOCATE (tmp_index(num_entries))
886
887 CALL sort(idx_prim, num_entries, tmp_index)
888
889 ALLOCATE (idx_sec_work(num_entries))
890 ALLOCATE (eigvec_entries_work(num_entries))
891 IF (PRESENT(idx_spin)) ALLOCATE (idx_spin_work(num_entries))
892
893 DO ii = 1, num_entries
894 idx_sec_work(ii) = idx_sec(tmp_index(ii))
895 eigvec_entries_work(ii) = eigvec_entries(tmp_index(ii))
896 IF (PRESENT(idx_spin)) idx_spin_work(ii) = idx_spin(tmp_index(ii))
897 END DO
898
899 DEALLOCATE (tmp_index)
900 DEALLOCATE (idx_sec)
901 DEALLOCATE (eigvec_entries)
902
903 CALL move_alloc(idx_sec_work, idx_sec)
904 CALL move_alloc(eigvec_entries_work, eigvec_entries)
905 IF (PRESENT(idx_spin)) THEN
906 DEALLOCATE (idx_spin)
907 CALL move_alloc(idx_spin_work, idx_spin)
908 END IF
909
910 !Now check for multiple entries in first idx to check necessity of sorting in second idx
911 CALL sort_unique(idx_prim, unique_entries)
912 IF (.NOT. unique_entries) THEN
913 ALLOCATE (idx_prim_work(num_entries))
914 idx_prim_work(:) = idx_prim(:)
915 ! Find duplicate entries in idx_prim
916 DO ii = 1, num_entries
917 IF (idx_prim_work(ii) == 0) cycle
918 num_mults = count(idx_prim_work == idx_prim_work(ii))
919 IF (num_mults > 1) THEN
920 !Set all duplicate entries to 0
921 idx_prim_work(ii:ii + num_mults - 1) = 0
922 !Start sorting in secondary index
923 ALLOCATE (idx_sec_work(num_mults))
924 ALLOCATE (eigvec_entries_work(num_mults))
925 idx_sec_work(:) = idx_sec(ii:ii + num_mults - 1)
926 eigvec_entries_work(:) = eigvec_entries(ii:ii + num_mults - 1)
927 IF (PRESENT(idx_spin)) THEN
928 ALLOCATE (idx_spin_work(num_mults))
929 idx_spin_work(:) = idx_spin(ii:ii + num_mults - 1)
930 END IF
931 ALLOCATE (tmp_index(num_mults))
932 CALL sort(idx_sec_work, num_mults, tmp_index)
933
934 !Now write newly sorted indices to original arrays
935 DO kk = ii, ii + num_mults - 1
936 idx_sec(kk) = idx_sec_work(kk - ii + 1)
937 eigvec_entries(kk) = eigvec_entries_work(tmp_index(kk - ii + 1))
938 IF (PRESENT(idx_spin)) idx_spin(kk) = idx_spin_work(tmp_index(kk - ii + 1))
939 END DO
940 !Deallocate work arrays
941 DEALLOCATE (tmp_index)
942 DEALLOCATE (idx_sec_work)
943 DEALLOCATE (eigvec_entries_work)
944 IF (PRESENT(idx_spin)) DEALLOCATE (idx_spin_work)
945 END IF
946 idx_prim_work(ii) = idx_prim(ii)
947 END DO
948 DEALLOCATE (idx_prim_work)
949 END IF
950
951 CALL timestop(handle)
952
953 END SUBROUTINE sort_excitations
954
955! **************************************************************************************************
956!> \brief Roughly estimates the needed runtime and memory during the BSE run
957!> \param n_ov_joint ...
958!> \param unit_nr ...
959!> \param bse_abba ...
960!> \param para_env ...
961!> \param diag_runtime_est ...
962! **************************************************************************************************
963 SUBROUTINE estimate_bse_resources(n_ov_joint, unit_nr, bse_abba, &
964 para_env, diag_runtime_est)
965
966 INTEGER, INTENT(IN) :: n_ov_joint, unit_nr
967 LOGICAL :: bse_abba
968 TYPE(mp_para_env_type), POINTER :: para_env
969 REAL(kind=dp) :: diag_runtime_est
970
971 CHARACTER(LEN=*), PARAMETER :: routinen = 'estimate_BSE_resources'
972
973 INTEGER :: handle, num_bse_matrices
974 INTEGER(KIND=int_8) :: full_dim
975 REAL(kind=dp) :: mem_est, mem_est_per_rank
976
977 CALL timeset(routinen, handle)
978
979 ! Number of matrices with size of A in TDA is 2 (A itself and W_ijab)
980 num_bse_matrices = 2
981 ! With the full diagonalization of ABBA, we need several auxiliary matrices in the process
982 ! The maximum number is 2 + 2 + 6 (additional B and C matrix as well as 6 matrices to create C)
983 IF (bse_abba) THEN
984 num_bse_matrices = 10
985 END IF
986
987 full_dim = int(n_ov_joint, kind=int_8)**2*int(num_bse_matrices, kind=int_8)
988 mem_est = real(8*full_dim, kind=dp)/real(1024**3, kind=dp)
989 mem_est_per_rank = real(mem_est/para_env%num_pe, kind=dp)
990
991 IF (unit_nr > 0) THEN
992 ! WRITE (unit_nr, '(T2,A4,T7,A40,T68,F13.3)') 'BSE|', 'Total peak memory estimate from BSE [GB]', &
993 ! mem_est
994 WRITE (unit_nr, '(T2,A4,T7,A40,T68,ES13.3)') 'BSE|', 'Total peak memory estimate from BSE [GB]', &
995 mem_est
996 WRITE (unit_nr, '(T2,A4,T7,A47,T68,F13.3)') 'BSE|', 'Peak memory estimate per MPI rank from BSE [GB]', &
997 mem_est_per_rank
998 WRITE (unit_nr, '(T2,A4)') 'BSE|'
999 END IF
1000 ! Rough estimation of diagonalization runtimes. Baseline was a full BSE Naphthalene
1001 ! run with 11000x11000 entries in A/B/C, which took 10s on 32 ranks
1002 diag_runtime_est = real(int(n_ov_joint, kind=int_8)/11000_int_8, kind=dp)**3* &
1003 10*32/real(para_env%num_pe, kind=dp)
1004
1005 CALL timestop(handle)
1006
1007 END SUBROUTINE estimate_bse_resources
1008
1009! **************************************************************************************************
1010!> \brief Filters eigenvector entries above a given threshold to describe excitations in the
1011!> singleparticle basis
1012!> \param fm_eigvec ...
1013!> \param idx_homo ...
1014!> \param idx_virt ...
1015!> \param eigvec_entries ...
1016!> \param i_exc ...
1017!> \param virtual ...
1018!> \param num_entries ...
1019!> \param mp2_env ...
1020!> \param offsets ...
1021!> \param virtual_per_spin ...
1022!> \param idx_spin ...
1023! **************************************************************************************************
1024 SUBROUTINE filter_eigvec_contrib(fm_eigvec, idx_homo, idx_virt, eigvec_entries, &
1025 i_exc, virtual, num_entries, mp2_env, &
1026 offsets, virtual_per_spin, idx_spin)
1027
1028 TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec
1029 INTEGER, ALLOCATABLE, DIMENSION(:) :: idx_homo, idx_virt
1030 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigvec_entries
1031 INTEGER :: i_exc, virtual, num_entries
1032 TYPE(mp2_type), INTENT(INOUT) :: mp2_env
1033 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: offsets, virtual_per_spin
1034 INTEGER, ALLOCATABLE, DIMENSION(:), OPTIONAL :: idx_spin
1035
1036 CHARACTER(LEN=*), PARAMETER :: routinen = 'filter_eigvec_contrib'
1037
1038 INTEGER :: eigvec_idx, handle, ii, iproc, isp, jj, &
1039 kk, ksp, ncol_local, nrow_local, &
1040 num_entries_local, r_local, v_local
1041 INTEGER, ALLOCATABLE, DIMENSION(:) :: num_entries_to_comm
1042 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
1043 REAL(kind=dp) :: eigvec_entry
1044 TYPE(integ_mat_buffer_type), ALLOCATABLE, &
1045 DIMENSION(:) :: buffer_entries
1046 TYPE(mp_para_env_type), POINTER :: para_env
1047
1048 CALL timeset(routinen, handle)
1049
1050 para_env => fm_eigvec%matrix_struct%para_env
1051
1052 CALL cp_fm_get_info(matrix=fm_eigvec, &
1053 nrow_local=nrow_local, &
1054 ncol_local=ncol_local, &
1055 row_indices=row_indices, &
1056 col_indices=col_indices)
1057
1058 ALLOCATE (num_entries_to_comm(0:para_env%num_pe - 1))
1059 num_entries_to_comm(:) = 0
1060
1061 DO jj = 1, ncol_local
1062 !First check if i is localized on this proc
1063 IF (col_indices(jj) /= i_exc) THEN
1064 cycle
1065 END IF
1066 DO ii = 1, nrow_local
1067 eigvec_idx = row_indices(ii)
1068 eigvec_entry = fm_eigvec%local_data(ii, jj)
1069 IF (abs(eigvec_entry) > mp2_env%bse%eps_x) THEN
1070 num_entries_to_comm(para_env%mepos) = num_entries_to_comm(para_env%mepos) + 1
1071 END IF
1072 END DO
1073 END DO
1074
1075 !Gather number of entries of other processes
1076 CALL para_env%sum(num_entries_to_comm)
1077
1078 num_entries_local = num_entries_to_comm(para_env%mepos)
1079
1080 ALLOCATE (buffer_entries(0:para_env%num_pe - 1))
1081
1082 DO iproc = 0, para_env%num_pe - 1
1083 ALLOCATE (buffer_entries(iproc)%msg(num_entries_to_comm(iproc)))
1084 ALLOCATE (buffer_entries(iproc)%indx(num_entries_to_comm(iproc), 3))
1085 buffer_entries(iproc)%msg = 0.0_dp
1086 buffer_entries(iproc)%indx = 0
1087 END DO
1088
1089 kk = 1
1090 DO jj = 1, ncol_local
1091 !First check if i is localized on this proc
1092 IF (col_indices(jj) /= i_exc) THEN
1093 cycle
1094 END IF
1095 DO ii = 1, nrow_local
1096 eigvec_idx = row_indices(ii)
1097 eigvec_entry = fm_eigvec%local_data(ii, jj)
1098 IF (abs(eigvec_entry) > mp2_env%bse%eps_x) THEN
1099 ! Decode spin block from the joint row index (blocks are contiguous; sigma is the
1100 ! largest offset strictly below eigvec_idx). offsets absent -> closed shell, sigma=1.
1101 isp = 1
1102 r_local = eigvec_idx
1103 v_local = virtual
1104 IF (PRESENT(offsets)) THEN
1105 DO ksp = SIZE(offsets), 1, -1
1106 IF (eigvec_idx > offsets(ksp)) THEN
1107 isp = ksp
1108 EXIT
1109 END IF
1110 END DO
1111 r_local = eigvec_idx - offsets(isp)
1112 v_local = virtual_per_spin(isp)
1113 END IF
1114 buffer_entries(para_env%mepos)%indx(kk, 1) = (r_local - 1)/v_local + 1
1115 buffer_entries(para_env%mepos)%indx(kk, 2) = mod(r_local - 1, v_local) + 1
1116 buffer_entries(para_env%mepos)%indx(kk, 3) = isp
1117 buffer_entries(para_env%mepos)%msg(kk) = eigvec_entry
1118 kk = kk + 1
1119 END IF
1120 END DO
1121 END DO
1122
1123 DO iproc = 0, para_env%num_pe - 1
1124 CALL para_env%sum(buffer_entries(iproc)%msg)
1125 CALL para_env%sum(buffer_entries(iproc)%indx)
1126 END DO
1127
1128 !Now sum up gathered information
1129 num_entries = sum(num_entries_to_comm)
1130 ALLOCATE (idx_homo(num_entries))
1131 ALLOCATE (idx_virt(num_entries))
1132 ALLOCATE (eigvec_entries(num_entries))
1133 IF (PRESENT(idx_spin)) ALLOCATE (idx_spin(num_entries))
1134
1135 kk = 1
1136 DO iproc = 0, para_env%num_pe - 1
1137 IF (num_entries_to_comm(iproc) /= 0) THEN
1138 DO ii = 1, num_entries_to_comm(iproc)
1139 idx_homo(kk) = buffer_entries(iproc)%indx(ii, 1)
1140 idx_virt(kk) = buffer_entries(iproc)%indx(ii, 2)
1141 IF (PRESENT(idx_spin)) idx_spin(kk) = buffer_entries(iproc)%indx(ii, 3)
1142 eigvec_entries(kk) = buffer_entries(iproc)%msg(ii)
1143 kk = kk + 1
1144 END DO
1145 END IF
1146 END DO
1147
1148 !Deallocate all the used arrays
1149 DO iproc = 0, para_env%num_pe - 1
1150 DEALLOCATE (buffer_entries(iproc)%msg)
1151 DEALLOCATE (buffer_entries(iproc)%indx)
1152 END DO
1153 DEALLOCATE (buffer_entries)
1154 DEALLOCATE (num_entries_to_comm)
1155 NULLIFY (row_indices)
1156 NULLIFY (col_indices)
1157
1158 !Now sort the results according to the involved singleparticle orbitals
1159 ! (homo first, then virtual). idx_spin is payload, permuted alongside the entries.
1160 IF (PRESENT(idx_spin)) THEN
1161 CALL sort_excitations(idx_homo, idx_virt, eigvec_entries, idx_spin)
1162 ELSE
1163 CALL sort_excitations(idx_homo, idx_virt, eigvec_entries)
1164 END IF
1165
1166 CALL timestop(handle)
1167
1168 END SUBROUTINE filter_eigvec_contrib
1169
1170! **************************************************************************************************
1171!> \brief Spin-block layout for the open-shell (joint) BSE matrix: per-spin OV-pair counts and the
1172!> block offsets into the joint matrix of dimension n_ov_joint = sum_sigma homo*virtual.
1173!> \param homo_red per-spin (reduced) number of occupied levels
1174!> \param virt_red per-spin (reduced) number of virtual levels
1175!> \param n_ov per-spin OV-pair count (OUT)
1176!> \param offsets per-spin block offset into the joint matrix (OUT)
1177!> \param n_ov_joint total joint dimension (OUT)
1178! **************************************************************************************************
1179 SUBROUTINE get_bse_spin_block_layout(homo_red, virt_red, n_ov, offsets, n_ov_joint)
1180 INTEGER, DIMENSION(:), INTENT(IN) :: homo_red, virt_red
1181 INTEGER, DIMENSION(:), INTENT(OUT) :: n_ov, offsets
1182 INTEGER, INTENT(OUT) :: n_ov_joint
1183
1184 INTEGER :: isp
1185
1186 n_ov_joint = 0
1187 DO isp = 1, SIZE(homo_red)
1188 offsets(isp) = n_ov_joint
1189 n_ov(isp) = homo_red(isp)*virt_red(isp)
1190 n_ov_joint = n_ov_joint + n_ov(isp)
1191 END DO
1192
1193 END SUBROUTINE get_bse_spin_block_layout
1194
1195! **************************************************************************************************
1196!> \brief Determines indices within the given energy cutoffs and truncates Eigenvalues and matrices
1197!> \param fm_mat_S_ia_bse ...
1198!> \param fm_mat_S_ij_bse ...
1199!> \param fm_mat_S_ab_bse ...
1200!> \param fm_mat_S_trunc ...
1201!> \param fm_mat_S_ij_trunc ...
1202!> \param fm_mat_S_ab_trunc ...
1203!> \param Eigenval_scf ...
1204!> \param Eigenval ...
1205!> \param Eigenval_reduced ...
1206!> \param homo ...
1207!> \param virtual ...
1208!> \param dimen_RI ...
1209!> \param unit_nr ...
1210!> \param bse_lev_virt ...
1211!> \param homo_red ...
1212!> \param virt_red ...
1213!> \param mp2_env ...
1214!> \param window Absolute MO window to retain.
1215!> \param print_window Whether to print the cutoff summary.
1216! **************************************************************************************************
1217 SUBROUTINE truncate_bse_matrices(fm_mat_S_ia_bse, fm_mat_S_ij_bse, fm_mat_S_ab_bse, &
1218 fm_mat_S_trunc, fm_mat_S_ij_trunc, fm_mat_S_ab_trunc, &
1219 Eigenval_scf, Eigenval, Eigenval_reduced, &
1220 homo, virtual, dimen_RI, unit_nr, &
1221 bse_lev_virt, &
1222 homo_red, virt_red, &
1223 mp2_env, &
1224 window, print_window)
1225
1226 TYPE(cp_fm_type), INTENT(IN) :: fm_mat_s_ia_bse, fm_mat_s_ij_bse, &
1227 fm_mat_s_ab_bse
1228 TYPE(cp_fm_type), INTENT(INOUT) :: fm_mat_s_trunc, fm_mat_s_ij_trunc, &
1229 fm_mat_s_ab_trunc
1230 REAL(kind=dp), DIMENSION(:) :: eigenval_scf, eigenval
1231 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: eigenval_reduced
1232 INTEGER, INTENT(IN) :: homo, virtual, dimen_ri, unit_nr, &
1233 bse_lev_virt
1234 INTEGER, INTENT(OUT) :: homo_red, virt_red
1235 TYPE(mp2_type), INTENT(INOUT) :: mp2_env
1236 TYPE(mo_window_type), INTENT(IN) :: window
1237 LOGICAL, INTENT(IN) :: print_window
1238
1239 CHARACTER(LEN=*), PARAMETER :: routinen = 'truncate_BSE_matrices'
1240
1241 INTEGER :: handle, homo_incl, virt_incl
1242 TYPE(cp_blacs_env_type), POINTER :: context
1243 TYPE(cp_fm_struct_type), POINTER :: fm_struct_ab, fm_struct_ia, fm_struct_ij
1244 TYPE(mp_para_env_type), POINTER :: para_env
1245
1246 CALL timeset(routinen, handle)
1247
1248 homo_incl = window%first_mo
1249 virt_incl = window%last_mo - homo
1250 homo_red = homo - homo_incl + 1
1251 virt_red = virt_incl
1252
1253 IF (print_window .AND. unit_nr > 0) THEN
1254 IF (mp2_env%bse%bse_cutoff_occ > 0) THEN
1255 WRITE (unit_nr, '(T2,A4,T7,A29,T71,F10.3)') 'BSE|', 'Cutoff occupied orbitals [eV]', &
1256 mp2_env%bse%bse_cutoff_occ*evolt
1257 ELSE
1258 WRITE (unit_nr, '(T2,A4,T7,A37)') 'BSE|', 'No cutoff given for occupied orbitals'
1259 END IF
1260 IF (mp2_env%bse%bse_cutoff_empty > 0) THEN
1261 WRITE (unit_nr, '(T2,A4,T7,A26,T71,F10.3)') 'BSE|', 'Cutoff empty orbitals [eV]', &
1262 mp2_env%bse%bse_cutoff_empty*evolt
1263 ELSE
1264 WRITE (unit_nr, '(T2,A4,T7,A34)') 'BSE|', 'No cutoff given for empty orbitals'
1265 END IF
1266 WRITE (unit_nr, '(T2,A4,T7,A20,T71,I10)') 'BSE|', 'First occupied index', homo_incl
1267 WRITE (unit_nr, '(T2,A4,T7,A32,T71,I10)') 'BSE|', 'Last empty index (not MO index!)', virt_incl
1268 WRITE (unit_nr, '(T2,A4,T7,A35,T71,F10.3)') 'BSE|', 'Energy of first occupied index [eV]', &
1269 eigenval(homo_incl)*evolt
1270 WRITE (unit_nr, '(T2,A4,T7,A31,T71,F10.3)') 'BSE|', 'Energy of last empty index [eV]', &
1271 eigenval(homo + virt_incl)*evolt
1272 WRITE (unit_nr, '(T2,A4,T7,A54,T71,F10.3)') 'BSE|', &
1273 'Energy difference of first occupied index to HOMO [eV]', &
1274 -(eigenval(homo_incl) - eigenval(homo))*evolt
1275 WRITE (unit_nr, '(T2,A4,T7,A50,T71,F10.3)') 'BSE|', &
1276 'Energy difference of last empty index to LUMO [eV]', &
1277 (eigenval(homo + virt_incl) - eigenval(homo + 1))*evolt
1278 WRITE (unit_nr, '(T2,A4,T7,A35,T71,I10)') 'BSE|', 'Number of GW-corrected occupied MOs', &
1279 mp2_env%ri_g0w0%corr_mos_occ
1280 WRITE (unit_nr, '(T2,A4,T7,A32,T71,I10)') 'BSE|', 'Number of GW-corrected empty MOs', &
1281 bse_lev_virt
1282 WRITE (unit_nr, '(T2,A4)') 'BSE|'
1283 END IF
1284 IF (unit_nr > 0) THEN
1285 IF (homo - homo_incl + 1 > mp2_env%ri_g0w0%corr_mos_occ) THEN
1286 cpabort("Number of GW-corrected occupied MOs too small for chosen BSE cutoff")
1287 END IF
1288 IF (virt_incl > bse_lev_virt) THEN
1289 cpabort("Number of GW-corrected virtual MOs too small for chosen BSE cutoff")
1290 END IF
1291 END IF
1292 !Truncate full fm_S matrices
1293 !Allocate new truncated matrices of proper size
1294 para_env => fm_mat_s_ia_bse%matrix_struct%para_env
1295 context => fm_mat_s_ia_bse%matrix_struct%context
1296
1297 CALL cp_fm_struct_create(fm_struct_ia, para_env, context, dimen_ri, homo_red*virt_red)
1298 CALL cp_fm_struct_create(fm_struct_ij, para_env, context, dimen_ri, homo_red*homo_red)
1299 CALL cp_fm_struct_create(fm_struct_ab, para_env, context, dimen_ri, virt_red*virt_red)
1300
1301 CALL cp_fm_create(fm_mat_s_trunc, fm_struct_ia, name="fm_S_trunc", set_zero=.true.)
1302 CALL cp_fm_create(fm_mat_s_ij_trunc, fm_struct_ij, name="fm_S_ij_trunc", set_zero=.true.)
1303 CALL cp_fm_create(fm_mat_s_ab_trunc, fm_struct_ab, name="fm_S_ab_trunc", set_zero=.true.)
1304
1305 !Copy parts of original matrices to truncated ones
1306 IF (mp2_env%bse%bse_cutoff_occ > 0 .OR. mp2_env%bse%bse_cutoff_empty > 0) THEN
1307 !Truncate eigenvals
1308 ALLOCATE (eigenval_reduced(homo_red + virt_red))
1309 ! Include USE_KS_ENERGIES input
1310 IF (mp2_env%bse%use_ks_energies) THEN
1311 eigenval_reduced(:) = eigenval_scf(homo_incl:homo + virt_incl)
1312 ELSE
1313 eigenval_reduced(:) = eigenval(homo_incl:homo + virt_incl)
1314 END IF
1315
1316 CALL truncate_fm(fm_mat_s_trunc, fm_mat_s_ia_bse, virtual, &
1317 homo_red, virt_red, unit_nr, mp2_env, &
1318 nrow_offset=homo_incl)
1319 CALL truncate_fm(fm_mat_s_ij_trunc, fm_mat_s_ij_bse, homo, &
1320 homo_red, homo_red, unit_nr, mp2_env, &
1321 homo_incl, homo_incl)
1322 CALL truncate_fm(fm_mat_s_ab_trunc, fm_mat_s_ab_bse, bse_lev_virt, &
1323 virt_red, virt_red, unit_nr, mp2_env)
1324
1325 ELSE
1326 IF (unit_nr > 0) THEN
1327 WRITE (unit_nr, '(T2,A4,T7,A37)') 'BSE|', 'No truncation of BSE matrices applied'
1328 WRITE (unit_nr, '(T2,A4)') 'BSE|'
1329 END IF
1330 ALLOCATE (eigenval_reduced(homo_red + virt_red))
1331 ! Include USE_KS_ENERGIES input
1332 IF (mp2_env%bse%use_ks_energies) THEN
1333 eigenval_reduced(:) = eigenval_scf(:)
1334 ELSE
1335 eigenval_reduced(:) = eigenval(:)
1336 END IF
1337 CALL cp_fm_to_fm_submat_general(fm_mat_s_ia_bse, fm_mat_s_trunc, dimen_ri, homo_red*virt_red, &
1338 1, 1, 1, 1, context)
1339 CALL cp_fm_to_fm_submat_general(fm_mat_s_ij_bse, fm_mat_s_ij_trunc, dimen_ri, homo_red*homo_red, &
1340 1, 1, 1, 1, context)
1341 CALL cp_fm_to_fm_submat_general(fm_mat_s_ab_bse, fm_mat_s_ab_trunc, dimen_ri, virt_red*virt_red, &
1342 1, 1, 1, 1, context)
1343 END IF
1344
1345 CALL cp_fm_struct_release(fm_struct_ia)
1346 CALL cp_fm_struct_release(fm_struct_ij)
1347 CALL cp_fm_struct_release(fm_struct_ab)
1348
1349 NULLIFY (para_env)
1350 NULLIFY (context)
1351
1352 CALL timestop(handle)
1353
1354 END SUBROUTINE truncate_bse_matrices
1355
1356! **************************************************************************************************
1357!> \brief ...
1358!> \param fm_eigvec ...
1359!> \param fm_eigvec_reshuffled ...
1360!> \param homo ...
1361!> \param virtual ...
1362!> \param n_exc ...
1363!> \param do_transpose ...
1364!> \param unit_nr ...
1365!> \param mp2_env ...
1366! **************************************************************************************************
1367 SUBROUTINE reshuffle_eigvec(fm_eigvec, fm_eigvec_reshuffled, homo, virtual, n_exc, do_transpose, &
1368 unit_nr, mp2_env)
1369
1370 TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec
1371 TYPE(cp_fm_type), INTENT(INOUT) :: fm_eigvec_reshuffled
1372 INTEGER, INTENT(IN) :: homo, virtual, n_exc
1373 LOGICAL, INTENT(IN) :: do_transpose
1374 INTEGER, INTENT(IN) :: unit_nr
1375 TYPE(mp2_type), INTENT(INOUT) :: mp2_env
1376
1377 CHARACTER(LEN=*), PARAMETER :: routinen = 'reshuffle_eigvec'
1378
1379 INTEGER :: handle, my_m_col, my_n_row
1380 INTEGER, DIMENSION(4) :: reordering
1381 TYPE(cp_fm_struct_type), POINTER :: fm_struct_eigvec_col, &
1382 fm_struct_eigvec_reshuffled
1383 TYPE(cp_fm_type) :: fm_eigvec_col
1384
1385 CALL timeset(routinen, handle)
1386
1387 ! Define reordering:
1388 ! (ia,11) to (a1,i1) for transposition
1389 ! (ia,11) to (i1,a1) for default
1390 IF (do_transpose) THEN
1391 reordering = [2, 3, 1, 4]
1392 my_n_row = virtual
1393 my_m_col = homo
1394 ELSE
1395 reordering = [1, 3, 2, 4]
1396 my_n_row = homo
1397 my_m_col = virtual
1398 END IF
1399
1400 CALL cp_fm_struct_create(fm_struct_eigvec_col, &
1401 fm_eigvec%matrix_struct%para_env, fm_eigvec%matrix_struct%context, &
1402 homo*virtual, 1)
1403 CALL cp_fm_struct_create(fm_struct_eigvec_reshuffled, &
1404 fm_eigvec%matrix_struct%para_env, fm_eigvec%matrix_struct%context, &
1405 my_n_row, my_m_col)
1406
1407 ! Resort indices
1408 CALL cp_fm_create(fm_eigvec_col, fm_struct_eigvec_col, name="BSE_column_vector")
1409 CALL cp_fm_set_all(fm_eigvec_col, 0.0_dp)
1410 CALL cp_fm_create(fm_eigvec_reshuffled, fm_struct_eigvec_reshuffled, name="BSE_reshuffled_eigenvector")
1411 CALL cp_fm_set_all(fm_eigvec_reshuffled, 0.0_dp)
1412 ! Fill matrix
1413 CALL cp_fm_to_fm_submat(fm_eigvec, fm_eigvec_col, &
1414 homo*virtual, 1, &
1415 1, n_exc, &
1416 1, 1)
1417 ! Reshuffle
1418 CALL fm_general_add_bse(fm_eigvec_reshuffled, fm_eigvec_col, 1.0_dp, &
1419 virtual, 1, &
1420 1, 1, &
1421 unit_nr, reordering, mp2_env)
1422
1423 CALL cp_fm_release(fm_eigvec_col)
1424 CALL cp_fm_struct_release(fm_struct_eigvec_col)
1425 CALL cp_fm_struct_release(fm_struct_eigvec_reshuffled)
1426
1427 CALL timestop(handle)
1428
1429 END SUBROUTINE reshuffle_eigvec
1430
1431! **************************************************************************************************
1432!> \brief Borrowed from the tddfpt module with slight adaptions
1433!> \param qs_env ...
1434!> \param mos ...
1435!> \param istate ...
1436!> \param info_approximation ...
1437!> \param stride ...
1438!> \param append_cube ...
1439!> \param print_section ...
1440! **************************************************************************************************
1441 SUBROUTINE print_bse_nto_cubes(qs_env, mos, istate, info_approximation, &
1442 stride, append_cube, print_section)
1443
1444 TYPE(qs_environment_type), POINTER :: qs_env
1445 TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mos
1446 INTEGER, INTENT(IN) :: istate
1447 CHARACTER(LEN=10) :: info_approximation
1448 INTEGER, DIMENSION(:), POINTER :: stride
1449 LOGICAL, INTENT(IN) :: append_cube
1450 TYPE(section_vals_type), POINTER :: print_section
1451
1452 CHARACTER(LEN=*), PARAMETER :: routinen = 'print_bse_nto_cubes'
1453
1454 CHARACTER(LEN=default_path_length) :: filename, info_approx_trunc, &
1455 my_pos_cube, title
1456 INTEGER :: handle, i, iset, nmo, unit_nr_cube
1457 LOGICAL :: mpi_io
1458 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
1459 TYPE(cell_type), POINTER :: cell
1460 TYPE(cp_fm_type), POINTER :: mo_coeff
1461 TYPE(cp_logger_type), POINTER :: logger
1462 TYPE(dft_control_type), POINTER :: dft_control
1463 TYPE(particle_list_type), POINTER :: particles
1464 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1465 TYPE(pw_c1d_gs_type) :: wf_g
1466 TYPE(pw_env_type), POINTER :: pw_env
1467 TYPE(pw_pool_p_type), DIMENSION(:), POINTER :: pw_pools
1468 TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
1469 TYPE(pw_r3d_rs_type) :: wf_r
1470 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1471 TYPE(qs_subsys_type), POINTER :: subsys
1472
1473 logger => cp_get_default_logger()
1474 CALL timeset(routinen, handle)
1475
1476 CALL get_qs_env(qs_env=qs_env, dft_control=dft_control, pw_env=pw_env)
1477 CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, pw_pools=pw_pools)
1478 CALL auxbas_pw_pool%create_pw(wf_r)
1479 CALL auxbas_pw_pool%create_pw(wf_g)
1480
1481 CALL get_qs_env(qs_env, subsys=subsys)
1482 CALL qs_subsys_get(subsys, particles=particles)
1483
1484 my_pos_cube = "REWIND"
1485 IF (append_cube) THEN
1486 my_pos_cube = "APPEND"
1487 END IF
1488
1489 CALL get_qs_env(qs_env=qs_env, &
1490 atomic_kind_set=atomic_kind_set, &
1491 qs_kind_set=qs_kind_set, &
1492 cell=cell, &
1493 particle_set=particle_set)
1494
1495 DO iset = 1, 2
1496 CALL get_mo_set(mo_set=mos(iset), mo_coeff=mo_coeff, nmo=nmo)
1497 DO i = 1, nmo
1498 CALL calculate_wavefunction(mo_coeff, i, wf_r, wf_g, atomic_kind_set, qs_kind_set, &
1499 cell, dft_control, particle_set, pw_env)
1500 IF (iset == 1) THEN
1501 WRITE (filename, '(A6,I3.3,A5,I2.2,a11)') "_NEXC_", istate, "_NTO_", i, "_Hole_State"
1502 ELSE IF (iset == 2) THEN
1503 WRITE (filename, '(A6,I3.3,A5,I2.2,a15)') "_NEXC_", istate, "_NTO_", i, "_Particle_State"
1504 END IF
1505 info_approx_trunc = trim(adjustl(info_approximation))
1506 info_approx_trunc = info_approx_trunc(2:len_trim(info_approx_trunc) - 1)
1507 filename = trim(info_approx_trunc)//trim(filename)
1508 mpi_io = .true.
1509 unit_nr_cube = cp_print_key_unit_nr(logger, print_section, '', extension=".cube", &
1510 middle_name=trim(filename), file_position=my_pos_cube, &
1511 log_filename=.false., ignore_should_output=.true., mpi_io=mpi_io)
1512 IF (iset == 1) THEN
1513 WRITE (title, *) "Natural Transition Orbital Hole State", i
1514 ELSE IF (iset == 2) THEN
1515 WRITE (title, *) "Natural Transition Orbital Particle State", i
1516 END IF
1517 CALL cp_pw_to_cube(wf_r, unit_nr_cube, title, particles=particles, stride=stride, mpi_io=mpi_io)
1518 CALL cp_print_key_finished_output(unit_nr_cube, logger, print_section, '', &
1519 ignore_should_output=.true., mpi_io=mpi_io)
1520 END DO
1521 END DO
1522
1523 CALL auxbas_pw_pool%give_back_pw(wf_g)
1524 CALL auxbas_pw_pool%give_back_pw(wf_r)
1525
1526 CALL timestop(handle)
1527 END SUBROUTINE print_bse_nto_cubes
1528
1529! **************************************************************************************************
1530!> \brief Checks BSE input section and adapts them if necessary
1531!> \param homo ...
1532!> \param virtual ...
1533!> \param unit_nr ...
1534!> \param mp2_env ...
1535!> \param qs_env ...
1536! **************************************************************************************************
1537 SUBROUTINE adapt_bse_input_params(homo, virtual, unit_nr, mp2_env, qs_env)
1538
1539 INTEGER, INTENT(IN) :: homo, virtual, unit_nr
1540 TYPE(mp2_type) :: mp2_env
1541 TYPE(qs_environment_type), POINTER :: qs_env
1542
1543 CHARACTER(LEN=*), PARAMETER :: routinen = 'adapt_BSE_input_params'
1544
1545 INTEGER :: handle, i, j, n, ndim_periodic_cell, &
1546 ndim_periodic_poisson, &
1547 num_state_list_exceptions
1548 TYPE(cell_type), POINTER :: cell_ref
1549 TYPE(pw_env_type), POINTER :: pw_env
1550 TYPE(pw_poisson_type), POINTER :: poisson_env
1551
1552 CALL timeset(routinen, handle)
1553 ! Get environment infos for later usage
1554 NULLIFY (pw_env, cell_ref, poisson_env)
1555 CALL get_qs_env(qs_env, pw_env=pw_env, cell_ref=cell_ref)
1556 CALL pw_env_get(pw_env, poisson_env=poisson_env)
1557 ndim_periodic_poisson = count(poisson_env%parameters%periodic == 1)
1558 ndim_periodic_cell = sum(cell_ref%perd(1:3)) ! Borrowed from cell_methods.F/write_cell_low
1559
1560 ! Handle negative NUM_PRINT_EXC
1561 IF (mp2_env%bse%num_print_exc < 0 .OR. &
1562 mp2_env%bse%num_print_exc > homo*virtual) THEN
1563 mp2_env%bse%num_print_exc = homo*virtual
1564 IF (unit_nr > 0) THEN
1565 CALL cp_hint(__location__, &
1566 "Keyword NUM_PRINT_EXC is either negative or too large. "// &
1567 "Printing all computed excitations.")
1568 END IF
1569 END IF
1570
1571 ! Default to NUM_PRINT_EXC if too large or negative,
1572 ! but only if NTOs are called - would be confusing for the user otherwise
1573 ! Prepare and adapt user inputs for NTO analysis
1574 ! Logic: Explicit state list overrides NUM_PRINT_EXC_NTOS
1575 ! If only NUM_PRINT_EXC_NTOS is given, we write the array 1,...,NUM_PRINT_EXC_NTOS to
1576 ! bse_nto_state_list
1577 IF (mp2_env%bse%do_nto_analysis) THEN
1578 IF (mp2_env%bse%explicit_nto_list) THEN
1579 IF (mp2_env%bse%num_print_exc_ntos > 0) THEN
1580 IF (unit_nr > 0) THEN
1581 CALL cp_hint(__location__, &
1582 "Keywords NUM_PRINT_EXC_NTOS and STATE_LIST are both given in input. "// &
1583 "Overriding NUM_PRINT_EXC_NTOS.")
1584 END IF
1585 END IF
1586 ! Check if all states are within the range
1587 ! Count them and initialize new array afterwards
1588 num_state_list_exceptions = 0
1589 DO i = 1, SIZE(mp2_env%bse%bse_nto_state_list)
1590 IF (mp2_env%bse%bse_nto_state_list(i) < 1 .OR. &
1591 mp2_env%bse%bse_nto_state_list(i) > mp2_env%bse%num_print_exc) THEN
1592 num_state_list_exceptions = num_state_list_exceptions + 1
1593 END IF
1594 END DO
1595 IF (num_state_list_exceptions > 0) THEN
1596 IF (unit_nr > 0) THEN
1597 CALL cp_hint(__location__, &
1598 "STATE_LIST contains indices outside the range of included excitation levels. "// &
1599 "Ignoring these states.")
1600 END IF
1601 END IF
1602 n = SIZE(mp2_env%bse%bse_nto_state_list) - num_state_list_exceptions
1603 ALLOCATE (mp2_env%bse%bse_nto_state_list_final(n))
1604 mp2_env%bse%bse_nto_state_list_final(:) = 0
1605 i = 1
1606 DO j = 1, SIZE(mp2_env%bse%bse_nto_state_list)
1607 IF (mp2_env%bse%bse_nto_state_list(j) >= 1 .AND. &
1608 mp2_env%bse%bse_nto_state_list(j) <= mp2_env%bse%num_print_exc) THEN
1609 mp2_env%bse%bse_nto_state_list_final(i) = mp2_env%bse%bse_nto_state_list(j)
1610 i = i + 1
1611 END IF
1612 END DO
1613
1614 mp2_env%bse%num_print_exc_ntos = SIZE(mp2_env%bse%bse_nto_state_list_final)
1615 ELSE
1616 IF (mp2_env%bse%num_print_exc_ntos > mp2_env%bse%num_print_exc .OR. &
1617 mp2_env%bse%num_print_exc_ntos < 0) THEN
1618 mp2_env%bse%num_print_exc_ntos = mp2_env%bse%num_print_exc
1619 END IF
1620 ALLOCATE (mp2_env%bse%bse_nto_state_list_final(mp2_env%bse%num_print_exc_ntos))
1621 DO i = 1, mp2_env%bse%num_print_exc_ntos
1622 mp2_env%bse%bse_nto_state_list_final(i) = i
1623 END DO
1624 END IF
1625 END IF
1626
1627 ! Takes care of triplet states, when oscillator strengths are 0
1628 IF (mp2_env%bse%bse_spin_config /= 0 .AND. &
1629 mp2_env%bse%eps_nto_osc_str > 0) THEN
1630 IF (unit_nr > 0) THEN
1631 CALL cp_warn(__location__, &
1632 "Cannot apply EPS_OSC_STR for Triplet excitations. "// &
1633 "Resetting EPS_OSC_STR to default.")
1634 END IF
1635 mp2_env%bse%eps_nto_osc_str = -1.0_dp
1636 END IF
1637
1638 ! Take care of number for computed exciton descriptors
1639 IF (mp2_env%bse%num_print_exc_descr < 0 .OR. &
1640 mp2_env%bse%num_print_exc_descr > mp2_env%bse%num_print_exc) THEN
1641 IF (unit_nr > 0) THEN
1642 CALL cp_hint(__location__, &
1643 "Keyword NUM_PRINT_EXC_DESCR is either negative or too large. "// &
1644 "Printing exciton descriptors up to NUM_PRINT_EXC.")
1645 END IF
1646 mp2_env%bse%num_print_exc_descr = mp2_env%bse%num_print_exc
1647 END IF
1648
1649 ! Handle screening factor options
1650 IF (mp2_env%BSE%screening_factor > 0.0_dp) THEN
1651 IF (mp2_env%BSE%screening_method /= bse_screening_alpha) THEN
1652 IF (unit_nr > 0) THEN
1653 CALL cp_warn(__location__, &
1654 "Screening factor is only supported for &SCREENING_IN_W ALPHA. "// &
1655 "Resetting SCREENING_IN_W to ALPHA.")
1656 END IF
1657 mp2_env%BSE%screening_method = bse_screening_alpha
1658 END IF
1659 IF (mp2_env%BSE%screening_factor > 1.0_dp) THEN
1660 IF (unit_nr > 0) THEN
1661 CALL cp_warn(__location__, &
1662 "Screening factor is larger than 1.0. ")
1663 END IF
1664 END IF
1665 END IF
1666
1667 IF (mp2_env%BSE%screening_factor < 0.0_dp .AND. &
1668 mp2_env%BSE%screening_method == bse_screening_alpha) THEN
1669 IF (unit_nr > 0) THEN
1670 CALL cp_warn(__location__, &
1671 "Screening factor is negative. Defaulting to 0.25")
1672 END IF
1673 mp2_env%BSE%screening_factor = 0.25_dp
1674 END IF
1675
1676 IF (mp2_env%BSE%screening_factor == 0.0_dp) THEN
1677 ! Use RPA internally in this case
1678 mp2_env%BSE%screening_method = bse_screening_rpa
1679 END IF
1680 IF (mp2_env%BSE%screening_factor == 1.0_dp) THEN
1681 ! Use TDHF internally in this case
1682 mp2_env%BSE%screening_method = bse_screening_tdhf
1683 END IF
1684
1685 ! Add warning for usage of KS energies
1686 IF (mp2_env%bse%use_ks_energies) THEN
1687 IF (unit_nr > 0) THEN
1688 CALL cp_warn(__location__, &
1689 "Using KS energies for BSE calculations. Therefore, no quantities "// &
1690 "of the preceeding GW calculation enter the BSE.")
1691 END IF
1692 END IF
1693
1694 ! Add warning if periodic calculation is invoked
1695 IF (ndim_periodic_poisson /= 0) THEN
1696 IF (unit_nr > 0) THEN
1697 CALL cp_warn(__location__, &
1698 "Poisson solver should be invoked by PERIODIC NONE. "// &
1699 "The applied length gauge might give misleading results for "// &
1700 "oscillator strengths.")
1701 END IF
1702 END IF
1703 IF (ndim_periodic_cell /= 0) THEN
1704 IF (unit_nr > 0) THEN
1705 CALL cp_warn(__location__, &
1706 "CELL in SUBSYS should be invoked with PERIODIC NONE. "// &
1707 "The applied length gauge might give misleading results for "// &
1708 "oscillator strengths.")
1709 END IF
1710 END IF
1711
1712 CALL timestop(handle)
1713 END SUBROUTINE adapt_bse_input_params
1714
1715! **************************************************************************************************
1716
1717! **************************************************************************************************
1718!> \brief ...
1719!> \param fm_multipole_ai_trunc ...
1720!> \param fm_multipole_ij_trunc ...
1721!> \param fm_multipole_ab_trunc ...
1722!> \param qs_env ...
1723!> \param mo_coeff ...
1724!> \param rpoint ...
1725!> \param n_moments ...
1726!> \param homo_red ...
1727!> \param virtual_red ...
1728!> \param context_BSE ...
1729!> \param ispin spin channel whose mo_set supplies homo/nao (default 1); open-shell beta needs 2
1730! **************************************************************************************************
1731 SUBROUTINE get_multipoles_mo(fm_multipole_ai_trunc, fm_multipole_ij_trunc, fm_multipole_ab_trunc, &
1732 qs_env, mo_coeff, rpoint, n_moments, &
1733 homo_red, virtual_red, context_BSE, ispin)
1734
1735 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:), &
1736 INTENT(INOUT) :: fm_multipole_ai_trunc, &
1737 fm_multipole_ij_trunc, &
1738 fm_multipole_ab_trunc
1739 TYPE(qs_environment_type), POINTER :: qs_env
1740 TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: mo_coeff
1741 REAL(dp), ALLOCATABLE, DIMENSION(:), INTENT(INOUT) :: rpoint
1742 INTEGER, INTENT(IN) :: n_moments, homo_red, virtual_red
1743 TYPE(cp_blacs_env_type), POINTER :: context_bse
1744 INTEGER, INTENT(IN), OPTIONAL :: ispin
1745
1746 CHARACTER(LEN=*), PARAMETER :: routinen = 'get_multipoles_mo'
1747
1748 INTEGER :: handle, idir, my_ispin, n_multipole, &
1749 n_occ, n_virt, nao, nmo_mp2
1750 REAL(kind=dp), DIMENSION(:), POINTER :: ref_point
1751 TYPE(cp_fm_struct_type), POINTER :: fm_struct_mp_ab_trunc, fm_struct_mp_ai_trunc, &
1752 fm_struct_mp_ij_trunc, fm_struct_multipoles_ao, fm_struct_nao_nmo, fm_struct_nmo_nmo
1753 TYPE(cp_fm_type) :: fm_work
1754 TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_multipole_per_dir
1755 TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_multipole, matrix_s
1756 TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
1757 TYPE(mp_para_env_type), POINTER :: para_env_bse
1758 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1759 POINTER :: sab_orb
1760
1761 CALL timeset(routinen, handle)
1762
1763 my_ispin = 1
1764 IF (PRESENT(ispin)) my_ispin = ispin
1765
1766 !First, we calculate the AO dipoles
1767 NULLIFY (sab_orb, matrix_s)
1768 CALL get_qs_env(qs_env, &
1769 mos=mos, &
1770 matrix_s=matrix_s, &
1771 sab_orb=sab_orb)
1772
1773 ! Use the same blacs environment as for the MO coefficients to ensure correct multiplication dbcsr x fm later on
1774 fm_struct_multipoles_ao => mos(my_ispin)%mo_coeff%matrix_struct
1775 ! BSE has different contexts and blacsenvs
1776 para_env_bse => context_bse%para_env
1777 ! Get size of multipole tensor
1778 n_multipole = (6 + 11*n_moments + 6*n_moments**2 + n_moments**3)/6 - 1
1779 NULLIFY (matrix_multipole)
1780 CALL dbcsr_allocate_matrix_set(matrix_multipole, n_multipole)
1781 ALLOCATE (fm_multipole_per_dir(n_multipole))
1782 DO idir = 1, n_multipole
1783 CALL dbcsr_init_p(matrix_multipole(idir)%matrix)
1784 CALL dbcsr_create(matrix_multipole(idir)%matrix, name="ao_multipole", &
1785 template=matrix_s(1)%matrix, matrix_type=dbcsr_type_symmetric)
1786 CALL cp_dbcsr_alloc_block_from_nbl(matrix_multipole(idir)%matrix, sab_orb)
1787 CALL dbcsr_set(matrix_multipole(idir)%matrix, 0._dp)
1788 END DO
1789
1790 CALL get_reference_point(rpoint, qs_env=qs_env, reference=use_mom_ref_coac, ref_point=ref_point)
1791
1792 CALL build_local_moment_matrix(qs_env, matrix_multipole, n_moments, ref_point=rpoint)
1793
1794 NULLIFY (sab_orb)
1795
1796 ! Now we transform them to MO
1797 ! n_occ is the number of occupied MOs, nao the number of all AOs
1798 ! Writing homo to n_occ instead if nmo,
1799 ! takes care of ADDED_MOS, which would overwrite nmo of qs_env-mos, if invoked
1800 CALL get_mo_set(mo_set=mos(my_ispin), homo=n_occ, nao=nao)
1801 ! Takes into account removed nullspace values from SVD
1802 nmo_mp2 = mo_coeff(1)%matrix_struct%ncol_global
1803 n_virt = nmo_mp2 - n_occ
1804
1805 ! At the end, we need four different layouts of matrices in this multiplication, e.g. for a dipole:
1806 ! D_pq = full multipole matrix for occupied and unoccupied
1807 ! Final result:D_pq= C_{mu p} <\mu|\vec{r}|\nu> C_{\nu q} EQ.I
1808 ! \_______/ \___________/ \______/
1809 ! fm_coeff matrix_multipole fm_coeff
1810 ! (EQ.Ia) (EQ.Ib) (EQ.Ia)
1811 ! Intermediate work matrices:
1812 ! fm_work = <\mu|\vec{r}|\nu> C_{\nu q} EQ.II
1813
1814 ! Struct for the full multipole matrix
1815 CALL cp_fm_struct_create(fm_struct_nao_nmo, &
1816 fm_struct_multipoles_ao%para_env, fm_struct_multipoles_ao%context, &
1817 nao, nmo_mp2)
1818 CALL cp_fm_struct_create(fm_struct_nmo_nmo, &
1819 fm_struct_multipoles_ao%para_env, fm_struct_multipoles_ao%context, &
1820 nmo_mp2, nmo_mp2)
1821
1822 ! At the very end, we copy the multipoles corresponding to truncated BSE indices in i and a
1823 CALL cp_fm_struct_create(fm_struct_mp_ai_trunc, para_env_bse, &
1824 context_bse, virtual_red, homo_red)
1825 CALL cp_fm_struct_create(fm_struct_mp_ij_trunc, para_env_bse, &
1826 context_bse, homo_red, homo_red)
1827 CALL cp_fm_struct_create(fm_struct_mp_ab_trunc, para_env_bse, &
1828 context_bse, virtual_red, virtual_red)
1829 DO idir = 1, n_multipole
1830 CALL cp_fm_create(fm_multipole_ai_trunc(idir), matrix_struct=fm_struct_mp_ai_trunc, &
1831 name="dipoles_mo_ai_trunc")
1832 CALL cp_fm_set_all(fm_multipole_ai_trunc(idir), 0.0_dp)
1833 CALL cp_fm_create(fm_multipole_ij_trunc(idir), matrix_struct=fm_struct_mp_ij_trunc, &
1834 name="dipoles_mo_ij_trunc")
1835 CALL cp_fm_set_all(fm_multipole_ij_trunc(idir), 0.0_dp)
1836 CALL cp_fm_create(fm_multipole_ab_trunc(idir), matrix_struct=fm_struct_mp_ab_trunc, &
1837 name="dipoles_mo_ab_trunc")
1838 CALL cp_fm_set_all(fm_multipole_ab_trunc(idir), 0.0_dp)
1839 END DO
1840
1841 ! Need another temporary matrix to store intermediate result from right multiplication
1842 ! D = C_{mu a} <\mu|\vec{r}|\nu> C_{\nu i}
1843 CALL cp_fm_create(fm_work, matrix_struct=fm_struct_nao_nmo, name="multipole_work")
1844 CALL cp_fm_set_all(fm_work, 0.0_dp)
1845
1846 DO idir = 1, n_multipole
1847 ! Create the full multipole matrix per direction
1848 CALL cp_fm_create(fm_multipole_per_dir(idir), matrix_struct=fm_struct_nmo_nmo, name="multipoles_mo")
1849 CALL cp_fm_set_all(fm_multipole_per_dir(idir), 0.0_dp)
1850 ! Fill final (MO) multipole matrix
1851 CALL cp_dbcsr_sm_fm_multiply(matrix_multipole(idir)%matrix, mo_coeff(1), &
1852 fm_work, ncol=nmo_mp2)
1853 ! Now obtain the multipoles by the final multiplication;
1854 ! We do that inside the loop to obtain multipoles per axis for print
1855 CALL parallel_gemm('T', 'N', nmo_mp2, nmo_mp2, nao, 1.0_dp, mo_coeff(1), fm_work, 0.0_dp, fm_multipole_per_dir(idir))
1856
1857 ! Truncate full matrix to the BSE indices
1858 ! D_ai
1859 CALL cp_fm_to_fm_submat_general(fm_multipole_per_dir(idir), &
1860 fm_multipole_ai_trunc(idir), &
1861 virtual_red, &
1862 homo_red, &
1863 n_occ + 1, &
1864 n_occ - homo_red + 1, &
1865 1, &
1866 1, &
1867 fm_multipole_per_dir(idir)%matrix_struct%context)
1868 ! D_ij
1869 CALL cp_fm_to_fm_submat_general(fm_multipole_per_dir(idir), &
1870 fm_multipole_ij_trunc(idir), &
1871 homo_red, &
1872 homo_red, &
1873 n_occ - homo_red + 1, &
1874 n_occ - homo_red + 1, &
1875 1, &
1876 1, &
1877 fm_multipole_per_dir(idir)%matrix_struct%context)
1878 ! D_ab
1879 CALL cp_fm_to_fm_submat_general(fm_multipole_per_dir(idir), &
1880 fm_multipole_ab_trunc(idir), &
1881 virtual_red, &
1882 virtual_red, &
1883 n_occ + 1, &
1884 n_occ + 1, &
1885 1, &
1886 1, &
1887 fm_multipole_per_dir(idir)%matrix_struct%context)
1888 END DO
1889
1890 !Release matrices and structs
1891 NULLIFY (fm_struct_multipoles_ao)
1892 CALL cp_fm_struct_release(fm_struct_mp_ai_trunc)
1893 CALL cp_fm_struct_release(fm_struct_mp_ij_trunc)
1894 CALL cp_fm_struct_release(fm_struct_mp_ab_trunc)
1895 CALL cp_fm_struct_release(fm_struct_nao_nmo)
1896 CALL cp_fm_struct_release(fm_struct_nmo_nmo)
1897 DO idir = 1, n_multipole
1898 CALL cp_fm_release(fm_multipole_per_dir(idir))
1899 END DO
1900 DEALLOCATE (fm_multipole_per_dir)
1901 CALL cp_fm_release(fm_work)
1902 CALL dbcsr_deallocate_matrix_set(matrix_multipole)
1903
1904 CALL timestop(handle)
1905
1906 END SUBROUTINE get_multipoles_mo
1907
1908! **************************************************************************************************
1909!> \brief Computes trace of form Tr{A^T B C} for exciton descriptors
1910!> \param fm_A Full Matrix, typically X or Y, in format homo x virtual
1911!> \param fm_B ...
1912!> \param fm_C ...
1913!> \param alpha ...
1914! **************************************************************************************************
1915 SUBROUTINE trace_exciton_descr(fm_A, fm_B, fm_C, alpha)
1916
1917 TYPE(cp_fm_type), INTENT(IN) :: fm_a, fm_b, fm_c
1918 REAL(kind=dp), INTENT(OUT) :: alpha
1919
1920 CHARACTER(LEN=*), PARAMETER :: routinen = 'trace_exciton_descr'
1921
1922 INTEGER :: handle, ncol_a, ncol_b, ncol_c, nrow_a, &
1923 nrow_b, nrow_c
1924 TYPE(cp_fm_type) :: fm_work_ia
1925
1926 CALL timeset(routinen, handle)
1927
1928 CALL cp_fm_create(fm_work_ia, fm_a%matrix_struct)
1929 CALL cp_fm_get_info(fm_a, nrow_global=nrow_a, ncol_global=ncol_a)
1930 CALL cp_fm_get_info(fm_b, nrow_global=nrow_b, ncol_global=ncol_b)
1931 CALL cp_fm_get_info(fm_c, nrow_global=nrow_c, ncol_global=ncol_c)
1932
1933 ! Check matrix sizes
1934 cpassert(nrow_a == nrow_b .AND. ncol_a == ncol_c .AND. ncol_b == nrow_c)
1935
1936 CALL cp_fm_set_all(fm_work_ia, 0.0_dp)
1937
1938 CALL parallel_gemm("N", "N", nrow_a, ncol_a, nrow_c, 1.0_dp, &
1939 fm_b, fm_c, 0.0_dp, fm_work_ia)
1940
1941 CALL cp_fm_trace(fm_a, fm_work_ia, alpha)
1942
1943 CALL cp_fm_release(fm_work_ia)
1944
1945 CALL timestop(handle)
1946
1947 END SUBROUTINE trace_exciton_descr
1948
1949! **************************************************************************************************
1950!> \brief Column-concatenate per-spin ia-slabs into the joint dimen_RI x n_ov_joint slab.
1951!> Sigma-block of spin isp occupies columns offsets(isp)+1 .. offsets(isp)+n_ov(isp).
1952!> fm_S_joint must be pre-created and zeroed by the caller.
1953!> \param fm_S_ia per-spin ia-slabs, shape (dimen_RI, n_ov(isp)) per spin
1954!> \param offsets per-spin column offsets into fm_S_joint (0-based)
1955!> \param n_ov per-spin OV-pair counts
1956!> \param dimen_RI RI auxiliary basis dimension (row count)
1957!> \param fm_S_joint pre-created output slab (dimen_RI x n_ov_joint)
1958! **************************************************************************************************
1959 SUBROUTINE assemble_joint_ov_slab(fm_S_ia, offsets, n_ov, dimen_RI, fm_S_joint)
1960 TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: fm_s_ia
1961 INTEGER, DIMENSION(:), INTENT(IN) :: offsets, n_ov
1962 INTEGER, INTENT(IN) :: dimen_ri
1963 TYPE(cp_fm_type), INTENT(INOUT) :: fm_s_joint
1964
1965 CHARACTER(LEN=*), PARAMETER :: routinen = 'assemble_joint_ov_slab'
1966
1967 INTEGER :: handle, isp
1968
1969 CALL timeset(routinen, handle)
1970 DO isp = 1, SIZE(fm_s_ia)
1971 CALL cp_fm_to_fm_submat(fm_s_ia(isp), fm_s_joint, dimen_ri, n_ov(isp), 1, 1, 1, offsets(isp) + 1)
1972 END DO
1973 CALL timestop(handle)
1974
1975 END SUBROUTINE assemble_joint_ov_slab
1976
1977END MODULE bse_util
Define the atomic kind types and their sub types.
Auxiliary routines for GW + Bethe-Salpeter for computing electronic excitations.
Definition bse_util.F:13
subroutine, public assemble_joint_ov_slab(fm_s_ia, offsets, n_ov, dimen_ri, fm_s_joint)
Column-concatenate per-spin ia-slabs into the joint dimen_RI x n_ov_joint slab. Sigma-block of spin i...
Definition bse_util.F:1960
subroutine, public estimate_bse_resources(n_ov_joint, unit_nr, bse_abba, para_env, diag_runtime_est)
Roughly estimates the needed runtime and memory during the BSE run.
Definition bse_util.F:965
subroutine, public trace_exciton_descr(fm_a, fm_b, fm_c, alpha)
Computes trace of form Tr{A^T B C} for exciton descriptors.
Definition bse_util.F:1916
subroutine, public fm_general_add_bse(fm_out, fm_in, beta, nrow_secidx_in, ncol_secidx_in, nrow_secidx_out, ncol_secidx_out, unit_nr, reordering, mp2_env, row_offset, col_offset)
Adds and reorders full matrices with a combined index structure, e.g. adding W_ij,...
Definition bse_util.F:204
subroutine, public get_multipoles_mo(fm_multipole_ai_trunc, fm_multipole_ij_trunc, fm_multipole_ab_trunc, qs_env, mo_coeff, rpoint, n_moments, homo_red, virtual_red, context_bse, ispin)
...
Definition bse_util.F:1734
subroutine, public truncate_fm(fm_out, fm_in, ncol_in, nrow_out, ncol_out, unit_nr, mp2_env, nrow_offset, ncol_offset)
Routine for truncating a full matrix as given by the energy cutoffs in the input file....
Definition bse_util.F:473
subroutine, public deallocate_matrices_bse(fm_mat_s_bar_ia_bse, fm_mat_s_bar_ij_bse, fm_mat_s_trunc, fm_mat_s_ij_trunc, fm_mat_s_ab_trunc, fm_mat_q_static_bse_gemm, mp2_env)
...
Definition bse_util.F:766
subroutine, public filter_eigvec_contrib(fm_eigvec, idx_homo, idx_virt, eigvec_entries, i_exc, virtual, num_entries, mp2_env, offsets, virtual_per_spin, idx_spin)
Filters eigenvector entries above a given threshold to describe excitations in the singleparticle bas...
Definition bse_util.F:1027
subroutine, public reshuffle_eigvec(fm_eigvec, fm_eigvec_reshuffled, homo, virtual, n_exc, do_transpose, unit_nr, mp2_env)
...
Definition bse_util.F:1369
subroutine, public mult_b_with_w(fm_mat_s_ij_bse, fm_mat_s_ia_bse, fm_mat_s_bar_ia_bse, fm_mat_s_bar_ij_bse, fm_mat_q_static_bse_gemm, dimen_ri, homo, virtual)
Multiplies B-matrix (RI-3c-Integrals) with W (screening) to obtain \bar{B}.
Definition bse_util.F:115
subroutine, public adapt_bse_input_params(homo, virtual, unit_nr, mp2_env, qs_env)
Checks BSE input section and adapts them if necessary.
Definition bse_util.F:1538
subroutine, public get_bse_spin_block_layout(homo_red, virt_red, n_ov, offsets, n_ov_joint)
Spin-block layout for the open-shell (joint) BSE matrix: per-spin OV-pair counts and the block offset...
Definition bse_util.F:1180
subroutine, public sort_excitations(idx_prim, idx_sec, eigvec_entries, idx_spin)
Sorts excitation entries by ascending primary index, reordering the secondary index,...
Definition bse_util.F:868
subroutine, public comp_eigvec_coeff_bse(fm_work, eig_vals, beta, gamma, do_transpose)
Routine for computing the coefficients of the eigenvectors of the BSE matrix from a multiplication wi...
Definition bse_util.F:801
subroutine, public print_bse_nto_cubes(qs_env, mos, istate, info_approximation, stride, append_cube, print_section)
Borrowed from the tddfpt module with slight adaptions.
Definition bse_util.F:1443
subroutine, public truncate_bse_matrices(fm_mat_s_ia_bse, fm_mat_s_ij_bse, fm_mat_s_ab_bse, fm_mat_s_trunc, fm_mat_s_ij_trunc, fm_mat_s_ab_trunc, eigenval_scf, eigenval, eigenval_reduced, homo, virtual, dimen_ri, unit_nr, bse_lev_virt, homo_red, virt_red, mp2_env, window, print_window)
Determines indices within the given energy cutoffs and truncates Eigenvalues and matrices.
Definition bse_util.F:1225
Handles all functions related to the CELL.
Definition cell_types.F:15
methods related to the blacs parallel environment
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
subroutine, public dbcsr_init_p(matrix)
...
subroutine, public dbcsr_set(matrix, alpha)
...
DBCSR operations in CP2K.
subroutine, public cp_dbcsr_sm_fm_multiply(matrix, fm_in, fm_out, ncol, alpha, beta)
multiply a dbcsr with a fm matrix
Basic linear algebra operations for full matrices.
subroutine, public cp_fm_uplo_to_full(matrix, work, uplo)
given a triangular matrix according to uplo, computes the corresponding full matrix
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_invert(matrix, n, info_out)
used to replace the cholesky decomposition by the inverse
subroutine, public cp_fm_cholesky_decompose(matrix, n, info_out)
used to replace a symmetric positive def. matrix M with its cholesky decomposition U: M = U^T * U,...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_to_fm_submat_general(source, destination, nrows, ncols, s_firstrow, s_firstcol, d_firstrow, d_firstcol, global_context)
General copy of a submatrix of fm matrix to a submatrix of another fm matrix. The two matrices can ha...
subroutine, public cp_fm_to_fm_submat(msource, mtarget, nrow, ncol, s_firstrow, s_firstcol, t_firstrow, t_firstcol)
copy just a part ot the matrix
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer function, public cp_print_key_unit_nr(logger, basis_section, print_key_path, extension, middle_name, local, log_filename, ignore_should_output, file_form, file_position, file_action, file_status, do_backup, on_file, is_new_file, mpi_io, fout)
...
subroutine, public cp_print_key_finished_output(unit_nr, logger, basis_section, print_key_path, local, ignore_should_output, on_file, mpi_io)
should be called after you finish working with a unit obtained with cp_print_key_unit_nr,...
A wrapper around pw_to_cube() which accepts particle_list_type.
subroutine, public cp_pw_to_cube(pw, unit_nr, title, particles, zeff, stride, max_file_size_mb, zero_tails, silent, mpi_io)
...
Calculation of the incomplete Gamma function F_n(t) for multi-center integrals over Cartesian Gaussia...
Definition gamma.F:15
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public use_mom_ref_coac
integer, parameter, public bse_screening_tdhf
integer, parameter, public bse_screening_alpha
integer, parameter, public bse_screening_rpa
integer, parameter, public bse_abba
objects that represent the structure of input sections and the data contained in an input section
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_path_length
Definition kinds.F:58
Interface to the message passing library MPI.
Common selection and union operations for contiguous molecular-orbital windows.
Definition mo_window.F:11
Calculates the moment integrals <a|r^m|b>.
subroutine, public get_reference_point(rpoint, drpoint, qs_env, fist_env, reference, ref_point, ifirst, ilast)
...
Types needed for MP2 calculations.
Definition mp2_types.F:14
basic linear algebra operations for full matrixes
represent a simple array based list of the given type
Define the data structure for the particle information.
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public evolt
Definition physcon.F:183
container for various plainwaves related things
subroutine, public pw_env_get(pw_env, pw_pools, cube_info, gridlevel_info, auxbas_pw_pool, auxbas_grid, auxbas_rs_desc, auxbas_rs_grid, rs_descs, rs_grids, xc_pw_pool, vdw_pw_pool, poisson_env, interp_section)
returns the various attributes of the pw env
functions related to the poisson solver on regular grids
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Calculate the plane wave density by collocating the primitive Gaussian functions (pgf).
subroutine, public calculate_wavefunction(mo_vectors, ivector, rho, rho_gspace, atomic_kind_set, qs_kind_set, cell, dft_control, particle_set, pw_env, basis_type)
maps a given wavefunction on the grid
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, mimic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, matrix_vhxc, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, xcint_weights, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Define the quickstep kind type and their sub types.
Definition and initialisation of the mo data type.
Definition qs_mo_types.F:22
subroutine, public get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, uniform_occupation, kts, mu, flexible_electron_count)
Get the components of a MO set data structure.
Calculates the moment integrals <a|r^m|b> and <a|r x d/dr|b>.
Definition qs_moments.F:14
subroutine, public build_local_moment_matrix(qs_env, moments, nmoments, ref_point, ref_points, basis_type, all_images, minimum_image, neighbor_image, first_component)
...
Definition qs_moments.F:160
Define the neighbor list data types and the corresponding functionality.
types that represent a quickstep subsys
subroutine, public qs_subsys_get(subsys, atomic_kinds, atomic_kind_set, particles, particle_set, local_particles, molecules, molecule_set, molecule_kinds, molecule_kind_set, local_molecules, para_env, colvar_p, shell_particles, core_particles, gci, multipoles, natom, nparticle, ncore, nshell, nkind, atprop, virial, results, cell, cell_ref, use_ref_cell, energy, force, qs_kind_set, cp_subsys, nelectron_total, nelectron_spin)
...
Auxiliary routines necessary to redistribute an fm_matrix from a given blacs_env to another.
subroutine, public communicate_buffer(para_env, num_entries_rec, num_entries_send, buffer_rec, buffer_send, req_array, do_indx, do_msg)
...
All kind of helpful little routines.
Definition util.F:14
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...
stores all the informations relevant to an mpi environment
contained for different pw related things
environment for the poisson solver
to create arrays of pools
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Provides all information about a quickstep kind.