LCOV - code coverage report
Current view: top level - src/fm - cp_fm_struct.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 212 244 86.9 %
Date: 2025-01-30 06:53:08 Functions: 16 18 88.9 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief represent the structure of a full matrix
      10             : !> \par History
      11             : !>      08.2002 created [fawzi]
      12             : !> \author Fawzi Mohamed
      13             : ! **************************************************************************************************
      14             : MODULE cp_fm_struct
      15             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_release,&
      16             :                                               cp_blacs_env_type
      17             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      18             :                                               cp_logger_get_default_unit_nr,&
      19             :                                               cp_logger_type,&
      20             :                                               cp_to_string
      21             :    USE machine,                         ONLY: m_cpuid_vlen,&
      22             :                                               m_flush
      23             :    USE message_passing,                 ONLY: mp_para_env_release,&
      24             :                                               mp_para_env_type
      25             : #include "../base/base_uses.f90"
      26             : 
      27             :    IMPLICIT NONE
      28             :    PRIVATE
      29             : 
      30             :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      31             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_fm_struct'
      32             : 
      33             : ! the default blacs block sizes
      34             : ! consider using #ifdefs to give them the optimal values
      35             : ! these can be changed using scf_control
      36             : ! *** these are used by default
      37             :    INTEGER, PRIVATE :: optimal_blacs_col_block_size = 64
      38             :    INTEGER, PRIVATE :: optimal_blacs_row_block_size = 64
      39             :    LOGICAL, PRIVATE :: force_block_size = .FALSE.
      40             : 
      41             :    PUBLIC :: cp_fm_struct_type, cp_fm_struct_p_type
      42             :    PUBLIC :: cp_fm_struct_create, cp_fm_struct_retain, cp_fm_struct_release, &
      43             :              cp_fm_struct_equivalent, &
      44             :              cp_fm_struct_get, cp_fm_struct_double, cp_fm_struct_config, &
      45             :              cp_fm_struct_get_nrow_block, cp_fm_struct_get_ncol_block, &
      46             :              cp_fm_struct_write_info
      47             : 
      48             : ! **************************************************************************************************
      49             : !> \brief keeps the information about the structure of a full matrix
      50             : !> \param para_env the parallel environment of the matrices with this structure
      51             : !> \param context the blacs context (parallel environment for scalapack),
      52             : !>        should be compatible with para_env
      53             : !> \param descriptor the scalapack descriptor of the matrices, when using
      54             : !>        scalapack (ncol_block=descriptor(6), ncol_global=descriptor(4),
      55             : !>        nrow_block=descriptor(5), nrow_global=descriptor(3))
      56             : !> \param ncol_block number of columns of a scalapack block
      57             : !> \param nrow_block number of rows of a scalapack block
      58             : !> \param nrow_global number of rows of the matrix
      59             : !> \param ncol_global number of rows
      60             : !> \param first_p_pos position of the first processor (for scalapack)
      61             : !> \param row_indices real (global) indices of the rows (defined only for
      62             : !>        the local rows really used)
      63             : !> \param col_indices real (global) indices of the cols (defined only for
      64             : !>        the local cols really used)
      65             : !> \param nrow_locals nrow_locals(i) number of local rows of the matrix really
      66             : !>        used on the processors with context%mepos(1)==i
      67             : !> \param ncol_locals ncol_locals(i) number of local rows of the matrix really
      68             : !>        used on the processors with context%mepos(2)==i
      69             : !> \param ref_count reference count (see doc/ReferenceCounting.html)
      70             : !> \param local_leading_dimension leading dimension of the data that is
      71             : !>        stored on this processor
      72             : !>
      73             : !>      readonly attributes:
      74             : !> \param nrow_local number of local rows really used on the actual processor
      75             : !> \param ncol_local number of local cols really used on the actual processor
      76             : !> \note
      77             : !>      use cp_fm_struct_get to extract information from this structure
      78             : !> \par History
      79             : !>      08.2002 created [fawzi]
      80             : !> \author Fawzi Mohamed
      81             : ! **************************************************************************************************
      82             :    TYPE cp_fm_struct_type
      83             :       TYPE(mp_para_env_type), POINTER :: para_env => NULL()
      84             :       TYPE(cp_blacs_env_type), POINTER :: context => NULL()
      85             :       INTEGER, DIMENSION(9) :: descriptor = -1
      86             :       INTEGER :: nrow_block = -1, ncol_block = -1, nrow_global = -1, ncol_global = -1
      87             :       INTEGER, DIMENSION(2) :: first_p_pos = -1
      88             :       INTEGER, DIMENSION(:), POINTER :: row_indices => NULL(), col_indices => NULL(), &
      89             :                                         nrow_locals => NULL(), ncol_locals => NULL()
      90             :       INTEGER :: ref_count = -1, local_leading_dimension = -1
      91             :    CONTAINS
      92             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: g2p_row => cp_fm_indxg2p_row
      93             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: g2p_col => cp_fm_indxg2p_col
      94             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: g2l_row => cp_fm_indxg2l_row
      95             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: g2l_col => cp_fm_indxg2l_col
      96             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: l2g_row => cp_fm_indxl2g_row
      97             :       PROCEDURE, PASS(struct), NON_OVERRIDABLE :: l2g_col => cp_fm_indxl2g_col
      98             :    END TYPE cp_fm_struct_type
      99             : ! **************************************************************************************************
     100             :    TYPE cp_fm_struct_p_type
     101             :       TYPE(cp_fm_struct_type), POINTER :: struct => NULL()
     102             :    END TYPE cp_fm_struct_p_type
     103             : 
     104             : CONTAINS
     105             : 
     106             : ! **************************************************************************************************
     107             : !> \brief allocates and initializes a full matrix structure
     108             : !> \param fmstruct the pointer that will point to the new structure
     109             : !> \param para_env the parallel environment
     110             : !> \param context the blacs context of this matrix
     111             : !> \param nrow_global the number of row of the full matrix
     112             : !> \param ncol_global the number of columns of the full matrix
     113             : !> \param nrow_block the number of rows of a block of the matrix,
     114             : !>        omit or set to -1 to use the built-in defaults
     115             : !> \param ncol_block the number of columns of a block of the matrix,
     116             : !>        omit or set to -1 to use the built-in defaults
     117             : !> \param descriptor the scalapack descriptor of the matrix (if not given
     118             : !>        a new one is allocated
     119             : !> \param first_p_pos ...
     120             : !> \param local_leading_dimension the leading dimension of the locally stored
     121             : !>        data block
     122             : !> \param template_fmstruct a matrix structure where to take the default values
     123             : !> \param square_blocks ...
     124             : !> \param force_block ...
     125             : !> \par History
     126             : !>      08.2002 created [fawzi]
     127             : !> \author Fawzi Mohamed
     128             : ! **************************************************************************************************
     129      463278 :    SUBROUTINE cp_fm_struct_create(fmstruct, para_env, context, nrow_global, &
     130             :                                   ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, &
     131             :                                   local_leading_dimension, template_fmstruct, square_blocks, force_block)
     132             : 
     133             :       TYPE(cp_fm_struct_type), POINTER             :: fmstruct
     134             :       TYPE(mp_para_env_type), TARGET, OPTIONAL     :: para_env
     135             :       INTEGER, INTENT(in), OPTIONAL                :: nrow_global, ncol_global
     136             :       INTEGER, INTENT(in), OPTIONAL                :: nrow_block, ncol_block
     137             :       INTEGER, INTENT(in), OPTIONAL                :: local_leading_dimension
     138             :       TYPE(cp_blacs_env_type), TARGET, OPTIONAL    :: context
     139             :       INTEGER, DIMENSION(9), INTENT(in), OPTIONAL  :: descriptor
     140             :       INTEGER, OPTIONAL, DIMENSION(2)              :: first_p_pos
     141             :       TYPE(cp_fm_struct_type), POINTER, OPTIONAL   :: template_fmstruct
     142             :       LOGICAL, OPTIONAL, INTENT(in)                :: square_blocks
     143             :       LOGICAL, OPTIONAL, INTENT(in)                :: force_block
     144             : 
     145             :       INTEGER                                      :: i, nmax_block, vlen
     146             : #if defined(__parallel)
     147             :       INTEGER                                      :: iunit, stat
     148             :       INTEGER, EXTERNAL                            :: numroc
     149             :       TYPE(cp_logger_type), POINTER                :: logger
     150             : #endif
     151             : 
     152             :       LOGICAL :: my_square_blocks, my_force_block
     153             : 
     154     5559336 :       ALLOCATE (fmstruct)
     155             : 
     156      463278 :       IF (.NOT. PRESENT(template_fmstruct)) THEN
     157      414440 :          CPASSERT(PRESENT(context))
     158      414440 :          CPASSERT(PRESENT(nrow_global))
     159      414440 :          CPASSERT(PRESENT(ncol_global))
     160      414440 :          fmstruct%local_leading_dimension = 1
     161      414440 :          fmstruct%nrow_block = 0 ! populate default later
     162      414440 :          fmstruct%ncol_block = 0 ! populate default later
     163             :       ELSE
     164       48838 :          fmstruct%context => template_fmstruct%context
     165       48838 :          fmstruct%para_env => template_fmstruct%para_env
     166      927922 :          fmstruct%descriptor = template_fmstruct%descriptor
     167       48838 :          fmstruct%nrow_block = template_fmstruct%nrow_block
     168       48838 :          fmstruct%nrow_global = template_fmstruct%nrow_global
     169       48838 :          fmstruct%ncol_block = template_fmstruct%ncol_block
     170       48838 :          fmstruct%ncol_global = template_fmstruct%ncol_global
     171      244190 :          fmstruct%first_p_pos = template_fmstruct%first_p_pos
     172             :          fmstruct%local_leading_dimension = &
     173       48838 :             template_fmstruct%local_leading_dimension
     174             :       END IF
     175             : 
     176             :       ! allow to request default block size (zero or negative value)
     177      463278 :       IF (PRESENT(nrow_block)) fmstruct%nrow_block = nrow_block
     178      463278 :       IF (PRESENT(ncol_block)) fmstruct%ncol_block = ncol_block
     179      463278 :       IF (0 >= fmstruct%nrow_block) THEN
     180      386685 :          fmstruct%nrow_block = optimal_blacs_row_block_size
     181             :       END IF
     182      463278 :       IF (0 >= fmstruct%ncol_block) THEN
     183      378405 :          fmstruct%ncol_block = optimal_blacs_col_block_size
     184             :       END IF
     185      463278 :       CPASSERT(0 < fmstruct%nrow_block .AND. 0 < fmstruct%ncol_block)
     186             : 
     187      463278 :       IF (PRESENT(context)) THEN
     188      414440 :          fmstruct%context => context
     189      414440 :          fmstruct%para_env => context%para_env
     190             :       END IF
     191      463278 :       IF (PRESENT(para_env)) fmstruct%para_env => para_env
     192      463278 :       CALL fmstruct%context%retain()
     193      463278 :       CALL fmstruct%para_env%retain()
     194             : 
     195      463278 :       IF (PRESENT(nrow_global)) THEN
     196      460934 :          fmstruct%nrow_global = nrow_global
     197      460934 :          fmstruct%local_leading_dimension = 1
     198             :       END IF
     199      463278 :       IF (PRESENT(ncol_global)) THEN
     200      463034 :          fmstruct%ncol_global = ncol_global
     201             :       END IF
     202             : 
     203      463278 :       my_force_block = force_block_size
     204      463278 :       IF (PRESENT(force_block)) my_force_block = force_block
     205      463278 :       IF (.NOT. my_force_block) THEN
     206      432429 :          vlen = m_cpuid_vlen()
     207             :          nmax_block = (fmstruct%nrow_global + fmstruct%context%num_pe(1) - 1)/ &
     208      432429 :                       (fmstruct%context%num_pe(1))
     209      432429 :          IF (1 < vlen) THEN ! flooring not ceiling (OOB)
     210      432429 :             fmstruct%nrow_block = fmstruct%nrow_block/vlen*vlen
     211      432429 :             nmax_block = nmax_block/vlen*vlen
     212             :          END IF
     213      432429 :          fmstruct%nrow_block = MAX(MIN(fmstruct%nrow_block, nmax_block), 1)
     214             : 
     215             :          nmax_block = (fmstruct%ncol_global + fmstruct%context%num_pe(2) - 1)/ &
     216      432429 :                       (fmstruct%context%num_pe(2))
     217      432429 :          IF (1 < vlen) THEN ! flooring not ceiling (OOB)
     218      432429 :             fmstruct%ncol_block = fmstruct%ncol_block/vlen*vlen
     219      432429 :             nmax_block = nmax_block/vlen*vlen
     220             :          END IF
     221      432429 :          fmstruct%ncol_block = MAX(MIN(fmstruct%ncol_block, nmax_block), 1)
     222             :       END IF
     223             : 
     224             :       ! square matrix -> square blocks (otherwise, e.g., PDPOTRF fails)
     225      463278 :       my_square_blocks = fmstruct%nrow_global == fmstruct%ncol_global
     226             :       ! however, requesting non-square blocks takes precedence
     227      463278 :       IF (PRESENT(square_blocks)) my_square_blocks = square_blocks
     228      463278 :       IF (my_square_blocks) THEN
     229      285371 :          fmstruct%nrow_block = MIN(fmstruct%nrow_block, fmstruct%ncol_block)
     230      285371 :          fmstruct%ncol_block = fmstruct%nrow_block
     231             :       END IF
     232             : 
     233             :       ALLOCATE (fmstruct%nrow_locals(0:(fmstruct%context%num_pe(1) - 1)), &
     234     2316390 :                 fmstruct%ncol_locals(0:(fmstruct%context%num_pe(2) - 1)))
     235      463278 :       IF (.NOT. PRESENT(template_fmstruct)) &
     236     1243320 :          fmstruct%first_p_pos = (/0, 0/)
     237      463278 :       IF (PRESENT(first_p_pos)) fmstruct%first_p_pos = first_p_pos
     238             : 
     239     1303478 :       fmstruct%nrow_locals = 0
     240      926556 :       fmstruct%ncol_locals = 0
     241             : #if defined(__parallel)
     242             :       fmstruct%nrow_locals(fmstruct%context%mepos(1)) = &
     243             :          numroc(fmstruct%nrow_global, fmstruct%nrow_block, &
     244             :                 fmstruct%context%mepos(1), fmstruct%first_p_pos(1), &
     245      463278 :                 fmstruct%context%num_pe(1))
     246             :       fmstruct%ncol_locals(fmstruct%context%mepos(2)) = &
     247             :          numroc(fmstruct%ncol_global, fmstruct%ncol_block, &
     248             :                 fmstruct%context%mepos(2), fmstruct%first_p_pos(2), &
     249      463278 :                 fmstruct%context%num_pe(2))
     250     2143678 :       CALL fmstruct%para_env%sum(fmstruct%nrow_locals)
     251     1389834 :       CALL fmstruct%para_env%sum(fmstruct%ncol_locals)
     252     1303478 :       fmstruct%nrow_locals(:) = fmstruct%nrow_locals(:)/fmstruct%context%num_pe(2)
     253      926556 :       fmstruct%ncol_locals(:) = fmstruct%ncol_locals(:)/fmstruct%context%num_pe(1)
     254             : 
     255     1766756 :       IF (SUM(fmstruct%ncol_locals) .NE. fmstruct%ncol_global .OR. &
     256             :           SUM(fmstruct%nrow_locals) .NE. fmstruct%nrow_global) THEN
     257             :          ! try to collect some output if this is going to happen again
     258             :          ! this seems to trigger on blanc, but should really never happen
     259           0 :          logger => cp_get_default_logger()
     260           0 :          iunit = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
     261           0 :          WRITE (iunit, *) "mepos", fmstruct%context%mepos(1:2), "numpe", fmstruct%context%num_pe(1:2)
     262           0 :          WRITE (iunit, *) "ncol_global", fmstruct%ncol_global
     263           0 :          WRITE (iunit, *) "nrow_global", fmstruct%nrow_global
     264           0 :          WRITE (iunit, *) "ncol_locals", fmstruct%ncol_locals
     265           0 :          WRITE (iunit, *) "nrow_locals", fmstruct%nrow_locals
     266           0 :          CALL m_flush(iunit)
     267             :       END IF
     268             : 
     269      926556 :       IF (SUM(fmstruct%ncol_locals) .NE. fmstruct%ncol_global) &
     270           0 :          CPABORT("sum of local cols not equal global cols")
     271     1303478 :       IF (SUM(fmstruct%nrow_locals) .NE. fmstruct%nrow_global) &
     272           0 :          CPABORT("sum of local row not equal global rows")
     273             : #else
     274             :       ! block = full matrix
     275             :       fmstruct%nrow_block = fmstruct%nrow_global
     276             :       fmstruct%ncol_block = fmstruct%ncol_global
     277             :       fmstruct%nrow_locals(fmstruct%context%mepos(1)) = fmstruct%nrow_global
     278             :       fmstruct%ncol_locals(fmstruct%context%mepos(2)) = fmstruct%ncol_global
     279             : #endif
     280             : 
     281             :       fmstruct%local_leading_dimension = MAX(fmstruct%local_leading_dimension, &
     282      463278 :                                              fmstruct%nrow_locals(fmstruct%context%mepos(1)))
     283      463278 :       IF (PRESENT(local_leading_dimension)) THEN
     284           0 :          IF (MAX(1, fmstruct%nrow_locals(fmstruct%context%mepos(1))) > local_leading_dimension) &
     285             :             CALL cp_abort(__LOCATION__, "local_leading_dimension too small ("// &
     286             :                           cp_to_string(local_leading_dimension)//"<"// &
     287           0 :                           cp_to_string(fmstruct%local_leading_dimension)//")")
     288           0 :          fmstruct%local_leading_dimension = local_leading_dimension
     289             :       END IF
     290             : 
     291      463278 :       NULLIFY (fmstruct%row_indices, fmstruct%col_indices)
     292             : 
     293             :       ! the max should go away
     294     1389834 :       ALLOCATE (fmstruct%row_indices(MAX(fmstruct%nrow_locals(fmstruct%context%mepos(1)), 1)))
     295     5856326 :       DO i = 1, SIZE(fmstruct%row_indices)
     296             : #ifdef __parallel
     297     5856326 :          fmstruct%row_indices(i) = fmstruct%l2g_row(i, fmstruct%context%mepos(1))
     298             : #else
     299             :          fmstruct%row_indices(i) = i
     300             : #endif
     301             :       END DO
     302     1389834 :       ALLOCATE (fmstruct%col_indices(MAX(fmstruct%ncol_locals(fmstruct%context%mepos(2)), 1)))
     303     6178010 :       DO i = 1, SIZE(fmstruct%col_indices)
     304             : #ifdef __parallel
     305     6178010 :          fmstruct%col_indices(i) = fmstruct%l2g_col(i, fmstruct%context%mepos(2))
     306             : #else
     307             :          fmstruct%col_indices(i) = i
     308             : #endif
     309             :       END DO
     310             : 
     311      463278 :       fmstruct%ref_count = 1
     312             : 
     313      463278 :       IF (PRESENT(descriptor)) THEN
     314           0 :          fmstruct%descriptor = descriptor
     315             :       ELSE
     316     4632780 :          fmstruct%descriptor = 0
     317             : #if defined(__parallel)
     318             :          ! local leading dimension needs to be at least 1
     319             :          CALL descinit(fmstruct%descriptor, fmstruct%nrow_global, &
     320             :                        fmstruct%ncol_global, fmstruct%nrow_block, &
     321             :                        fmstruct%ncol_block, fmstruct%first_p_pos(1), &
     322             :                        fmstruct%first_p_pos(2), fmstruct%context, &
     323      463278 :                        fmstruct%local_leading_dimension, stat)
     324      463278 :          CPASSERT(stat == 0)
     325             : #endif
     326             :       END IF
     327      463278 :    END SUBROUTINE cp_fm_struct_create
     328             : 
     329             : ! **************************************************************************************************
     330             : !> \brief retains a full matrix structure
     331             : !> \param fmstruct the structure to retain
     332             : !> \par History
     333             : !>      08.2002 created [fawzi]
     334             : !> \author Fawzi Mohamed
     335             : ! **************************************************************************************************
     336     1472417 :    SUBROUTINE cp_fm_struct_retain(fmstruct)
     337             :       TYPE(cp_fm_struct_type), INTENT(INOUT)             :: fmstruct
     338             : 
     339     1472417 :       CPASSERT(fmstruct%ref_count > 0)
     340     1472417 :       fmstruct%ref_count = fmstruct%ref_count + 1
     341     1472417 :    END SUBROUTINE cp_fm_struct_retain
     342             : 
     343             : ! **************************************************************************************************
     344             : !> \brief releases a full matrix structure
     345             : !> \param fmstruct the structure to release
     346             : !> \par History
     347             : !>      08.2002 created [fawzi]
     348             : !> \author Fawzi Mohamed
     349             : ! **************************************************************************************************
     350     1963642 :    SUBROUTINE cp_fm_struct_release(fmstruct)
     351             :       TYPE(cp_fm_struct_type), POINTER                   :: fmstruct
     352             : 
     353     1963642 :       IF (ASSOCIATED(fmstruct)) THEN
     354     1935695 :          CPASSERT(fmstruct%ref_count > 0)
     355     1935695 :          fmstruct%ref_count = fmstruct%ref_count - 1
     356     1935695 :          IF (fmstruct%ref_count < 1) THEN
     357      463278 :             CALL cp_blacs_env_release(fmstruct%context)
     358      463278 :             CALL mp_para_env_release(fmstruct%para_env)
     359      463278 :             IF (ASSOCIATED(fmstruct%row_indices)) THEN
     360      463278 :                DEALLOCATE (fmstruct%row_indices)
     361             :             END IF
     362      463278 :             IF (ASSOCIATED(fmstruct%col_indices)) THEN
     363      463278 :                DEALLOCATE (fmstruct%col_indices)
     364             :             END IF
     365      463278 :             IF (ASSOCIATED(fmstruct%nrow_locals)) THEN
     366      463278 :                DEALLOCATE (fmstruct%nrow_locals)
     367             :             END IF
     368      463278 :             IF (ASSOCIATED(fmstruct%ncol_locals)) THEN
     369      463278 :                DEALLOCATE (fmstruct%ncol_locals)
     370             :             END IF
     371      463278 :             DEALLOCATE (fmstruct)
     372             :          END IF
     373             :       END IF
     374     1963642 :       NULLIFY (fmstruct)
     375     1963642 :    END SUBROUTINE cp_fm_struct_release
     376             : 
     377             : ! **************************************************************************************************
     378             : !> \brief returns true if the two matrix structures are equivalent, false
     379             : !>      otherwise.
     380             : !> \param fmstruct1 one of the full matrix structures to compare
     381             : !> \param fmstruct2 the second of the full matrix structures to compare
     382             : !> \return ...
     383             : !> \par History
     384             : !>      08.2002 created [fawzi]
     385             : !> \author Fawzi Mohamed
     386             : ! **************************************************************************************************
     387     2287347 :    FUNCTION cp_fm_struct_equivalent(fmstruct1, fmstruct2) RESULT(res)
     388             :       TYPE(cp_fm_struct_type), POINTER                   :: fmstruct1, fmstruct2
     389             :       LOGICAL                                            :: res
     390             : 
     391             :       INTEGER                                            :: i
     392             : 
     393     2287347 :       CPASSERT(ASSOCIATED(fmstruct1))
     394     2287347 :       CPASSERT(ASSOCIATED(fmstruct2))
     395     2287347 :       CPASSERT(fmstruct1%ref_count > 0)
     396     2287347 :       CPASSERT(fmstruct2%ref_count > 0)
     397     2287347 :       IF (ASSOCIATED(fmstruct1, fmstruct2)) THEN
     398             :          res = .TRUE.
     399             :       ELSE
     400             :          res = (fmstruct1%context == fmstruct2%context) .AND. &
     401             :                (fmstruct1%nrow_global == fmstruct2%nrow_global) .AND. &
     402             :                (fmstruct1%ncol_global == fmstruct2%ncol_global) .AND. &
     403             :                (fmstruct1%nrow_block == fmstruct2%nrow_block) .AND. &
     404             :                (fmstruct1%ncol_block == fmstruct2%ncol_block) .AND. &
     405             :                (fmstruct1%local_leading_dimension == &
     406      461451 :                 fmstruct2%local_leading_dimension)
     407     4614510 :          DO i = 1, 9
     408     4614510 :             res = res .AND. (fmstruct1%descriptor(i) == fmstruct1%descriptor(i))
     409             :          END DO
     410             :       END IF
     411     2287347 :    END FUNCTION cp_fm_struct_equivalent
     412             : 
     413             : ! **************************************************************************************************
     414             : !> \brief returns the values of various attributes of the matrix structure
     415             : !> \param fmstruct the structure you want info about
     416             : !> \param para_env ...
     417             : !> \param context ...
     418             : !> \param descriptor ...
     419             : !> \param ncol_block ...
     420             : !> \param nrow_block ...
     421             : !> \param nrow_global ...
     422             : !> \param ncol_global ...
     423             : !> \param first_p_pos ...
     424             : !> \param row_indices ...
     425             : !> \param col_indices ...
     426             : !> \param nrow_local ...
     427             : !> \param ncol_local ...
     428             : !> \param nrow_locals ...
     429             : !> \param ncol_locals ...
     430             : !> \param local_leading_dimension ...
     431             : !> \par History
     432             : !>      08.2002 created [fawzi]
     433             : !> \author Fawzi Mohamed
     434             : ! **************************************************************************************************
     435     6018782 :    SUBROUTINE cp_fm_struct_get(fmstruct, para_env, context, &
     436             :                                descriptor, ncol_block, nrow_block, nrow_global, &
     437             :                                ncol_global, first_p_pos, row_indices, &
     438             :                                col_indices, nrow_local, ncol_local, nrow_locals, ncol_locals, &
     439             :                                local_leading_dimension)
     440             :       TYPE(cp_fm_struct_type), INTENT(IN)                :: fmstruct
     441             :       TYPE(mp_para_env_type), OPTIONAL, POINTER          :: para_env
     442             :       TYPE(cp_blacs_env_type), OPTIONAL, POINTER         :: context
     443             :       INTEGER, DIMENSION(9), INTENT(OUT), OPTIONAL       :: descriptor
     444             :       INTEGER, INTENT(out), OPTIONAL                     :: ncol_block, nrow_block, nrow_global, &
     445             :                                                             ncol_global
     446             :       INTEGER, DIMENSION(2), INTENT(out), OPTIONAL       :: first_p_pos
     447             :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: row_indices, col_indices
     448             :       INTEGER, INTENT(out), OPTIONAL                     :: nrow_local, ncol_local
     449             :       INTEGER, DIMENSION(:), OPTIONAL, POINTER           :: nrow_locals, ncol_locals
     450             :       INTEGER, INTENT(out), OPTIONAL                     :: local_leading_dimension
     451             : 
     452     6018782 :       IF (PRESENT(para_env)) para_env => fmstruct%para_env
     453     6018782 :       IF (PRESENT(context)) context => fmstruct%context
     454     6018782 :       IF (PRESENT(descriptor)) descriptor = fmstruct%descriptor
     455     6018782 :       IF (PRESENT(ncol_block)) ncol_block = fmstruct%ncol_block
     456     6018782 :       IF (PRESENT(nrow_block)) nrow_block = fmstruct%nrow_block
     457     6018782 :       IF (PRESENT(nrow_global)) nrow_global = fmstruct%nrow_global
     458     6018782 :       IF (PRESENT(ncol_global)) ncol_global = fmstruct%ncol_global
     459     6018782 :       IF (PRESENT(first_p_pos)) first_p_pos = fmstruct%first_p_pos
     460     6018782 :       IF (PRESENT(nrow_locals)) nrow_locals => fmstruct%nrow_locals
     461     6018782 :       IF (PRESENT(ncol_locals)) ncol_locals => fmstruct%ncol_locals
     462     6018782 :       IF (PRESENT(local_leading_dimension)) local_leading_dimension = &
     463       41211 :          fmstruct%local_leading_dimension
     464             : 
     465     6018782 :       IF (PRESENT(nrow_local)) nrow_local = fmstruct%nrow_locals(fmstruct%context%mepos(1))
     466     6018782 :       IF (PRESENT(ncol_local)) ncol_local = fmstruct%ncol_locals(fmstruct%context%mepos(2))
     467             : 
     468     6018782 :       IF (PRESENT(row_indices)) row_indices => fmstruct%row_indices
     469     6018782 :       IF (PRESENT(col_indices)) col_indices => fmstruct%col_indices
     470     6018782 :    END SUBROUTINE cp_fm_struct_get
     471             : 
     472             : ! **************************************************************************************************
     473             : !> \brief Write nicely formatted info about the FM struct to the given I/O unit
     474             : !> \param fmstruct a cp_fm_struct_type instance
     475             : !> \param io_unit the I/O unit to use for writing
     476             : ! **************************************************************************************************
     477           3 :    SUBROUTINE cp_fm_struct_write_info(fmstruct, io_unit)
     478             :       TYPE(cp_fm_struct_type), INTENT(IN)                :: fmstruct
     479             :       INTEGER, INTENT(IN)                                :: io_unit
     480             : 
     481             :       INTEGER, PARAMETER                                 :: oblock_size = 8
     482             : 
     483             :       CHARACTER(len=30)                                  :: fm
     484             :       INTEGER                                            :: oblock
     485             : 
     486           3 :       WRITE (fm, "(A,I2,A)") "(A,I5,A,I5,A,", oblock_size, "I6)"
     487             : 
     488           3 :       WRITE (io_unit, '(A,I12)') "CP_FM_STRUCT | No. of matrix columns:   ", fmstruct%ncol_global
     489           3 :       WRITE (io_unit, '(A,I12)') "CP_FM_STRUCT | No. of matrix rows:      ", fmstruct%nrow_global
     490           3 :       WRITE (io_unit, '(A,I12)') "CP_FM_STRUCT | No. of block columns:    ", fmstruct%ncol_block
     491           3 :       WRITE (io_unit, '(A,I12)') "CP_FM_STRUCT | No. of block rows:       ", fmstruct%nrow_block
     492             : 
     493           3 :       WRITE (io_unit, '(A)') "CP_FM_STRUCT | Number of local columns: "
     494           6 :       DO oblock = 0, (SIZE(fmstruct%ncol_locals) - 1)/oblock_size
     495           3 :          WRITE (io_unit, fm) "CP_FM_STRUCT | CPUs ", &
     496           3 :             oblock*oblock_size, "..", (oblock + 1)*oblock_size - 1, ": ", &
     497           9 :             fmstruct%ncol_locals(oblock*oblock_size:MIN(SIZE(fmstruct%ncol_locals), (oblock + 1)*oblock_size) - 1)
     498             :       END DO
     499             : 
     500           3 :       WRITE (io_unit, '(A)') "CP_FM_STRUCT | Number of local rows:    "
     501           6 :       DO oblock = 0, (SIZE(fmstruct%nrow_locals) - 1)/oblock_size
     502           3 :          WRITE (io_unit, fm) "CP_FM_STRUCT | CPUs ", &
     503           3 :             oblock*oblock_size, "..", (oblock + 1)*oblock_size - 1, ": ", &
     504           9 :             fmstruct%nrow_locals(oblock*oblock_size:MIN(SIZE(fmstruct%nrow_locals), (oblock + 1)*oblock_size) - 1)
     505             :       END DO
     506           3 :    END SUBROUTINE cp_fm_struct_write_info
     507             : 
     508             : ! **************************************************************************************************
     509             : !> \brief creates a struct with twice the number of blocks on each core.
     510             : !>        If matrix A has to be multiplied with B anc C, a
     511             : !>        significant speedup of pdgemm can be acchieved by joining the matrices
     512             : !>        in a new one with this structure (see arnoldi in rt_matrix_exp)
     513             : !> \param fmstruct the struct to create
     514             : !> \param struct struct of either A or B
     515             : !> \param context ...
     516             : !> \param col in which direction the matrix should be enlarged
     517             : !> \param row in which direction the matrix should be enlarged
     518             : !> \par History
     519             : !>      06.2009 created [fschiff]
     520             : !> \author Florian Schiffmann
     521             : ! **************************************************************************************************
     522        5202 :    SUBROUTINE cp_fm_struct_double(fmstruct, struct, context, col, row)
     523             :       TYPE(cp_fm_struct_type), POINTER                   :: fmstruct
     524             :       TYPE(cp_fm_struct_type), INTENT(INOUT)             :: struct
     525             :       TYPE(cp_blacs_env_type), INTENT(INOUT), TARGET     :: context
     526             :       LOGICAL, INTENT(in)                                :: col, row
     527             : 
     528             :       INTEGER :: n_doubled_items_in_partially_filled_block, ncol_block, ncol_global, newdim_col, &
     529             :          newdim_row, nfilled_blocks, nfilled_blocks_remain, nprocs_col, nprocs_row, nrow_block, &
     530             :          nrow_global
     531             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     532             : 
     533             :       CALL cp_fm_struct_get(struct, nrow_global=nrow_global, &
     534             :                             ncol_global=ncol_global, nrow_block=nrow_block, &
     535        5202 :                             ncol_block=ncol_block)
     536        5202 :       newdim_row = nrow_global
     537        5202 :       newdim_col = ncol_global
     538        5202 :       nprocs_row = context%num_pe(1)
     539        5202 :       nprocs_col = context%num_pe(2)
     540        5202 :       para_env => struct%para_env
     541             : 
     542        5202 :       IF (col) THEN
     543        5202 :          IF (ncol_global == 0) THEN
     544         120 :             newdim_col = 0
     545             :          ELSE
     546             :             ! ncol_block            nfilled_blocks_remain * ncol_block
     547             :             !     |<--->|           |<--->|
     548             :             !     |-----|-----|-----|-----|---|
     549             :             !     |  0  |  1  |  2  |  0  | 1 | <- context%mepos(2)
     550             :             !     |-----|-----|-----|-----|---|
     551             :             !     |<--- nfilled_blocks -->|<->  -- items (columns) in partially filled blocks
     552             :             !     |     * ncol_block      |
     553        5082 :             n_doubled_items_in_partially_filled_block = 2*MOD(ncol_global, ncol_block)
     554        5082 :             nfilled_blocks = ncol_global/ncol_block
     555        5082 :             nfilled_blocks_remain = MOD(nfilled_blocks, nprocs_col)
     556        5082 :             newdim_col = 2*(nfilled_blocks/nprocs_col)
     557        5082 :             IF (n_doubled_items_in_partially_filled_block > ncol_block) THEN
     558             :                ! doubled number of columns in a partially filled block does not fit into a single block.
     559             :                ! Due to cyclic distribution of ScaLAPACK blocks, an extra block for each core needs to be added
     560             :                ! |-----|-----|-----|----|     |-----|-----|-----|-----|-----|-----|-----|-----|-----|---|
     561             :                ! |  0  |  1  |  2  |  0 | --> |  0  |  1  |  2  |  0  |  1  |  2  |  0  |  1  |  2  |  0|
     562             :                ! |-----|-----|-----|----|     |-----|-----|-----|-----|-----|-----|-----|-----|-----|---|
     563             :                !    a     a     a     b          a1    a1    a1    a2    a2    a2    b1  empty empty  b2
     564           0 :                newdim_col = newdim_col + 1
     565             : 
     566             :                ! the number of columns which does not fit into the added extra block
     567           0 :                n_doubled_items_in_partially_filled_block = n_doubled_items_in_partially_filled_block - ncol_block
     568        5082 :             ELSE IF (nfilled_blocks_remain > 0) THEN
     569             :                ! |-----|-----|-----|-----|--|    |-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
     570             :                ! |  0  |  1  |  2  |  0  | 1| -> |  0  |  1  |  2  |  0  |  1  |  2  |  0  |  1  |  2  |  0  |
     571             :                ! |-----|-----|-----|-----|--|    |-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
     572             :                !    a     a     a     b    b        a1    a1    a1    a2    a2    a2    b1  b1 b2 empty   b2
     573           0 :                newdim_col = newdim_col + 1
     574           0 :                n_doubled_items_in_partially_filled_block = 0
     575             :             END IF
     576             : 
     577        5082 :             newdim_col = (newdim_col*nprocs_col + nfilled_blocks_remain)*ncol_block + n_doubled_items_in_partially_filled_block
     578             :          END IF
     579             :       END IF
     580             : 
     581        5202 :       IF (row) THEN
     582           0 :          IF (nrow_global == 0) THEN
     583           0 :             newdim_row = 0
     584             :          ELSE
     585           0 :             n_doubled_items_in_partially_filled_block = 2*MOD(nrow_global, nrow_block)
     586           0 :             nfilled_blocks = nrow_global/nrow_block
     587           0 :             nfilled_blocks_remain = MOD(nfilled_blocks, nprocs_row)
     588           0 :             newdim_row = 2*(nfilled_blocks/nprocs_row)
     589           0 :             IF (n_doubled_items_in_partially_filled_block > nrow_block) THEN
     590           0 :                newdim_row = newdim_row + 1
     591           0 :                n_doubled_items_in_partially_filled_block = n_doubled_items_in_partially_filled_block - nrow_block
     592           0 :             ELSE IF (nfilled_blocks_remain > 0) THEN
     593           0 :                newdim_row = newdim_row + 1
     594           0 :                n_doubled_items_in_partially_filled_block = 0
     595             :             END IF
     596             : 
     597           0 :             newdim_row = (newdim_row*nprocs_row + nfilled_blocks_remain)*nrow_block + n_doubled_items_in_partially_filled_block
     598             :          END IF
     599             :       END IF
     600             : 
     601             :       ! square_blocks=.FALSE. ensures that matrix blocks of the doubled matrix will have
     602             :       ! nrow_block x ncol_block shape even in case of a square doubled matrix
     603             :       CALL cp_fm_struct_create(fmstruct=fmstruct, para_env=para_env, &
     604             :                                context=context, &
     605             :                                nrow_global=newdim_row, &
     606             :                                ncol_global=newdim_col, &
     607             :                                ncol_block=ncol_block, &
     608             :                                nrow_block=nrow_block, &
     609        5202 :                                square_blocks=.FALSE.)
     610             : 
     611        5202 :    END SUBROUTINE cp_fm_struct_double
     612             : ! **************************************************************************************************
     613             : !> \brief allows to modify the default settings for matrix creation
     614             : !> \param nrow_block ...
     615             : !> \param ncol_block ...
     616             : !> \param force_block ...
     617             : ! **************************************************************************************************
     618        9801 :    SUBROUTINE cp_fm_struct_config(nrow_block, ncol_block, force_block)
     619             :       INTEGER, INTENT(IN), OPTIONAL                      :: nrow_block, ncol_block
     620             :       LOGICAL, INTENT(IN), OPTIONAL                      :: force_block
     621             : 
     622             :       INTEGER                                            :: vlen
     623             : 
     624        9801 :       vlen = m_cpuid_vlen()
     625        9801 :       IF (PRESENT(ncol_block)) THEN
     626        9801 :          IF (0 < ncol_block) THEN
     627        9801 :             optimal_blacs_col_block_size = (ncol_block + vlen - 1)/vlen*vlen
     628             :          END IF
     629             :       END IF
     630        9801 :       IF (PRESENT(nrow_block)) THEN
     631        9801 :          IF (0 < nrow_block) THEN
     632        9801 :             optimal_blacs_row_block_size = (nrow_block + vlen - 1)/vlen*vlen
     633             :          END IF
     634             :       END IF
     635        9801 :       IF (PRESENT(force_block)) force_block_size = force_block
     636             : 
     637        9801 :    END SUBROUTINE cp_fm_struct_config
     638             : 
     639             : ! **************************************************************************************************
     640             : !> \brief ...
     641             : !> \return ...
     642             : ! **************************************************************************************************
     643       15209 :    FUNCTION cp_fm_struct_get_nrow_block() RESULT(res)
     644             :       INTEGER                                            :: res
     645             : 
     646       15209 :       res = optimal_blacs_row_block_size
     647       15209 :    END FUNCTION cp_fm_struct_get_nrow_block
     648             : 
     649             : ! **************************************************************************************************
     650             : !> \brief ...
     651             : !> \return ...
     652             : ! **************************************************************************************************
     653       15209 :    FUNCTION cp_fm_struct_get_ncol_block() RESULT(res)
     654             :       INTEGER                                            :: res
     655             : 
     656       15209 :       res = optimal_blacs_col_block_size
     657       15209 :    END FUNCTION cp_fm_struct_get_ncol_block
     658             : 
     659             : ! **************************************************************************************************
     660             : !> \brief wrapper to scalapack function INDXG2P that computes the row process
     661             : !>         coordinate which possesses the entry of a distributed matrix specified
     662             : !>         by a global index INDXGLOB.
     663             : !> \param struct ...
     664             : !> \param INDXGLOB ...
     665             : !> \return ...
     666             : !> \author Mauro Del Ben [MDB] - 12.2012, modified by F. Stein
     667             : ! **************************************************************************************************
     668    10580534 :    FUNCTION cp_fm_indxg2p_row(struct, INDXGLOB) RESULT(G2P)
     669             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     670             :       INTEGER, INTENT(IN) :: INDXGLOB
     671             :       INTEGER                                  :: G2P
     672             : 
     673             : #if defined(__parallel)
     674             :       INTEGER :: number_of_process_rows
     675             :       INTEGER, EXTERNAL :: indxg2p
     676             : #endif
     677             : 
     678             : #if defined(__parallel)
     679             : 
     680    10580534 :       CALL struct%context%get(number_of_process_rows=number_of_process_rows)
     681             : 
     682    10580534 :       G2P = indxg2p(INDXGLOB, struct%nrow_block, 0, struct%first_p_pos(1), number_of_process_rows)
     683             : 
     684             : #else
     685             :       MARK_USED(struct)
     686             :       MARK_USED(indxglob)
     687             : 
     688             :       G2P = 0
     689             : 
     690             : #endif
     691             : 
     692    10580534 :    END FUNCTION cp_fm_indxg2p_row
     693             : 
     694             : ! **************************************************************************************************
     695             : !> \brief wrapper to scalapack function INDXG2P that computes the col process
     696             : !>         coordinate which possesses the entry of a distributed matrix specified
     697             : !>         by a global index INDXGLOB.
     698             : !> \param struct ...
     699             : !> \param INDXGLOB ...
     700             : !> \return ...
     701             : !> \author Mauro Del Ben [MDB] - 12.2012, modified by F. Stein
     702             : ! **************************************************************************************************
     703     7697271 :    FUNCTION cp_fm_indxg2p_col(struct, INDXGLOB) RESULT(G2P)
     704             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     705             :       INTEGER, INTENT(IN) :: INDXGLOB
     706             :       INTEGER                                  :: G2P
     707             : 
     708             : #if defined(__parallel)
     709             :       INTEGER :: number_of_process_columns
     710             :       INTEGER, EXTERNAL :: indxg2p
     711             : #endif
     712             : 
     713             : #if defined(__parallel)
     714             : 
     715     7697271 :       CALL struct%context%get(number_of_process_columns=number_of_process_columns)
     716             : 
     717     7697271 :       G2P = indxg2p(INDXGLOB, struct%ncol_block, 0, struct%first_p_pos(2), number_of_process_columns)
     718             : 
     719             : #else
     720             :       MARK_USED(struct)
     721             :       MARK_USED(indxglob)
     722             : 
     723             :       G2P = 0
     724             : 
     725             : #endif
     726             : 
     727     7697271 :    END FUNCTION cp_fm_indxg2p_col
     728             : 
     729             : ! **************************************************************************************************
     730             : !> \brief wrapper to scalapack function INDXG2L that computes the local index
     731             : !>         of a distributed matrix entry pointed to by the global index INDXGLOB.
     732             : !>
     733             : !>  Arguments
     734             : !>  =========
     735             : !>
     736             : !>  INDXGLOB  (global input) INTEGER
     737             : !>            The global index of the distributed matrix entry.
     738             : !>
     739             : !>  NB        (global input) INTEGER
     740             : !>            Block size, size of the blocks the distributed matrix is
     741             : !>            split into.
     742             : !>
     743             : !>  IPROC     (local dummy) INTEGER
     744             : !>            Dummy argument in this case in order to unify the calling
     745             : !>            sequence of the tool-routines.
     746             : !>
     747             : !>  ISRCPROC  (local dummy) INTEGER
     748             : !>            Dummy argument in this case in order to unify the calling
     749             : !>            sequence of the tool-routines.
     750             : !>
     751             : !>  NPROCS    (global input) INTEGER
     752             : !>            The total number processes over which the distributed
     753             : !>            matrix is distributed.
     754             : !>
     755             : !> \param struct ...
     756             : !> \param INDXGLOB ...
     757             : !> \return ...
     758             : !> \author Mauro Del Ben [MDB] - 12.2012
     759             : ! **************************************************************************************************
     760     1494329 :    FUNCTION cp_fm_indxg2l_row(struct, INDXGLOB) RESULT(G2L)
     761             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     762             :       INTEGER, INTENT(IN)                      :: INDXGLOB
     763             :       INTEGER                                  :: G2L
     764             : 
     765             : #if defined(__parallel)
     766             :       INTEGER :: number_of_process_rows
     767             :       INTEGER, EXTERNAL :: indxg2l
     768             : #endif
     769             : 
     770             : #if defined(__parallel)
     771             : 
     772     1494329 :       CALL struct%context%get(number_of_process_rows=number_of_process_rows)
     773             : 
     774     1494329 :       G2L = indxg2l(INDXGLOB, struct%nrow_block, 0, struct%first_p_pos(1), number_of_process_rows)
     775             : 
     776             : #else
     777             :       MARK_USED(struct)
     778             : 
     779             :       G2L = INDXGLOB
     780             : 
     781             : #endif
     782             : 
     783     1494329 :    END FUNCTION cp_fm_indxg2l_row
     784             : 
     785             : ! **************************************************************************************************
     786             : !> \brief wrapper to scalapack function INDXG2L that computes the local index
     787             : !>         of a distributed matrix entry pointed to by the global index INDXGLOB.
     788             : !>
     789             : !>  Arguments
     790             : !>  =========
     791             : !>
     792             : !>  INDXGLOB  (global input) INTEGER
     793             : !>            The global index of the distributed matrix entry.
     794             : !>
     795             : !>  NB        (global input) INTEGER
     796             : !>            Block size, size of the blocks the distributed matrix is
     797             : !>            split into.
     798             : !>
     799             : !>  IPROC     (local dummy) INTEGER
     800             : !>            Dummy argument in this case in order to unify the calling
     801             : !>            sequence of the tool-routines.
     802             : !>
     803             : !>  ISRCPROC  (local dummy) INTEGER
     804             : !>            Dummy argument in this case in order to unify the calling
     805             : !>            sequence of the tool-routines.
     806             : !>
     807             : !>  NPROCS    (global input) INTEGER
     808             : !>            The total number processes over which the distributed
     809             : !>            matrix is distributed.
     810             : !>
     811             : !> \param struct ...
     812             : !> \param INDXGLOB ...
     813             : !> \return ...
     814             : !> \author Mauro Del Ben [MDB] - 12.2012
     815             : ! **************************************************************************************************
     816      581131 :    FUNCTION cp_fm_indxg2l_col(struct, INDXGLOB) RESULT(G2L)
     817             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     818             :       INTEGER, INTENT(IN)                      :: INDXGLOB
     819             :       INTEGER                                  :: G2L
     820             : 
     821             : #if defined(__parallel)
     822             :       INTEGER :: number_of_process_columns
     823             :       INTEGER, EXTERNAL :: indxg2l
     824             : #endif
     825             : 
     826             : #if defined(__parallel)
     827             : 
     828      581131 :       CALL struct%context%get(number_of_process_columns=number_of_process_columns)
     829             : 
     830      581131 :       G2L = indxg2l(INDXGLOB, struct%ncol_block, 0, struct%first_p_pos(2), number_of_process_columns)
     831             : 
     832             : #else
     833             :       MARK_USED(struct)
     834             : 
     835             :       G2L = INDXGLOB
     836             : 
     837             : #endif
     838             : 
     839      581131 :    END FUNCTION cp_fm_indxg2l_col
     840             : 
     841             : ! **************************************************************************************************
     842             : !> \brief wrapper to scalapack function INDXL2G that computes the global index
     843             : !>         of a distributed matrix entry pointed to by the local index INDXLOC
     844             : !>         of the process indicated by IPROC.
     845             : !>
     846             : !>  Arguments
     847             : !>  =========
     848             : !>
     849             : !>  INDXLOC   (global input) INTEGER
     850             : !>            The local index of the distributed matrix entry.
     851             : !>
     852             : !>  NB        (global input) INTEGER
     853             : !>            Block size, size of the blocks the distributed matrix is
     854             : !>            split into.
     855             : !>
     856             : !>  IPROC     (local input) INTEGER
     857             : !>            The coordinate of the process whose local array row or
     858             : !>            column is to be determined.
     859             : !>
     860             : !>  ISRCPROC  (global input) INTEGER
     861             : !>            The coordinate of the process that possesses the first
     862             : !>            row/column of the distributed matrix.
     863             : !>
     864             : !>  NPROCS    (global input) INTEGER
     865             : !>            The total number processes over which the distributed
     866             : !>            matrix is distributed.
     867             : !>
     868             : !> \param struct ...
     869             : !> \param INDXLOC ...
     870             : !> \param IPROC ...
     871             : !> \return ...
     872             : !> \author Mauro Del Ben [MDB] - 12.2012
     873             : ! **************************************************************************************************
     874     5418131 :    FUNCTION cp_fm_indxl2g_row(struct, INDXLOC, IPROC) RESULT(L2G)
     875             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     876             :       INTEGER, INTENT(IN)                      :: INDXLOC, IPROC
     877             :       INTEGER                                  :: L2G
     878             : 
     879             : #if defined(__parallel)
     880             :       INTEGER :: number_of_process_rows
     881             :       INTEGER, EXTERNAL :: indxl2g
     882             : 
     883     5418131 :       CALL struct%context%get(number_of_process_rows=number_of_process_rows)
     884             : 
     885     5418131 :       L2G = indxl2g(INDXLOC, struct%nrow_block, IPROC, struct%first_p_pos(1), number_of_process_rows)
     886             : 
     887             : #else
     888             :       MARK_USED(struct)
     889             :       MARK_USED(indxloc)
     890             :       MARK_USED(iproc)
     891             : 
     892             :       L2G = INDXLOC
     893             : 
     894             : #endif
     895             : 
     896     5418131 :    END FUNCTION cp_fm_indxl2g_row
     897             : 
     898             : ! **************************************************************************************************
     899             : !> \brief wrapper to scalapack function INDXL2G that computes the global index
     900             : !>         of a distributed matrix entry pointed to by the local index INDXLOC
     901             : !>         of the process indicated by IPROC.
     902             : !>
     903             : !>  Arguments
     904             : !>  =========
     905             : !>
     906             : !>  INDXLOC   (global input) INTEGER
     907             : !>            The local index of the distributed matrix entry.
     908             : !>
     909             : !>  NB        (global input) INTEGER
     910             : !>            Block size, size of the blocks the distributed matrix is
     911             : !>            split into.
     912             : !>
     913             : !>  IPROC     (local input) INTEGER
     914             : !>            The coordinate of the process whose local array row or
     915             : !>            column is to be determined.
     916             : !>
     917             : !>  ISRCPROC  (global input) INTEGER
     918             : !>            The coordinate of the process that possesses the first
     919             : !>            row/column of the distributed matrix.
     920             : !>
     921             : !>  NPROCS    (global input) INTEGER
     922             : !>            The total number processes over which the distributed
     923             : !>            matrix is distributed.
     924             : !>
     925             : !> \param struct ...
     926             : !> \param INDXLOC ...
     927             : !> \param IPROC ...
     928             : !> \return ...
     929             : !> \author Mauro Del Ben [MDB] - 12.2012
     930             : ! **************************************************************************************************
     931     5774892 :    FUNCTION cp_fm_indxl2g_col(struct, INDXLOC, IPROC) RESULT(L2G)
     932             :       CLASS(cp_fm_struct_type), INTENT(IN) :: struct
     933             :       INTEGER, INTENT(IN)                      :: INDXLOC, IPROC
     934             :       INTEGER                                  :: L2G
     935             : 
     936             : #if defined(__parallel)
     937             :       INTEGER :: number_of_process_columns
     938             :       INTEGER, EXTERNAL :: indxl2g
     939             : 
     940     5774892 :       CALL struct%context%get(number_of_process_columns=number_of_process_columns)
     941             : 
     942     5774892 :       L2G = indxl2g(INDXLOC, struct%ncol_block, IPROC, struct%first_p_pos(2), number_of_process_columns)
     943             : 
     944             : #else
     945             :       MARK_USED(struct)
     946             :       MARK_USED(indxloc)
     947             :       MARK_USED(iproc)
     948             : 
     949             :       L2G = INDXLOC
     950             : 
     951             : #endif
     952             : 
     953     5774892 :    END FUNCTION cp_fm_indxl2g_col
     954             : 
     955           0 : END MODULE cp_fm_struct

Generated by: LCOV version 1.15