LCOV - code coverage report
Current view: top level - src - gw_ri_rs_large_cell_gamma.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:92574dc) Lines: 7.7 % 426 33
Test Date: 2026-09-24 01:27:39 Functions: 18.2 % 11 2

            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 GW using RI-RS Approximation for molecules
      10              : !> \par History
      11              : !>      04.2026 created [Ritaj Tyagi]
      12              : ! **************************************************************************************************
      13              : MODULE gw_ri_rs_large_cell_Gamma
      14              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      15              :    USE basis_set_types,                 ONLY: gto_basis_set_type
      16              :    USE cell_types,                      ONLY: cell_type,&
      17              :                                               get_cell,&
      18              :                                               pbc
      19              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      20              :                                               cp_blacs_env_release,&
      21              :                                               cp_blacs_env_type
      22              :    USE cp_dbcsr_api,                    ONLY: &
      23              :         dbcsr_add, dbcsr_binary_read, dbcsr_binary_write, dbcsr_create, dbcsr_distribution_get, &
      24              :         dbcsr_distribution_new, dbcsr_distribution_release, dbcsr_distribution_type, &
      25              :         dbcsr_finalize, dbcsr_get_info, dbcsr_p_type, dbcsr_put_block, dbcsr_release, dbcsr_scale, &
      26              :         dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      27              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      28              :                                               copy_fm_to_dbcsr,&
      29              :                                               dbcsr_deallocate_matrix_set,&
      30              :                                               max_elements_per_block
      31              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_type
      32              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      33              :                                               cp_fm_release,&
      34              :                                               cp_fm_type
      35              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      36              :                                               cp_logger_type
      37              :    USE cp_output_handling,              ONLY: cp_p_file,&
      38              :                                               cp_print_key_should_output
      39              :    USE gw_ri_rs_compute_Z_lP_utils,     ONLY: build_gram_jacobi_blas,&
      40              :                                               build_jacobi_diag_from_phi,&
      41              :                                               scale_rows_by_diag,&
      42              :                                               solve_D_lp_distributed,&
      43              :                                               store_Z_lP_columns
      44              :    USE gw_ri_rs_grid_setup_main,        ONLY: setup_ri_rs_grid
      45              :    USE gw_ri_rs_utils,                  ONLY: precompute_ri_rs_radii
      46              :    USE gw_tensor_large_cell_Gamma,      ONLY: G_occ_vir,&
      47              :                                               compute_QP_energies,&
      48              :                                               delete_unnecessary_files,&
      49              :                                               fill_fm_Sigma_c_Gamma_time,&
      50              :                                               get_W_MIC
      51              :    USE gw_utils,                        ONLY: de_init_bs_env
      52              :    USE gw_utils_compute_integrals,      ONLY: build_3c_integral_block_ctx,&
      53              :                                               gw_3c_ctx_create,&
      54              :                                               gw_3c_ctx_release,&
      55              :                                               gw_3c_ctx_type,&
      56              :                                               gw_3c_ws_create,&
      57              :                                               gw_3c_ws_release,&
      58              :                                               gw_3c_ws_type
      59              :    USE gw_utils_dbcsr,                  ONLY: dbcsr_contract_ABA,&
      60              :                                               hadamard_product
      61              :    USE gw_utils_fm,                     ONLY: fm_contract_ABA
      62              :    USE input_section_types,             ONLY: section_vals_type
      63              :    USE kinds,                           ONLY: dp
      64              :    USE machine,                         ONLY: m_walltime
      65              :    USE message_passing,                 ONLY: mp_para_env_type
      66              :    USE mp2_ri_2c,                       ONLY: RI_2c_integral_mat
      67              :    USE orbital_pointers,                ONLY: indco,&
      68              :                                               ncoset
      69              :    USE particle_types,                  ONLY: particle_type
      70              :    USE post_scf_bandstructure_types,    ONLY: post_scf_bandstructure_type
      71              :    USE qs_environment_types,            ONLY: get_qs_env,&
      72              :                                               qs_environment_type
      73              : #include "./base/base_uses.f90"
      74              : 
      75              :    IMPLICIT NONE
      76              : 
      77              :    PRIVATE
      78              : 
      79              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gw_ri_rs_large_cell_Gamma'
      80              : 
      81              :    PUBLIC :: gw_calc_ri_rs_large_cell_Gamma, &
      82              :              release_dbcsr_topology_and_matrices, &
      83              :              setup_square_topology
      84              : 
      85              : CONTAINS
      86              : 
      87              : ! **************************************************************************************************
      88              : !> \brief GW calculation using RI-RS formalism for molecules
      89              : !> \param qs_env ...
      90              : !> \param bs_env Band-structure environment containing GW parameters.
      91              : ! **************************************************************************************************
      92              : 
      93            0 :    SUBROUTINE gw_calc_ri_rs_large_cell_Gamma(qs_env, bs_env)
      94              : 
      95              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      96              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
      97              : 
      98              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'gw_calc_ri_rs_large_cell_Gamma'
      99              : 
     100              :       INTEGER                                            :: handle
     101            0 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_Sigma_x_Gamma, fm_W_time
     102            0 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :, :)  :: fm_Sigma_c_Gamma_time
     103              : 
     104            0 :       CALL timeset(routineN, handle)
     105              : 
     106              :        !!========================================================================
     107              :        !! 0. Precompute AO and RI Radii
     108              :        !!    Per-atom cutoff radii from the most diffuse Gaussian primitives in
     109              :        !!    the AO and RI auxiliary basis sets. Stored in bs_env%ri_rs%
     110              :        !!    radius_ao_per_atom and radius_ri_per_atom, used for sphere-cutoff
     111              :        !!    and phi_local screening.
     112              :        !!========================================================================
     113            0 :       CALL precompute_ri_rs_radii(bs_env)
     114              : 
     115              :        !!========================================================================
     116              :        !! 1. Grid Generation for RI-RS
     117              :        !!    (Modified Lebedev grids from Ivan Duchemin and Xavier Blase)
     118              :        !!    Generate flattened 1D array of grid points for RI-RS.
     119              :        !!    Equation: r_g(k) = R_A + r_g(A)
     120              :        !!========================================================================
     121            0 :       CALL setup_ri_rs_grid(bs_env, bs_env%ri_rs%grid_points)
     122              : 
     123              :        !!========================================================================
     124              :        !! 2. Atomic Basis Evaluation
     125              :        !!    Compute values of spherical atomic basis functions at grid points.
     126              :        !!    Expression: ϕ_μl = ϕ_μ(r_l) (mat_phi_mu_l)
     127              :        !!========================================================================
     128              :       CALL atomic_basis_at_grid_point(bs_env, bs_env%ri_rs%grid_points, &
     129            0 :                                       bs_env%ri_rs%mat_phi_mu_l)
     130              : 
     131              :        !!========================================================================
     132              :        !! 3. Compute RI-RS Coefficients (Z_lp)
     133              :        !!    Solve the regularized system for each atom P, where the grid domain
     134              :        !!    is restricted to r_l within a cutoff distance of atom P:
     135              :        !!    a. D_ll' = [ Σ_μ ϕ_μ(r_l) ϕ_μ(r_l') ]^2 (Equation 13)
     136              :        !!    b. D_lP  = Σ_{μν} ϕ_μ(r_l) ϕ_ν(r_l) (μν|P) (Equation 15)
     137              :        !!    c. Conditioning:
     138              :        !!       Dvec_l   = 1 / sqrt(D_ll)  (Diagonal scaling vector)
     139              :        !!       D'_ll' = Dvec_l * D_ll' * Dvec_l' + λδ_ll'
     140              :        !!       D'_lP  = Dvec_l * D_lP
     141              :        !!    d. Solve: Σ_l' D'_ll' * Z'_l'P = D'_lP (Equation 14)
     142              :        !!    e. Rescale: Z_lP = Z'_lP * Dvec_l   (Z_lP stored in mat_Z_lP)
     143              :        !!========================================================================
     144              :       CALL compute_Z_lP(qs_env, bs_env, bs_env%ri_rs%grid_points, &
     145            0 :                         bs_env%ri_rs%mat_phi_mu_l, bs_env%ri_rs%mat_Z_lP)
     146            0 :       bs_env%ri_rs%grid_built = .TRUE.
     147              : 
     148              :        !!========================================================================
     149              :        !! 4. Compute Independent-Particle Polarizability (χ)
     150              :        !!    G^occ_µλ(i|τ|)  = sum_n^occ C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
     151              :        !!    G^vir_µλ(i|τ|)  = sum_n^vir C_µn e^(-|(ϵ_n-ϵ_F)τ|) C_λn
     152              :        !!    G^occ_ll'(i|τ|) = sum_µν ϕ_µ(r_l) G^occ_µν ϕ_ν(r_l')
     153              :        !!    G^vir_ll'(i|τ|) = sum_µν ϕ_µ(r_l) G^vir_µν ϕ_ν(r_l')
     154              :        !!    χ_ll'(iτ)       = G^occ_ll'(i|τ|) * G^vir_ll'(i|τ|)
     155              :        !!    χ_PQ(iτ)        = sum_ll' Z_lP χ_ll'(iτ) Z_l'Q
     156              :        !!========================================================================
     157              :       CALL get_mat_chi_Gamma_tau(bs_env, bs_env%mat_chi_Gamma_tau, &
     158            0 :                                  bs_env%ri_rs%mat_phi_mu_l, bs_env%ri_rs%mat_Z_lP)
     159              : 
     160              :        !!========================================================================
     161              :        !! 5. Compute Screened Interaction (W^MIC)
     162              :        !!    χ_PQ(iτ) -> χ_PQ(iω) -> ε_PQ(iω) -> W_PQ(iω) -> W^MIC_PQ(iτ)
     163              :        !!========================================================================
     164            0 :       CALL get_W_MIC(bs_env, qs_env, bs_env%mat_chi_Gamma_tau, fm_W_time)
     165              : 
     166              :        !!========================================================================
     167              :        !! 6. Compute Exact Exchange Self-Energy (Σ^x)
     168              :        !!    D_µν          = sum_n^occ C_µn C_νn
     169              :        !!    D_ll'         = sum_µν ϕ_µ(r_l) D_µν ϕ_ν(r_l')
     170              :        !!    V^trunc_ll'   = sum_PQ Z_lP V^trunc_PQ Z_l'Q
     171              :        !!    Σ^x_ll'       = D_ll' * V^trunc_ll'
     172              :        !!    Σ^x_λσ(k=0)   = -sum_ll' ϕ_λ(r_l) Σ^x_ll' ϕ_σ(r_l')
     173              :        !!========================================================================
     174              :       CALL compute_Sigma_x(bs_env, qs_env, bs_env%ri_rs%mat_phi_mu_l, &
     175            0 :                            bs_env%ri_rs%mat_Z_lP, fm_Sigma_x_Gamma)
     176              : 
     177              :        !!========================================================================
     178              :        !! 7. Compute Correlation Self-Energy (Σ^c)
     179              :        !!    W^MIC_ll'(iτ) =  sum_PQ Z_lP W^MIC_PQ(iτ) Z_l'Q
     180              :        !!    Σ^c_ll'(iτ)   = -G^occ_ll'(i|τ|) * W^MIC_ll'(iτ), for τ < 0
     181              :        !!    Σ^c_ll'(iτ)   =  G^vir_ll'(i|τ|) * W^MIC_ll'(iτ), for τ > 0
     182              :        !!    Σ^c_λσ(iτ)    =  sum_ll' ϕ_λ(r_l) Σ^c_ll'(iτ) ϕ_σ(r_l')
     183              :        !!========================================================================
     184              :       CALL compute_Sigma_c(bs_env, fm_W_time, bs_env%ri_rs%mat_phi_mu_l, &
     185            0 :                            bs_env%ri_rs%mat_Z_lP, fm_Sigma_c_Gamma_time)
     186              : 
     187              :        !!========================================================================
     188              :        !! 8. Compute Quasiparticle Energies
     189              :        !!    Σ^c_λσ(iτ) -> Σ^c_nn(ϵ)
     190              :        !!    ϵ_nk^GW = ϵ_nk^DFT + Σ^c_nn(ϵ) + Σ^x_nn - v^xc_nn
     191              :        !!========================================================================
     192            0 :       CALL compute_QP_energies(bs_env, qs_env, fm_Sigma_x_Gamma, fm_Sigma_c_Gamma_time)
     193              : 
     194            0 :       CALL de_init_bs_env(qs_env, bs_env)
     195              : 
     196            0 :       CALL timestop(handle)
     197              : 
     198            0 :    END SUBROUTINE gw_calc_ri_rs_large_cell_Gamma
     199              : 
     200              : ! **************************************************************************************************
     201              : !> \brief Evaluates atomic basis functions on a real-space grid and builds a sparse DBCSR matrix.
     202              : !> \param bs_env ...
     203              : !> \param ri_rs_grid_points ...
     204              : !> \param mat_phi_mu_l ...
     205              : ! **************************************************************************************************
     206              : 
     207            0 :    SUBROUTINE atomic_basis_at_grid_point(bs_env, ri_rs_grid_points, mat_phi_mu_l)
     208              : 
     209              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     210              :       REAL(KIND=dp), ALLOCATABLE, INTENT(INOUT)          :: ri_rs_grid_points(:, :)
     211              :       TYPE(dbcsr_type), INTENT(OUT)                      :: mat_phi_mu_l
     212              : 
     213              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'atomic_basis_at_grid_point'
     214              : 
     215              :       INTEGER                                            :: c_size, chunk_size, handle, i, i_blk, &
     216              :                                                             iatom, natom, npcol, nprow, &
     217              :                                                             num_grid_chunks, r_end, r_start
     218            0 :       INTEGER, DIMENSION(:), POINTER                     :: col_dist, r_blk_sizes, row_dist, sizes_AO
     219            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: atom_col_buffer
     220              :       TYPE(cell_type), POINTER                           :: cell
     221              :       TYPE(dbcsr_distribution_type)                      :: dbcsr_dist_ks, dist
     222              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     223            0 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     224              : 
     225            0 :       CALL timeset(routineN, handle)
     226              : 
     227              :       ! Setup Grid Blocking
     228            0 :       chunk_size = max_elements_per_block
     229              : 
     230            0 :       natom = bs_env%n_atom
     231            0 :       cell => bs_env%ri_rs%cell
     232            0 :       para_env => bs_env%para_env
     233            0 :       particle_set => bs_env%ri_rs%particle_set
     234            0 :       sizes_AO => bs_env%sizes_AO
     235            0 :       CPASSERT(ASSOCIATED(cell))
     236            0 :       CPASSERT(ASSOCIATED(para_env))
     237            0 :       CPASSERT(ASSOCIATED(particle_set))
     238            0 :       CPASSERT(SIZE(sizes_AO) == natom)
     239            0 :       CPASSERT(SIZE(ri_rs_grid_points, 2) == bs_env%ri_rs%n_grid_points)
     240              : 
     241              :       ! =========================================================================
     242              :       ! 1. SETUP DBCSR MATRIX TOPOLOGY
     243              :       ! =========================================================================
     244              : 
     245              :       ! B. Define Row Block Sizes (Grid chunks of max size 256)
     246            0 :       num_grid_chunks = CEILING(REAL(bs_env%ri_rs%n_grid_points, KIND=dp)/REAL(chunk_size, KIND=dp))
     247            0 :       ALLOCATE (r_blk_sizes(num_grid_chunks))
     248            0 :       r_blk_sizes = chunk_size
     249            0 :       IF (MOD(bs_env%ri_rs%n_grid_points, chunk_size) /= 0) THEN
     250            0 :          r_blk_sizes(num_grid_chunks) = MOD(bs_env%ri_rs%n_grid_points, chunk_size)
     251              :       END IF
     252              : 
     253              :       ! C. Fetch CP2K's Default Process Grid Configuration
     254            0 :       CALL dbcsr_get_info(bs_env%mat_ao_ao%matrix, distribution=dbcsr_dist_ks)
     255            0 :       CALL dbcsr_distribution_get(dbcsr_dist_ks, nprows=nprow, npcols=npcol)
     256              : 
     257              :       ! D. Build Custom Mappings using Round-Robin across the 2D process grid
     258              : 
     259            0 :       ALLOCATE (row_dist(num_grid_chunks))
     260            0 :       DO i = 1, num_grid_chunks
     261            0 :          row_dist(i) = MOD(i - 1, nprow)
     262              :       END DO
     263              : 
     264            0 :       ALLOCATE (col_dist(natom))
     265            0 :       DO i = 1, natom
     266            0 :          col_dist(i) = MOD(i - 1, npcol)
     267              :       END DO
     268              : 
     269              :       ! E. Create the DBCSR Distribution and Initialize the Matrix
     270              :       CALL dbcsr_distribution_new(dist, template=dbcsr_dist_ks, &
     271            0 :                                   row_dist=row_dist, col_dist=col_dist)
     272              : 
     273              :       CALL dbcsr_create(mat_phi_mu_l, name="phi_val_sparse", dist=dist, &
     274              :                         matrix_type=dbcsr_type_no_symmetry, &
     275            0 :                         row_blk_size=r_blk_sizes, col_blk_size=sizes_AO)
     276              : 
     277              :       ! =========================================================================
     278              :       ! 2. STREAM DATA DIRECTLY INTO SPARSE MATRIX
     279              :       ! =========================================================================
     280              :       ! Iterate over the atoms assigned to this specific MPI rank
     281            0 :       DO iatom = para_env%mepos + 1, natom, para_env%num_pe
     282              : 
     283            0 :          c_size = sizes_AO(iatom)
     284              : 
     285              :          ! Allocate a temporary dense buffer just for this specific atom
     286            0 :          ALLOCATE (atom_col_buffer(bs_env%ri_rs%n_grid_points, c_size))
     287            0 :          atom_col_buffer = 0.0_dp
     288              : 
     289              :          ! Evaluate the basis functions on the grid. Skip grid points outside the spatial
     290              :          ! extent of the most diffuse AO Gaussian on iatom; beyond that radius the contribution
     291              :          ! is guaranteed below eps_filter.
     292              :          CALL fill_phi_for_atom(atom_col_buffer, ri_rs_grid_points, bs_env%ri_rs%n_grid_points, &
     293              :                                 iatom, bs_env, &
     294            0 :                                 r2_threshold=bs_env%ri_rs%radius_ao_per_atom(iatom)**2)
     295              : 
     296              :          ! Slice the dense column into chunks and insert into DBCSR
     297            0 :          DO i_blk = 1, num_grid_chunks
     298            0 :             r_start = (i_blk - 1)*chunk_size + 1
     299            0 :             r_end = MIN(i_blk*chunk_size, bs_env%ri_rs%n_grid_points)
     300              : 
     301              :             ! Apply dynamic sparsity filtering: Only store blocks with physical significance
     302            0 :             IF (MAXVAL(ABS(atom_col_buffer(r_start:r_end, 1:c_size))) > bs_env%eps_filter) THEN
     303              :                CALL dbcsr_put_block(mat_phi_mu_l, row=i_blk, col=iatom, &
     304            0 :                                     block=atom_col_buffer(r_start:r_end, 1:c_size))
     305              :             END IF
     306              :          END DO
     307              : 
     308            0 :          DEALLOCATE (atom_col_buffer)
     309              : 
     310              :       END DO
     311              : 
     312              :       ! Finalize triggers internal MPI communication to route blocks to their correct 2D process owners
     313            0 :       CALL dbcsr_finalize(mat_phi_mu_l)
     314              : 
     315            0 :       IF (bs_env%unit_nr > 0) THEN
     316            0 :          WRITE (bs_env%unit_nr, *) "Done with evaluation of phi"
     317              :       END IF
     318              : 
     319              :       ! -------------------------------------------------------------------------
     320              :       ! CLEANUP
     321              :       ! -------------------------------------------------------------------------
     322            0 :       DEALLOCATE (r_blk_sizes, row_dist, col_dist)
     323            0 :       CALL dbcsr_distribution_release(dist)
     324              : 
     325            0 :       CALL timestop(handle)
     326              : 
     327            0 :    END SUBROUTINE atomic_basis_at_grid_point
     328              : 
     329              : ! **************************************************************************************************
     330              : !> \brief Compute value of all basis functions for a single atom across all grid points.
     331              : !>        Sums contributions from periodic images of `iatom` (loop over (ix, iy, iz) cells gated
     332              : !>        by `cell%perd`). Each per-image squared distance is compared against `r2_threshold`
     333              : !>        (per-atom AO Gaussian extent²); images beyond that radius contribute below eps_filter
     334              : !>        and are skipped.
     335              : !> \param phi_val ...
     336              : !> \param ri_rs_grid ...
     337              : !> \param npts ...
     338              : !> \param iatom ...
     339              : !> \param bs_env ...
     340              : !> \param r2_threshold per-image squared-distance threshold; CYCLE if r² > r2_threshold. Pass
     341              : !>        HUGE(1.0_dp) to disable.
     342              : ! **************************************************************************************************
     343              : 
     344            0 :    SUBROUTINE fill_phi_for_atom(phi_val, ri_rs_grid, npts, iatom, bs_env, r2_threshold)
     345              : 
     346              :       REAL(KIND=dp), INTENT(INOUT)                       :: phi_val(:, :)
     347              :       INTEGER, INTENT(IN)                                :: npts
     348              :       REAL(KIND=dp), INTENT(IN)                          :: ri_rs_grid(3, npts)
     349              :       INTEGER, INTENT(IN)                                :: iatom
     350              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     351              :       REAL(KIND=dp), INTENT(IN)                          :: r2_threshold
     352              : 
     353              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'fill_phi_for_atom'
     354              : 
     355              :       INTEGER :: first_sgf, handle, i_pt, ico, iend_co, ikind, ipgf, iset, isgf, ishell, &
     356              :          istart_co, ix, ix_max, ix_min, iy, iy_max, iy_min, iz, iz_max, iz_min, l, last_sgf, lx, &
     357              :          ly, lz, n_cart_total, row_idx
     358              :       REAL(KIND=dp)                                      :: alpha, cell_vector(3), dist_vec(3), &
     359              :                                                             dist_vec_raw(3), exp_val, poly, r2, &
     360              :                                                             r_atom(3), weight
     361              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: hmat
     362              :       TYPE(cell_type), POINTER                           :: cell
     363              :       TYPE(gto_basis_set_type), POINTER                  :: orb_basis_set
     364            0 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     365              : 
     366            0 :       CALL timeset(routineN, handle)
     367              : 
     368              :       ! Get Atom Info
     369            0 :       cell => bs_env%ri_rs%cell
     370            0 :       particle_set => bs_env%ri_rs%particle_set
     371            0 :       ikind = particle_set(iatom)%atomic_kind%kind_number
     372            0 :       orb_basis_set => bs_env%basis_set_AO(ikind)%gto_basis_set
     373            0 :       CALL get_cell(cell=cell, h=hmat)
     374            0 :       CPASSERT(ASSOCIATED(orb_basis_set))
     375              : 
     376            0 :       IF (cell%perd(1) == 1) THEN; ix_min = -1; ix_max = 1; ELSE; ix_min = 0; ix_max = 0
     377              :       END IF
     378            0 :       IF (cell%perd(2) == 1) THEN; iy_min = -1; iy_max = 1; ELSE; iy_min = 0; iy_max = 0
     379              :       END IF
     380            0 :       IF (cell%perd(3) == 1) THEN; iz_min = -1; iz_max = 1; ELSE; iz_min = 0; iz_max = 0
     381              :       END IF
     382              : 
     383            0 :       r_atom = particle_set(iatom)%r
     384              : 
     385              :       !$OMP PARALLEL DO DEFAULT(NONE) &
     386              :       !$OMP SHARED(phi_val, ri_rs_grid, npts, orb_basis_set, r_atom, hmat, &
     387              :       !$OMP        ncoset, indco, cell, ix_min, ix_max, &
     388              :       !$OMP        iy_min, iy_max, iz_min, iz_max, r2_threshold) &
     389              :       !$OMP PRIVATE(i_pt, dist_vec_raw, ix, iy, iz, cell_vector, dist_vec, r2, iset, &
     390              :       !$OMP         n_cart_total, ishell, l, istart_co, iend_co, first_sgf, last_sgf, &
     391              :       !$OMP         ipgf, alpha, exp_val, isgf, ico, row_idx, weight, lx, ly, lz, poly) &
     392            0 :       !$OMP SCHEDULE(DYNAMIC)
     393              : 
     394              :       DO i_pt = 1, npts
     395              : 
     396              :          dist_vec_raw = ri_rs_grid(:, i_pt) - r_atom
     397              : 
     398              :          DO ix = ix_min, ix_max
     399              :          DO iy = iy_min, iy_max
     400              :          DO iz = iz_min, iz_max
     401              : 
     402              :             cell_vector(1:3) = MATMUL(hmat, REAL([ix, iy, iz], dp))
     403              : 
     404              :             dist_vec = dist_vec_raw - cell_vector
     405              : 
     406              :             r2 = DOT_PRODUCT(dist_vec, dist_vec)
     407              : 
     408              :             IF (r2 > r2_threshold) CYCLE
     409              : 
     410              :             DO iset = 1, orb_basis_set%nset
     411              :                n_cart_total = ncoset(orb_basis_set%lmax(iset))
     412              : 
     413              :                DO ishell = 1, orb_basis_set%nshell(iset)
     414              :                   l = orb_basis_set%l(ishell, iset)
     415              :                   istart_co = ncoset(l - 1) + 1
     416              :                   iend_co = ncoset(l)
     417              : 
     418              :                   first_sgf = orb_basis_set%first_sgf(ishell, iset)
     419              :                   last_sgf = orb_basis_set%last_sgf(ishell, iset)
     420              : 
     421              :                   DO ipgf = 1, orb_basis_set%npgf(iset)
     422              :                      alpha = orb_basis_set%zet(ipgf, iset)
     423              :                      exp_val = EXP(-alpha*r2)
     424              : 
     425              :                      DO isgf = first_sgf, last_sgf
     426              :                         DO ico = istart_co, iend_co
     427              :                            row_idx = (ipgf - 1)*n_cart_total + ico
     428              :                            weight = orb_basis_set%sphi(row_idx, isgf)
     429              :                            lx = indco(1, ico)
     430              :                            ly = indco(2, ico)
     431              :                            lz = indco(3, ico)
     432              :                            poly = (dist_vec(1)**lx)*(dist_vec(2)**ly)*(dist_vec(3)**lz)
     433              : 
     434              :                            phi_val(i_pt, isgf) = phi_val(i_pt, isgf) + (weight*poly*exp_val)
     435              : 
     436              :                         END DO
     437              :                      END DO
     438              :                   END DO
     439              :                END DO
     440              :             END DO
     441              :          END DO
     442              :          END DO
     443              :          END DO
     444              :       END DO
     445              :       !$OMP END PARALLEL DO
     446              : 
     447            0 :       CALL timestop(handle)
     448              : 
     449            0 :    END SUBROUTINE fill_phi_for_atom
     450              : 
     451              : ! **************************************************************************************************
     452              : !> \brief Compute RI-RS Coefficients (Z_lP)
     453              : !> \param qs_env ...
     454              : !> \param bs_env ...
     455              : !> \param ri_rs_grid_points ...
     456              : !> \param mat_phi_mu_l ...
     457              : !> \param mat_Z_lP ...
     458              : ! **************************************************************************************************
     459              : 
     460            0 :    SUBROUTINE compute_Z_lP(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
     461              : 
     462              :       ! Arguments
     463              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     464              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     465              :       REAL(KIND=dp), ALLOCATABLE, INTENT(INOUT)          :: ri_rs_grid_points(:, :)
     466              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_phi_mu_l
     467              :       TYPE(dbcsr_type), INTENT(OUT)                      :: mat_Z_lP
     468              : 
     469              :       CHARACTER(LEN=*), PARAMETER :: key = 'PROPERTIES%BANDSTRUCTURE%GW%PRINT%RESTART', &
     470              :          routineN = 'compute_Z_lP'
     471              : 
     472              :       INTEGER :: atom_j_mepos, atom_j_stride, atom_P, atom_P_start, atom_P_stride, col_end, &
     473              :          col_start, group_handle, handle, handle_dpotrf, handle_dpotrs, i_blk, ikind, info, j, l, &
     474              :          loc_idx, max_ao_size, max_loc_ri, my_group, n_ao_total, n_grid_total, n_groups, n_loc_ri, &
     475              :          n_local_grid, n_procs_per_atom, natom, nkind, npcol_phi, num_grid_chunks, P_loop_atom, &
     476              :          ri_atom
     477            0 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: local_grid_idx, row_offset
     478            0 :       INTEGER, DIMENSION(:), POINTER                     :: col_dist_ri, r_blk_sizes, ri_blk_sizes, &
     479            0 :                                                             row_dist_grid
     480              :       REAL(KIND=dp)                                      :: cutoff_ri, cutoff_ri_2, d_sP, dist2_min, &
     481              :                                                             r2_threshold, r_c, t1, t2, t3
     482            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cutoff_ri_per_atom, cutoff_ri_per_kind, &
     483            0 :                                                             d_vec_local
     484            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: D_local, d_lp_local, phi_local, &
     485            0 :                                                             sphere_grid
     486              :       REAL(KIND=dp), DIMENSION(3)                        :: dist_vec_raw, pos_P
     487            0 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     488              :       TYPE(cell_type), POINTER                           :: cell
     489              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_sub
     490              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_b, fm_struct_D
     491              :       TYPE(cp_fm_type)                                   :: fm_b, fm_D
     492              :       TYPE(cp_logger_type), POINTER                      :: logger
     493              :       TYPE(dbcsr_distribution_type)                      :: dist_phi, dist_Z
     494            0 :       TYPE(gw_3c_ctx_type)                               :: ctx_3c
     495              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_sub
     496            0 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     497              :       TYPE(section_vals_type), POINTER                   :: input
     498              : 
     499            0 :       CALL timeset(routineN, handle)
     500              : 
     501            0 :       t1 = m_walltime()
     502              : 
     503            0 :       CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, input=input, cell=cell)
     504            0 :       atomic_kind_set => bs_env%ri_rs%atomic_kind_set
     505              : 
     506              :       ! ---------------------------------------------------------------------
     507              :       ! Subgroup setup. Default G=1 keeps the single-rank BLAS path; G>1 splits
     508              :       ! ranks into atom-groups so the Cholesky on D_local distributes across G
     509              :       ! ranks (memory ~1/G) and the compute_d_lp build also splits across the
     510              :       ! subgroup. G=1 leaves para_env_sub / blacs_env_sub NULL — no subgroup
     511              :       ! comms created, atom_P loop uses per-rank round-robin, compute_d_lp runs
     512              :       ! its full atom_j range on each rank, no allreduce.
     513              :       ! ---------------------------------------------------------------------
     514            0 :       n_procs_per_atom = MIN(bs_env%ri_rs%n_procs_per_atom_z_lp, para_env%num_pe)
     515            0 :       IF (n_procs_per_atom < 1) n_procs_per_atom = 1
     516              : 
     517            0 :       NULLIFY (para_env_sub, blacs_env_sub)
     518            0 :       IF (n_procs_per_atom > 1) THEN
     519            0 :          n_groups = para_env%num_pe/n_procs_per_atom
     520            0 :          my_group = MIN(para_env%mepos/n_procs_per_atom, n_groups - 1)
     521            0 :          ALLOCATE (para_env_sub)
     522            0 :          CALL para_env_sub%from_split(para_env, my_group)
     523            0 :          CALL cp_blacs_env_create(blacs_env=blacs_env_sub, para_env=para_env_sub)
     524            0 :          atom_P_start = my_group + 1
     525            0 :          atom_P_stride = n_groups
     526            0 :          atom_j_mepos = para_env_sub%mepos
     527            0 :          atom_j_stride = para_env_sub%num_pe
     528              :       ELSE
     529            0 :          atom_P_start = para_env%mepos + 1
     530            0 :          atom_P_stride = para_env%num_pe
     531            0 :          atom_j_mepos = 0
     532            0 :          atom_j_stride = 1
     533              :       END IF
     534              : 
     535            0 :       natom = bs_env%n_atom
     536            0 :       n_ao_total = bs_env%i_ao_end_from_atom(natom)
     537            0 :       n_grid_total = bs_env%ri_rs%n_grid_points
     538            0 :       CPASSERT(SIZE(ri_rs_grid_points, 2) == n_grid_total)
     539              : 
     540              :       ! =========================================================================
     541              :       ! 1. SETUP DBCSR TOPOLOGY & EXACT OFFSETS
     542              :       ! =========================================================================
     543            0 :       CALL dbcsr_get_info(mat_phi_mu_l, row_blk_size=r_blk_sizes, distribution=dist_phi)
     544              :       CALL dbcsr_distribution_get(dist_phi, row_dist=row_dist_grid, &
     545            0 :                                   group=group_handle, npcols=npcol_phi)
     546              : 
     547            0 :       num_grid_chunks = SIZE(r_blk_sizes)
     548              : 
     549            0 :       ALLOCATE (row_offset(num_grid_chunks))
     550            0 :       row_offset(1) = 0
     551            0 :       DO i_blk = 2, num_grid_chunks
     552            0 :          row_offset(i_blk) = row_offset(i_blk - 1) + r_blk_sizes(i_blk - 1)
     553              :       END DO
     554              : 
     555            0 :       ALLOCATE (ri_blk_sizes(natom), col_dist_ri(natom))
     556            0 :       DO atom_P = 1, natom
     557            0 :          ri_blk_sizes(atom_P) = bs_env%i_RI_end_from_atom(atom_P) - bs_env%i_RI_start_from_atom(atom_P) + 1
     558            0 :          col_dist_ri(atom_P) = MOD(atom_P - 1, npcol_phi)
     559              :       END DO
     560              : 
     561            0 :       CALL dbcsr_distribution_new(dist_Z, template=dist_phi, row_dist=row_dist_grid, col_dist=col_dist_ri)
     562              : 
     563            0 :       IF (bs_env%ri_rs%Z_lP_exists) THEN
     564              :          CALL dbcsr_binary_read(filepath=TRIM(bs_env%prefix)//"Z_lP.matrix", &
     565              :                                 distribution=dist_Z, &
     566            0 :                                 matrix_new=mat_Z_lP)
     567            0 :          IF (bs_env%unit_nr > 0) THEN
     568              :             WRITE (bs_env%unit_nr, '(T2,A,T57,A,F7.1,A)') &
     569            0 :                'Read Z_lP from file ', ' Execution time', m_walltime() - t1, ' s'
     570            0 :             WRITE (bs_env%unit_nr, '(A)') ' '
     571              :          END IF
     572              :       ELSE
     573              : 
     574              :          CALL dbcsr_create(mat_Z_lP, name="mat_Z_lP", dist=dist_Z, &
     575              :                            matrix_type=dbcsr_type_no_symmetry, &
     576            0 :                            row_blk_size=r_blk_sizes, col_blk_size=ri_blk_sizes)
     577              : 
     578            0 :          max_ao_size = 0
     579            0 :          DO j = 1, natom
     580            0 :             max_ao_size = MAX(max_ao_size, bs_env%i_ao_end_from_atom(j) - bs_env%i_ao_start_from_atom(j) + 1)
     581              :          END DO
     582            0 :          max_loc_ri = MAXVAL(ri_blk_sizes)
     583              : 
     584              :          ! Per-atom RI-RS integration sphere:
     585              :          !   cutoff_ri(P) = r_c + r_AO(P)
     586              :          ! where r_c is the truncated-Coulomb cutoff of the RI metric. The
     587              :          ! CUTOFF_RADIUS_RI_RS keyword (when > 0) overrides the entire cutoff calculation.
     588            0 :          nkind = SIZE(atomic_kind_set)
     589            0 :          ALLOCATE (cutoff_ri_per_atom(natom))
     590              : 
     591            0 :          IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp) THEN
     592            0 :             cutoff_ri_per_atom(:) = bs_env%ri_rs%cutoff_radius_ri_rs
     593              :          ELSE
     594            0 :             r_c = bs_env%ri_metric%cutoff_radius
     595            0 :             DO P_loop_atom = 1, natom
     596              :                cutoff_ri_per_atom(P_loop_atom) = &
     597            0 :                   r_c + bs_env%ri_rs%radius_ao_per_atom(P_loop_atom)
     598              :             END DO
     599              :          END IF
     600              : 
     601            0 :          ALLOCATE (cutoff_ri_per_kind(nkind))
     602            0 :          cutoff_ri_per_kind(:) = 0.0_dp
     603            0 :          IF (bs_env%unit_nr > 0) THEN
     604            0 :             DO P_loop_atom = 1, natom
     605            0 :                ikind = particle_set(P_loop_atom)%atomic_kind%kind_number
     606              :                cutoff_ri_per_kind(ikind) = MAX(cutoff_ri_per_kind(ikind), &
     607            0 :                                                cutoff_ri_per_atom(P_loop_atom))
     608              :             END DO
     609            0 :             WRITE (bs_env%unit_nr, '(T2,A)') 'Per-kind maximum RI-RS sphere cutoff (Bohr):'
     610            0 :             WRITE (bs_env%unit_nr, '(T4,A4,A14)') 'Kind', 'max cutoff_ri'
     611            0 :             DO ikind = 1, nkind
     612              :                WRITE (bs_env%unit_nr, '(T4,A4,F14.4)') &
     613            0 :                   atomic_kind_set(ikind)%element_symbol, &
     614            0 :                   cutoff_ri_per_kind(ikind)
     615              :             END DO
     616            0 :             WRITE (bs_env%unit_nr, '(A)') ' '
     617            0 :             DEALLOCATE (cutoff_ri_per_kind)
     618              :          END IF
     619              : 
     620              :          ! Shared 3c-integral context: hoists libint / t_c_g0 / md_ftable / contracted
     621              :          ! sphi tables out of the per-triple call so compute_d_lp threads only allocate
     622              :          ! a lightweight per-thread workspace. MPI-collective; must be outside any
     623              :          ! OMP region.
     624              :          CALL gw_3c_ctx_create(ctx_3c, bs_env, bs_env%ri_metric, &
     625              :                                basis_j=bs_env%basis_set_AO, basis_k=bs_env%basis_set_AO, &
     626            0 :                                basis_i=bs_env%basis_set_RI)
     627              : 
     628              :          ! =========================================================================
     629              :          ! 2. MPI LOOP OVER ATOMS (Fully independent, no MPI barriers inside)
     630              :          ! phi_local for each atom_P's cutoff sphere is built on the fly via
     631              :          ! fill_phi_for_atom — no dense replicated phi_global, no allreduce.
     632              :          ! =========================================================================
     633            0 :          DO atom_P = atom_P_start, natom, atom_P_stride
     634              : 
     635            0 :             n_loc_ri = ri_blk_sizes(atom_P)
     636            0 :             pos_P(:) = particle_set(atom_P)%r(:)
     637              : 
     638            0 :             cutoff_ri = cutoff_ri_per_atom(atom_P)
     639            0 :             cutoff_ri_2 = cutoff_ri**2
     640              : 
     641              :             ! ---------------------------------------------------------------------
     642              :             ! A. Determine Local Grid Domain based on cutoff_ri (PBC distance)
     643              :             ! ---------------------------------------------------------------------
     644            0 :             n_local_grid = 0
     645            0 :             DO l = 1, n_grid_total
     646            0 :                dist_vec_raw = pbc(ri_rs_grid_points(1:3, l), pos_P(1:3), cell)
     647            0 :                dist2_min = DOT_PRODUCT(dist_vec_raw, dist_vec_raw)
     648            0 :                IF (dist2_min <= cutoff_ri_2) n_local_grid = n_local_grid + 1
     649              :             END DO
     650              : 
     651            0 :             ALLOCATE (local_grid_idx(n_local_grid))
     652              : 
     653            0 :             n_local_grid = 0
     654            0 :             DO l = 1, n_grid_total
     655            0 :                dist_vec_raw = pbc(ri_rs_grid_points(1:3, l), pos_P(1:3), cell)
     656            0 :                dist2_min = DOT_PRODUCT(dist_vec_raw, dist_vec_raw)
     657            0 :                IF (dist2_min <= cutoff_ri_2) THEN
     658            0 :                   n_local_grid = n_local_grid + 1
     659            0 :                   local_grid_idx(n_local_grid) = l
     660              :                END IF
     661              :             END DO
     662              : 
     663              :             ! ---------------------------------------------------------------------
     664              :             ! B. Build phi_local on the fly via fill_phi_for_atom.
     665              :             !    Only source atoms whose AO basis can reach the cutoff sphere of
     666              :             !    atom_P (MIC distance) contribute; the rest are pruned. The
     667              :             !    periodic fill_phi_for_atom sums over (ix, iy, iz) images of
     668              :             !    ri_atom internally.
     669              :             ! ---------------------------------------------------------------------
     670            0 :             ALLOCATE (sphere_grid(3, n_local_grid))
     671            0 :             DO loc_idx = 1, n_local_grid
     672            0 :                sphere_grid(:, loc_idx) = ri_rs_grid_points(:, local_grid_idx(loc_idx))
     673              :             END DO
     674              : 
     675            0 :             ALLOCATE (phi_local(n_local_grid, n_ao_total))
     676            0 :             phi_local = 0.0_dp
     677              : 
     678            0 :             DO ri_atom = 1, natom
     679            0 :                dist_vec_raw = pbc(particle_set(ri_atom)%r(:), pos_P(:), cell)
     680            0 :                d_sP = NORM2(dist_vec_raw)
     681            0 :                IF (d_sP > bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) CYCLE
     682              : 
     683            0 :                col_start = bs_env%i_ao_start_from_atom(ri_atom)
     684            0 :                col_end = bs_env%i_ao_end_from_atom(ri_atom)
     685            0 :                r2_threshold = bs_env%ri_rs%radius_ao_per_atom(ri_atom)**2
     686              : 
     687              :                CALL fill_phi_for_atom(phi_local(:, col_start:col_end), sphere_grid, &
     688            0 :                                       n_local_grid, ri_atom, bs_env, r2_threshold)
     689              :             END DO
     690              : 
     691            0 :             DEALLOCATE (sphere_grid)
     692              : 
     693              :             ! ---------------------------------------------------------------------
     694              :             ! C. Build Local RHS Matrix (d_lp_local) first so the subgroup-
     695              :             !    distributed compute_d_lp + allreduce is not entangled with the LHS
     696              :             !    build. compute_d_lp does not depend on D_local or d_vec_local.
     697              :             ! ---------------------------------------------------------------------
     698            0 :             ALLOCATE (d_lp_local(n_local_grid, n_loc_ri))
     699            0 :             d_lp_local = 0.0_dp
     700              : 
     701            0 :             t2 = m_walltime()
     702              : 
     703              :             CALL compute_d_lp(bs_env, ctx_3c, phi_local, d_lp_local, n_local_grid, &
     704            0 :                               n_loc_ri, atom_P, max_ao_size, atom_j_mepos, atom_j_stride)
     705              : 
     706              :             ! Reduce per-subgroup-rank partials into the replicated d_lp_local.
     707              :             ! Skipped for G=1 (BLAS path): each rank has the full sum locally.
     708            0 :             IF (n_procs_per_atom > 1) THEN
     709            0 :                CALL para_env_sub%sum(d_lp_local)
     710              :             END IF
     711              : 
     712            0 :             t3 = m_walltime()
     713              : 
     714              :             ! ---------------------------------------------------------------------
     715              :             ! D. Build d_vec_local (Jacobi diagonal) + LHS — BLAS or ScaLAPACK
     716              :             ! ---------------------------------------------------------------------
     717            0 :             ALLOCATE (d_vec_local(n_local_grid))
     718              : 
     719            0 :             IF (n_procs_per_atom == 1) THEN
     720              :                CALL build_gram_jacobi_blas(phi_local, n_local_grid, n_ao_total, &
     721            0 :                                            bs_env%ri_rs%tikhonov, D_local, d_vec_local)
     722              :             ELSE
     723              :                ! ScaLAPACK path: d_vec computed directly from phi (= 1/||phi_i||^2);
     724              :                ! solve_D_lp_distributed builds D block-cyclic internally with
     725              :                ! the squared+scaled values, so no dense D_local on this rank.
     726              :                CALL build_jacobi_diag_from_phi(phi_local, n_local_grid, n_ao_total, &
     727            0 :                                                d_vec_local)
     728              :             END IF
     729              : 
     730              :             ! ---------------------------------------------------------------------
     731              :             ! E. Pre-scale d_lp by d_vec
     732              :             ! ---------------------------------------------------------------------
     733            0 :             CALL scale_rows_by_diag(d_lp_local, d_vec_local, n_local_grid, n_loc_ri)
     734              : 
     735              :             ! ---------------------------------------------------------------------
     736              :             ! F. Solve — BLAS dpotrf/dpotrs or ScaLAPACK pdpotrf/pdpotrs
     737              :             ! ---------------------------------------------------------------------
     738            0 :             IF (n_procs_per_atom == 1) THEN
     739            0 :                CALL timeset(routineN//"_dpotrf", handle_dpotrf)
     740            0 :                CALL dpotrf('L', n_local_grid, D_local, n_local_grid, info)
     741            0 :                CALL timestop(handle_dpotrf)
     742            0 :                IF (info /= 0) CPABORT("RI-RS Cholesky factorization failed")
     743            0 :                CALL timeset(routineN//"_dpotrs", handle_dpotrs)
     744              :                CALL dpotrs('L', n_local_grid, n_loc_ri, D_local, n_local_grid, &
     745            0 :                            d_lp_local, n_local_grid, info)
     746            0 :                CALL timestop(handle_dpotrs)
     747            0 :                IF (info /= 0) CPABORT("RI-RS Cholesky solve failed")
     748            0 :                DEALLOCATE (D_local)
     749              :             ELSE
     750              :                CALL solve_D_lp_distributed(phi_local, d_vec_local, d_lp_local, &
     751              :                                            n_local_grid, n_ao_total, n_loc_ri, &
     752              :                                            bs_env%ri_rs%tikhonov, &
     753              :                                            para_env_sub, blacs_env_sub, &
     754            0 :                                            fm_struct_D, fm_struct_b, fm_D, fm_b, info)
     755            0 :                IF (info /= 0) CPABORT("Distributed RI-RS Cholesky solve failed")
     756              :             END IF
     757              : 
     758              :             ! ---------------------------------------------------------------------
     759              :             ! G. Post-scale solution by d_vec (common to both paths)
     760              :             ! ---------------------------------------------------------------------
     761            0 :             CALL scale_rows_by_diag(d_lp_local, d_vec_local, n_local_grid, n_loc_ri)
     762              : 
     763              :             ! ---------------------------------------------------------------------
     764              :             ! H. Scatter Local Solution Back to Global DBCSR Matrix.
     765              :             !    Under ScaLAPACK (G>1) the d_lp_local solution is identical on all
     766              :             !    G subgroup ranks (gathered via cp_fm_get_submatrix); only the
     767              :             !    subgroup root writes to mat_Z_lP so each atom column is emitted
     768              :             !    exactly once. DBCSR routes blocks to their global owner on finalize.
     769              :             !    local_grid_idx is ascending (built by the ordered scan above), so
     770              :             !    a single walking pointer over chunks works.
     771              :             ! ---------------------------------------------------------------------
     772            0 :             IF (n_procs_per_atom == 1 .OR. para_env_sub%mepos == 0) THEN
     773              :                CALL store_Z_lP_columns(mat_Z_lP, d_lp_local, local_grid_idx, n_local_grid, &
     774              :                                        n_loc_ri, atom_P, r_blk_sizes, row_offset, &
     775            0 :                                        bs_env%eps_filter)
     776              :             END IF
     777              : 
     778            0 :             DEALLOCATE (d_vec_local, d_lp_local)
     779            0 :             DEALLOCATE (local_grid_idx, phi_local)
     780              : 
     781              :          END DO
     782              : 
     783            0 :          DEALLOCATE (cutoff_ri_per_atom)
     784            0 :          CALL gw_3c_ctx_release(ctx_3c)
     785              : 
     786            0 :          CALL dbcsr_finalize(mat_Z_lP)
     787              : 
     788            0 :          IF (bs_env%unit_nr > 0) THEN
     789              :             WRITE (bs_env%unit_nr, '(T2,A,T57,A,F7.1,A)') &
     790            0 :                'Computed Z_lP ', ' Execution time', m_walltime() - t1, ' s'
     791            0 :             WRITE (bs_env%unit_nr, '(A)') ' '
     792              :          END IF
     793              : 
     794            0 :          logger => cp_get_default_logger()
     795              : 
     796            0 :          IF (BTEST(cp_print_key_should_output(logger%iter_info, input, key), cp_p_file)) THEN
     797            0 :             CALL dbcsr_binary_write(matrix=mat_Z_lP, filepath=TRIM(bs_env%prefix)//"Z_lP.matrix")
     798              :          END IF
     799              : 
     800              :       END IF
     801              : 
     802            0 :       DEALLOCATE (row_offset, ri_blk_sizes, col_dist_ri)
     803            0 :       CALL dbcsr_distribution_release(dist_Z)
     804              : 
     805            0 :       IF (n_procs_per_atom > 1) THEN
     806            0 :          CALL cp_blacs_env_release(blacs_env_sub)
     807            0 :          CALL para_env_sub%free()
     808            0 :          DEALLOCATE (para_env_sub)
     809              :       END IF
     810              : 
     811            0 :       DEALLOCATE (ri_rs_grid_points)
     812              : 
     813            0 :       CALL timestop(handle)
     814              : 
     815            0 :    END SUBROUTINE compute_Z_lP
     816              : 
     817              : ! **************************************************************************************************
     818              : !> \brief Computes the dense localized RHS d_lp(l,P) = Σ_{μν,R,S} ϕ_μ(r_l)·ϕ_ν(r_l)·(μν|P) for one
     819              : !>        RI atom P. OMP-threaded over (atom_j, atom_k) AO-pair blocks: per thread, sweep all
     820              : !>        (cell_R, cell_S) periodic images of (atom_j, atom_k) about atom_P at cell (0,0,0); each
     821              : !>        3c block is built by build_3c_integral_block_ctx (cached libint / sphi tables in ctx,
     822              : !>        kind-radius triangle screen → `screened` short-circuits negligible image triples), and
     823              : !>        grid-chunked pair densities are contracted into a private d_lp partial that is reduced
     824              : !>        into d_lp at the end of the parallel region.
     825              : !> \param bs_env ...
     826              : !> \param ctx shared 3c-integral context (gw_3c_ctx_create)
     827              : !> \param phi_val ϕ_μ(r_l) on the local-sphere grid (n_grid_total × n_ao)
     828              : !> \param d_lp output (n_grid_total × n_loc_ri), zeroed by the caller, accumulated here
     829              : !> \param n_grid_total number of local-sphere grid rows
     830              : !> \param n_loc_ri number of RI functions of atom_P
     831              : !> \param atom_P RI atom (pinned to cell (0,0,0))
     832              : !> \param max_ao_size ...
     833              : !> \param atom_j_mepos ...
     834              : !> \param atom_j_stride ...
     835              : ! **************************************************************************************************
     836              : 
     837            0 :    SUBROUTINE compute_d_lp(bs_env, ctx, phi_val, d_lp, n_grid_total, n_loc_ri, atom_P, &
     838              :                            max_ao_size, atom_j_mepos, atom_j_stride)
     839              : 
     840              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     841              :       TYPE(gw_3c_ctx_type), INTENT(IN)                   :: ctx
     842              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: phi_val
     843              :       INTEGER, INTENT(IN)                                :: n_grid_total, n_loc_ri
     844              :       REAL(KIND=dp), INTENT(INOUT)                       :: d_lp(n_grid_total, n_loc_ri)
     845              :       INTEGER, INTENT(IN)                                :: atom_P, max_ao_size, atom_j_mepos, &
     846              :                                                             atom_j_stride
     847              : 
     848              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'compute_d_lp'
     849              :       INTEGER, PARAMETER                                 :: grid_chunk = 1024
     850              : 
     851              :       INTEGER :: atom_j, atom_k, c, handle, handle_dgemm, ix_max, ix_min, ix_R, ix_S, iy_max, &
     852              :          iy_min, iy_R, iy_S, iz_max, iz_min, iz_R, iz_S, j, jk_idx, jsize, jstart, k, ksize, &
     853              :          kstart, l, l0, natom, ri
     854              :       INTEGER, DIMENSION(3)                              :: cell_R_vec, cell_S_vec
     855              :       LOGICAL                                            :: any_kept, screened
     856            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: d_lp_prv, int_2d_prv, rho_chunk
     857            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: int_3c_prv, int_3c_sum
     858            0 :       TYPE(gw_3c_ws_type)                                :: ws
     859              : 
     860            0 :       CALL timeset(routineN, handle)
     861              : 
     862            0 :       natom = bs_env%n_atom
     863              : 
     864            0 :       IF (bs_env%ri_rs%cell%perd(1) == 1) THEN; ix_min = -1; ix_max = 1; ELSE; ix_min = 0; ix_max = 0
     865              :       END IF
     866            0 :       IF (bs_env%ri_rs%cell%perd(2) == 1) THEN; iy_min = -1; iy_max = 1; ELSE; iy_min = 0; iy_max = 0
     867              :       END IF
     868            0 :       IF (bs_env%ri_rs%cell%perd(3) == 1) THEN; iz_min = -1; iz_max = 1; ELSE; iz_min = 0; iz_max = 0
     869              :       END IF
     870              : 
     871              :       !$OMP PARALLEL DEFAULT(NONE) &
     872              :       !$OMP SHARED(bs_env, ctx, phi_val, d_lp, n_grid_total, n_loc_ri, atom_P, max_ao_size, &
     873              :       !$OMP        natom, ix_min, ix_max, iy_min, iy_max, iz_min, iz_max, &
     874              :       !$OMP        atom_j_mepos, atom_j_stride) &
     875              :       !$OMP PRIVATE(any_kept, atom_j, atom_k, c, handle_dgemm, j, jk_idx, jsize, jstart, k, &
     876              :       !$OMP         ksize, kstart, l, l0, ri, ix_R, iy_R, iz_R, ix_S, iy_S, iz_S, cell_R_vec, &
     877            0 :       !$OMP         cell_S_vec, screened, d_lp_prv, int_2d_prv, rho_chunk, int_3c_prv, int_3c_sum, ws)
     878              : 
     879              :       CALL gw_3c_ws_create(ws, ctx)
     880              :       ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, n_loc_ri))
     881              :       ALLOCATE (int_3c_sum(max_ao_size, max_ao_size, n_loc_ri))
     882              :       ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, n_loc_ri))
     883              :       ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
     884              :       ALLOCATE (d_lp_prv(n_grid_total, n_loc_ri))
     885              :       d_lp_prv(:, :) = 0.0_dp
     886              : 
     887              :       ! atom_P pinned at cell (0,0,0); enumerate (atom_j, cell_R) × (atom_k, cell_S). The ctx
     888              :       ! integral builder's kind_radius triangle screen sets screened=.TRUE. for the bulk of
     889              :       ! image triples (one or both AO atoms beyond the truncated-Coulomb reach of atom_P),
     890              :       ! so the 27 × 27 = 729 candidate cells collapse to "adjacent cells" in practice.
     891              :       ! MPI-stride atom_j over the subgroup (atom_j_stride = 1 for the BLAS path, > 1 for the
     892              :       ! ScaLAPACK path). COLLAPSE(2) dropped because the outer stride is non-unit under
     893              :       ! ScaLAPACK; the inner atom_k loop carries enough work for DYNAMIC.
     894              :       !$OMP DO SCHEDULE(DYNAMIC)
     895              :       DO atom_j = atom_j_mepos + 1, natom, atom_j_stride
     896              :          DO atom_k = 1, natom
     897              :             jstart = bs_env%i_ao_start_from_atom(atom_j)
     898              :             jsize = bs_env%i_ao_end_from_atom(atom_j) - jstart + 1
     899              :             kstart = bs_env%i_ao_start_from_atom(atom_k)
     900              :             ksize = bs_env%i_ao_end_from_atom(atom_k) - kstart + 1
     901              : 
     902              :             int_3c_sum(1:jsize, 1:ksize, 1:n_loc_ri) = 0.0_dp
     903              :             any_kept = .FALSE.
     904              : 
     905              :             DO ix_R = ix_min, ix_max
     906              :             DO iy_R = iy_min, iy_max
     907              :             DO iz_R = iz_min, iz_max
     908              :                cell_R_vec = [ix_R, iy_R, iz_R]
     909              :                DO ix_S = ix_min, ix_max
     910              :                DO iy_S = iy_min, iy_max
     911              :                DO iz_S = iz_min, iz_max
     912              :                   cell_S_vec = [ix_S, iy_S, iz_S]
     913              : 
     914              :                   int_3c_prv(1:jsize, 1:ksize, 1:n_loc_ri) = 0.0_dp
     915              : 
     916              :                   CALL build_3c_integral_block_ctx(int_3c_prv( &
     917              :                                                    1:jsize, 1:ksize, 1:n_loc_ri), ctx, ws, &
     918              :                                                    atom_j=atom_j, atom_k=atom_k, atom_i=atom_P, &
     919              :                                                    cell_j=cell_R_vec, cell_k=cell_S_vec, cell_i=[0, 0, 0], &
     920              :                                                    screened=screened)
     921              :                   IF (screened) CYCLE
     922              : 
     923              :                   any_kept = .TRUE.
     924              :                   int_3c_sum(1:jsize, 1:ksize, 1:n_loc_ri) = &
     925              :                      int_3c_sum(1:jsize, 1:ksize, 1:n_loc_ri) + &
     926              :                      int_3c_prv(1:jsize, 1:ksize, 1:n_loc_ri)
     927              :                END DO
     928              :                END DO
     929              :                END DO
     930              :             END DO
     931              :             END DO
     932              :             END DO
     933              : 
     934              :             IF (.NOT. any_kept) CYCLE
     935              : 
     936              :             ! Flatten 3D B_{μν,P} → 2D B_{(μν),P}
     937              :             DO ri = 1, n_loc_ri
     938              :                DO k = 1, ksize
     939              :                   DO j = 1, jsize
     940              :                      jk_idx = (k - 1)*jsize + j
     941              :                      int_2d_prv(jk_idx, ri) = int_3c_sum(j, k, ri)
     942              :                   END DO
     943              :                END DO
     944              :             END DO
     945              : 
     946              :             ! Pair density ρ(l,μν) = ϕ_μ(r_l)ϕ_ν(r_l) in grid chunks, contracted on the fly:
     947              :             ! d_{l,P} += ρ(l,μν) B_{(μν),P}  (dgemm runs serially inside the parallel region)
     948              :             DO l0 = 1, n_grid_total, grid_chunk
     949              :                c = MIN(grid_chunk, n_grid_total - l0 + 1)
     950              :                DO k = 1, ksize
     951              :                   DO j = 1, jsize
     952              :                      jk_idx = (k - 1)*jsize + j
     953              :                      DO l = 1, c
     954              :                         rho_chunk(l, jk_idx) = phi_val(l0 + l - 1, jstart + j - 1)* &
     955              :                                                phi_val(l0 + l - 1, kstart + k - 1)
     956              :                      END DO
     957              :                   END DO
     958              :                END DO
     959              :                CALL timeset(routineN//"_dgemm", handle_dgemm)
     960              :                CALL dgemm("N", "N", c, n_loc_ri, jsize*ksize, &
     961              :                           1.0_dp, rho_chunk, grid_chunk, &
     962              :                           int_2d_prv, max_ao_size*max_ao_size, &
     963              :                           1.0_dp, d_lp_prv(l0, 1), n_grid_total)
     964              :                CALL timestop(handle_dgemm)
     965              :             END DO
     966              :          END DO
     967              :       END DO
     968              :       !$OMP END DO
     969              : 
     970              :       !$OMP CRITICAL (compute_d_lp_reduce)
     971              :       d_lp(1:n_grid_total, 1:n_loc_ri) = d_lp(1:n_grid_total, 1:n_loc_ri) + &
     972              :                                          d_lp_prv(1:n_grid_total, 1:n_loc_ri)
     973              :       !$OMP END CRITICAL (compute_d_lp_reduce)
     974              : 
     975              :       DEALLOCATE (int_3c_prv, int_3c_sum, int_2d_prv, rho_chunk, d_lp_prv)
     976              :       CALL gw_3c_ws_release(ws)
     977              : 
     978              :       !$OMP END PARALLEL
     979              : 
     980            0 :       CALL timestop(handle)
     981              : 
     982            0 :    END SUBROUTINE compute_d_lp
     983              : 
     984              : ! **************************************************************************************************
     985              : !> \brief Computes the χ(iτ, k=0) matrix
     986              : !> \param bs_env ...
     987              : !> \param mat_chi_Gamma_tau ...
     988              : !> \param mat_phi_mu_l ...
     989              : !> \param mat_Z_lP ...
     990              : ! **************************************************************************************************
     991              : 
     992            0 :    SUBROUTINE get_mat_chi_Gamma_tau(bs_env, mat_chi_Gamma_tau, mat_phi_mu_l, mat_Z_lP)
     993              : 
     994              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
     995              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: mat_chi_Gamma_tau
     996              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_phi_mu_l, mat_Z_lP
     997              : 
     998              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_mat_chi_Gamma_tau'
     999              : 
    1000              :       INTEGER                                            :: handle, i, i_t, ispin, npcol
    1001            0 :       INTEGER, DIMENSION(:), POINTER                     :: blk_ao, blk_grid, dist_col_grid, &
    1002            0 :                                                             dist_row_grid
    1003              :       REAL(KIND=dp)                                      :: t1, tau
    1004              :       TYPE(dbcsr_distribution_type)                      :: dist_grid_grid, dist_phi
    1005              :       TYPE(dbcsr_type)                                   :: matrix_chi_grid, matrix_chi_grid_spin, &
    1006              :                                                             matrix_G_occ_grid, matrix_G_vir_grid
    1007              : 
    1008            0 :       CALL timeset(routineN, handle)
    1009              : 
    1010              :       ! =========================================================================
    1011              :       ! 1. SETUP CORE TOPOLOGIES
    1012              :       ! =========================================================================
    1013            0 :       CALL dbcsr_get_info(mat_phi_mu_l, distribution=dist_phi, row_blk_size=blk_grid, col_blk_size=blk_ao)
    1014            0 :       CALL dbcsr_distribution_get(dist_phi, row_dist=dist_row_grid, npcols=npcol)
    1015              : 
    1016              :       ! Build a perfectly safe column distribution for the Grid dimension
    1017            0 :       ALLOCATE (dist_col_grid(SIZE(blk_grid)))
    1018            0 :       DO i = 1, SIZE(blk_grid)
    1019            0 :          dist_col_grid(i) = MOD(i - 1, npcol)
    1020              :       END DO
    1021              : 
    1022              :       CALL dbcsr_distribution_new(dist_grid_grid, template=dist_phi, &
    1023            0 :                                   row_dist=dist_row_grid, col_dist=dist_col_grid)
    1024              : 
    1025            0 :       CALL dbcsr_create(matrix_G_occ_grid, "G_occ_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1026            0 :       CALL dbcsr_create(matrix_G_vir_grid, "G_vir_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1027            0 :       CALL dbcsr_create(matrix_chi_grid, "chi_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1028            0 :       CALL dbcsr_create(matrix_chi_grid_spin, "chi_grid_spin", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1029              : 
    1030              :       ! =========================================================================
    1031              :       ! 2. MAIN IMAGINARY TIME LOOP
    1032              :       ! =========================================================================
    1033            0 :       DO i_t = 1, bs_env%num_time_freq_points
    1034            0 :          t1 = m_walltime()
    1035              : 
    1036            0 :          tau = bs_env%time_frequency_grid%imaginary_time(i_t)
    1037            0 :          CALL dbcsr_set(matrix_chi_grid, 0.0_dp)
    1038              : 
    1039              :          ! ----------------------------------------------------------------------
    1040              :          ! A. SPIN LOOP (Allocations safely encapsulated in wrappers)
    1041              :          ! ----------------------------------------------------------------------
    1042            0 :          DO ispin = 1, bs_env%n_spin
    1043              : 
    1044              :             ! G^occ_µλ(i|τ|,k=0) = sum_n^occ C_µn(k=0) e^(-|(ϵ_nk=0-ϵ_F)τ|) C_λn(k=0)
    1045              :             ! G^occ_ll'(i|τ|,k=0) = sum_µν ϕ_µ(r_l) G^occ_µν ϕ_ν(r_l')
    1046              :             CALL build_G_grid(bs_env, tau, ispin, .TRUE., .FALSE., mat_phi_mu_l, &
    1047            0 :                               matrix_G_occ_grid, bs_env%eps_filter)
    1048              : 
    1049              :             ! G^vir_µλ(i|τ|,k=0) = sum_n^vir C_µn(k=0) e^(-|(ϵ_nk=0-ϵ_F)τ|) C_λn(k=0)
    1050              :             ! G^vir_ll'(i|τ|,k=0) = sum_µν ϕ_µ(r_l) G^vir_µν ϕ_ν(r_l')
    1051              :             CALL build_G_grid(bs_env, tau, ispin, .FALSE., .TRUE., mat_phi_mu_l, &
    1052            0 :                               matrix_G_vir_grid, bs_env%eps_filter)
    1053              : 
    1054              :             ! -------------------------------------------------------------------
    1055              :             ! B. ELEMENT-WISE HADAMARD PRODUCT
    1056              :             ! -------------------------------------------------------------------
    1057              :             ! χ_ll'(iτ,k=0) = G^occ_ll'(i|τ|,k=0) * G^vir_ll'(i|τ|,k=0)
    1058            0 :             CALL hadamard_product(matrix_G_occ_grid, matrix_G_vir_grid, matrix_chi_grid_spin, bs_env%spin_degeneracy)
    1059              : 
    1060              :             ! Accumulate spin contributions
    1061            0 :             CALL dbcsr_add(matrix_chi_grid, matrix_chi_grid_spin, 1.0_dp, 1.0_dp)
    1062              : 
    1063              :          END DO ! ispin
    1064              : 
    1065              :          ! ----------------------------------------------------------------------
    1066              :          ! C. TRANSFORM TO AUXILIARY BASIS & EXPORT DIRECTLY
    1067              :          ! χ_aux        = Z^T * χ_grid * Z
    1068              :          ! χ_PQ(iτ,k=0) = sum_ll' Z_lP χ_ll'(iτ,k=0) Z_l'Q
    1069              :          ! Result is dumped directly into the final array mat_chi_Gamma_tau!
    1070              :          ! ----------------------------------------------------------------------
    1071              :          CALL dbcsr_contract_ABA("T", "N", mat_Z_lP, matrix_chi_grid, &
    1072            0 :                                  mat_chi_Gamma_tau(i_t)%matrix, bs_env%eps_filter)
    1073              : 
    1074            0 :          IF (bs_env%unit_nr > 0) THEN
    1075              :             WRITE (bs_env%unit_nr, '(T2,A,I13,A,I3,A,F7.1,A)') &
    1076            0 :                'Computed χ(iτ,k=0) for time point', i_t, ' /', bs_env%num_time_freq_points, &
    1077            0 :                ',    Execution time', m_walltime() - t1, ' s'
    1078              :          END IF
    1079              : 
    1080              :       END DO ! i_t
    1081              : 
    1082              :       ! =========================================================================
    1083              :       ! 3. FINAL CLEANUP
    1084              :       ! =========================================================================
    1085            0 :       CALL dbcsr_release(matrix_G_occ_grid)
    1086            0 :       CALL dbcsr_release(matrix_G_vir_grid)
    1087            0 :       CALL dbcsr_release(matrix_chi_grid)
    1088            0 :       CALL dbcsr_release(matrix_chi_grid_spin)
    1089            0 :       CALL dbcsr_distribution_release(dist_grid_grid)
    1090            0 :       DEALLOCATE (dist_col_grid)
    1091              : 
    1092            0 :       IF (bs_env%unit_nr > 0) WRITE (bs_env%unit_nr, '(A)') ' '
    1093              : 
    1094            0 :       CALL timestop(handle)
    1095              : 
    1096            0 :    END SUBROUTINE get_mat_chi_Gamma_tau
    1097              : 
    1098              : ! **************************************************************************************************
    1099              : !> \brief Computes Green's Function in grid basis
    1100              : !> \param bs_env ...
    1101              : !> \param tau ...
    1102              : !> \param ispin ...
    1103              : !> \param occ ...
    1104              : !> \param vir ...
    1105              : !> \param mat_phi_mu_l ...
    1106              : !> \param matrix_G_grid ...
    1107              : !> \param eps_filter ...
    1108              : ! **************************************************************************************************
    1109              : 
    1110            0 :    SUBROUTINE build_G_grid(bs_env, tau, ispin, occ, vir, mat_phi_mu_l, matrix_G_grid, eps_filter)
    1111              : 
    1112              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1113              :       REAL(KIND=dp), INTENT(IN)                          :: tau
    1114              :       INTEGER, INTENT(IN)                                :: ispin
    1115              :       LOGICAL, INTENT(IN)                                :: occ, vir
    1116              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_phi_mu_l, matrix_G_grid
    1117              :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter
    1118              : 
    1119              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'build_G_grid'
    1120              : 
    1121              :       INTEGER                                            :: handle
    1122            0 :       INTEGER, DIMENSION(:), POINTER                     :: blk_ao, dist_row_ao
    1123              :       TYPE(cp_fm_type), POINTER                          :: fm_G
    1124              :       TYPE(dbcsr_distribution_type)                      :: dist_ao_ao
    1125              :       TYPE(dbcsr_type)                                   :: matrix_G_ao
    1126              : 
    1127            0 :       CALL timeset(routineN, handle)
    1128              : 
    1129              :       ! 1. Select the correct FM matrix based on occ/vir flags
    1130            0 :       IF (occ) THEN
    1131            0 :          fm_G => bs_env%fm_Gocc
    1132              :       ELSE
    1133            0 :          fm_G => bs_env%fm_Gvir
    1134              :       END IF
    1135              : 
    1136              :       ! 2. Compute Dense FM Green's Function
    1137              :       ! G^occ/vir_µλ(i|τ|,k=0) = sum_G^occ/vir_µλn^occ/vir C_µn(k=0) e^(-|(ϵ_nk=0-ϵ_F)τ|) C_λn(k=0)
    1138            0 :       CALL G_occ_vir(bs_env, tau, fm_G, ispin, occ=occ, vir=vir)
    1139              : 
    1140              :       ! 3. Setup AO DBCSR Topology and Create Matrix dynamically
    1141            0 :       CALL setup_square_topology(mat_phi_mu_l, 'COL', dist_ao_ao, blk_ao, dist_row_ao)
    1142              : 
    1143              :       CALL dbcsr_create(matrix_G_ao, name="G_ao", dist=dist_ao_ao, &
    1144              :                         matrix_type=dbcsr_type_no_symmetry, &
    1145            0 :                         row_blk_size=blk_ao, col_blk_size=blk_ao)
    1146              : 
    1147              :       ! 4. Convert FM to Sparse DBCSR
    1148            0 :       CALL copy_fm_to_dbcsr(fm_G, matrix_G_ao, keep_sparsity=.FALSE.)
    1149              : 
    1150              :       ! 5. Transform to Grid Basis: G_grid = phi * G_ao * phi^T
    1151              :       ! G^occ/vir_ll'(i|τ|,k=0) = sum_µν ϕ_µ(r_l) G^occ/vir_µν ϕ_ν(r_l')
    1152              :       CALL dbcsr_contract_ABA("N", "T", mat_phi_mu_l, matrix_G_ao, matrix_G_grid, &
    1153            0 :                               eps_filter)
    1154              : 
    1155              :       ! 6. Release AO matrix and topology
    1156            0 :       CALL release_dbcsr_topology_and_matrices(dist=dist_ao_ao, mapped_dist=dist_row_ao, m1=matrix_G_ao)
    1157              : 
    1158            0 :       CALL timestop(handle)
    1159              : 
    1160            0 :    END SUBROUTINE build_G_grid
    1161              : 
    1162              : ! **************************************************************************************************
    1163              : !> \brief Computes the exact exchange part of the GW self-energy
    1164              : !> \param bs_env ...
    1165              : !> \param qs_env ...
    1166              : !> \param mat_phi_mu_l ...
    1167              : !> \param mat_Z_lP ...
    1168              : !> \param fm_Sigma_x_Gamma ...
    1169              : ! **************************************************************************************************
    1170              : 
    1171            0 :    SUBROUTINE compute_Sigma_x(bs_env, qs_env, mat_phi_mu_l, mat_Z_lP, fm_Sigma_x_Gamma)
    1172              : 
    1173              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1174              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1175              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_phi_mu_l, mat_Z_lP
    1176              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_Sigma_x_Gamma
    1177              : 
    1178              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'compute_Sigma_x'
    1179              : 
    1180              :       INTEGER                                            :: handle, ispin
    1181            0 :       INTEGER, DIMENSION(:), POINTER                     :: blk_aux, blk_grid, dist_col_grid, &
    1182            0 :                                                             dist_row_aux
    1183              :       REAL(KIND=dp)                                      :: t1
    1184            0 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_Vtr_Gamma
    1185              :       TYPE(dbcsr_distribution_type)                      :: dist_aux_aux, dist_grid_grid
    1186              :       TYPE(dbcsr_type)                                   :: mat_Sigma_x_Gamma, matrix_D_grid, &
    1187              :                                                             matrix_Sigma_x_grid, matrix_V_aux, &
    1188              :                                                             matrix_V_grid
    1189              : 
    1190            0 :       CALL timeset(routineN, handle)
    1191              : 
    1192            0 :       t1 = m_walltime()
    1193              : 
    1194            0 :       ALLOCATE (fm_Sigma_x_Gamma(bs_env%n_spin))
    1195            0 :       DO ispin = 1, bs_env%n_spin
    1196            0 :          CALL cp_fm_create(fm_Sigma_x_Gamma(ispin), bs_env%fm_s_Gamma%matrix_struct)
    1197              :       END DO
    1198              : 
    1199            0 :       CALL dbcsr_create(mat_Sigma_x_Gamma, template=bs_env%mat_ao_ao%matrix)
    1200              : 
    1201              :       ! =========================================================================
    1202              :       ! 1. SETUP CORE TOPOLOGIES
    1203              :       ! =========================================================================
    1204            0 :       CALL setup_square_topology(mat_phi_mu_l, 'ROW', dist_grid_grid, blk_grid, dist_col_grid)
    1205            0 :       CALL setup_square_topology(mat_Z_lP, 'COL', dist_aux_aux, blk_aux, dist_row_aux)
    1206              : 
    1207              :       ! =========================================================================
    1208              :       ! 2. COMPUTE V^tr_ll'
    1209              :       ! =========================================================================
    1210              :       CALL RI_2c_integral_mat(qs_env, fm_Vtr_Gamma, bs_env%fm_RI_RI, bs_env%n_RI, &
    1211            0 :                               bs_env%trunc_coulomb, do_kpoints=.FALSE.)
    1212              : 
    1213              :       ! M^-1(k=0) V^tr(τ) M^-1(k=0) -> fm_Vtr_Gamma
    1214            0 :       CALL fm_contract_ABA(bs_env%fm_Minv_Gamma, fm_Vtr_Gamma(:, 1))
    1215              : 
    1216            0 :       CALL dbcsr_create(matrix_V_aux, "V_aux", dist_aux_aux, dbcsr_type_no_symmetry, blk_aux, blk_aux)
    1217            0 :       CALL dbcsr_create(matrix_V_grid, "V_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1218              : 
    1219            0 :       CALL copy_fm_to_dbcsr(fm_Vtr_Gamma(1, 1), matrix_V_aux, keep_sparsity=.FALSE.)
    1220              : 
    1221              :       ! V^tr_ll' = sum_PQ Z_lP V^trunc_PQ Z_l'Q
    1222              :       CALL dbcsr_contract_ABA("N", "T", mat_Z_lP, matrix_V_aux, matrix_V_grid, &
    1223            0 :                               bs_env%eps_filter)
    1224            0 :       CALL dbcsr_release(matrix_V_aux)
    1225              : 
    1226              :       ! =========================================================================
    1227              :       ! 3. SPIN LOOP FOR EXACT EXCHANGE
    1228              :       ! =========================================================================
    1229            0 :       DO ispin = 1, bs_env%n_spin
    1230              : 
    1231              :          ! Density matrix on grid is essentially G_occ at tau = 0.0
    1232              :          ! D_µν  = sum_n^occ C_µn(k=0) C_νn(k=0)
    1233              :          ! D_ll' = sum_µν ϕ_µ(r_l) D_µν ϕ_ν(r_l')
    1234            0 :          CALL dbcsr_create(matrix_D_grid, "D_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1235            0 :          CALL build_G_grid(bs_env, 0.0_dp, ispin, .TRUE., .FALSE., mat_phi_mu_l, matrix_D_grid, bs_env%eps_filter)
    1236              : 
    1237              :          ! Element-wise Hadamard product: Σ^x_grid = D_grid ◦ V_grid
    1238              :          ! Σ^x_ll' = D_ll' * V^tr_ll'
    1239            0 :          CALL dbcsr_create(matrix_Sigma_x_grid, template=matrix_V_grid)
    1240            0 :          CALL hadamard_product(matrix_D_grid, matrix_V_grid, matrix_Sigma_x_grid, 1.0_dp)
    1241              : 
    1242            0 :          CALL dbcsr_release(matrix_D_grid)
    1243              : 
    1244              :          ! Transform back to AO basis: Σ^x_ao = -1.0 * phi^T * Σ^x_grid * phi
    1245              :          ! Σ^x_λσ(k=0)   = -sum_ll' ϕ_λ(r_l) Σ^x_ll' ϕ_σ(r_l')
    1246              :          CALL dbcsr_contract_ABA("T", "N", mat_phi_mu_l, matrix_Sigma_x_grid, &
    1247            0 :                                  mat_Sigma_x_Gamma, bs_env%eps_filter)
    1248            0 :          CALL dbcsr_scale(mat_Sigma_x_Gamma, -1.0_dp)
    1249              : 
    1250            0 :          CALL dbcsr_release(matrix_Sigma_x_grid)
    1251              : 
    1252              :          ! Data I/O and Export to CP2K Full Matrices
    1253            0 :          CALL copy_dbcsr_to_fm(mat_Sigma_x_Gamma, fm_Sigma_x_Gamma(ispin))
    1254              : 
    1255              :       END DO ! ispin
    1256              : 
    1257            0 :       IF (bs_env%unit_nr > 0) THEN
    1258              :          WRITE (bs_env%unit_nr, '(T2,A,T58,A,F7.1,A)') &
    1259            0 :             'Computed Σ^x(k=0),', ' Execution time', m_walltime() - t1, ' s'
    1260            0 :          WRITE (bs_env%unit_nr, '(A)') ' '
    1261              :       END IF
    1262              : 
    1263              :       ! =========================================================================
    1264              :       ! 4. CLEANUP
    1265              :       ! =========================================================================
    1266              :       CALL release_dbcsr_topology_and_matrices(dist=dist_grid_grid, mapped_dist=dist_col_grid, &
    1267            0 :                                                m1=mat_Sigma_x_Gamma, m2=matrix_V_grid)
    1268            0 :       CALL release_dbcsr_topology_and_matrices(dist=dist_aux_aux, mapped_dist=dist_row_aux)
    1269              : 
    1270            0 :       CALL cp_fm_release(fm_Vtr_Gamma)
    1271              : 
    1272            0 :       CALL timestop(handle)
    1273              : 
    1274            0 :    END SUBROUTINE compute_Sigma_x
    1275              : 
    1276              : ! **************************************************************************************************
    1277              : !> \brief Computes the correlation part of the GW self-energy
    1278              : !> \param bs_env ...
    1279              : !> \param fm_W_time ...
    1280              : !> \param mat_phi_mu_l ...
    1281              : !> \param mat_Z_lP ...
    1282              : !> \param fm_Sigma_c_Gamma_time ...
    1283              : ! **************************************************************************************************
    1284              : 
    1285            0 :    SUBROUTINE compute_Sigma_c(bs_env, fm_W_time, mat_phi_mu_l, mat_Z_lP, fm_Sigma_c_Gamma_time)
    1286              : 
    1287              :       TYPE(post_scf_bandstructure_type), POINTER         :: bs_env
    1288              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_W_time
    1289              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_phi_mu_l, mat_Z_lP
    1290              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :, :)  :: fm_Sigma_c_Gamma_time
    1291              : 
    1292              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'compute_Sigma_c'
    1293              : 
    1294              :       INTEGER                                            :: handle, i_t, ispin
    1295            0 :       INTEGER, DIMENSION(:), POINTER                     :: blk_aux, blk_grid, dist_col_grid, &
    1296            0 :                                                             dist_row_aux
    1297              :       REAL(KIND=dp)                                      :: t1, tau
    1298              :       TYPE(dbcsr_distribution_type)                      :: dist_aux_aux, dist_grid_grid
    1299            0 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_Sigma_neg_tau, mat_Sigma_pos_tau
    1300              :       TYPE(dbcsr_type) :: matrix_G_occ_grid, matrix_G_vir_grid, matrix_Sigma_neg_grid, &
    1301              :          matrix_Sigma_pos_grid, matrix_W_aux, matrix_W_grid
    1302              : 
    1303            0 :       CALL timeset(routineN, handle)
    1304              : 
    1305              :       ! =========================================================================
    1306              :       ! 1. SETUP CORE TOPOLOGIES AND PRE-ALLOCATE OUTPUT ARRAYS
    1307              :       ! =========================================================================
    1308            0 :       CALL setup_square_topology(mat_phi_mu_l, 'ROW', dist_grid_grid, blk_grid, dist_col_grid)
    1309            0 :       CALL setup_square_topology(mat_Z_lP, 'COL', dist_aux_aux, blk_aux, dist_row_aux)
    1310              : 
    1311              :       ! Pre-allocate local DBCSR matrices to act as targets for final output
    1312            0 :       NULLIFY (mat_Sigma_neg_tau, mat_Sigma_pos_tau)
    1313            0 :       ALLOCATE (mat_Sigma_neg_tau(bs_env%num_time_freq_points, bs_env%n_spin))
    1314            0 :       ALLOCATE (mat_Sigma_pos_tau(bs_env%num_time_freq_points, bs_env%n_spin))
    1315              : 
    1316            0 :       DO i_t = 1, bs_env%num_time_freq_points
    1317            0 :          DO ispin = 1, bs_env%n_spin
    1318            0 :             ALLOCATE (mat_Sigma_neg_tau(i_t, ispin)%matrix)
    1319            0 :             ALLOCATE (mat_Sigma_pos_tau(i_t, ispin)%matrix)
    1320            0 :             CALL dbcsr_create(mat_Sigma_neg_tau(i_t, ispin)%matrix, template=bs_env%mat_ao_ao%matrix)
    1321            0 :             CALL dbcsr_create(mat_Sigma_pos_tau(i_t, ispin)%matrix, template=bs_env%mat_ao_ao%matrix)
    1322              :          END DO
    1323              :       END DO
    1324              : 
    1325              :       ! =========================================================================
    1326              :       ! 2. MAIN IMAGINARY TIME LOOP
    1327              :       ! =========================================================================
    1328            0 :       DO i_t = 1, bs_env%num_time_freq_points
    1329            0 :          tau = bs_env%time_frequency_grid%imaginary_time(i_t)
    1330              : 
    1331              :          ! -------------------------------------------------------------------
    1332              :          ! Compute W_grid = Z * W_aux * Z^T
    1333              :          ! -------------------------------------------------------------------
    1334            0 :          CALL dbcsr_create(matrix_W_aux, "W_aux", dist_aux_aux, dbcsr_type_no_symmetry, blk_aux, blk_aux)
    1335            0 :          CALL dbcsr_create(matrix_W_grid, "W_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1336              : 
    1337            0 :          CALL copy_fm_to_dbcsr(fm_W_time(i_t), matrix_W_aux, keep_sparsity=.FALSE.)
    1338              : 
    1339              :          ! W^MIC_ll'(iτ,k=0) = sum_PQ Z_lP W^MIC_PQ(iτ) Z_l'Q
    1340              :          CALL dbcsr_contract_ABA("N", "T", mat_Z_lP, matrix_W_aux, matrix_W_grid, &
    1341            0 :                                  bs_env%eps_filter)
    1342              : 
    1343            0 :          CALL dbcsr_release(matrix_W_aux) ! Clean up aux basis immediately
    1344              : 
    1345            0 :          DO ispin = 1, bs_env%n_spin
    1346            0 :             t1 = m_walltime()
    1347              : 
    1348              :             ! -------------------------------------------------------------------
    1349              :             ! A. Transform Green's Functions to the Grid
    1350              :             ! -------------------------------------------------------------------
    1351            0 :             CALL dbcsr_create(matrix_G_occ_grid, "G_occ_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1352            0 :             CALL dbcsr_create(matrix_G_vir_grid, "G_vir_grid", dist_grid_grid, dbcsr_type_no_symmetry, blk_grid, blk_grid)
    1353              : 
    1354              :             ! G^occ_µλ(i|τ|,k=0) = sum_G^occ_µλn^occ C_µn(k=0) e^(-|(ϵ_nk=0-ϵ_F)τ|) C_λn(k=0)
    1355              :             ! G^occ_ll'(i|τ|,k=0) = sum_µν ϕ_µ(r_l) G^occ_µν ϕ_ν(r_l')
    1356            0 :             CALL build_G_grid(bs_env, tau, ispin, .TRUE., .FALSE., mat_phi_mu_l, matrix_G_occ_grid, bs_env%eps_filter)
    1357              : 
    1358              :             ! G^vir_µλ(i|τ|,k=0) = sum_n^vir C_µn(k=0) e^(-|(ϵ_nk=0-ϵ_F)τ|) C_λn(k=0)
    1359              :             ! G^vir_ll'(i|τ|,k=0) = sum_µν ϕ_µ(r_l) G^vir_µν ϕ_ν(r_l')
    1360            0 :             CALL build_G_grid(bs_env, tau, ispin, .FALSE., .TRUE., mat_phi_mu_l, matrix_G_vir_grid, bs_env%eps_filter)
    1361              : 
    1362              :             ! -------------------------------------------------------------------
    1363              :             ! B. Element-wise Hadamard Products for Sigma_c on Grid
    1364              :             ! Σ_neg_grid = G_occ_grid ◦ W_grid
    1365              :             ! Σ_pos_grid = G_vir_grid ◦ W_grid
    1366              :             ! -------------------------------------------------------------------
    1367            0 :             CALL dbcsr_create(matrix_Sigma_neg_grid, template=matrix_W_grid)
    1368            0 :             CALL dbcsr_create(matrix_Sigma_pos_grid, template=matrix_W_grid)
    1369              : 
    1370              :             ! Σ^c_ll'(iτ,k=0)   = -G^occ_ll'(i|τ|,k=0) * W^MIC_ll'(iτ,k=0), for τ < 0
    1371            0 :             CALL hadamard_product(matrix_G_occ_grid, matrix_W_grid, matrix_Sigma_neg_grid, 1.0_dp)
    1372              : 
    1373              :             ! Σ^c_ll'(iτ,k=0)   =  G^vir_ll'(i|τ|,k=0) * W^MIC_ll'(iτ,k=0), for τ > 0
    1374            0 :             CALL hadamard_product(matrix_G_vir_grid, matrix_W_grid, matrix_Sigma_pos_grid, 1.0_dp)
    1375              : 
    1376              :             ! Instantly purge massive G_grid arrays to save memory
    1377            0 :             CALL dbcsr_release(matrix_G_occ_grid)
    1378            0 :             CALL dbcsr_release(matrix_G_vir_grid)
    1379              : 
    1380              :             ! -------------------------------------------------------------------
    1381              :             ! C. Transform Sigma back to AO Basis
    1382              :             ! Σ_AO = phi^T * Σ_grid * phi
    1383              :             ! -------------------------------------------------------------------
    1384              : 
    1385              :             ! Σ^c_λσ(iτ,k=0)    = sum_ll' ϕ_λ(r_l) Σ^c_ll'(iτ,k=0) ϕ_σ(r_l'), for τ < 0
    1386              :             CALL dbcsr_contract_ABA("T", "N", mat_phi_mu_l, matrix_Sigma_neg_grid, &
    1387            0 :                                     mat_Sigma_neg_tau(i_t, ispin)%matrix, bs_env%eps_filter)
    1388            0 :             CALL dbcsr_scale(mat_Sigma_neg_tau(i_t, ispin)%matrix, -1.0_dp)
    1389              : 
    1390              :             ! Σ^c_λσ(iτ,k=0)    = sum_ll' ϕ_λ(r_l) Σ^c_ll'(iτ,k=0) ϕ_σ(r_l'), for τ > 0
    1391              :             CALL dbcsr_contract_ABA("T", "N", mat_phi_mu_l, matrix_Sigma_pos_grid, &
    1392            0 :                                     mat_Sigma_pos_tau(i_t, ispin)%matrix, bs_env%eps_filter)
    1393              : 
    1394              :             ! Purge Grid Sigma arrays
    1395            0 :             CALL dbcsr_release(matrix_Sigma_neg_grid)
    1396            0 :             CALL dbcsr_release(matrix_Sigma_pos_grid)
    1397              : 
    1398            0 :             IF (bs_env%unit_nr > 0) THEN
    1399              :                WRITE (bs_env%unit_nr, '(T2,A,I10,A,I3,A,F7.1,A)') &
    1400            0 :                   'Computed Σ^c(iτ,k=0) for time point ', i_t, ' /', bs_env%num_time_freq_points, &
    1401            0 :                   ',    Execution time', m_walltime() - t1, ' s'
    1402              :             END IF
    1403              : 
    1404              :          END DO ! ispin
    1405              : 
    1406              :          ! Release the W_grid for this time point
    1407            0 :          CALL dbcsr_release(matrix_W_grid)
    1408              : 
    1409              :       END DO ! i_t
    1410              : 
    1411            0 :       IF (bs_env%unit_nr > 0) WRITE (bs_env%unit_nr, '(A)') ' '
    1412              : 
    1413              :       ! -------------------------------------------------------------------------
    1414              :       ! 3. FINALIZE AND CLEANUP
    1415              :       ! -------------------------------------------------------------------------
    1416              :       CALL fill_fm_Sigma_c_Gamma_time(fm_Sigma_c_Gamma_time, bs_env, &
    1417            0 :                                       mat_Sigma_pos_tau, mat_Sigma_neg_tau)
    1418              : 
    1419            0 :       CALL cp_fm_release(fm_W_time)
    1420              : 
    1421            0 :       CALL dbcsr_deallocate_matrix_set(mat_Sigma_neg_tau)
    1422            0 :       CALL dbcsr_deallocate_matrix_set(mat_Sigma_pos_tau)
    1423              : 
    1424            0 :       CALL release_dbcsr_topology_and_matrices(dist=dist_grid_grid, mapped_dist=dist_col_grid)
    1425            0 :       CALL release_dbcsr_topology_and_matrices(dist=dist_aux_aux, mapped_dist=dist_row_aux)
    1426              : 
    1427            0 :       CALL delete_unnecessary_files(bs_env)
    1428            0 :       CALL timestop(handle)
    1429              : 
    1430            0 :    END SUBROUTINE compute_Sigma_c
    1431              : 
    1432              : ! **************************************************************************************************
    1433              : !> \brief DBCSR Topology Generation
    1434              : !> \param matrix_template ...
    1435              : !> \param dim_type ...
    1436              : !> \param square_dist ...
    1437              : !> \param blk_sizes ...
    1438              : !> \param mapped_dist ...
    1439              : ! **************************************************************************************************
    1440              : 
    1441        26880 :    SUBROUTINE setup_square_topology(matrix_template, dim_type, square_dist, blk_sizes, mapped_dist)
    1442              : 
    1443              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_template
    1444              :       CHARACTER(LEN=*), INTENT(IN)                       :: dim_type
    1445              :       TYPE(dbcsr_distribution_type), INTENT(OUT)         :: square_dist
    1446              :       INTEGER, DIMENSION(:), INTENT(OUT), POINTER        :: blk_sizes, mapped_dist
    1447              : 
    1448              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'setup_square_topology'
    1449              : 
    1450              :       INTEGER                                            :: handle, i, np, npcols, nprows
    1451         8960 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk, col_dist, row_blk, row_dist
    1452              :       TYPE(dbcsr_distribution_type)                      :: dist_template
    1453              : 
    1454         8960 :       CALL timeset(routineN, handle)
    1455              : 
    1456              :       CALL dbcsr_get_info(matrix_template, distribution=dist_template, &
    1457         8960 :                           row_blk_size=row_blk, col_blk_size=col_blk)
    1458              :       CALL dbcsr_distribution_get(dist_template, row_dist=row_dist, col_dist=col_dist, &
    1459         8960 :                                   nprows=nprows, npcols=npcols)
    1460              : 
    1461         8960 :       IF (TRIM(dim_type) == 'ROW') THEN
    1462              :          ! Creates ROW x ROW (e.g., Grid x Grid from mat_phi_mu_l)
    1463          600 :          blk_sizes => row_blk
    1464          600 :          np = npcols
    1465         1800 :          ALLOCATE (mapped_dist(SIZE(blk_sizes)))
    1466         6960 :          DO i = 1, SIZE(blk_sizes)
    1467         6960 :             mapped_dist(i) = MOD(i - 1, np)
    1468              :          END DO
    1469              :          CALL dbcsr_distribution_new(square_dist, template=dist_template, &
    1470          600 :                                      row_dist=row_dist, col_dist=mapped_dist)
    1471              : 
    1472         8360 :       ELSE IF (TRIM(dim_type) == 'COL') THEN
    1473              :          ! Creates COL x COL (e.g., Aux x Aux from mat_Z_lP)
    1474         8360 :          blk_sizes => col_blk
    1475         8360 :          np = nprows
    1476        25080 :          ALLOCATE (mapped_dist(SIZE(blk_sizes)))
    1477        25080 :          DO i = 1, SIZE(blk_sizes)
    1478        25080 :             mapped_dist(i) = MOD(i - 1, np)
    1479              :          END DO
    1480              :          CALL dbcsr_distribution_new(square_dist, template=dist_template, &
    1481         8360 :                                      row_dist=mapped_dist, col_dist=col_dist)
    1482              :       END IF
    1483              : 
    1484         8960 :       CALL timestop(handle)
    1485              : 
    1486         8960 :    END SUBROUTINE setup_square_topology
    1487              : 
    1488              : ! **************************************************************************************************
    1489              : !> \brief DBCSR matrices deallocation
    1490              : !> \param dist ...
    1491              : !> \param mapped_dist    ...
    1492              : !> \param m1 ...
    1493              : !> \param m2 ...
    1494              : !> \param m3 ...
    1495              : !> \param m4 ...
    1496              : ! **************************************************************************************************
    1497              : 
    1498        13560 :    SUBROUTINE release_dbcsr_topology_and_matrices(dist, mapped_dist, m1, m2, m3, m4)
    1499              : 
    1500              :       TYPE(dbcsr_distribution_type), INTENT(INOUT), &
    1501              :          OPTIONAL                                        :: dist
    1502              :       INTEGER, DIMENSION(:), INTENT(INOUT), OPTIONAL, &
    1503              :          POINTER                                         :: mapped_dist
    1504              :       TYPE(dbcsr_type), INTENT(INOUT), OPTIONAL          :: m1, m2, m3, m4
    1505              : 
    1506              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'release_dbcsr_topology_and_matrices'
    1507              : 
    1508              :       INTEGER                                            :: handle
    1509              : 
    1510        13560 :       CALL timeset(routineN, handle)
    1511              : 
    1512        13560 :       IF (PRESENT(dist)) CALL dbcsr_distribution_release(dist)
    1513        13560 :       IF (PRESENT(mapped_dist)) THEN
    1514         8960 :          IF (ASSOCIATED(mapped_dist)) THEN
    1515         8960 :             DEALLOCATE (mapped_dist)
    1516              :             NULLIFY (mapped_dist)
    1517              :          END IF
    1518              :       END IF
    1519        13560 :       IF (PRESENT(m1)) CALL dbcsr_release(m1)
    1520        13560 :       IF (PRESENT(m2)) CALL dbcsr_release(m2)
    1521        13560 :       IF (PRESENT(m3)) CALL dbcsr_release(m3)
    1522        13560 :       IF (PRESENT(m4)) CALL dbcsr_release(m4)
    1523              : 
    1524        13560 :       CALL timestop(handle)
    1525              : 
    1526        13560 :    END SUBROUTINE release_dbcsr_topology_and_matrices
    1527              : 
    1528              : END MODULE gw_ri_rs_large_cell_Gamma
        

Generated by: LCOV version 2.0-1