LCOV - code coverage report
Current view: top level - src/emd - rt_bse_ri_rs.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:21ef868) Lines: 98.0 % 248 243
Test Date: 2026-08-14 07:04:57 Functions: 100.0 % 11 11

            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 RT-BSE RI-RS kernels: SEX and Hartree evaluated by collocation on grid points r_l.
      10              : !>        Once-built grid objects:
      11              : !>          φ_µ(r_l)  [grid×AO],   Z_lP  [grid×RI],
      12              : !>          V^aux_PQ = [M^-1 V^tr M^-1]_PQ  [RI×RI],  W^0_ll' = sum_PQ Z_lP (V + W^c(ω=0))_PQ Z_l'Q.
      13              : !>        Per-call kernels, collocation X = φ_µ(r_l) (AO domain, written φ_lµ below):
      14              : !>          SEX:      ρ^grid_ll' = sum_µν φ_lµ Δρ_µν φ_l'ν ;
      15              : !>                    Σ_µν = pref * sum_ll' φ_lµ [ρ^grid ∘ W^0]_ll' φ_l'ν
      16              : !>          Hartree:  n_l = sum_µν φ_lµ Δρ_µν φ_lν ;
      17              : !>                    v_l = sum_PQl' Z_lP V^aux_PQ Z_l'Q n_l'   (applied factorized, stage 2) ;
      18              : !>                    V^H_µν = sum_l φ_lµ v_l φ_lν      (diagonal-only, no grid×grid)
      19              : !>        Independent of which GW variant produced bs_env%fm_W_MIC_freq_zero.
      20              : !> \author Maximilian Graml (05.26)
      21              : ! **************************************************************************************************
      22              : MODULE rt_bse_ri_rs
      23              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_scale_and_add
      24              :    USE cp_cfm_types,                    ONLY: cp_cfm_create,&
      25              :                                               cp_cfm_release,&
      26              :                                               cp_cfm_to_fm,&
      27              :                                               cp_cfm_type,&
      28              :                                               cp_fm_to_cfm
      29              :    USE cp_dbcsr_api,                    ONLY: &
      30              :         dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_distribution_type, dbcsr_get_info, &
      31              :         dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
      32              :         dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_release, dbcsr_scale, &
      33              :         dbcsr_type, dbcsr_type_no_symmetry
      34              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_get_diag
      35              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      36              :                                               copy_fm_to_dbcsr
      37              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      38              :                                               cp_fm_release,&
      39              :                                               cp_fm_type
      40              :    USE gw_large_cell_Gamma_ri_rs,       ONLY: contract_A_B_A,&
      41              :                                               hadamard_product_inplace,&
      42              :                                               release_dbcsr_topology_and_matrices,&
      43              :                                               setup_square_topology
      44              :    USE gw_large_cell_gamma,             ONLY: multiply_fm_W_MIC_time_with_Minv_Gamma
      45              :    USE gw_non_periodic_ri_rs,           ONLY: atomic_basis_at_grid_point,&
      46              :                                               compute_coeff_Z_lP,&
      47              :                                               precompute_ri_rs_radii,&
      48              :                                               ri_rs_grid_assembler
      49              :    USE kinds,                           ONLY: dp
      50              :    USE machine,                         ONLY: m_walltime
      51              :    USE message_passing,                 ONLY: mp_para_env_type
      52              :    USE mp2_ri_2c,                       ONLY: RI_2c_integral_mat
      53              :    USE post_scf_bandstructure_types,    ONLY: post_scf_bandstructure_type
      54              :    USE qs_environment_types,            ONLY: qs_environment_type
      55              : #include "../base/base_uses.f90"
      56              : 
      57              :    IMPLICIT NONE
      58              : 
      59              :    PRIVATE
      60              : 
      61              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rt_bse_ri_rs'
      62              : 
      63              :    PUBLIC :: rt_bse_ri_rs_ensure_grid, &
      64              :              rt_bse_ri_rs_ensure_V_grid, &
      65              :              rt_bse_ri_rs_ensure_W0_grid, &
      66              :              compute_sigma_ri_rs, &
      67              :              compute_sigma_ri_rs_complex, &
      68              :              compute_hartree_ri_rs, &
      69              :              compute_hartree_ri_rs_complex, &
      70              :              compute_hartree_ri_rs_from_diag, &
      71              :              hartree_potential_from_diag_ri_rs
      72              : 
      73              : CONTAINS
      74              : 
      75              : ! **************************************************************************************************
      76              : !> \brief Make sure the AO collocation φ_µ(r_l) (mat_phi_mu_l) and the RI fit coefficients
      77              : !>        Z_lP (mat_Z_lP) are populated in memory.
      78              : !>        If GW was run with RI-RS the grid is already built; otherwise build it here so the
      79              : !>        AO-RI GW + RI-RS RT-BSE combination is possible.
      80              : !> \param bs_env ...
      81              : !> \param qs_env ...
      82              : ! **************************************************************************************************
      83           32 :    SUBROUTINE rt_bse_ri_rs_ensure_grid(bs_env, qs_env)
      84              : 
      85              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
      86              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      87              : 
      88              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rt_bse_ri_rs_ensure_grid'
      89              : 
      90              :       INTEGER                                            :: handle
      91              :       REAL(KIND=dp)                                      :: t1
      92              : 
      93           32 :       CALL timeset(routineN, handle)
      94              : 
      95           32 :       IF (bs_env%ri_rs%grid_built) THEN
      96           24 :          CALL timestop(handle)
      97           24 :          RETURN
      98              :       END IF
      99              : 
     100            8 :       t1 = m_walltime()
     101              : 
     102            8 :       CALL ri_rs_grid_assembler(qs_env, bs_env, bs_env%ri_rs%grid_points)
     103              :       ! Per-atom AO/RI screening radii required by the screened grid-fill and d_lP routines; the
     104              :       ! GW RI-RS driver populates these, but the standalone RT-BSE grid build must do so itself.
     105            8 :       IF (.NOT. ALLOCATED(bs_env%ri_rs%radius_ao_per_atom)) THEN
     106            8 :          CALL precompute_ri_rs_radii(qs_env, bs_env)
     107              :       END IF
     108              :       CALL atomic_basis_at_grid_point(qs_env, bs_env, bs_env%ri_rs%grid_points, &
     109            8 :                                       bs_env%ri_rs%mat_phi_mu_l)
     110              :       CALL compute_coeff_Z_lP(qs_env, bs_env, bs_env%ri_rs%grid_points, &
     111            8 :                               bs_env%ri_rs%mat_phi_mu_l, bs_env%ri_rs%mat_Z_lP)
     112              : 
     113            8 :       bs_env%ri_rs%grid_built = .TRUE.
     114              : 
     115            8 :       IF (bs_env%unit_nr > 0) THEN
     116              :          WRITE (bs_env%unit_nr, '(T2,A,T58,A,F7.1,A)') &
     117            4 :             'Built RI-RS grid for RT-BSE (no GW_RI_RS used),', ' Execution time', &
     118            8 :             m_walltime() - t1, ' s'
     119            4 :          WRITE (bs_env%unit_nr, '(A)') ' '
     120              :       END IF
     121              : 
     122            8 :       CALL timestop(handle)
     123              : 
     124              :    END SUBROUTINE rt_bse_ri_rs_ensure_grid
     125              : 
     126              : ! **************************************************************************************************
     127              : !> \brief Build V^aux_PQ = [M^-1 V^tr M^-1]_PQ (truncated Coulomb in the RI basis, M^-1-sandwiched
     128              : !>        to match the W^MIC convention). The grid Coulomb V_ll' = sum_PQ Z_lP V^aux_PQ Z_l'Q is
     129              : !>        never materialized -- the Hartree stage applies it factorized:
     130              : !>          v_l = sum_PQl' Z_lP V^aux_PQ Z_l'Q n_l'
     131              : !>        Needed by RT-BSE RI-RS Hartree.
     132              : !> \param bs_env ...
     133              : !> \param qs_env ...
     134              : ! **************************************************************************************************
     135           16 :    SUBROUTINE rt_bse_ri_rs_ensure_V_grid(bs_env, qs_env)
     136              : 
     137              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     138              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     139              : 
     140              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rt_bse_ri_rs_ensure_V_grid'
     141              : 
     142              :       INTEGER                                            :: handle
     143           16 :       INTEGER, DIMENSION(:), POINTER                     :: blk_aux, dist_row_aux
     144              :       REAL(KIND=dp)                                      :: t1
     145           16 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_Vtr_Gamma
     146              :       TYPE(dbcsr_distribution_type)                      :: dist_aux_aux
     147              : 
     148           16 :       CALL timeset(routineN, handle)
     149              : 
     150           16 :       IF (bs_env%ri_rs%V_grid_built) THEN
     151            0 :          CALL timestop(handle)
     152            0 :          RETURN
     153              :       END IF
     154              : 
     155           16 :       CALL rt_bse_ri_rs_ensure_grid(bs_env, qs_env)
     156           16 :       t1 = m_walltime()
     157              : 
     158           16 :       CALL setup_square_topology(bs_env%ri_rs%mat_Z_lP, 'COL', dist_aux_aux, blk_aux, dist_row_aux)
     159              : 
     160              :       CALL RI_2c_integral_mat(qs_env, fm_Vtr_Gamma, bs_env%fm_RI_RI, bs_env%n_RI, &
     161           16 :                               bs_env%trunc_coulomb, do_kpoints=.FALSE.)
     162              :       ! Apply M^-1 sandwich to match the W^MIC convention; same scale as W^c when both used.
     163           16 :       CALL multiply_fm_W_MIC_time_with_Minv_Gamma(bs_env, qs_env, fm_Vtr_Gamma(:, 1))
     164              : 
     165              :       ! Store the M^-1-sandwiched RI-basis Coulomb; the grid kernel Z V Z^T is applied factorized.
     166              :       CALL dbcsr_create(bs_env%ri_rs%mat_V_aux_rtbse, "V_aux_rtbse", dist_aux_aux, &
     167           16 :                         dbcsr_type_no_symmetry, blk_aux, blk_aux)
     168              :       CALL copy_fm_to_dbcsr(fm_Vtr_Gamma(1, 1), bs_env%ri_rs%mat_V_aux_rtbse, &
     169           16 :                             keep_sparsity=.FALSE.)
     170              : 
     171           16 :       bs_env%ri_rs%V_grid_built = .TRUE.
     172              : 
     173           16 :       IF (bs_env%unit_nr > 0) THEN
     174              :          WRITE (bs_env%unit_nr, '(T2,A,T57,A,F7.1,A)') &
     175            8 :             'Precomputed RT-BSE RI-RS V_aux kernel,', ' Execution time', &
     176           16 :             m_walltime() - t1, ' s'
     177            8 :          WRITE (bs_env%unit_nr, '(A)') ' '
     178              :       END IF
     179              : 
     180           16 :       CALL release_dbcsr_topology_and_matrices(dist=dist_aux_aux, mapped_dist=dist_row_aux)
     181           16 :       CALL cp_fm_release(fm_Vtr_Gamma)
     182              : 
     183           16 :       CALL timestop(handle)
     184              : 
     185           32 :    END SUBROUTINE rt_bse_ri_rs_ensure_V_grid
     186              : 
     187              : ! **************************************************************************************************
     188              : !> \brief Build W^0_ll' = sum_PQ Z_lP (V + W^c(ω=0))_PQ Z_l'Q (statically screened W on the grid).
     189              : !>        Needed by RT-BSE RI-RS SEX/COH. Reuses bs_env%fm_W_MIC_freq_zero which must already
     190              : !>        contain M^-1 W^c(ω=0) M^-1 (built by either GW path under the BSE rtp_method gate).
     191              : !>        W^0 enters only through the Hadamard ρ^grid ∘ W^0 -- its elements are needed, so it is
     192              : !>        the one persistent grid×grid object of the kernel layer.
     193              : !> \param bs_env ...
     194              : !> \param qs_env ...
     195              : ! **************************************************************************************************
     196           16 :    SUBROUTINE rt_bse_ri_rs_ensure_W0_grid(bs_env, qs_env)
     197              : 
     198              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     199              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     200              : 
     201              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rt_bse_ri_rs_ensure_W0_grid'
     202              : 
     203              :       INTEGER                                            :: handle
     204           16 :       INTEGER, DIMENSION(:), POINTER                     :: blk_aux, blk_grid, dist_col_grid, &
     205           16 :                                                             dist_row_aux
     206              :       REAL(KIND=dp)                                      :: t1
     207           16 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_Vtr_Gamma
     208              :       TYPE(dbcsr_distribution_type)                      :: dist_aux_aux, dist_grid_grid
     209              :       TYPE(dbcsr_type)                                   :: matrix_V_aux, matrix_W_aux
     210              : 
     211           16 :       CALL timeset(routineN, handle)
     212              : 
     213           16 :       IF (bs_env%ri_rs%W0_grid_built) THEN
     214            0 :          CALL timestop(handle)
     215            0 :          RETURN
     216              :       END IF
     217              : 
     218              :       ! W(w=0) is built by the GW step only under its RTBSE rtp_method gate; reaching this consumer
     219              :       ! without it means gate and consumer disagree. Abort rather than read a never-created cp_fm.
     220           16 :       IF (.NOT. ASSOCIATED(bs_env%fm_W_MIC_freq_zero%matrix_struct)) THEN
     221              :          CALL cp_abort(__LOCATION__, &
     222              :                        "RT-BSE RI-RS kernel needs the screened interaction W(w=0), which the GW "// &
     223              :                        "step did not build. Select the RT-BSE propagator with '&RTBSE' or "// &
     224            0 :                        "'&RTBSE RTBSE', not '&RTBSE TDDFT'.")
     225              :       END IF
     226              : 
     227           16 :       CALL rt_bse_ri_rs_ensure_grid(bs_env, qs_env)
     228           16 :       t1 = m_walltime()
     229              : 
     230              :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'ROW', dist_grid_grid, blk_grid, &
     231           16 :                                  dist_col_grid)
     232           16 :       CALL setup_square_topology(bs_env%ri_rs%mat_Z_lP, 'COL', dist_aux_aux, blk_aux, dist_row_aux)
     233              : 
     234              :       CALL RI_2c_integral_mat(qs_env, fm_Vtr_Gamma, bs_env%fm_RI_RI, bs_env%n_RI, &
     235           16 :                               bs_env%trunc_coulomb, do_kpoints=.FALSE.)
     236           16 :       CALL multiply_fm_W_MIC_time_with_Minv_Gamma(bs_env, qs_env, fm_Vtr_Gamma(:, 1))
     237              : 
     238              :       CALL dbcsr_create(matrix_V_aux, "V_aux_rtbse_W0", dist_aux_aux, dbcsr_type_no_symmetry, &
     239           16 :                         blk_aux, blk_aux)
     240           16 :       CALL copy_fm_to_dbcsr(fm_Vtr_Gamma(1, 1), matrix_V_aux, keep_sparsity=.FALSE.)
     241              : 
     242              :       CALL dbcsr_create(matrix_W_aux, "W_aux_rtbse", dist_aux_aux, dbcsr_type_no_symmetry, &
     243           16 :                         blk_aux, blk_aux)
     244           16 :       CALL copy_fm_to_dbcsr(bs_env%fm_W_MIC_freq_zero, matrix_W_aux, keep_sparsity=.FALSE.)
     245           16 :       CALL dbcsr_add(matrix_W_aux, matrix_V_aux, 1.0_dp, 1.0_dp)
     246              : 
     247              :       CALL dbcsr_create(bs_env%ri_rs%mat_W0_grid_rtbse, "W0_grid_rtbse", dist_grid_grid, &
     248           16 :                         dbcsr_type_no_symmetry, blk_grid, blk_grid)
     249              :       CALL contract_A_B_A("N", "T", bs_env%ri_rs%mat_Z_lP, matrix_W_aux, &
     250           16 :                           bs_env%ri_rs%mat_W0_grid_rtbse, bs_env%eps_filter)
     251              : 
     252           16 :       bs_env%ri_rs%W0_grid_built = .TRUE.
     253           16 :       bs_env%ri_rs%rtbse_kernels_ready = .TRUE.
     254              : 
     255           16 :       IF (bs_env%unit_nr > 0) THEN
     256              :          WRITE (bs_env%unit_nr, '(T2,A,T57,A,F7.1,A)') &
     257            8 :             'Precomputed RT-BSE RI-RS W0_grid kernel,', ' Execution time', &
     258           16 :             m_walltime() - t1, ' s'
     259            8 :          WRITE (bs_env%unit_nr, '(A)') ' '
     260              :       END IF
     261              : 
     262           16 :       CALL release_dbcsr_topology_and_matrices(dist=dist_grid_grid, mapped_dist=dist_col_grid)
     263              :       CALL release_dbcsr_topology_and_matrices(dist=dist_aux_aux, mapped_dist=dist_row_aux, &
     264           16 :                                                m1=matrix_V_aux, m2=matrix_W_aux)
     265           16 :       CALL cp_fm_release(fm_Vtr_Gamma)
     266              : 
     267           16 :       CALL timestop(handle)
     268              : 
     269           32 :    END SUBROUTINE rt_bse_ri_rs_ensure_W0_grid
     270              : 
     271              : ! **************************************************************************************************
     272              : !> \brief AO-domain SEX:  Σ_µν = pref * sum_ll' φ_lµ [ρ^grid ∘ W^0]_ll' φ_l'ν,
     273              : !>        ρ^grid_ll' = sum_µν φ_lµ Δρ_µν φ_l'ν.
     274              : !>        The grid×grid ρ^grid is intrinsic to SEX -- the Hadamard needs W^0's elements, so no
     275              : !>        factorized application exists (unlike the Hartree V_ll'). Real input, real output;
     276              : !>        used for COH (input S^-1) and the init reference (ρ^0); dynamic Δρ goes through the
     277              : !>        complex variant. Mirrors the AO-RI get_sigma(rtbse_env, sigma_fm, prefactor, rho_fm) API.
     278              : !> \param bs_env ...
     279              : !> \param sigma_AO_fm result, AO x AO
     280              : !> \param prefactor scaling applied to the final result
     281              : !> \param rho_AO_fm input density-like matrix, AO x AO
     282              : !> \param grid_diag_accum ...
     283              : ! **************************************************************************************************
     284         3504 :    SUBROUTINE compute_sigma_ri_rs(bs_env, sigma_AO_fm, prefactor, rho_AO_fm, &
     285         3504 :                                   grid_diag_accum)
     286              : 
     287              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     288              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: sigma_AO_fm
     289              :       REAL(KIND=dp), INTENT(IN)                          :: prefactor
     290              :       TYPE(cp_fm_type), INTENT(IN)                       :: rho_AO_fm
     291              :       REAL(KIND=dp), INTENT(INOUT), OPTIONAL             :: grid_diag_accum(:)
     292              : 
     293              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_sigma_ri_rs'
     294              : 
     295              :       INTEGER                                            :: handle, n_grid
     296         3504 :       INTEGER, DIMENSION(:), POINTER                     :: blk_ao, blk_grid, dist_col_grid, &
     297         3504 :                                                             dist_row_ao
     298         3504 :       REAL(KIND=dp), ALLOCATABLE                         :: diag_local(:)
     299              :       TYPE(dbcsr_distribution_type)                      :: dist_ao_ao, dist_grid_grid
     300              :       TYPE(dbcsr_type)                                   :: matrix_rho_AO, matrix_rho_grid, &
     301              :                                                             matrix_Sigma_AO
     302              : 
     303         3504 :       CALL timeset(routineN, handle)
     304              : 
     305         3504 :       CPASSERT(bs_env%ri_rs%W0_grid_built)
     306              : 
     307         3504 :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'COL', dist_ao_ao, blk_ao, dist_row_ao)
     308              :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'ROW', dist_grid_grid, blk_grid, &
     309         3504 :                                  dist_col_grid)
     310              : 
     311              :       CALL dbcsr_create(matrix_rho_AO, "rho_AO_ri_rs", dist_ao_ao, dbcsr_type_no_symmetry, &
     312         3504 :                         blk_ao, blk_ao)
     313         3504 :       CALL copy_fm_to_dbcsr(rho_AO_fm, matrix_rho_AO, keep_sparsity=.FALSE.)
     314              : 
     315              :       ! ρ^grid_ll' = sum_µν φ_lµ Δρ_µν φ_l'ν   (the SEX-intrinsic grid×grid transient)
     316              :       CALL dbcsr_create(matrix_rho_grid, "rho_grid_ri_rs", dist_grid_grid, &
     317         3504 :                         dbcsr_type_no_symmetry, blk_grid, blk_grid)
     318              :       ! No eps_filter on the SEX projections: a Δρ-dependent block drop breaks kernel
     319              :       ! self-adjointness (L non-Hermitian). The W0 Hadamard below supplies the symmetric,
     320              :       ! Δρ-independent grid sparsity, so unfiltered projections stay sparse via W0.
     321              :       ! PERF(rirs-selfadjoint): a retain_sparsity-to-W0 build (dbcsr_multiply) gives identical
     322              :       ! numbers with W0-sparse memory; NOT YET APPLIED, needs a perf test.
     323              :       CALL contract_A_B_A("N", "T", bs_env%ri_rs%mat_phi_mu_l, matrix_rho_AO, &
     324         3504 :                           matrix_rho_grid, 0.0_dp)
     325              : 
     326              :       ! Harvest n_l = diag(ρ^grid) BEFORE the in-place Hadamard destroys it; the Hartree reuses it
     327              :       ! (compute_hartree_ri_rs_from_diag) instead of rebuilding φρφ^T. Bare accumulate (caller
     328              :       ! pre-zeroes): the cross-spin Hartree density is the spin SUM of these, and spin_degeneracy is
     329              :       ! applied to the V_H OUTPUT (post-filter, bit-identical) -- never to the diagonal, which would
     330              :       ! shift the stage-3 eps_filter cut (coarse-filter sensitivity).
     331         3504 :       IF (PRESENT(grid_diag_accum)) THEN
     332         2240 :          n_grid = SIZE(grid_diag_accum)
     333         6720 :          ALLOCATE (diag_local(n_grid))
     334         2240 :          diag_local = 0.0_dp
     335         2240 :          CALL dbcsr_get_diag(matrix_rho_grid, diag_local)
     336         2240 :          CALL bs_env%para_env%sum(diag_local)
     337       671040 :          grid_diag_accum(:) = grid_diag_accum(:) + diag_local(:)
     338         2240 :          DEALLOCATE (diag_local)
     339              :       END IF
     340              : 
     341              :       ! ρ^grid_ll' <- ρ^grid_ll' * W^0_ll'   (in place; blocks without a W^0 partner zeroed)
     342              :       CALL hadamard_product_inplace(matrix_rho_grid, bs_env%ri_rs%mat_W0_grid_rtbse, &
     343         3504 :                                     1.0_dp)
     344              : 
     345              :       ! Σ_µν = sum_ll' φ_lµ [ρ^grid ∘ W^0]_ll' φ_l'ν
     346         3504 :       CALL dbcsr_create(matrix_Sigma_AO, template=matrix_rho_AO)
     347              :       ! Unfiltered for self-adjointness (see the forward projection above; PERF note there).
     348              :       CALL contract_A_B_A("T", "N", bs_env%ri_rs%mat_phi_mu_l, matrix_rho_grid, &
     349         3504 :                           matrix_Sigma_AO, 0.0_dp)
     350              : 
     351         3504 :       CALL dbcsr_scale(matrix_Sigma_AO, prefactor)
     352         3504 :       CALL copy_dbcsr_to_fm(matrix_Sigma_AO, sigma_AO_fm)
     353              : 
     354              :       CALL release_dbcsr_topology_and_matrices(dist=dist_ao_ao, mapped_dist=dist_row_ao, &
     355         3504 :                                                m1=matrix_rho_AO, m2=matrix_Sigma_AO)
     356              :       CALL release_dbcsr_topology_and_matrices(dist=dist_grid_grid, mapped_dist=dist_col_grid, &
     357         3504 :                                                m1=matrix_rho_grid)
     358              : 
     359         3504 :       CALL timestop(handle)
     360              : 
     361         7008 :    END SUBROUTINE compute_sigma_ri_rs
     362              : 
     363              : ! **************************************************************************************************
     364              : !> \brief Complex-input AO SEX via Re/Im split: the kernel is real, so complex linearity holds as
     365              : !>        Σ[Δρ] = Σ[Re Δρ] + i Σ[Im Δρ].  Required for non-Hermitian Δρ inputs
     366              : !>        (TDA OV-only / ABBA OV+VO).
     367              : !> \param bs_env ...
     368              : !> \param sigma_AO_cfm result, AO x AO (complex)
     369              : !> \param prefactor scaling applied to the final result
     370              : !> \param rho_AO_cfm input AO x AO complex matrix
     371              : !> \param grid_diag_re_accum optional: accumulate diag(φ.Re(ρ).φ^T) (bare; for the Hartree reuse)
     372              : !> \param grid_diag_im_accum optional: accumulate diag(φ.Im(ρ).φ^T) (bare; for the Hartree reuse)
     373              : ! **************************************************************************************************
     374         8760 :    SUBROUTINE compute_sigma_ri_rs_complex(bs_env, sigma_AO_cfm, prefactor, rho_AO_cfm, &
     375         1752 :                                           grid_diag_re_accum, grid_diag_im_accum)
     376              : 
     377              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     378              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: sigma_AO_cfm
     379              :       REAL(KIND=dp), INTENT(IN)                          :: prefactor
     380              :       TYPE(cp_cfm_type), INTENT(IN)                      :: rho_AO_cfm
     381              :       REAL(KIND=dp), INTENT(INOUT), OPTIONAL             :: grid_diag_re_accum(:), &
     382              :                                                             grid_diag_im_accum(:)
     383              : 
     384              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_sigma_ri_rs_complex'
     385              : 
     386              :       INTEGER                                            :: handle
     387              :       TYPE(cp_cfm_type)                                  :: cfm_real_part
     388              :       TYPE(cp_fm_type)                                   :: fm_rho, fm_sigma
     389              : 
     390         1752 :       CALL timeset(routineN, handle)
     391              : 
     392         1752 :       CALL cp_fm_create(fm_rho, bs_env%fm_s_Gamma%matrix_struct)
     393         1752 :       CALL cp_fm_create(fm_sigma, bs_env%fm_s_Gamma%matrix_struct)
     394         1752 :       CALL cp_cfm_create(cfm_real_part, bs_env%fm_s_Gamma%matrix_struct)
     395              : 
     396              :       ! Re/Im each harvest into their own accumulator; absent optionals propagate as absent.
     397         1752 :       CALL cp_cfm_to_fm(msource=rho_AO_cfm, mtargetr=fm_rho)
     398              :       CALL compute_sigma_ri_rs(bs_env, fm_sigma, prefactor, fm_rho, &
     399         2064 :                                grid_diag_accum=grid_diag_re_accum)
     400         1752 :       CALL cp_fm_to_cfm(msourcer=fm_sigma, mtarget=cfm_real_part)
     401              : 
     402         1752 :       CALL cp_cfm_to_fm(msource=rho_AO_cfm, mtargeti=fm_rho)
     403              :       CALL compute_sigma_ri_rs(bs_env, fm_sigma, prefactor, fm_rho, &
     404         2704 :                                grid_diag_accum=grid_diag_im_accum)
     405         1752 :       CALL cp_fm_to_cfm(msourcei=fm_sigma, mtarget=sigma_AO_cfm)
     406              : 
     407              :       CALL cp_cfm_scale_and_add(CMPLX(1.0_dp, 0.0_dp, kind=dp), sigma_AO_cfm, &
     408         1752 :                                 CMPLX(1.0_dp, 0.0_dp, kind=dp), cfm_real_part)
     409              : 
     410         1752 :       CALL cp_fm_release(fm_rho)
     411         1752 :       CALL cp_fm_release(fm_sigma)
     412         1752 :       CALL cp_cfm_release(cfm_real_part)
     413              : 
     414         1752 :       CALL timestop(handle)
     415              : 
     416         1752 :    END SUBROUTINE compute_sigma_ri_rs_complex
     417              : 
     418              : ! **************************************************************************************************
     419              : !> \brief AO-domain Hartree via RI-RS:
     420              : !>          n_l = sum_µν φ_lµ Δρ_µν φ_lν = (φ ρ φ^T)_ll  (diagonal of materialized grid×grid) ;
     421              : !>          v_l = sum_PQl' Z_lP V^aux_PQ Z_l'Q n_l'   (factorized, stage 2) ;
     422              : !>          V^H_µν = sum_l φ_lµ v_l φ_lν   (diagonal-only row-scale, stage 3)
     423              : !>        Real input, real output; complex inputs go through compute_hartree_ri_rs_complex.
     424              : !> \param bs_env ...
     425              : !> \param rho_AO_fm input AO x AO density matrix
     426              : !> \param V_H_AO_fm output AO x AO Hartree potential
     427              : ! **************************************************************************************************
     428          444 :    SUBROUTINE compute_hartree_ri_rs(bs_env, rho_AO_fm, V_H_AO_fm)
     429              : 
     430              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     431              :       TYPE(cp_fm_type), INTENT(IN)                       :: rho_AO_fm
     432              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: V_H_AO_fm
     433              : 
     434              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_hartree_ri_rs'
     435              : 
     436              :       INTEGER                                            :: handle, n_grid
     437          444 :       INTEGER, DIMENSION(:), POINTER                     :: blk_ao, blk_grid, dist_col_grid, &
     438          444 :                                                             dist_row_ao
     439              :       REAL(KIND=dp), ALLOCATABLE                         :: n_vec(:)
     440              :       TYPE(dbcsr_distribution_type)                      :: dist_ao_ao, dist_grid_grid
     441              :       TYPE(dbcsr_type)                                   :: matrix_rho_AO, matrix_rho_grid
     442              : 
     443          444 :       CALL timeset(routineN, handle)
     444              : 
     445          444 :       CPASSERT(bs_env%ri_rs%V_grid_built)
     446              : 
     447          444 :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'COL', dist_ao_ao, blk_ao, dist_row_ao)
     448              :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'ROW', dist_grid_grid, blk_grid, &
     449          444 :                                  dist_col_grid)
     450              : 
     451              :       CALL dbcsr_create(matrix_rho_AO, "rho_AO_hartree", dist_ao_ao, dbcsr_type_no_symmetry, &
     452          444 :                         blk_ao, blk_ao)
     453          444 :       CALL copy_fm_to_dbcsr(rho_AO_fm, matrix_rho_AO, keep_sparsity=.FALSE.)
     454              : 
     455         5236 :       n_grid = SUM(blk_grid)
     456         1332 :       ALLOCATE (n_vec(n_grid))
     457              : 
     458              :       ! stage 1: n_l = (φ ρ φ^T)_ll. A grid×AO row-dot (iterate φρ, look up φ) silently drops
     459              :       ! off-rank pairs at ≥2 ranks — φ is sparse and the product is not co-located with φ — so
     460              :       ! materialize φρφ^T and take its diagonal, co-location-safe like the SEX grid kernel.
     461              :       CALL dbcsr_create(matrix_rho_grid, "rho_grid_hartree", dist_grid_grid, &
     462          444 :                         dbcsr_type_no_symmetry, blk_grid, blk_grid)
     463              :       ! No eps_filter: a Δρ-dependent diagonal-block drop zeroes n_l inconsistently between OV
     464              :       ! pairs and breaks Hartree self-adjointness (L non-Hermitian).
     465              :       ! PERF(rirs-selfadjoint): this full grid×grid is built only for its diagonal n_l; a
     466              :       ! diagonal-only build would avoid it. NOT YET APPLIED, needs a perf test.
     467              :       CALL contract_A_B_A("N", "T", bs_env%ri_rs%mat_phi_mu_l, matrix_rho_AO, &
     468          444 :                           matrix_rho_grid, 0.0_dp)
     469          444 :       n_vec = 0.0_dp
     470          444 :       CALL dbcsr_get_diag(matrix_rho_grid, n_vec)
     471          444 :       CALL bs_env%para_env%sum(n_vec)
     472              :       CALL release_dbcsr_topology_and_matrices(dist=dist_grid_grid, mapped_dist=dist_col_grid, &
     473          444 :                                                m1=matrix_rho_grid)
     474              :       CALL release_dbcsr_topology_and_matrices(dist=dist_ao_ao, mapped_dist=dist_row_ao, &
     475          444 :                                                m1=matrix_rho_AO)
     476              : 
     477              :       ! stages 2-3: factorized Coulomb v = Z V^aux Z^T n, then V^H = φ^T diag(v) φ.
     478          444 :       CALL hartree_potential_from_diag_ri_rs(bs_env, n_vec, V_H_AO_fm)
     479              : 
     480          444 :       DEALLOCATE (n_vec)
     481              : 
     482          444 :       CALL timestop(handle)
     483              : 
     484          888 :    END SUBROUTINE compute_hartree_ri_rs
     485              : 
     486              : ! **************************************************************************************************
     487              : !> \brief Hartree stages 2-3 from a precomputed grid density n_l (skips the stage-1 φρφ^T build):
     488              : !>          v_l = sum_PQl' Z_lP V^aux_PQ Z_l'Q n_l'   (factorized Coulomb) ;
     489              : !>          V^H_µν = sum_l φ_lµ v_l φ_lν   (Φ_lν = v_l φ_lν rowscale, then V^H = φ^T Φ).
     490              : !>        n_l is harvested as diag(φρφ^T) inside compute_sigma_ri_rs (the SEX grid kernel), so the
     491              : !>        Hartree never rebuilds the grid×grid product. Real in/out.
     492              : !> \param bs_env ...
     493              : !> \param n_vec grid density n_l (length n_grid, replicated)
     494              : !> \param V_H_AO_fm output AO x AO Hartree potential
     495              : ! **************************************************************************************************
     496         2204 :    SUBROUTINE hartree_potential_from_diag_ri_rs(bs_env, n_vec, V_H_AO_fm)
     497              : 
     498              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     499              :       REAL(KIND=dp), INTENT(IN)                          :: n_vec(:)
     500              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: V_H_AO_fm
     501              : 
     502              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'hartree_potential_from_diag_ri_rs'
     503              : 
     504              :       INTEGER                                            :: handle
     505         2204 :       INTEGER, DIMENSION(:), POINTER                     :: blk_ao, dist_row_ao
     506              :       REAL(KIND=dp), ALLOCATABLE                         :: u_ri(:), v_vec(:), w_ri(:)
     507              :       TYPE(dbcsr_distribution_type)                      :: dist_ao_ao
     508              :       TYPE(dbcsr_type)                                   :: matrix_Phi, matrix_V_H_AO
     509              : 
     510         2204 :       CALL timeset(routineN, handle)
     511              : 
     512         2204 :       CPASSERT(bs_env%ri_rs%V_grid_built)
     513              : 
     514         2204 :       CALL setup_square_topology(bs_env%ri_rs%mat_phi_mu_l, 'COL', dist_ao_ao, blk_ao, dist_row_ao)
     515         6612 :       ALLOCATE (v_vec(SIZE(n_vec)))
     516              : 
     517              :       ! stage 2: v_l = sum_PQl' Z_lP V^aux_PQ Z_l'Q n_l'  (factorized; helper zeroes each output)
     518         8816 :       ALLOCATE (w_ri(bs_env%n_RI), u_ri(bs_env%n_RI))
     519              :       ! w_Q = sum_l Z_lQ n_l
     520              :       CALL dbcsr_matvec_replicated(bs_env%ri_rs%mat_Z_lP, n_vec, w_ri, bs_env%para_env, &
     521         2204 :                                    transposed=.TRUE.)
     522              :       ! u_P = sum_Q V^aux_PQ w_Q
     523         2204 :       CALL dbcsr_matvec_replicated(bs_env%ri_rs%mat_V_aux_rtbse, w_ri, u_ri, bs_env%para_env)
     524              :       ! v_l = sum_P Z_lP u_P
     525         2204 :       CALL dbcsr_matvec_replicated(bs_env%ri_rs%mat_Z_lP, u_ri, v_vec, bs_env%para_env)
     526         2204 :       DEALLOCATE (w_ri, u_ri)
     527              : 
     528              :       ! stage 3: V^H_µν = sum_l φ_lµ v_l φ_lν  (Φ_lν = v_l φ_lν rowscale, then V^H = φ^T Φ)
     529         2204 :       CALL dbcsr_create(matrix_Phi, template=bs_env%ri_rs%mat_phi_mu_l)
     530         2204 :       CALL dbcsr_copy(matrix_Phi, bs_env%ri_rs%mat_phi_mu_l)
     531         2204 :       CALL dbcsr_scale_rows_replicated(matrix_Phi, v_vec)
     532              : 
     533              :       CALL dbcsr_create(matrix_V_H_AO, "V_H_AO_hartree", dist_ao_ao, dbcsr_type_no_symmetry, &
     534         2204 :                         blk_ao, blk_ao)
     535              :       ! No eps_filter: a Δρ-dependent block drop breaks Hartree kernel self-adjointness.
     536              :       CALL dbcsr_multiply("T", "N", 1.0_dp, bs_env%ri_rs%mat_phi_mu_l, matrix_Phi, &
     537         2204 :                           0.0_dp, matrix_V_H_AO, filter_eps=0.0_dp)
     538         2204 :       CALL dbcsr_release(matrix_Phi)
     539              : 
     540         2204 :       CALL copy_dbcsr_to_fm(matrix_V_H_AO, V_H_AO_fm)
     541              : 
     542         2204 :       DEALLOCATE (v_vec)
     543              : 
     544              :       CALL release_dbcsr_topology_and_matrices(dist=dist_ao_ao, mapped_dist=dist_row_ao, &
     545         2204 :                                                m1=matrix_V_H_AO)
     546              : 
     547         2204 :       CALL timestop(handle)
     548              : 
     549         4408 :    END SUBROUTINE hartree_potential_from_diag_ri_rs
     550              : 
     551              : ! **************************************************************************************************
     552              : !> \brief Complex Hartree from precomputed grid diagonals: V^H = V^H[n_re] + i V^H[n_im], each via
     553              : !>        hartree_potential_from_diag_ri_rs (stages 2-3 only). n_re/n_im are the spin-summed grid
     554              : !>        densities harvested in the SEX kernel; this is the cross-spin / TDA complex consumer that
     555              : !>        replaces compute_hartree_ri_rs_complex when SEX already built the grid. n_im optional: when
     556              : !>        absent the result is purely real (matches the Re-only real-input Hartree).
     557              : !> \param bs_env ...
     558              : !> \param n_re grid density Re part (length n_grid, replicated)
     559              : !> \param V_H_AO_cfm output AO x AO complex Hartree potential
     560              : !> \param n_im optional grid density Im part (length n_grid, replicated)
     561              : ! **************************************************************************************************
     562         1120 :    SUBROUTINE compute_hartree_ri_rs_from_diag(bs_env, n_re, V_H_AO_cfm, n_im)
     563              : 
     564              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     565              :       REAL(KIND=dp), INTENT(IN)                          :: n_re(:)
     566              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: V_H_AO_cfm
     567              :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: n_im(:)
     568              : 
     569              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_hartree_ri_rs_from_diag'
     570              : 
     571              :       INTEGER                                            :: handle
     572              :       TYPE(cp_cfm_type)                                  :: cfm_real_part
     573              :       TYPE(cp_fm_type)                                   :: fm_v
     574              : 
     575         1120 :       CALL timeset(routineN, handle)
     576              : 
     577         1120 :       CALL cp_fm_create(fm_v, bs_env%fm_s_Gamma%matrix_struct)
     578              : 
     579         1120 :       CALL hartree_potential_from_diag_ri_rs(bs_env, n_re, fm_v)
     580         1120 :       IF (PRESENT(n_im)) THEN
     581          640 :          CALL cp_cfm_create(cfm_real_part, bs_env%fm_s_Gamma%matrix_struct)
     582          640 :          CALL cp_fm_to_cfm(msourcer=fm_v, mtarget=cfm_real_part)
     583          640 :          CALL hartree_potential_from_diag_ri_rs(bs_env, n_im, fm_v)
     584          640 :          CALL cp_fm_to_cfm(msourcei=fm_v, mtarget=V_H_AO_cfm)
     585              :          CALL cp_cfm_scale_and_add(CMPLX(1.0_dp, 0.0_dp, kind=dp), V_H_AO_cfm, &
     586          640 :                                    CMPLX(1.0_dp, 0.0_dp, kind=dp), cfm_real_part)
     587          640 :          CALL cp_cfm_release(cfm_real_part)
     588              :       ELSE
     589          480 :          CALL cp_fm_to_cfm(msourcer=fm_v, mtarget=V_H_AO_cfm)
     590              :       END IF
     591              : 
     592         1120 :       CALL cp_fm_release(fm_v)
     593              : 
     594         1120 :       CALL timestop(handle)
     595              : 
     596         1120 :    END SUBROUTINE compute_hartree_ri_rs_from_diag
     597              : 
     598              : ! **************************************************************************************************
     599              : !> \brief Complex-input Hartree potential via RI-RS. Re/Im split: feed each part to the real
     600              : !>        compute_hartree_ri_rs and reassemble. Real-input Hartree on a non-Hermitian input
     601              : !>        would silently drop Im and break Hermitian conjugacy of OV+VO contributions in TDA.
     602              : !> \param bs_env ...
     603              : !> \param rho_AO_cfm input AO x AO complex density-like matrix
     604              : !> \param V_H_AO_cfm output AO x AO complex Hartree potential
     605              : ! **************************************************************************************************
     606          880 :    SUBROUTINE compute_hartree_ri_rs_complex(bs_env, rho_AO_cfm, V_H_AO_cfm)
     607              : 
     608              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     609              :       TYPE(cp_cfm_type), INTENT(IN)                      :: rho_AO_cfm
     610              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: V_H_AO_cfm
     611              : 
     612              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_hartree_ri_rs_complex'
     613              : 
     614              :       INTEGER                                            :: handle
     615              :       TYPE(cp_cfm_type)                                  :: cfm_real_part
     616              :       TYPE(cp_fm_type)                                   :: fm_rho, fm_v
     617              : 
     618          220 :       CALL timeset(routineN, handle)
     619              : 
     620          220 :       CALL cp_fm_create(fm_rho, bs_env%fm_s_Gamma%matrix_struct)
     621          220 :       CALL cp_fm_create(fm_v, bs_env%fm_s_Gamma%matrix_struct)
     622          220 :       CALL cp_cfm_create(cfm_real_part, bs_env%fm_s_Gamma%matrix_struct)
     623              : 
     624          220 :       CALL cp_cfm_to_fm(msource=rho_AO_cfm, mtargetr=fm_rho)
     625          220 :       CALL compute_hartree_ri_rs(bs_env, fm_rho, fm_v)
     626          220 :       CALL cp_fm_to_cfm(msourcer=fm_v, mtarget=cfm_real_part)
     627              : 
     628          220 :       CALL cp_cfm_to_fm(msource=rho_AO_cfm, mtargeti=fm_rho)
     629          220 :       CALL compute_hartree_ri_rs(bs_env, fm_rho, fm_v)
     630          220 :       CALL cp_fm_to_cfm(msourcei=fm_v, mtarget=V_H_AO_cfm)
     631              : 
     632              :       CALL cp_cfm_scale_and_add(CMPLX(1.0_dp, 0.0_dp, kind=dp), V_H_AO_cfm, &
     633          220 :                                 CMPLX(1.0_dp, 0.0_dp, kind=dp), cfm_real_part)
     634              : 
     635          220 :       CALL cp_fm_release(fm_rho)
     636          220 :       CALL cp_fm_release(fm_v)
     637          220 :       CALL cp_cfm_release(cfm_real_part)
     638              : 
     639          220 :       CALL timestop(handle)
     640              : 
     641          220 :    END SUBROUTINE compute_hartree_ri_rs_complex
     642              : 
     643              : ! **************************************************************************************************
     644              : !> \brief Scale each row of a dbcsr matrix by a replicated full-length vector:
     645              : !>        block(ir,ic) <- vec(global_row(ir)) * block(ir,ic). Value mutation only.
     646              : !> \param matrix ...
     647              : !> \param vec full-length replicated row-scaling vector
     648              : ! **************************************************************************************************
     649         2204 :    SUBROUTINE dbcsr_scale_rows_replicated(matrix, vec)
     650              : 
     651              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     652              :       REAL(KIND=dp), INTENT(IN)                          :: vec(:)
     653              : 
     654              :       INTEGER                                            :: col_blk, ic, ir, nblkrows_total, &
     655              :                                                             row_blk, row_off
     656         2204 :       INTEGER, ALLOCATABLE                               :: row_offset(:)
     657         2204 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_size
     658         2204 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: blk
     659              :       TYPE(dbcsr_iterator_type)                          :: iter
     660              : 
     661         2204 :       CALL dbcsr_get_info(matrix, nblkrows_total=nblkrows_total, row_blk_size=row_blk_size)
     662         6612 :       ALLOCATE (row_offset(nblkrows_total + 1))
     663         2204 :       row_offset(1) = 0
     664        25556 :       DO ir = 1, nblkrows_total
     665        25556 :          row_offset(ir + 1) = row_offset(ir) + row_blk_size(ir)
     666              :       END DO
     667              : 
     668         2204 :       CALL dbcsr_iterator_start(iter, matrix)
     669        25556 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     670        23352 :          CALL dbcsr_iterator_next_block(iter, row_blk, col_blk, blk)
     671        23352 :          row_off = row_offset(row_blk)
     672       165668 :          DO ic = 1, SIZE(blk, 2)
     673      4004424 :             DO ir = 1, SIZE(blk, 1)
     674      3981072 :                blk(ir, ic) = vec(row_off + ir)*blk(ir, ic)
     675              :             END DO
     676              :          END DO
     677              :       END DO
     678         2204 :       CALL dbcsr_iterator_stop(iter)
     679              : 
     680         2204 :       DEALLOCATE (row_offset)
     681              : 
     682         4408 :    END SUBROUTINE dbcsr_scale_rows_replicated
     683              : 
     684              : ! **************************************************************************************************
     685              : !> \brief Replicated matvec: vec_out = matrix * vec_in (or matrix^T * vec_in if transposed) for a
     686              : !>        possibly rectangular distributed dbcsr matrix and replicated full-length vectors.
     687              : !>        Iterates over local blocks and reduces.
     688              : !> \param matrix distributed dbcsr matrix (may be rectangular)
     689              : !> \param vec_in full input vector, replicated on all ranks (column length, or row length if transposed)
     690              : !> \param vec_out full output vector, replicated on all ranks (zeroed on entry; sum-reduced on exit)
     691              : !> \param para_env ...
     692              : !> \param transposed if .TRUE. compute vec_out = matrix^T * vec_in
     693              : ! **************************************************************************************************
     694         6612 :    SUBROUTINE dbcsr_matvec_replicated(matrix, vec_in, vec_out, para_env, transposed)
     695              : 
     696              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: matrix
     697              :       REAL(KIND=dp), INTENT(IN)                          :: vec_in(:)
     698              :       REAL(KIND=dp), INTENT(INOUT)                       :: vec_out(:)
     699              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     700              :       LOGICAL, INTENT(IN), OPTIONAL                      :: transposed
     701              : 
     702              :       INTEGER                                            :: col_blk, col_off, ic, ir, &
     703              :                                                             nblkcols_total, nblkrows_total, &
     704              :                                                             row_blk, row_off
     705         6612 :       INTEGER, ALLOCATABLE                               :: col_offset(:), row_offset(:)
     706         6612 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     707              :       LOGICAL                                            :: my_trans
     708         6612 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: block
     709              :       TYPE(dbcsr_iterator_type)                          :: iter
     710              : 
     711         6612 :       my_trans = .FALSE.
     712         2204 :       IF (PRESENT(transposed)) my_trans = transposed
     713              : 
     714              :       CALL dbcsr_get_info(matrix, nblkrows_total=nblkrows_total, &
     715              :                           nblkcols_total=nblkcols_total, &
     716         6612 :                           row_blk_size=row_blk_size, col_blk_size=col_blk_size)
     717              : 
     718        33060 :       ALLOCATE (row_offset(nblkrows_total + 1), col_offset(nblkcols_total + 1))
     719         6612 :       row_offset(1) = 0
     720        57724 :       DO ir = 1, nblkrows_total
     721        57724 :          row_offset(ir + 1) = row_offset(ir) + row_blk_size(ir)
     722              :       END DO
     723         6612 :       col_offset(1) = 0
     724        19836 :       DO ic = 1, nblkcols_total
     725        19836 :          col_offset(ic + 1) = col_offset(ic) + col_blk_size(ic)
     726              :       END DO
     727              : 
     728       849540 :       vec_out(:) = 0.0_dp
     729              : 
     730         6612 :       CALL dbcsr_iterator_start(iter, matrix)
     731        57724 :       DO WHILE (dbcsr_iterator_blocks_left(iter))
     732        51112 :          CALL dbcsr_iterator_next_block(iter, row_blk, col_blk, block)
     733        51112 :          row_off = row_offset(row_blk)
     734        51112 :          col_off = col_offset(col_blk)
     735        57724 :          IF (my_trans) THEN
     736       560448 :             DO ic = 1, SIZE(block, 2)
     737     15284128 :                DO ir = 1, SIZE(block, 1)
     738              :                   vec_out(col_off + ic) = vec_out(col_off + ic) + &
     739     15260776 :                                           block(ir, ic)*vec_in(row_off + ir)
     740              :                END DO
     741              :             END DO
     742              :          ELSE
     743       666240 :             DO ic = 1, SIZE(block, 2)
     744     17721752 :                DO ir = 1, SIZE(block, 1)
     745              :                   vec_out(row_off + ir) = vec_out(row_off + ir) + &
     746     17693992 :                                           block(ir, ic)*vec_in(col_off + ic)
     747              :                END DO
     748              :             END DO
     749              :          END IF
     750              :       END DO
     751         6612 :       CALL dbcsr_iterator_stop(iter)
     752              : 
     753         6612 :       DEALLOCATE (row_offset, col_offset)
     754              : 
     755      1692468 :       CALL para_env%sum(vec_out)
     756              : 
     757        15428 :    END SUBROUTINE dbcsr_matvec_replicated
     758              : 
     759              : END MODULE rt_bse_ri_rs
        

Generated by: LCOV version 2.0-1