LCOV - code coverage report
Current view: top level - src/fm - cp_fm_diag_utils.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:71c3ab0) Lines: 71.9 % 135 97
Test Date: 2026-07-25 06:35:44 Functions: 66.7 % 9 6

            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 Auxiliary tools to redistribute cp_fm_type matrices before and after diagonalization.
      10              : !>        Heuristics are used to determine the optimal number of CPUs for diagonalization and the
      11              : !>        input matrices are redistributed if necessary
      12              : !> \par History
      13              : !>      - [01.2018] moved redistribution related code from cp_fm_syevd here
      14              : !> \author Nico Holmberg [01.2018]
      15              : ! **************************************************************************************************
      16              : MODULE cp_fm_diag_utils
      17              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      18              :                                               cp_blacs_env_release,&
      19              :                                               cp_blacs_env_type
      20              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      21              :                                               cp_fm_struct_release,&
      22              :                                               cp_fm_struct_type
      23              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      24              :                                               cp_fm_get_info,&
      25              :                                               cp_fm_release,&
      26              :                                               cp_fm_type
      27              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      28              :                                               cp_logger_get_default_io_unit,&
      29              :                                               cp_logger_type
      30              :    USE kinds,                           ONLY: dp
      31              :    USE mathlib,                         ONLY: gcd
      32              :    USE message_passing,                 ONLY: mp_para_env_type
      33              : #include "../base/base_uses.f90"
      34              : 
      35              :    IMPLICIT NONE
      36              : 
      37              :    PRIVATE
      38              : 
      39              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_fm_diag_utils'
      40              : 
      41              :    ! Information on redistribution
      42              :    TYPE, PUBLIC :: cp_fm_redistribute_info
      43              :       INTEGER :: matrix_order = -1
      44              :       INTEGER :: num_pe_old = -1 ! number of processes before a potential redistribute
      45              :       INTEGER :: num_pe_new = -1 ! number of processes after a potential redistribute
      46              :       INTEGER :: num_pe_opt = -1 ! optimal number of processes for the given matrix
      47              :       INTEGER :: num_pe_max_nz_col = -1 ! the maximal number of processes s.t. no column has zero width, may be < 0 if ignored
      48              :       LOGICAL :: redistribute = .FALSE. ! whether or not the matrix was actually redistributed
      49              :    CONTAINS
      50              :       PROCEDURE, PASS(self) :: write => cp_fm_redistribute_info_write
      51              :    END TYPE cp_fm_redistribute_info
      52              : 
      53              :    ! Container for redistribution settings and temporary work structs
      54              :    TYPE cp_fm_redistribute_type
      55              :       ! Settings
      56              :       INTEGER                                  :: a = -1, x = -1
      57              :       LOGICAL                                  :: should_print = .FALSE.
      58              :       LOGICAL                                  :: elpa_force_redistribute = .FALSE.
      59              :       ! Temporaries
      60              :       INTEGER, DIMENSION(:), POINTER           :: group_distribution => NULL(), &
      61              :                                                   group_partition => NULL()
      62              :       TYPE(cp_blacs_env_type), POINTER         :: blacs_env_new => NULL()
      63              :       TYPE(mp_para_env_type), POINTER          :: para_env_new => NULL()
      64              :    END TYPE cp_fm_redistribute_type
      65              : 
      66              :    ! Permanent instance of the redistribute type
      67              :    TYPE(cp_fm_redistribute_type), PRIVATE, &
      68              :       SAVE                                     :: work_redistribute
      69              : 
      70              :    ! Public subroutines
      71              : 
      72              :    PUBLIC :: cp_fm_redistribute_start, &
      73              :              cp_fm_redistribute_end, &
      74              :              cp_fm_redistribute_init
      75              : 
      76              : CONTAINS
      77              : 
      78              : ! **************************************************************************************************
      79              : !> \brief Write the redistribute info nicely formatted to the given I/O unit
      80              : !> \param self reference to the cp_fm_redistribute_info instance
      81              : !> \param io_unit I/O unit to use for writing
      82              : ! **************************************************************************************************
      83            0 :    SUBROUTINE cp_fm_redistribute_info_write(self, io_unit)
      84              :       CLASS(cp_fm_redistribute_info), INTENT(IN) :: self
      85              :       INTEGER, INTENT(IN) :: io_unit
      86              : 
      87            0 :       WRITE (UNIT=io_unit, FMT="(A)") ""
      88              :       WRITE (UNIT=io_unit, FMT="(T2,A,T71,I10)") &
      89            0 :          "CP_FM_DIAG| Number of processes over which the matrix is distributed ", self%num_pe_old, &
      90            0 :          "CP_FM_DIAG| Matrix order ", self%matrix_order
      91              :       WRITE (UNIT=io_unit, FMT="(T2,A,T71,I10)") &
      92            0 :          "CP_FM_DIAG| Optimal number of CPUs ", self%num_pe_opt
      93            0 :       IF (self%num_pe_max_nz_col < 0) THEN
      94              :          WRITE (UNIT=io_unit, FMT="(T2,A,T71,A10)") &
      95            0 :             "CP_FM_DIAG| Maximum number of CPUs (with non-zero columns) ", "<N/A>"
      96              :       ELSE
      97              :          WRITE (UNIT=io_unit, FMT="(T2,A,T71,I10)") &
      98            0 :             "CP_FM_DIAG| Maximum number of CPUs (with non-zero columns): ", self%num_pe_max_nz_col
      99              :       END IF
     100            0 :       IF (self%redistribute) THEN
     101              :          WRITE (UNIT=io_unit, FMT="(T2,A,T71,I10)") &
     102            0 :             "CP_FM_DIAG| Number of processes for the redistribution ", self%num_pe_new
     103              :       ELSE
     104              :          WRITE (UNIT=io_unit, FMT="(T2,A)") &
     105            0 :             "CP_FM_DIAG| The matrix will NOT be redistributed"
     106              :       END IF
     107            0 :       WRITE (UNIT=io_unit, FMT="(A)") ""
     108              : 
     109            0 :    END SUBROUTINE cp_fm_redistribute_info_write
     110              : 
     111              : ! **************************************************************************************************
     112              : !> \brief  Releases the temporary storage needed when redistributing arrays
     113              : !> \param  has_redistributed flag that determines if the processors holds a part of the
     114              : !>                           redistributed array
     115              : !> \author Nico Holmberg [01.2018]
     116              : ! **************************************************************************************************
     117       268841 :    SUBROUTINE cp_fm_redistribute_work_finalize(has_redistributed)
     118              :       LOGICAL, INTENT(IN)                                :: has_redistributed
     119              : 
     120       268841 :       IF (ASSOCIATED(work_redistribute%group_distribution)) THEN
     121       268841 :          IF (has_redistributed) THEN
     122       136294 :             CALL cp_blacs_env_release(work_redistribute%blacs_env_new)
     123              :          END IF
     124       268841 :          CALL work_redistribute%para_env_new%free()
     125       268841 :          DEALLOCATE (work_redistribute%para_env_new)
     126       268841 :          DEALLOCATE (work_redistribute%group_distribution)
     127       268841 :          DEALLOCATE (work_redistribute%group_partition)
     128              :       END IF
     129              :       ! Return work to its initial state
     130       268841 :       work_redistribute = cp_fm_redistribute_type()
     131              : 
     132       268841 :    END SUBROUTINE cp_fm_redistribute_work_finalize
     133              : 
     134              : ! **************************************************************************************************
     135              : !> \brief  Initializes the parameters that determine how to calculate the optimal number of CPUs
     136              : !>         for diagonalizing a matrix. The parameters are read from the GLOBAL input section.
     137              : !> \param a                integer parameter used to define the rule for determining the optimal
     138              : !>                         number of CPUs for diagonalization
     139              : !> \param x                integer parameter used to define the rule for determining the optimal
     140              : !>                         number of CPUs for diagonalization
     141              : !> \param should_print     flag that determines if information about the redistribution process
     142              : !>                         should be printed
     143              : !> \param elpa_force_redistribute  flag that if redistribution should always be performed when
     144              : !>                                 the ELPA diagonalization library is in use
     145              : !> \author Nico Holmberg [01.2018]
     146              : ! **************************************************************************************************
     147        11087 :    SUBROUTINE cp_fm_redistribute_init(a, x, should_print, elpa_force_redistribute)
     148              :       INTEGER, INTENT(IN)                                :: a, x
     149              :       LOGICAL, INTENT(IN)                                :: should_print, elpa_force_redistribute
     150              : 
     151              :       work_redistribute%a = a
     152              :       work_redistribute%x = x
     153              :       work_redistribute%should_print = should_print
     154              :       work_redistribute%elpa_force_redistribute = elpa_force_redistribute
     155              :       ! Init work
     156        11087 :       work_redistribute = cp_fm_redistribute_type()
     157              : 
     158        11087 :    END SUBROUTINE cp_fm_redistribute_init
     159              : 
     160              : ! **************************************************************************************************
     161              : !> \brief  Calculates the optimal number of CPUs for diagonalizing a matrix.
     162              : !> \param  size  the size of the diagonalized matrix
     163              : !> \return the optimal number of CPUs
     164              : !> \author Nico Holmberg [01.2018]
     165              : ! **************************************************************************************************
     166       272985 :    PURE FUNCTION cp_fm_diag_get_optimal_ncpu(size) RESULT(ncpu)
     167              :       INTEGER, INTENT(IN)                                :: size
     168              :       INTEGER                                            :: ncpu
     169              : 
     170              :       ncpu = ((size + work_redistribute%a*work_redistribute%x - 1)/ &
     171       272985 :               (work_redistribute%a*work_redistribute%x))*work_redistribute%a
     172              : 
     173       272985 :    END FUNCTION cp_fm_diag_get_optimal_ncpu
     174              : 
     175              : #if defined(__parallel)
     176              : ! **************************************************************************************************
     177              : !> \brief  Determines the largest number of CPUs a matrix can be distributed on without any of the
     178              : !>         processors getting a zero-width column (currently only needed for ELPA).
     179              : !> \param  matrix the matrix that will be diagonalized
     180              : !> \return the maximum number of CPUs for ELPA
     181              : !> \author Nico Holmberg [01.2018]
     182              : ! **************************************************************************************************
     183        16222 :    FUNCTION cp_fm_max_ncpu_non_zero_column(matrix) RESULT(ncpu)
     184              :       TYPE(cp_fm_type), INTENT(IN)                       :: matrix
     185              :       INTEGER                                            :: ncpu
     186              : 
     187              :       INTEGER                                            :: gcd_max, ipe, jpe, ncol_block, &
     188              :                                                             ncol_global, npcol, nrow_block, &
     189              :                                                             nrow_global, num_pe_old, nzero
     190        16222 :       INTEGER, DIMENSION(:), POINTER                     :: ncol_locals
     191              :       INTEGER, EXTERNAL                                  :: numroc
     192              : 
     193        16222 :       NULLIFY (ncol_locals)
     194              :       ! First check if there are any zero width columns in current layout
     195              :       CALL cp_fm_get_info(matrix, ncol_locals=ncol_locals, &
     196              :                           nrow_global=nrow_global, ncol_global=ncol_global, &
     197        16222 :                           nrow_block=nrow_block, ncol_block=ncol_block)
     198        32444 :       nzero = COUNT(ncol_locals == 0)
     199        16222 :       num_pe_old = matrix%matrix_struct%para_env%num_pe
     200        16222 :       ncpu = num_pe_old - nzero
     201              : 
     202              :       ! Avoid layouts with odd number of CPUs (blacs grid layout will be square)
     203        16222 :       IF (ncpu > 2) THEN
     204            0 :          ncpu = ncpu - MODULO(ncpu, 2)
     205              :       END IF
     206              : 
     207              :       ! if there are no zero-width columns and the number of processors was even, leave it at that
     208        16222 :       IF (ncpu == num_pe_old) THEN
     209              :          RETURN
     210              :       END IF
     211              : 
     212              :       ! Iteratively search for the maximum number of CPUs for ELPA
     213              :       ! On each step, we test whether the blacs grid created with ncpu processes
     214              :       ! contains any columns with zero width
     215            0 :       DO WHILE (ncpu > 1)
     216              :          ! Determine layout of new blacs grid with ncpu CPUs
     217              :          ! (snippet copied from cp_blacs_env.F:cp_blacs_env_create)
     218            0 :          gcd_max = -1
     219            0 :          DO ipe = 1, CEILING(SQRT(REAL(ncpu, dp)))
     220            0 :             jpe = ncpu/ipe
     221            0 :             IF (ipe*jpe /= ncpu) THEN
     222              :                CYCLE
     223              :             END IF
     224            0 :             IF (gcd(ipe, jpe) >= gcd_max) THEN
     225            0 :                npcol = jpe
     226            0 :                gcd_max = gcd(ipe, jpe)
     227              :             END IF
     228              :          END DO
     229              : 
     230              :          ! Count the number of processors without any columns
     231              :          ! (snippet copied from cp_fm_struct.F:cp_fm_struct_create)
     232            0 :          nzero = 0
     233            0 :          DO ipe = 0, npcol - 1
     234            0 :             IF (numroc(ncol_global, ncol_block, ipe, 0, npcol) == 0) THEN
     235            0 :                nzero = nzero + 1
     236              :             END IF
     237              :          END DO
     238              : 
     239            0 :          IF (nzero == 0) THEN
     240              :             EXIT
     241              :          END IF
     242              : 
     243            0 :          ncpu = ncpu - nzero
     244              : 
     245            0 :          IF (ncpu > 2) THEN
     246            0 :             ncpu = ncpu - MODULO(ncpu, 2)
     247              :          END IF
     248              :       END DO
     249              : 
     250        16222 :    END FUNCTION cp_fm_max_ncpu_non_zero_column
     251              : #endif
     252              : 
     253              : ! **************************************************************************************************
     254              : !> \brief   Determines the optimal number of CPUs for matrix diagonalization and redistributes
     255              : !>          the input matrices if necessary
     256              : !> \param matrix           the input cp_fm_type matrix to be diagonalized
     257              : !> \param eigenvectors     the cp_fm_type matrix that will hold the eigenvectors of the input matrix
     258              : !> \param matrix_new       the redistributed input matrix which will subsequently be diagonalized,
     259              : !>                         or a pointer to the original matrix if no redistribution is required
     260              : !> \param eigenvectors_new the redistributed eigenvectors matrix, or a pointer to the original
     261              : !>                         matrix if no redistribution is required
     262              : !> \param caller_is_elpa   flag that determines if ELPA is used for diagonalization
     263              : !> \param redist_info      get info about the redistribution
     264              : !> \par History
     265              : !>      - [01.2018] created by moving redistribution related code from cp_fm_syevd here
     266              : !> \author Nico Holmberg [01.2018]
     267              : ! **************************************************************************************************
     268        16222 :    SUBROUTINE cp_fm_redistribute_start(matrix, eigenvectors, matrix_new, eigenvectors_new, &
     269              :                                        caller_is_elpa, redist_info)
     270              : 
     271              :       TYPE(cp_fm_type), INTENT(IN)             :: matrix, eigenvectors
     272              :       TYPE(cp_fm_type), INTENT(OUT)            :: matrix_new, eigenvectors_new
     273              :       LOGICAL, OPTIONAL, INTENT(IN)            :: caller_is_elpa
     274              : 
     275              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_redistribute_start'
     276              : 
     277              :       INTEGER                                  :: handle
     278              :       LOGICAL                                  :: is_elpa
     279              :       TYPE(cp_fm_redistribute_info), OPTIONAL, INTENT(OUT) :: redist_info
     280              : 
     281              : #if defined(__parallel)
     282              :       REAL(KIND=dp)                            :: fake_local_data(1, 1)
     283              :       INTEGER                                  :: fake_descriptor(9), mepos_old, &
     284              :                                                   io_unit, ngroups, ncol_block, blksize, nrow_block
     285              :       TYPE(cp_fm_struct_type), POINTER         :: fm_struct_new
     286              :       TYPE(mp_para_env_type), POINTER          :: para_env
     287              :       TYPE(cp_logger_type), POINTER            :: logger
     288              :       TYPE(cp_fm_redistribute_info)          :: rdinfo
     289              : #endif
     290              : 
     291       272985 :       CALL timeset(routineN, handle)
     292       272985 :       is_elpa = .FALSE.
     293       272985 :       IF (PRESENT(caller_is_elpa)) THEN
     294              : #if defined(__ELPA)
     295        16222 :          is_elpa = caller_is_elpa
     296              : #else
     297              :          CPABORT("CP2K compiled without the ELPA library.")
     298              : #endif
     299              :       END IF
     300              : 
     301              : #if defined(__parallel)
     302              : 
     303       272985 :       logger => cp_get_default_logger()
     304       272985 :       io_unit = cp_logger_get_default_io_unit(logger)
     305              : 
     306              :       ! first figure out the optimal number of cpus
     307              :       ! this is pure heuristics, the defaults are based on rosa timings
     308              :       ! that demonstrate that timings go up sharply if too many tasks are used
     309              :       ! we take a multiple of 4, and approximately n/60
     310       272985 :       para_env => matrix%matrix_struct%para_env
     311       272985 :       mepos_old = para_env%mepos
     312       272985 :       ncol_block = -1 ! normally we also want to adjust the block size according to the optimal # of CPUs
     313       272985 :       nrow_block = -1
     314       272985 :       blksize = -1
     315              : 
     316       272985 :       rdinfo%matrix_order = matrix%matrix_struct%nrow_global
     317       272985 :       rdinfo%num_pe_old = para_env%num_pe
     318       272985 :       rdinfo%num_pe_opt = cp_fm_diag_get_optimal_ncpu(rdinfo%matrix_order)
     319       272985 :       rdinfo%num_pe_new = rdinfo%num_pe_opt
     320              :       rdinfo%num_pe_max_nz_col = -1
     321              :       rdinfo%redistribute = .FALSE.
     322              : 
     323       272985 :       IF (is_elpa) THEN
     324              :          ! with ELPA we don't have to redistribute if not necessary (scales, unlike ScaLAPACK)
     325        16222 :          rdinfo%num_pe_new = rdinfo%num_pe_old
     326              : 
     327              :          ! BUT: Diagonalization with ELPA fails when a processor column has zero width
     328              :          ! Determine the maximum number of CPUs the matrix can be distributed without zero-width columns
     329              :          ! for the current block size.
     330        16222 :          rdinfo%num_pe_max_nz_col = cp_fm_max_ncpu_non_zero_column(matrix)
     331              : 
     332              :          ! if the user wants to redistribute to the ScaLAPACK optimal number of CPUs anyway, let him if it's safe.
     333        16222 :          IF (work_redistribute%elpa_force_redistribute .AND. rdinfo%num_pe_opt < rdinfo%num_pe_max_nz_col) THEN
     334              :             ! Use heuristics to determine the need for redistribution (when num_pe_opt is smaller than the safe maximum)
     335              :             ! in this case we can also take the block size used for ScaLAPACK
     336            0 :             rdinfo%num_pe_new = rdinfo%num_pe_opt
     337        16222 :          ELSE IF (rdinfo%num_pe_old > rdinfo%num_pe_max_nz_col) THEN
     338              :             ! Otherwise, only redistribute if we have to
     339            0 :             rdinfo%num_pe_new = rdinfo%num_pe_max_nz_col
     340              :             ! do NOT let cp_fm_struct_create automatically adjust the block size because the
     341              :             ! calculated number of processors such that no block has 0 columns wouldn't match (see #578):
     342              :             ! if the automatically chosen block size is larger than the present one we would still end
     343              :             ! up with empty processors
     344              :          END IF
     345              : 
     346        16222 :          CALL cp_fm_get_info(matrix, ncol_block=ncol_block, nrow_block=nrow_block)
     347              : 
     348              :          ! On GPUs, ELPA requires the block size to be a power of 2
     349        16222 :          blksize = 1
     350        99498 :          DO WHILE (2*blksize <= MIN(nrow_block, ncol_block))
     351        16222 :             blksize = blksize*2
     352              :          END DO
     353        16222 :          nrow_block = blksize
     354        16222 :          ncol_block = blksize
     355              :       END IF
     356              : 
     357              :       ! finally, only redistribute if we're going to use less CPUs than before or changed the block size
     358              :       rdinfo%redistribute = (rdinfo%num_pe_old > rdinfo%num_pe_new) .OR. (blksize >= 0 .AND. &
     359       272985 :                                    ((blksize /= matrix%matrix_struct%ncol_block) .OR. (blksize /= matrix%matrix_struct%nrow_block)))
     360              : 
     361       272985 :       IF (work_redistribute%should_print .AND. io_unit > 0) THEN
     362            0 :          IF (is_elpa) THEN
     363            0 :             IF (work_redistribute%elpa_force_redistribute) THEN
     364              :                WRITE (UNIT=io_unit, FMT="(T2,A,T78,A3)") &
     365            0 :                   "CP_FM_DIAG| Force redistribute (ELPA):", "YES"
     366              :             ELSE
     367              :                WRITE (UNIT=io_unit, FMT="(T2,A,T79,A2)") &
     368            0 :                   "CP_FM_DIAG| Force redistribute (ELPA):", "NO"
     369              :             END IF
     370              :          END IF
     371            0 :          CALL rdinfo%write(io_unit)
     372              :       END IF
     373       272985 :       CALL para_env%sync()
     374              : 
     375              :       ! if the optimal is smaller than num_pe, we will redistribute the input matrix
     376       272985 :       IF (rdinfo%redistribute) THEN
     377              :          ! split comm, the first num_pe_new tasks will do the work
     378       806523 :          ALLOCATE (work_redistribute%group_distribution(0:rdinfo%num_pe_old - 1))
     379       268841 :          ALLOCATE (work_redistribute%group_partition(0:1))
     380       806523 :          work_redistribute%group_partition = [rdinfo%num_pe_new, rdinfo%num_pe_old - rdinfo%num_pe_new]
     381       268841 :          ALLOCATE (work_redistribute%para_env_new)
     382              :          CALL work_redistribute%para_env_new%from_split( &
     383              :             comm=para_env, ngroups=ngroups, group_distribution=work_redistribute%group_distribution, &
     384       268841 :             n_subgroups=2, group_partition=work_redistribute%group_partition)
     385              : 
     386       268841 :          IF (work_redistribute%group_distribution(mepos_old) == 0) THEN
     387              : 
     388              :             ! create blacs, should inherit the preferences for the layout and so on, from the higher level
     389       136294 :             NULLIFY (work_redistribute%blacs_env_new)
     390       136294 :             CALL cp_blacs_env_create(blacs_env=work_redistribute%blacs_env_new, para_env=work_redistribute%para_env_new)
     391              : 
     392              :             ! create new matrix
     393       136294 :             NULLIFY (fm_struct_new)
     394       136294 :             IF (nrow_block == -1 .OR. ncol_block == -1) THEN
     395              :                CALL cp_fm_struct_create(fmstruct=fm_struct_new, &
     396              :                                         para_env=work_redistribute%para_env_new, &
     397              :                                         context=work_redistribute%blacs_env_new, &
     398              :                                         nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
     399       130255 :                                         ncol_block=ncol_block, nrow_block=nrow_block)
     400              :             ELSE
     401              :                CALL cp_fm_struct_create(fmstruct=fm_struct_new, &
     402              :                                         para_env=work_redistribute%para_env_new, &
     403              :                                         context=work_redistribute%blacs_env_new, &
     404              :                                         nrow_global=rdinfo%matrix_order, ncol_global=rdinfo%matrix_order, &
     405         6039 :                                         ncol_block=ncol_block, nrow_block=nrow_block, force_block=.TRUE.)
     406              :             END IF
     407       136294 :             CALL cp_fm_create(matrix_new, matrix_struct=fm_struct_new, name="yevd_new_mat")
     408       136294 :             CALL cp_fm_create(eigenvectors_new, matrix_struct=fm_struct_new, name="yevd_new_vec")
     409       136294 :             CALL cp_fm_struct_release(fm_struct_new)
     410              : 
     411              :             ! redistribute old
     412              :             CALL pdgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
     413              :                           matrix%matrix_struct%descriptor, &
     414              :                           matrix_new%local_data(1, 1), 1, 1, matrix_new%matrix_struct%descriptor, &
     415       136294 :                           matrix%matrix_struct%context)
     416              :          ELSE
     417              :             ! these tasks must help redistribute (they own part of the data),
     418              :             ! but need fake 'new' data, and their descriptor must indicate this with -1
     419              :             ! see also scalapack comments on pdgemr2d
     420      1325470 :             fake_descriptor = -1
     421              :             CALL pdgemr2d(rdinfo%matrix_order, rdinfo%matrix_order, matrix%local_data(1, 1), 1, 1, &
     422              :                           matrix%matrix_struct%descriptor, &
     423              :                           fake_local_data(1, 1), 1, 1, fake_descriptor, &
     424       132547 :                           matrix%matrix_struct%context)
     425              :          END IF
     426              :       ELSE
     427              :          ! No need to redistribute, just return pointers to the original arrays
     428         4144 :          matrix_new = matrix
     429         4144 :          eigenvectors_new = eigenvectors
     430              :       END IF
     431              : 
     432       272985 :       IF (PRESENT(redist_info)) THEN
     433        16222 :          redist_info = rdinfo
     434              :       END IF
     435              : #else
     436              : 
     437              :       MARK_USED(matrix)
     438              :       MARK_USED(eigenvectors)
     439              :       MARK_USED(matrix_new)
     440              :       MARK_USED(eigenvectors_new)
     441              :       MARK_USED(redist_info)
     442              :       CPABORT("Routine called in non-parallel case.")
     443              : #endif
     444              : 
     445       272985 :       CALL timestop(handle)
     446              : 
     447       272985 :    END SUBROUTINE cp_fm_redistribute_start
     448              : 
     449              : ! **************************************************************************************************
     450              : !> \brief Redistributes eigenvectors and eigenvalues  back to the original communicator group
     451              : !> \param matrix           the input cp_fm_type matrix to be diagonalized
     452              : !> \param eigenvectors     the cp_fm_type matrix that will hold the eigenvectors of the input matrix
     453              : !> \param eig              global array holding the eigenvalues of the input matrixmatrix
     454              : !> \param matrix_new       the redistributed input matrix which will subsequently be diagonalized,
     455              : !>                         or a pointer to the original matrix if no redistribution is required
     456              : !> \param eigenvectors_new the redistributed eigenvectors matrix, or a pointer to the original
     457              : !>                         matrix if no redistribution is required
     458              : !> \par History
     459              : !>      - [01.2018] created by moving redistribution related code from cp_fm_syevd here
     460              : !> \author Nico Holmberg [01.2018]
     461              : ! **************************************************************************************************
     462       272985 :    SUBROUTINE cp_fm_redistribute_end(matrix, eigenvectors, eig, matrix_new, eigenvectors_new)
     463              : 
     464              :       TYPE(cp_fm_type), INTENT(IN)             :: matrix, eigenvectors
     465              :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT) :: eig
     466              :       TYPE(cp_fm_type), INTENT(INOUT)          :: matrix_new, eigenvectors_new
     467              : 
     468              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_fm_redistribute_end'
     469              : 
     470              :       INTEGER                                  :: handle
     471              : #if defined(__parallel)
     472              :       REAL(KIND=dp)                            :: fake_local_data(1, 1)
     473              :       INTEGER                                  :: fake_descriptor(9), mepos_old, n
     474              :       TYPE(mp_para_env_type), POINTER          :: para_env
     475              : #endif
     476              : 
     477       272985 :       CALL timeset(routineN, handle)
     478              : 
     479              : #if defined(__parallel)
     480              : 
     481              :       ! Check if matrix was redistributed
     482       272985 :       IF (ASSOCIATED(work_redistribute%group_distribution)) THEN
     483       268841 :          n = matrix%matrix_struct%nrow_global
     484       268841 :          para_env => matrix%matrix_struct%para_env
     485       268841 :          mepos_old = para_env%mepos
     486              : 
     487       268841 :          IF (work_redistribute%group_distribution(mepos_old) == 0) THEN
     488              :             ! redistribute results on CPUs that hold the redistributed matrix
     489              :             CALL pdgemr2d(n, n, eigenvectors_new%local_data(1, 1), 1, 1, eigenvectors_new%matrix_struct%descriptor, &
     490              :                           eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
     491       136294 :                           eigenvectors%matrix_struct%context)
     492       136294 :             CALL cp_fm_release(matrix_new)
     493       136294 :             CALL cp_fm_release(eigenvectors_new)
     494              :          ELSE
     495              :             ! these tasks must help redistribute (they own part of the data),
     496              :             ! but need fake 'new' data, and their descriptor must indicate this with -1
     497              :             ! see also scalapack comments on pdgemr2d
     498      1325470 :             fake_descriptor = -1
     499              :             CALL pdgemr2d(n, n, fake_local_data(1, 1), 1, 1, fake_descriptor, &
     500              :                           eigenvectors%local_data(1, 1), 1, 1, eigenvectors%matrix_struct%descriptor, &
     501       132547 :                           eigenvectors%matrix_struct%context)
     502              :          END IF
     503              :          ! free work
     504       268841 :          CALL cp_fm_redistribute_work_finalize(work_redistribute%group_distribution(mepos_old) == 0)
     505              : 
     506              :          ! finally, also the eigenvalues need to end up on the non-group member tasks
     507      7710393 :          CALL para_env%bcast(eig, 0)
     508              :       END IF
     509              : 
     510              : #else
     511              : 
     512              :       MARK_USED(matrix)
     513              :       MARK_USED(eigenvectors)
     514              :       MARK_USED(eig)
     515              :       MARK_USED(matrix_new)
     516              :       MARK_USED(eigenvectors_new)
     517              :       CPABORT("Routine called in non-parallel case.")
     518              : #endif
     519              : 
     520       272985 :       CALL timestop(handle)
     521              : 
     522       272985 :    END SUBROUTINE cp_fm_redistribute_end
     523              : 
     524            0 : END MODULE cp_fm_diag_utils
        

Generated by: LCOV version 2.0-1