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

Generated by: LCOV version 2.0-1