LCOV - code coverage report
Current view: top level - src/45_xgTools - m_xgTransposer.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 71.9 % 452 325
Test Date: 2026-09-19 15:24:51 Functions: 68.8 % 16 11

            Line data    Source code
       1              : !!****m* ABINIT/m_xgTransposer
       2              : !! NAME
       3              : !!  m_xgTransposer
       4              : !!
       5              : !! FUNCTION
       6              : !! This module is to be used to go to "KGB" representation and to "linear
       7              : !! algebra representation". It will replace most of prep_* subroutine
       8              : !! This should really help to do the transposition operation.
       9              : !!
      10              : !! NOTES
      11              : !! The transposer switches between two states. Let's assume for simplicity
      12              : !! that we have four MPI processes in the comm_cols communicator and
      13              : !! a single process in the comm_rows communicator:
      14              : !!
      15              : !!  STATE_LINALG=                       STATE_COLSROWS=
      16              : !!
      17              : !!              bands                            bands
      18              : !!      |-------------------|            |----|----|----|----|
      19              : !!      |        P0         |            |    |    |    |    |
      20              : !!      |                   |            |    |    |    |    |
      21              : !!      |-------------------|            |    |    |    |    |
      22              : !!      |        P1         |            |    |    |    |    |
      23              : !!      |                   |            |    |    |    |    |
      24              : !!  pw  |-------------------|        pw  | P0 | P1 | P2 | P3 |
      25              : !!      |        P2         |            |    |    |    |    |
      26              : !!      |                   |            |    |    |    |    |
      27              : !!      |-------------------|            |    |    |    |    |
      28              : !!      |        P3         |            |    |    |    |    |
      29              : !!      |                   |            |    |    |    |    |
      30              : !!      |-------------------|            |----|----|----|----|
      31              : !!
      32              : !! The user can define custom block sizes using ncolsColsRows_sub and nrowsLinalg_sub.
      33              : !!
      34              : !! TODO                                  IML 04/04/2025
      35              : !! -clean versions to always pass from my array version
      36              : !!  for ncolsColsRows or create wrappers so that if we
      37              : !!  give an array then we turn it into scalar
      38              : !! -add unitary tests for my custom transposition
      39              : !!
      40              : !! COPYRIGHT
      41              : !!  Copyright (C) 2017-2026 ABINIT group (J. Bieder, L. Baguet, IML)
      42              : !!  This file is distributed under the terms of the
      43              : !!  GNU General Public License, see ~abinit/COPYING
      44              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      45              : !!
      46              : !! NOTES
      47              : !!
      48              : !! SOURCE
      49              : 
      50              : #if defined HAVE_CONFIG_H
      51              : #include "config.h"
      52              : #endif
      53              : 
      54              : #include "abi_common.h"
      55              : 
      56              : ! nvtx related macro definition
      57              : #include "nvtx_macros.h"
      58              : 
      59              : module m_xgTransposer
      60              : 
      61              :   use, intrinsic :: iso_c_binding, only: c_double, c_size_t, c_loc
      62              : 
      63              :   use defs_basis, only : std_err, std_out, dp, ABI_GPU_KOKKOS, ABI_GPU_OPENMP, ABI_GPU_DISABLED
      64              :   use m_xomp
      65              :   use m_profiling_abi
      66              :   USE_MPI
      67              :   use m_xmpi
      68              :   use m_errors
      69              :   use m_xg
      70              :   use m_time
      71              : 
      72              : #if defined HAVE_YAKL
      73              :   use gator_mod
      74              : #endif
      75              : 
      76              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_YAKL)
      77              :  use m_gpu_toolbox, only : CPU_DEVICE_ID, gpu_device_synchronize, gpu_data_prefetch_async
      78              : #endif
      79              : 
      80              : #if defined(HAVE_GPU_MARKERS)
      81              :   use m_nvtx_data
      82              : #endif
      83              : 
      84              :   implicit none
      85              : 
      86              : #ifdef HAVE_MPI1
      87              :  include 'mpif.h'
      88              : #endif
      89              : 
      90              :   private
      91              : 
      92              :   integer, parameter, public :: STATE_LINALG = 1
      93              :   integer, parameter, public :: STATE_COLSROWS  = 2
      94              :   integer, parameter, public :: STATE_UNKNOW    = 3
      95              :   integer, parameter, public :: MPI_LINALG = 1
      96              :   integer, parameter, public :: MPI_ROWS   = 2
      97              :   integer, parameter, public :: MPI_COLS   = 3
      98              :   integer, parameter, public :: MPI_2DCART = 4
      99              :   integer, parameter, public :: TRANS_ALL2ALL = 1
     100              :   integer, parameter, public :: TRANS_GATHER = 2
     101              :   integer, parameter         :: TRANS_TYPE_CONSTRUCTED = 1
     102              :   integer, parameter         :: TRANS_TYPE_CONSTRUCTED_NULL_COMM = 2
     103              :   integer, parameter         :: TRANS_TYPE_COPIED = 3
     104              : 
     105              :   integer, parameter :: tim_toColsRows  = 1662
     106              :   integer, parameter :: tim_toLinalg    = 1663
     107              :   integer, parameter :: tim_all2allv    = 1664
     108              :   integer, parameter :: tim_gatherv     = 1665
     109              :   integer, parameter :: tim_reorganize  = 1666
     110              :   integer, parameter :: tim_init        = 1667
     111              :   integer, parameter :: tim_free        = 1668
     112              :   integer, parameter :: tim_transpose   = 1669
     113              : 
     114              :   type, private :: mpiData_t
     115              :     integer :: comm
     116              :     integer :: rank
     117              :     integer :: size
     118              :   end type mpiData_t
     119              : 
     120              :   type, private :: ptr_t
     121              :     double precision, pointer :: ptr(:,:) => null()
     122              :   end type ptr_t
     123              : 
     124              :   type, public :: xgTransposer_t
     125              :     type(xgBlock_t), pointer, private :: xgBlock_linalg => null()
     126              :     type(xgBlock_t), pointer, private :: xgBlock_colsrows => null()
     127              :     integer :: state
     128              :     type(mpiData_t), private :: mpiData(4)
     129              :     integer, allocatable, private :: lookup(:)
     130              :     integer, pointer, private :: nrowsLinalg(:) => null()
     131              :     integer, pointer, private :: ncolsColsRows_sub(:) => null() ! allows different bandpp per MPI process
     132              :     integer :: nspinor
     133              :     integer :: nrowsColsRows
     134              :     integer :: ncolsColsRows
     135              :     integer :: ncolsLinalg
     136              :     integer :: mpiAlgo
     137              :     integer :: type
     138              :     integer :: me_g0_fft
     139              :     integer :: gpu_option = ABI_GPU_DISABLED
     140              :     integer :: gpu_kokkos_nthrd = 1
     141              :     integer :: gpu_thread_limit = 1
     142              :     logical :: custom_ncolsColsRows = .false. ! use ncolsColsRows_sub instead of ncolsColsRows
     143              :     real(dp), ABI_CONTIGUOUS pointer:: buffer(:,:) => null()
     144              :   end type xgTransposer_t
     145              : 
     146              :   public :: xgTransposer_constructor
     147              :   public :: xgTransposer_copyConstructor
     148              :   public :: xgTransposer_transpose
     149              :   public :: xgTransposer_getRank
     150              :   public :: xgTransposer_getComm
     151              :   public :: xgTransposer_free
     152              : 
     153              :   contains
     154              : !!***
     155              : 
     156              : !!****f* m_xgTransposer/xgTransposer_constructor
     157              : !!
     158              : !! NAME
     159              : !! xgTransposer_constructor
     160              : 
     161        46026 :   subroutine xgTransposer_constructor(xgTransposer,xgBlock_linalg,xgBlock_colsrows,nspinor,&
     162              :       state,algo,comm_rows,comm_cols,ncpu_cols,ncpu_rows,me_g0_fft,gpu_option,gpu_thread_limit,&
     163        46026 :       custom_ncolsColsRows,ncolsColsRows_sub,nrowsLinalg_sub)
     164              : 
     165              :     type(xgTransposer_t)   , intent(inout) :: xgTransposer
     166              :     type(xgBlock_t), target, intent(in   ) :: xgBlock_linalg
     167              :     type(xgBlock_t), target, intent(in   ) :: xgBlock_colsrows
     168              :     integer                , intent(in   ) :: comm_rows,comm_cols
     169              :     integer                , intent(in   ) :: ncpu_rows,ncpu_cols
     170              :     integer                , intent(in   ) :: nspinor
     171              :     integer                , intent(in   ) :: state
     172              :     integer                , intent(in   ) :: algo
     173              :     integer                , intent(in   ) :: me_g0_fft
     174              :     integer, optional      , intent(in   ) :: gpu_option,gpu_thread_limit
     175              :     logical, optional      , intent(in   ) :: custom_ncolsColsRows ! query for pointer
     176              :     integer, optional, target, intent(in) :: ncolsColsRows_sub(:)
     177              :     integer, optional, target, intent(in) :: nrowsLinalg_sub(:)
     178              :     integer :: commLinalg
     179              :     integer :: ncols
     180              :     integer :: nrows
     181              :     integer :: ierr
     182              :     integer :: icol
     183              :     integer :: ncpuRows
     184              :     integer :: ncpuCols
     185              :     logical :: custom_ncolsColsRows_
     186              : #if defined HAVE_MPI
     187              :     integer :: comm_rows_,comm_cols_
     188              : #endif
     189              :     character(len=500) :: message
     190              :     double precision :: tsec(2)
     191              : 
     192        46026 :     call timab(tim_init,1,tsec)
     193              : 
     194        46026 :     xgTransposer%type = TRANS_TYPE_CONSTRUCTED
     195              : 
     196        46026 :     xgTransposer%xgBlock_linalg => xgBlock_linalg
     197        46026 :     xgTransposer%xgBlock_colsrows => xgBlock_colsrows
     198        46026 :     xgTransposer%state = state
     199        46026 :     xgTransposer%nspinor = nspinor
     200        46026 :     xgTransposer%me_g0_fft = me_g0_fft
     201        46026 :     xgTransposer%gpu_option = ABI_GPU_DISABLED
     202        46026 :     if(present(gpu_option)) xgTransposer%gpu_option = gpu_option
     203        46026 :     xgTransposer%gpu_thread_limit = 1
     204        46026 :     if(present(gpu_thread_limit)) xgTransposer%gpu_thread_limit = gpu_thread_limit
     205        46026 :     if (state==STATE_COLSROWS) then
     206            0 :         if (comm_rows==xmpi_comm_null.or.comm_cols==xmpi_comm_null) then
     207            0 :             ABI_ERROR('STATE_COLSROWS requires input comms')
     208              :         end if
     209            0 :         commLinalg = comm_cols
     210        46026 :     else if (state==STATE_LINALG) then
     211        46026 :         commLinalg = comm(xgBlock_linalg)
     212              :     else
     213            0 :         ABI_ERROR("Invalid transposer state")
     214              :     end if
     215        46026 :     xgTransposer%mpiData(MPI_LINALG)%comm = commLinalg
     216        46026 :     xgTransposer%mpiData(MPI_LINALG)%rank = xmpi_comm_rank(commLinalg)
     217        46026 :     xgTransposer%mpiData(MPI_LINALG)%size = xmpi_comm_size(commLinalg)
     218              : 
     219              : #if defined HAVE_MPI
     220        46026 :     if (comm_rows==xmpi_comm_null.and.comm_cols==xmpi_comm_null) then
     221           10 :       xgTransposer%type = TRANS_TYPE_CONSTRUCTED_NULL_COMM
     222           10 :       ncpuCols = ncpu_cols
     223           10 :       ncpuRows = ncpu_rows
     224        46016 :     else if (comm_rows==xmpi_comm_null) then
     225            0 :       ABI_ERROR("Comm_rows and comm_cols should have the same status : null or defined. Here only comm_rows is null.")
     226        46016 :     else if (comm_cols==xmpi_comm_null) then
     227            0 :       ABI_ERROR("Comm_rows and comm_cols should have the same status : null or defined. Here only comm_cols is null.")
     228              :     else
     229        46016 :       xgTransposer%mpiData(MPI_2DCART)%comm = xgTransposer%mpiData(MPI_LINALG)%comm
     230        46016 :       ncpuRows = xmpi_comm_size(comm_rows)
     231        46016 :       ncpuCols = xmpi_comm_size(comm_cols)
     232              :     end if
     233              : #else
     234              :     ncpuRows = 1
     235              :     ncpuCols = 1
     236              : #endif
     237        46026 :     if ( xgTransposer%mpiData(MPI_LINALG)%size < ncpuCols*ncpuRows ) then
     238            0 :       write(message,'(a,i6,a,i6,a)') "There is not enough MPI processes in the communication (", &
     239            0 :         xgTransposer%mpiData(MPI_LINALG)%size, "). Need at least ", ncpuCols*ncpuRows, " processes"
     240            0 :       ABI_ERROR(message)
     241              :     end if
     242              : 
     243        46026 :     if ( ( algo == TRANS_ALL2ALL .or. algo == TRANS_GATHER ) ) then
     244        46026 :       xgTransposer%mpiAlgo = algo
     245              :     else
     246            0 :       xgTransposer%mpiAlgo = TRANS_ALL2ALL
     247            0 :       ABI_COMMENT("Bad value for transposition MPI_algo. Will use ALLTOALL")
     248              :     end if
     249              : 
     250              :     !if ( xgTransposer%mpiAlgo == TRANS_ALL2ALL ) then
     251              :     !  ABI_COMMENT("Using mpi_alltoall for transposition")
     252              :     !else
     253              :     !  ABI_COMMENT("Using mpi_gatherv for transposition")
     254              :     !end if
     255              : 
     256              :     ! Nullify pointers in order to be able to query them
     257        46026 :     xgTransposer%nrowsLinalg => null()
     258        46026 :     xgTransposer%buffer => null()
     259        46026 :     xgTransposer%ncolsColsRows_sub => null()
     260              : 
     261              :     ! Attention: Do not check condition present() on the pointer because in Fortran
     262              :     ! "An unallocated variable passed as an argument is not PRESENT"
     263              :     ! in other words declared pointers with undefined status cannot be queried
     264        46026 :     custom_ncolsColsRows_ = .false.
     265        46026 :     if (present(custom_ncolsColsRows)) custom_ncolsColsRows_ = custom_ncolsColsRows
     266        46010 :     xgTransposer%custom_ncolsColsRows = custom_ncolsColsRows_
     267           16 :     if (custom_ncolsColsRows_) then
     268           16 :       if ( ncpuRows > 1 ) then
     269            0 :         write(message,'(a,i6)') "Custom ncolsColsRows not implemented for number of row MPI processes=", ncpuRows
     270            0 :         ABI_ERROR(message)
     271              :       end if
     272           16 :       xgTransposer%custom_ncolsColsRows = .true.
     273           16 :       if (state==STATE_LINALG) xgTransposer%ncolsColsRows_sub => ncolsColsRows_sub
     274              :       ! if state colsrows in will be constructed later in readDistribution
     275              :     end if
     276              : 
     277              :     ! The following allocates memory buffer associated either to xgBlock_linalg or to xgBlock_colsrows
     278              :     !! Assumes that only one of them is already allocated
     279        46026 :     select case (state)
     280              :     case (STATE_LINALG)
     281              : 
     282              :       ! We are in the linalg representation.
     283              :       ! We need to construct the colsrows parallelization
     284        46026 :       call xgBlock_getSize(xgBlock_linalg,nrows,ncols)
     285              : 
     286              :       ! Get total number of rows in ColsRows representation
     287        46026 :       call xmpi_sum(nrows,commLinalg,ierr)
     288              : 
     289              :       ! Check that ncols can be uniformly distributed across ncolsCols MPI processes
     290              :       ! Load balance is uniform, each MPI process has the same ncolsColsRows
     291        46026 :       if ( (.not.xgTransposer%custom_ncolsColsRows) .and. MOD(ncols,ncpuCols) /=0 ) then
     292            0 :         if ( ncols > ncpuCols ) then
     293            0 :           write(message,'(a,i6,a,i6,a)') "Unbalanced parallelization : ", ncols, " columns for ", ncpuCols, " MPI"
     294            0 :           ABI_ERROR(message)
     295              :         else
     296            0 :           write(message,'(i6,a)') (ncpuCols-ncols)*ncpuRows, " MPI will not be used because of the number of columns!!"
     297            0 :           ABI_ERROR(message)
     298              :           !ncpuCols = ncols
     299              :         end if
     300              :       end if
     301              : 
     302              :       ! Build the lookup table that maps each column to an MPI process
     303       138078 :       ABI_MALLOC(xgTransposer%lookup,(1:ncols))
     304              :       !ABI_MALLOC(xgTransposer%me_g0_lookup,())
     305       476306 :       do icol = 0, ncols-1
     306       476306 :         xgTransposer%lookup(icol+1) = MOD(icol,ncpuCols)
     307              :       end do
     308              : 
     309              : #if defined HAVE_MPI
     310        46026 :       if (comm_rows==xmpi_comm_null.and.comm_cols==xmpi_comm_null) then
     311           10 :         call xgTransposer_makeComm(xgTransposer,ncpuRows,ncpuCols,comm_rows_,comm_cols_)
     312              :       else
     313        46016 :         comm_rows_=comm_rows
     314        46016 :         comm_cols_=comm_cols
     315              :       end if
     316        46026 :       xgTransposer%mpiData(MPI_ROWS)%comm = comm_rows_
     317        46026 :       xgTransposer%mpiData(MPI_COLS)%comm = comm_cols_
     318              : #else
     319              :       xgTransposer%mpiData(MPI_ROWS)%comm = xmpi_comm_null
     320              :       xgTransposer%mpiData(MPI_COLS)%comm = xmpi_comm_null
     321              : #endif
     322        46026 :       call xgTransposer_setComm(xgTransposer)
     323        46026 :       call xgTransposer_computeDistribution(xgTransposer)
     324        92052 :       call xgTransposer_makeXgBlock(xgTransposer)
     325              : 
     326              :     case (STATE_COLSROWS)
     327              : 
     328              :       !write(std_out,'(a,i2,i2)') 'db @xgTransposer constructor enter case for # procs', ncpuRows,ncpuCols
     329              :       !call flush_unit(std_out)
     330              : 
     331              :       ! We are in the colsrows representation.
     332              :       ! We need to construct the linalg parallelization
     333              : 
     334              :       ! Load balance
     335              :       ! nrows are distributed uniformly across ncpuCols MPI processes for 1,...,ncpuCols-1
     336              :       ! The last MPI process uses remaining nrows. Read distribution from nrowsLinalg_sub
     337            0 :       call xgBlock_getSize(xgBlock_colsrows,nrows,ncols)
     338            0 :       ABI_MALLOC(xgTransposer%lookup,(1:ncols))
     339              : 
     340              : #if defined HAVE_MPI
     341            0 :       xgTransposer%mpiData(MPI_ROWS)%comm = comm_rows
     342            0 :       xgTransposer%mpiData(MPI_COLS)%comm = comm_cols
     343              : #else
     344              :       xgTransposer%mpiData(MPI_ROWS)%comm = xmpi_comm_null
     345              :       xgTransposer%mpiData(MPI_COLS)%comm = xmpi_comm_null
     346              : #endif
     347              : 
     348            0 :       call xgTransposer_setComm(xgTransposer)
     349            0 :       ABI_MALLOC(xgTransposer%nrowsLinalg,(xgTransposer%mpiData(MPI_LINALG)%size))
     350            0 :       xgTransposer%nrowsLinalg(:) = nrowsLinalg_sub(:)
     351            0 :       call xgTransposer_readDistribution(xgTransposer)
     352            0 :       call xgTransposer_makeXgBlock(xgTransposer)
     353              : 
     354              :     case default
     355        46026 :       ABI_ERROR("State is undefined")
     356              :     end select
     357              : 
     358        46026 :     call timab(tim_init,2,tsec)
     359              : 
     360              :     !write(*,*) 'transposer construction done'
     361              : 
     362        46026 :   end subroutine xgTransposer_constructor
     363              : !!***
     364              : 
     365              : !!****f* m_xgTransposer/xgTransposer_copyConstructor
     366              : !!
     367              : !! NAME
     368              : !! xgTransposer_copyConstructor
     369              : 
     370       143852 :   subroutine xgTransposer_copyConstructor(xgTransposer,xgTransposerInitialized,xgBlock_linalg,xgBlock_colsrows,state)
     371              : 
     372              :     type(xgTransposer_t)   , intent(inout) :: xgTransposer
     373              :     type(xgTransposer_t)   , intent(in   ) :: xgTransposerInitialized
     374              :     type(xgBlock_t), target, intent(in   ) :: xgBlock_linalg
     375              :     type(xgBlock_t), target, intent(in   ) :: xgBlock_colsrows
     376              :     integer                , intent(in   ) :: state
     377              :     integer :: commLinalg
     378              :     integer :: ncols, ncpuCols
     379              :     integer :: nrows, ncpuRows
     380              :     integer :: ierr
     381              :     integer :: icol
     382              :     character(len=500) :: message
     383              :     double precision :: tsec(2)
     384              : 
     385       143852 :     call timab(tim_init,1,tsec)
     386              : 
     387       143852 :     xgTransposer%type = TRANS_TYPE_COPIED
     388              : 
     389       143852 :     xgTransposer%xgBlock_linalg => xgBlock_linalg
     390       143852 :     xgTransposer%xgBlock_colsrows => xgBlock_colsrows
     391       143852 :     xgTransposer%state = state
     392       143852 :     if (state==STATE_COLSROWS) then
     393            0 :         commLinalg = xgTransposerInitialized%mpiData(MPI_LINALG)%comm
     394       143852 :     else if (state==STATE_LINALG) then
     395       143852 :         commLinalg = comm(xgBlock_linalg)
     396              :     else
     397            0 :         ABI_ERROR("Invalid transposer state")
     398              :     end if
     399              : 
     400       143852 :     if ( commLinalg /= xgTransposerInitialized%mpiData(MPI_LINALG)%comm ) then
     401            0 :       ABI_ERROR("Linalg communicators are different for the two transposers, this is not allowed.")
     402              :     end if
     403              : 
     404       719260 :     xgTransposer%mpiData(:)%comm = xgTransposerInitialized%mpiData(:)%comm
     405       143852 :     xgTransposer%mpiData(MPI_LINALG)%rank = xmpi_comm_rank(commLinalg)
     406       143852 :     xgTransposer%mpiData(MPI_LINALG)%size = xmpi_comm_size(commLinalg)
     407       143852 :     xgTransposer%mpiData(MPI_COLS)%rank = xmpi_comm_rank(xgTransposer%mpiData(MPI_COLS)%comm)
     408       143852 :     xgTransposer%mpiData(MPI_COLS)%size = xmpi_comm_size(xgTransposer%mpiData(MPI_COLS)%comm)
     409       143852 :     xgTransposer%mpiData(MPI_ROWS)%rank = xmpi_comm_rank(xgTransposer%mpiData(MPI_ROWS)%comm)
     410       143852 :     xgTransposer%mpiData(MPI_ROWS)%size = xmpi_comm_size(xgTransposer%mpiData(MPI_ROWS)%comm)
     411              : 
     412       143852 :     xgTransposer%mpiAlgo = xgTransposerInitialized%mpiAlgo
     413       143852 :     xgTransposer%nspinor = xgTransposerInitialized%nspinor
     414       143852 :     xgTransposer%me_g0_fft = xgTransposerInitialized%me_g0_fft
     415       143852 :     xgTransposer%gpu_option = xgTransposerInitialized%gpu_option
     416              : 
     417              :     ! Nullify pointers in order to be able to query them
     418       143852 :     xgTransposer%nrowsLinalg => null()
     419       143852 :     xgTransposer%buffer => null()
     420       143852 :     xgTransposer%ncolsColsRows_sub => null()
     421              :     !write(std_out,*) '@nrowsLinalg', associated(xgTransposer%nrowsLinalg)
     422              : 
     423       143852 :     xgTransposer%custom_ncolsColsRows = xgTransposerInitialized%custom_ncolsColsRows
     424       143852 :     if(xgTransposer%custom_ncolsColsRows .and. state==STATE_LINALG) then
     425            0 :         xgTransposer%ncolsColsRows_sub => xgTransposerInitialized%ncolsColsRows_sub
     426              :         ! if state colsrows in will be constructed later in readDistribution
     427              :     end if
     428              : 
     429       143852 :     ncpuCols = xgTransposer%mpiData(MPI_COLS)%size
     430       143852 :     ncpuRows = xgTransposer%mpiData(MPI_ROWS)%size
     431              : 
     432       143852 :     select case (state)
     433              :     case (STATE_LINALG)
     434              : 
     435       143852 :       call xgBlock_getSize(xgBlock_linalg,nrows,ncols)
     436              : 
     437              :       ! Get total number of rows in ColsRows representation
     438       143852 :       call xmpi_sum(nrows,commLinalg,ierr)
     439              : 
     440              :       ! Check that ncols can be uniformly distributed across ncolsCols MPI processes
     441       143852 :       if ( (.not.xgTransposer%custom_ncolsColsRows) .and. MOD(ncols,ncpuCols) /=0 ) then
     442            0 :         if ( ncols > ncpuCols ) then
     443            0 :           write(message,'(a,i6,a,i6,a)') "Unbalanced parallelization : ", ncols, " columns for ", ncpuCols, " MPI"
     444            0 :           ABI_ERROR(message)
     445              :         else
     446            0 :           write(message,'(i6,a)') (ncpuCols-ncols)*ncpuRows, " MPI will not be used  because of the number of columns!!"
     447            0 :           ABI_ERROR(message)
     448              :         end if
     449              :       end if
     450              : 
     451              :       ! Build the lookup table that maps each column to an MPI process
     452              :       ! Assures load balance so that each MPI process has the same charge
     453       431556 :       ABI_MALLOC(xgTransposer%lookup,(1:ncols))
     454       143852 :       if ( cols(xgTransposerInitialized%xgBlock_linalg) /= ncols ) then
     455            0 :         do icol = 0, ncols-1
     456            0 :             xgTransposer%lookup(icol+1) = MOD(icol,ncpuCols)
     457              :         end do
     458              :       else
     459      1169220 :         xgTransposer%lookup(:) = xgTransposerInitialized%lookup(:)
     460              :       end if
     461              : 
     462       143852 :       call xgTransposer_computeDistribution(xgTransposer)
     463       287704 :       call xgTransposer_makeXgBlock(xgTransposer)
     464              : 
     465              :     case (STATE_COLSROWS)
     466              : 
     467              :       !write(std_out,*) 'db @xgTransposer copyConstructor enter case'
     468              :       !call flush_unit(std_out)
     469              : 
     470            0 :       nrows = rows(xgBlock_colsrows)
     471            0 :       ncols = cols(xgBlock_colsrows)
     472            0 :       if ( (.not.xgTransposer%custom_ncolsColsRows) .and. MOD(nrows,ncpuCols) /=0 .and. nrows > ncpuCols) then
     473            0 :         write(message,'(a,i6,a,i6,a)') "Unbalanced parallelization : ", nrows, " rows for ", ncpuCols, " MPI"
     474            0 :         ABI_COMMENT(message)
     475              :       end if
     476            0 :       ABI_MALLOC(xgTransposer%lookup,(1:ncols))
     477              : 
     478            0 :       ABI_MALLOC(xgTransposer%nrowsLinalg,(xgTransposer%mpiData(MPI_LINALG)%size))
     479            0 :       xgTransposer%nrowsLinalg(:) = xgTransposerInitialized%nrowsLinalg(:)
     480            0 :       call xgTransposer_readDistribution(xgTransposer)
     481            0 :       call xgTransposer_makeXgBlock(xgTransposer)
     482              : 
     483              :     case default
     484       143852 :       ABI_ERROR("State is undefined")
     485              :     end select
     486              : 
     487       143852 :     call timab(tim_init,2,tsec)
     488              : 
     489       143852 :   end subroutine xgTransposer_copyConstructor
     490              : !!***
     491              : 
     492              : !!****f* m_xgTransposer/xgTransposer_setComm
     493              : !!
     494              : !! NAME
     495              : !! xgTransposer_setComm
     496              : 
     497        46026 :   subroutine xgTransposer_setComm(xgTransposer)
     498              : 
     499              :     type(xgTransposer_t), intent(inout) :: xgTransposer
     500              : 
     501        46026 :     xgTransposer%mpiData(MPI_ROWS)%rank = xmpi_comm_rank(xgTransposer%mpiData(MPI_ROWS)%comm)
     502        46026 :     xgTransposer%mpiData(MPI_ROWS)%size = xmpi_comm_size(xgTransposer%mpiData(MPI_ROWS)%comm)
     503        46026 :     xgTransposer%mpiData(MPI_COLS)%rank = xmpi_comm_rank(xgTransposer%mpiData(MPI_COLS)%comm)
     504        46026 :     xgTransposer%mpiData(MPI_COLS)%size = xmpi_comm_size(xgTransposer%mpiData(MPI_COLS)%comm)
     505              : 
     506        92052 :     select case(xgTransposer%state)
     507              :     case (STATE_LINALG)
     508        46026 :         call xgBlock_setComm(xgTransposer%xgBlock_colsrows,xgTransposer%mpiData(MPI_ROWS)%comm)
     509              :     case (STATE_COLSROWS)
     510            0 :         call xgBlock_setComm(xgTransposer%xgBlock_linalg,xgTransposer%mpiData(MPI_ROWS)%comm)
     511              :     case default
     512        46026 :       ABI_ERROR("State is undefined")
     513              :     end select
     514              : 
     515        46026 :   end subroutine xgTransposer_setComm
     516              : !!***
     517              : 
     518              : !!****f* m_xgTransposer/xgTransposer_makeComm
     519              : !!
     520              : !! NAME
     521              : !! xgTransposer_makeComm
     522              : 
     523           10 :   subroutine xgTransposer_makeComm(xgTransposer,ncpuRows,ncpuCols,comm_rows,comm_cols)
     524              : 
     525              :     type(xgTransposer_t), intent(inout) :: xgTransposer
     526              :     integer             , intent(in   ) :: ncpuRows
     527              :     integer             , intent(in   ) :: ncpuCols
     528              :     integer             , intent(out  ) :: comm_rows
     529              :     integer             , intent(out  ) :: comm_cols
     530              :     integer :: commColsRows
     531              : #if defined HAVE_MPI
     532              :     integer :: sizeGrid(2) !coordInGrid(2),
     533              :     logical :: periodic(2), selectDim(2), reorder
     534              :     integer :: ierr
     535              : 
     536           10 :     sizeGrid(1) = ncpuCols
     537           10 :     sizeGrid(2) = ncpuRows
     538              :     !sizeGrid(1) = ncpuRows
     539              :     !sizeGrid(2) = ncpuCols
     540           10 :     periodic = (/ .false., .false. /)
     541           10 :     reorder  = .false.
     542           10 :     call mpi_cart_create(xgTransposer%mpiData(MPI_LINALG)%comm,2,sizeGrid,periodic,reorder,commColsRows,ierr)
     543           10 :     if ( ierr /= xmpi_success ) then
     544            0 :       ABI_ERROR("xgTransposer failed to creat cartesian grid")
     545              :     end if
     546           10 :     xgTransposer%mpiData(MPI_2DCART)%comm = commColsRows
     547              : 
     548           10 :     selectDim = (/ .false., .true. /)
     549              :     !selectDim = (/ .true., .false. /)
     550           10 :     call mpi_cart_sub(commColsRows, selectDim, xgTransposer%mpiData(MPI_ROWS)%comm,ierr)
     551           10 :     if ( ierr /= xmpi_success ) then
     552            0 :       ABI_ERROR("xgTransposer failed to creat rows communicator")
     553              :     end if
     554           10 :     selectDim = (/ .true., .false. /)
     555              :     !selectDim = (/ .false., .true. /)
     556           10 :     call mpi_cart_sub(commColsRows, selectDim, xgTransposer%mpiData(MPI_COLS)%comm,ierr)
     557           10 :     if ( ierr /= xmpi_success ) then
     558            0 :       ABI_ERROR("xgTransposer failed to creat columns communicator")
     559              :     end if
     560              : #else
     561              :     commColsRows = xmpi_comm_null
     562              :     xgTransposer%mpiData(MPI_ROWS)%comm = xmpi_comm_null
     563              :     xgTransposer%mpiData(MPI_COLS)%comm = xmpi_comm_null
     564              : #endif
     565           10 :     comm_rows = xgTransposer%mpiData(MPI_ROWS)%comm
     566           10 :     comm_cols = xgTransposer%mpiData(MPI_COLS)%comm
     567              : 
     568           10 :   end subroutine xgTransposer_makeComm
     569              : !!***
     570              : 
     571              : !!****f* m_xgTransposer/xgTransposer_computeDistribution
     572              : !!
     573              : !! NAME
     574              : !! xgTransposer_computeDistribution
     575              : 
     576       189878 :   subroutine xgTransposer_computeDistribution(xgTransposer)
     577              : 
     578              :     type(xgTransposer_t), intent(inout) :: xgTransposer
     579              :     integer :: nRealPairs
     580              :     integer :: ierr
     581              :     integer :: icpu_cols,icpu_rows
     582              :     integer :: ncpuCols,ncpuRows
     583              :     integer :: ncolsColsRowsMe
     584              : 
     585       569634 :     ABI_MALLOC(xgTransposer%nrowsLinalg,(xgTransposer%mpiData(MPI_LINALG)%size))
     586       189878 :     nRealPairs = rows(xgTransposer%xgBlock_linalg)
     587       189878 :     if (MOD(nRealPairs,xgTransposer%nspinor)/=0) then
     588            0 :         ABI_ERROR('nspinor should divide nRealPairs!')
     589              :     end if
     590              : 
     591       189878 :     call xmpi_allgather(nRealPairs,xgTransposer%nrowsLinalg,xgTransposer%mpiData(MPI_LINALG)%comm,ierr)
     592       189878 :     if ( ierr /= xmpi_success ) then
     593            0 :         ABI_ERROR("Error while gathering number of rows in linalg")
     594              :     end if
     595              : 
     596       189878 :     ncpuCols = xgTransposer%mpiData(MPI_COLS)%size
     597       189878 :     ncpuRows = xgTransposer%mpiData(MPI_ROWS)%size
     598       189878 :     icpu_rows = xgTransposer%mpiData(MPI_ROWS)%rank
     599       189878 :     xgTransposer%nrowsColsRows = 0
     600       686364 :     do icpu_cols=0,ncpuCols-1
     601       686364 :         xgTransposer%nrowsColsRows = xgTransposer%nrowsColsRows + xgTransposer%nrowsLinalg(1+icpu_rows+icpu_cols*ncpuRows)
     602              :     end do
     603       189878 :     xgTransposer%ncolsColsRows = cols(xgTransposer%xgBlock_linalg)/ncpuCols
     604       189878 :     if (xgTransposer%custom_ncolsColsRows) then
     605           16 :       ncolsColsRowsMe = xgTransposer%ncolsColsRows_sub(xgTransposer%mpiData(MPI_LINALG)%rank+1)
     606           16 :       xgTransposer%ncolsColsRows = ncolsColsRowsMe ! overwrite
     607              :     end if
     608              : 
     609              :     !write(*,*) "In linalg, # of real pairs:", xgTransposer%nrowsLinalg
     610              :     !write(*,*) "In rows, # of real pairs for proc ", xgTransposer%mpiData(MPI_ROWS)%rank, ":", xgTransposer%nrowsColsRows
     611              :     !write(*,*) "In cols, # of cols for proc ", xgTransposer%mpiData(MPI_COLS)%rank, ":", xgTransposer%ncolsColsRows
     612              : 
     613       189878 :   end subroutine xgTransposer_computeDistribution
     614              : !!***
     615              : 
     616              : !!****f* m_xgTransposer/xgTransposer_readDistribution
     617              : !!
     618              : !! NAME
     619              : !! xgTransposer_readDistribution
     620              : !!
     621              : !! FUNCTION
     622              : !! Read custom distribution from xgTransposer%nrowsLinalg(:)
     623              : 
     624            0 :   subroutine xgTransposer_readDistribution(xgTransposer)
     625              : 
     626              :       ! Arguments
     627              :       type(xgTransposer_t), intent(inout) :: xgTransposer
     628              :       ! Variables
     629              :       integer :: iproc,nRealPairs,tot_ncols,ncols,ierr
     630              :       integer :: nprocs,commLinalg
     631              : 
     632              :       ! ***********************************************************
     633              : 
     634            0 :       nprocs = xgTransposer%mpiData(MPI_LINALG)%size
     635            0 :       xgTransposer%nrowsColsRows = rows(xgTransposer%xgBlock_colsrows)
     636            0 :       ncols = cols(xgTransposer%xgBlock_colsrows)
     637            0 :       xgTransposer%ncolsColsRows = ncols ! for current MPI process
     638              : 
     639            0 :       if(xgTransposer%custom_ncolsColsRows) then
     640            0 :           ABI_MALLOC(xgTransposer%ncolsColsRows_sub,(nprocs))
     641              : 
     642            0 :           commLinalg = xgTransposer%mpiData(MPI_LINALG)%comm
     643            0 :           ncols = cols(xgTransposer%xgBlock_colsrows)
     644            0 :           call xmpi_allgather(ncols,xgTransposer%ncolsColsRows_sub,commLinalg,ierr)
     645            0 :           if ( ierr /= xmpi_success ) then
     646            0 :               ABI_ERROR("Error while gathering number of columns in colsrows")
     647              :           end if
     648            0 :           call xmpi_sum(ncols,commLinalg,ierr)
     649            0 :           if ( ierr /= xmpi_success ) then
     650            0 :               ABI_ERROR("Error while summing number of columns in colsrows")
     651              :           end if
     652            0 :           tot_ncols = ncols ! update sum
     653              :       else
     654            0 :           tot_ncols = ncols*xgTransposer%mpiData(MPI_COLS)%size
     655              :       end if
     656              : 
     657            0 :       do iproc=1,size(xgTransposer%nrowsLinalg)
     658            0 :         nRealPairs = xgTransposer%nrowsLinalg(iproc)
     659            0 :         if (MOD(nRealPairs,xgTransposer%nspinor)/=0) then
     660            0 :             ABI_ERROR('nspinor should divide nRealPairs!')
     661              :         end if
     662              :       end do
     663              : 
     664            0 :       xgTransposer%ncolsLinalg = tot_ncols
     665              : 
     666              :       !write(*,*) "In linalg, # of real pairs:", xgTransposer%nrowsLinalg
     667              :       !write(*,*) "In linalg, # of cols:", xgTransposer%ncolsLinalg
     668              :       !write(*,*) "In rows, # of real pairs for proc ", xgTransposer%mpiData(MPI_ROWS)%rank, ":", xgTransposer%nrowsColsRows
     669              :       !write(*,*) "In cols, # of cols for proc ", xgTransposer%mpiData(MPI_COLS)%rank, ":", xgTransposer%ncolsColsRows
     670              : 
     671            0 :   end subroutine xgTransposer_readDistribution
     672              : !!***
     673              : 
     674              : !!****f* m_xgTransposer/xgTransposer_makeXgBlock
     675              : !!
     676              : !! NAME
     677              : !! xgTransposer_makeXgBlock
     678              : 
     679       189878 :   subroutine xgTransposer_makeXgBlock(xgTransposer)
     680              : 
     681              :     type(xgTransposer_t), intent(inout) :: xgTransposer
     682              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD && !defined HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
     683              :     real(dp), ABI_CONTIGUOUS pointer :: xgTransposer__buffer(:,:)
     684              : #endif
     685              :     integer :: ncolsColsRows, nrowsLinalgMe
     686              : 
     687       379756 :     select case (xgTransposer%state)
     688              :     case (STATE_LINALG)
     689              : 
     690       189878 :       ncolsColsRows = xgTransposer%ncolsColsRows
     691              :       !write(std_out,*) '@makeXgBlock dims', ncolsColsRows, xgTransposer%nrowsColsRows
     692              :       !call flush_unit(std_out)
     693              : 
     694              :       ! Assume xgBlock_colsrows is empty and not constructed because user cannot
     695              :       ! predict the size
     696       189878 :       if ( associated(xgTransposer%buffer) ) then
     697            0 :         if(xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     698              : #if defined HAVE_GPU && defined HAVE_YAKL
     699              :           ABI_FREE_MANAGED(xgTransposer%buffer)
     700              : #endif
     701              :         else
     702              :           if(xgTransposer%gpu_option == ABI_GPU_OPENMP) then
     703              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     704              : #ifdef HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
     705              :             !$OMP TARGET EXIT DATA MAP(delete:xgTransposer%buffer)
     706              : #else
     707              :             xgTransposer__buffer => xgTransposer%buffer
     708              :             !$OMP TARGET EXIT DATA MAP(delete:xgTransposer__buffer)
     709              : #endif
     710              : #endif
     711              :           end if
     712            0 :           ABI_FREE(xgTransposer%buffer)
     713              :         end if
     714              :       end if
     715              : 
     716       189878 :       if ( xgTransposer%mpiData(MPI_COLS)%size == 1 ) then
     717        37926 :         xgTransposer%xgBlock_colsrows = xgTransposer%xgBlock_linalg
     718              :       else
     719       151952 :         if(xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     720              : #if defined HAVE_GPU && defined HAVE_YAKL
     721              :           ABI_MALLOC_MANAGED(xgTransposer%buffer,(/2,ncolsColsRows*xgTransposer%nrowsColsRows/))
     722              : #endif
     723              :         else
     724       455856 :           ABI_MALLOC(xgTransposer%buffer,(2,ncolsColsRows*xgTransposer%nrowsColsRows))
     725              :         end if
     726              :         if(xgTransposer%gpu_option == ABI_GPU_OPENMP) then
     727              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     728              : #ifdef HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
     729              :           !$OMP TARGET ENTER DATA MAP(alloc:xgTransposer%buffer)
     730              : #else
     731              :           xgTransposer__buffer => xgTransposer%buffer
     732              :           !$OMP TARGET ENTER DATA MAP(alloc:xgTransposer__buffer)
     733              : #endif
     734              : #endif
     735              :         end if
     736              :         call xgBlock_map(xgTransposer%xgBlock_colsrows,xgTransposer%buffer,space(xgTransposer%xgBlock_linalg),&
     737              :           xgTransposer%nrowsColsRows,ncolsColsRows,xgTransposer%mpiData(MPI_ROWS)%comm,&
     738       151952 :           me_g0=xgTransposer%me_g0_fft,gpu_option=xgTransposer%gpu_option)
     739              :       end if
     740              :     case (STATE_COLSROWS)
     741              : 
     742              :       ! Assume xgBlock_linalg is empty and not constructed
     743              : 
     744              :       !write(std_out,*) 'db using @makeXgBlock not empty'
     745              :       !call flush_unit(std_out)
     746              : 
     747            0 :       nrowsLinalgMe = xgTransposer%nrowsLinalg(xgTransposer%mpiData(MPI_LINALG)%rank+1)
     748              : 
     749            0 :       if ( associated(xgTransposer%buffer) ) then
     750            0 :         if(xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     751              : #if defined HAVE_GPU && defined HAVE_YAKL
     752              :           ABI_FREE_MANAGED(xgTransposer%buffer)
     753              : #endif
     754              :         else
     755              :           if(xgTransposer%gpu_option == ABI_GPU_OPENMP) then
     756              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     757              : #ifdef HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
     758              :             !$OMP TARGET EXIT DATA MAP(delete:xgTransposer%buffer)
     759              : #else
     760              :             xgTransposer__buffer => xgTransposer%buffer
     761              :             !$OMP TARGET EXIT DATA MAP(delete:xgTransposer__buffer)
     762              : #endif
     763              : #endif
     764              :           end if
     765            0 :           ABI_FREE(xgTransposer%buffer)
     766              :         end if
     767              :       end if
     768              : 
     769            0 :       if ( xgTransposer%mpiData(MPI_COLS)%size == 1 ) then
     770            0 :         xgTransposer%xgBlock_linalg = xgTransposer%xgBlock_colsrows
     771              :       else
     772            0 :         if(xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     773              : #if defined HAVE_GPU && defined HAVE_YAKL
     774              :           ABI_MALLOC_MANAGED(xgTransposer%buffer,(/2,xgTransposer%ncolsLinalg*nrowsLinalgMe/))
     775              : #endif
     776              :         else
     777            0 :           ABI_MALLOC(xgTransposer%buffer,(2,xgTransposer%ncolsLinalg*nrowsLinalgMe))
     778              :         end if
     779              :         if(xgTransposer%gpu_option == ABI_GPU_OPENMP) then
     780              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     781              : #ifdef HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
     782              :           !$OMP TARGET ENTER DATA MAP(alloc:xgTransposer%buffer)
     783              : #else
     784              :           xgTransposer__buffer => xgTransposer%buffer
     785              :           !$OMP TARGET ENTER DATA MAP(alloc:xgTransposer__buffer)
     786              : #endif
     787              : #endif
     788              :         end if
     789              :         call xgBlock_map(xgTransposer%xgBlock_linalg,xgTransposer%buffer,space(xgTransposer%xgBlock_colsrows),&
     790              :           nrowsLinalgMe,xgTransposer%ncolsLinalg,xgTransposer%mpiData(MPI_COLS)%comm,&
     791            0 :           me_g0=xgTransposer%me_g0_fft,gpu_option=xgTransposer%gpu_option)
     792              :       end if
     793              : 
     794              :     case default
     795       189878 :       ABI_ERROR("State unknown")
     796              :     end select
     797              : 
     798              :     !if (associated(xgTransposer%buffer)) then
     799              :     !    write(std_out,*) '@makeXgBlock alloc buffer size', size(xgTransposer%buffer,1), size(xgTransposer%buffer,2)
     800              :     !    call flush_unit(std_out)
     801              :     !end if
     802              : 
     803       189878 :   end subroutine xgTransposer_makeXgBlock
     804              : !!***
     805              : 
     806              : !!****f* m_xgTransposer/xgTransposer_transpose
     807              : !!
     808              : !! NAME
     809              : !! xgTransposer_transpose
     810              : 
     811      2803692 :   subroutine xgTransposer_transpose(xgTransposer,toState)
     812              : 
     813              :     type(xgTransposer_t), intent(inout) :: xgTransposer
     814              :     integer             , intent(in   ) :: toState
     815              :     double precision :: tsec(2)
     816              : 
     817      2803692 :     call timab(tim_transpose,1,tsec)
     818              : 
     819      2803692 :     if ( toState /= STATE_LINALG .and. toState /= STATE_COLSROWS ) then
     820            0 :       ABI_ERROR("Bad value for toState")
     821              :     end if
     822              : 
     823              :     !write(std_out,*) "linalg", rows(xgTransposer%xgBlock_linalg)*cols(xgTransposer%xgBlock_linalg)
     824              :     !write(std_out,*) "colsrows", rows(xgTransposer%xgBlock_colsrows)*cols(xgTransposer%xgBlock_colsrows)
     825      2074480 :     select case (toState)
     826              :     case (STATE_LINALG)
     827      2074480 :       if ( xgTransposer%state == STATE_LINALG ) then
     828            0 :         ABI_WARNING("Array linalg has already been transposed")
     829              :       end if
     830      2074480 :       if ( xgTransposer%mpiData(MPI_COLS)%size > 1 ) then
     831      1212586 :         call xgTransposer_toLinalg(xgTransposer)
     832              :       else
     833       861894 :         xgTransposer%state = STATE_LINALG
     834              :       end if
     835              :     case (STATE_COLSROWS)
     836       729212 :       if ( xgTransposer%state == STATE_COLSROWS ) then
     837            0 :         ABI_WARNING("Array colsrows has already been transposed")
     838              :       end if
     839      3532904 :       if ( xgTransposer%mpiData(MPI_COLS)%size > 1 ) then
     840       440290 :         call xgTransposer_toColsRows(xgTransposer)
     841              :       else
     842       288922 :         xgTransposer%state = STATE_COLSROWS
     843              :       end if
     844              :     end select
     845              : 
     846      2803692 :     call timab(tim_transpose,2,tsec)
     847              : 
     848      2803692 :   end subroutine xgTransposer_transpose
     849              : !!***
     850              : 
     851              : !!****f* m_xgTransposer/xgTransposer_toLinalg
     852              : !!
     853              : !! NAME
     854              : !! xgTransposer_toLinalg
     855              : 
     856      1212586 :   subroutine xgTransposer_toLinalg(xgTransposer)
     857              : 
     858              :    type(xgTransposer_t), intent(inout) :: xgTransposer
     859      1212586 :    double precision, allocatable, target :: sendbuf(:,:)
     860      1212586 :    double precision, pointer :: recvbuf(:,:)
     861              :    !double precision, pointer :: buffer(:,:)
     862      1212586 :    integer, allocatable :: sendcounts(:), recvcounts(:)
     863      1212586 :    integer, allocatable :: sdispls(:), rdispls(:)
     864              :    integer :: ncpu_cols, ncpu_rows, comm, me_rows, me_cols
     865              :    integer :: nrowsColsRows
     866              :    integer :: ncolsColsRows
     867              :    integer :: nrowsLinalgMe
     868              :    integer :: icpu, ierr
     869              :    integer :: send_start,send_end
     870              :    !integer :: myrequest
     871              :    !integer, allocatable :: request(:), status(:)
     872      1212586 :    type(ptr_t), allocatable :: sendptrbuf(:)
     873      1212586 :    integer, pointer :: nrowsLinalg(:)
     874      1212586 :    integer, pointer :: ncolsColsRows_sub(:)
     875              :    double precision :: tsec(2)
     876              : 
     877              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
     878              :    double precision, allocatable :: recvbuf_mpi(:,:)
     879              :    integer(c_size_t) :: buffer_size
     880              : #endif
     881              : 
     882      1212586 :    call timab(tim_toLinalg,1,tsec)
     883              : 
     884      1212586 :    ncpu_cols = xgTransposer%mpiData(MPI_COLS)%size
     885      1212586 :    ncpu_rows = xgTransposer%mpiData(MPI_ROWS)%size
     886      1212586 :    comm = xgTransposer%mpiData(MPI_COLS)%comm
     887              : !   me = xgTransposer%mpiData(MPI_ROWS)%rank*ncpu
     888      1212586 :    me_rows = xgTransposer%mpiData(MPI_ROWS)%rank
     889              : 
     890              :    !write(std_out,'(a,i4,i4,i4)') '@xgTransposer_toLinalg for MPI proc in comm=', &
     891              :    !    xgTransposer%mpiData(MPI_LINALG)%rank, xgTransposer%mpiData(MPI_LINALG)%comm, comm
     892              : 
     893      1212586 :    nrowsColsRows = xgTransposer%nrowsColsRows
     894      1212586 :    ncolsColsRows = xgTransposer%ncolsColsRows
     895              : 
     896      1212586 :    nrowsLinalg => xgTransposer%nrowsLinalg
     897      1212586 :    if (xgTransposer%custom_ncolsColsRows) ncolsColsRows_sub => xgTransposer%ncolsColsRows_sub
     898      1212586 :    nrowsLinalgMe = nrowsLinalg(xgTransposer%mpiData(MPI_LINALG)%rank+1)
     899              : 
     900              :    !write(std_out,*) '@toLinalg nrowsColsRows, ncolsColsRows=', nrowsColsRows, ncolsColsRows
     901              :    !call flush_unit(std_out)
     902              : 
     903      3637758 :    ABI_MALLOC(sendbuf,(2,nrowsColsRows*ncolsColsRows))
     904              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     905              :    !$OMP TARGET ENTER DATA MAP(alloc:sendbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
     906              : #endif
     907      1212586 :    call xgTransposer_reorganizeData(xgTransposer,sendbuf)
     908              : 
     909      3637758 :    ABI_MALLOC(recvcounts,(ncpu_cols))
     910      2425172 :    ABI_MALLOC(rdispls,(ncpu_cols))
     911      1212586 :    if (xgTransposer%custom_ncolsColsRows) then ! non uniform sendcounts
     912            0 :      recvcounts(:) = 2*nrowsLinalgMe*ncolsColsRows_sub(:)
     913              :    else
     914      4164006 :      recvcounts(:) = 2*nrowsLinalgMe*ncolsColsRows !! Thank you fortran for not starting at 0 !
     915              :    end if
     916      1212586 :    rdispls(1) = 0
     917      2951420 :    do icpu = 2, ncpu_cols
     918      2951420 :      rdispls(icpu) = rdispls(icpu-1)+recvcounts(icpu-1)
     919              :    end do
     920              : 
     921              :    call xgBlock_reverseMap(xgTransposer%xgBlock_linalg,recvbuf,&
     922      1212586 :      & rows=1,cols=cols(xgTransposer%xgBlock_linalg)*nrowsLinalgMe)
     923              : 
     924              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
     925              :    ! just for debug
     926              :    if( xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     927              :       !call gpu_managed_ptr_status(C_LOC(recvbuf))
     928              :       buffer_size = size(recvbuf) * dp
     929              :       call gpu_data_prefetch_async(C_LOC(recvbuf), buffer_size, CPU_DEVICE_ID)
     930              :       call gpu_device_synchronize()
     931              : 
     932              :       ABI_MALLOC(recvbuf_mpi, (size(recvbuf,1), size(recvbuf,2)) )
     933              : 
     934              :    end if
     935              : #endif
     936              : 
     937      2425172 :    ABI_MALLOC(sendcounts,(ncpu_cols))
     938      2425172 :    ABI_MALLOC(sdispls,(ncpu_cols))
     939              :    !sendcounts(:) = 2*nrowsLinalg(me+1:me+ncpu)*ncolsColsRows
     940      4164006 :    do icpu=0,ncpu_cols-1
     941      4164006 :      sendcounts(icpu+1) = 2*nrowsLinalg(me_rows+1+icpu*ncpu_rows)*ncolsColsRows
     942              :      !write(*,*) "nrowsLinalg ", icpu, ncpu_rows, nrowsLinalg(me_rows+1+icpu*ncpu_rows)
     943              :    end do
     944      1212586 :    sdispls(1) = 0
     945      2951420 :    do icpu = 2, ncpu_cols
     946      2951420 :      sdispls(icpu) = sdispls(icpu-1)+sendcounts(icpu-1)
     947              :    end do
     948              : 
     949      2425172 :    select case(xgTransposer%mpiAlgo)
     950              :    case (TRANS_ALL2ALL)
     951              :      !ABI_MALLOC(request,(1))
     952              :      !myrequest = 1
     953              : 
     954              :      ABI_NVTX_START_RANGE(NVTX_TRANSPOSER_MPI_ALL2ALL)
     955              : 
     956      1212586 :      if( xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
     957              : 
     958              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
     959              :        call timab(tim_all2allv,1,tsec)
     960              :        call xmpi_alltoallv(sendbuf,     sendcounts, sdispls, &
     961              :                            recvbuf_mpi, recvcounts, rdispls, &
     962              :                            comm, ierr)
     963              :        call timab(tim_all2allv,2,tsec)
     964              :        !call xmpi_ialltoallv(sendbuf, sendcounts, sdispls, &
     965              :        !                    recvbuf, recvcounts, rdispls, &
     966              :        !                    comm, request(myrequest))
     967              : 
     968              :        ! copy back recvbuf_mpi into recvbuf
     969              :        recvbuf(:,:) = recvbuf_mpi(:,:)
     970              : 
     971              :        ABI_FREE(recvbuf_mpi)
     972              : #endif
     973              : 
     974              :      else
     975              : 
     976              :        !write(*,*) "sendcounts for proc ", me_rows, xmpi_comm_rank(comm), ":", sendcounts(:)
     977              :        !write(*,*) "recvcounts for proc ", me_rows, xmpi_comm_rank(comm), ":", recvcounts(:)
     978              : 
     979      1212586 :        call timab(tim_all2allv,1,tsec)
     980              :        call xmpi_alltoallv(sendbuf, sendcounts, sdispls, &
     981              :                            recvbuf, recvcounts, rdispls, &
     982      1212586 :                            comm, ierr, use_omp_map=(xgTransposer%gpu_option==ABI_GPU_OPENMP))
     983      1212586 :        call timab(tim_all2allv,2,tsec)
     984              :        !call xmpi_ialltoallv(sendbuf, sendcounts, sdispls, &
     985              :        !                    recvbuf, recvcounts, rdispls, &
     986              :        !                    comm, request(myrequest))
     987              : 
     988              :      end if
     989              : 
     990              :      ABI_NVTX_END_RANGE()
     991              : 
     992              :    case (TRANS_GATHER)
     993              : 
     994              :      !ABI_MALLOC(request,(ncpu))
     995            0 :      me_cols = xgTransposer%mpiData(MPI_COLS)%rank
     996              :      !myrequest = me+1
     997              : 
     998              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
     999              :      !$OMP TARGET UPDATE FROM(sendbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1000              : #endif
    1001            0 :      ABI_MALLOC(sendptrbuf,(1:ncpu_cols))
    1002            0 :      do icpu = 1, ncpu_cols
    1003            0 :        send_start = sdispls(icpu)/2+1
    1004            0 :        send_end   = sdispls(icpu)/2+sendcounts(icpu)/2
    1005            0 :        sendptrbuf(icpu)%ptr => sendbuf(:,send_start:send_end)
    1006            0 :        call timab(tim_gatherv,1,tsec)
    1007            0 :        call xmpi_gatherv(sendptrbuf(icpu)%ptr,sendcounts(icpu),recvbuf,recvcounts,rdispls,icpu-1,comm,ierr)
    1008            0 :        call timab(tim_gatherv,2,tsec)
    1009              :        !call mpi_igatherv(sendptrbuf(me+1)%ptr,sendcounts(icpu),MPI_DOUBLE_PRECISION,&
    1010              :        !  recvbuf,recvcounts,rdispls,MPI_DOUBLE_PRECISION,icpu-1,comm,request(icpu),ierr)
    1011              :      end do
    1012              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1013              :      !$OMP TARGET UPDATE TO(recvbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1014              : #endif
    1015              : 
    1016              :    case default
    1017      1212586 :      ABI_BUG("This algo does not exist")
    1018              :    end select
    1019              : 
    1020      1212586 :    xgTransposer%state = STATE_LINALG
    1021              : 
    1022              :    !ABI_MALLOC(status,(MPI_STATUS_SIZE))
    1023              :    !call mpi_wait(request(myrequest),status,ierr)
    1024      1212586 :    if ( ierr /= xmpi_success ) then
    1025            0 :      ABI_ERROR("Error while waiting for mpi")
    1026              :    end if
    1027              : 
    1028      1212586 :    if ( allocated(sendcounts) ) then
    1029      1212586 :      ABI_FREE(sendcounts)
    1030              :    end if
    1031              :    if ( allocated(sdispls) ) then
    1032      1212586 :      ABI_FREE(sdispls)
    1033              :    end if
    1034              : 
    1035      1212586 :    ABI_FREE(recvcounts)
    1036      1212586 :    ABI_FREE(rdispls)
    1037              : 
    1038              : 
    1039      1212586 :    if ( allocated(sendptrbuf) ) then
    1040            0 :      ABI_FREE(sendptrbuf)
    1041              :    end if
    1042              : 
    1043              :    !do icpu = 1, size(request)
    1044              :    !  if ( icpu /= myrequest ) then
    1045              :    !    call mpi_wait(request(icpu),status,ierr)
    1046              :    !    if ( ierr /= MPI_SUCCESS ) then
    1047              :    !      ABI_ERROR("Error while waiting for other mpi")
    1048              :    !    end if
    1049              :    !  end if
    1050              :    !end do
    1051              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1052              :    !$OMP TARGET EXIT DATA MAP(delete:sendbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1053              : #endif
    1054      1212586 :    ABI_FREE(sendbuf)
    1055              :    !ABI_FREE(status)
    1056              :    !ABI_FREE(request)
    1057              : 
    1058      1212586 :     call timab(tim_toLinalg,2,tsec)
    1059              : 
    1060      2425172 :   end subroutine xgTransposer_toLinalg
    1061              : !!***
    1062              : 
    1063              : !!****f* m_xgTransposer/xgTransposer_toColsRows
    1064              : !!
    1065              : !! NAME
    1066              : !! xgTransposer_toColsRows
    1067              : 
    1068       440290 :   subroutine xgTransposer_toColsRows(xgTransposer)
    1069              : 
    1070              :    type(xgTransposer_t), intent(inout) :: xgTransposer
    1071       440290 :    double precision, pointer :: sendbuf(:,:)
    1072       440290 :    double precision, allocatable :: recvbuf(:,:)
    1073              :    !double precision, allocatable :: buffer(:,:)
    1074       440290 :    integer, allocatable :: sendcounts(:), recvcounts(:)
    1075       440290 :    integer, allocatable :: sdispls(:), rdispls(:)
    1076              :    integer :: ncpu_rows, ncpu_cols, comm, me_rows, me_cols
    1077              :    integer :: nrowsColsRows
    1078              :    integer :: nrowsLinalgMe
    1079              :    integer :: ncolsColsRows
    1080              :    integer :: icpu,ierr
    1081              :    !integer :: myrequest
    1082              :    !integer, allocatable :: request(:), status(:)
    1083              :    type(xgBlock_t) :: xgBlock_toTransposed
    1084       440290 :    type(ptr_t), allocatable :: sendptrbuf(:)
    1085       440290 :    integer, pointer :: nrowsLinalg(:)
    1086       440290 :    integer, pointer :: ncolsColsRows_sub(:)
    1087              :    double precision :: tsec(2)
    1088              : 
    1089              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1090              :    double precision, allocatable :: sendbuf_mpi(:,:)
    1091              :    integer(c_size_t) :: buffer_size
    1092              : #endif
    1093              : 
    1094       440290 :     call timab(tim_toColsRows,1,tsec)
    1095              : 
    1096       440290 :    ncpu_cols = xgTransposer%mpiData(MPI_COLS)%size
    1097       440290 :    ncpu_rows = xgTransposer%mpiData(MPI_ROWS)%size
    1098       440290 :    comm = xgTransposer%mpiData(MPI_COLS)%comm
    1099       440290 :    me_rows = xgTransposer%mpiData(MPI_ROWS)%rank
    1100              : 
    1101       440290 :    nrowsColsRows = xgTransposer%nrowsColsRows
    1102       440290 :    ncolsColsRows = xgTransposer%ncolsColsRows
    1103              : 
    1104       440290 :    nrowsLinalg => xgTransposer%nrowsLinalg
    1105       440290 :    if (xgTransposer%custom_ncolsColsRows) ncolsColsRows_sub => xgTransposer%ncolsColsRows_sub
    1106       440290 :    nrowsLinalgMe = nrowsLinalg(xgTransposer%mpiData(MPI_LINALG)%rank+1)
    1107              : 
    1108      1320870 :    ABI_MALLOC(recvbuf,(2,nrowsColsRows*ncolsColsRows))
    1109              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1110              :    !$OMP TARGET ENTER DATA MAP(alloc:recvbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1111              : #endif
    1112      1320870 :    ABI_MALLOC(recvcounts,(ncpu_cols))
    1113       880580 :    ABI_MALLOC(rdispls,(ncpu_cols))
    1114              : 
    1115              :    ! 2 * ncolsColsRows * nrowsLinalg_sub(:)
    1116      1561694 :    recvcounts(:) = 2*ncolsColsRows*nrowsLinalg(1+me_rows:1+me_rows+(ncpu_cols-1)*ncpu_rows:ncpu_rows)
    1117       440290 :    rdispls(1) = 0
    1118      1121404 :    do icpu = 2, ncpu_cols
    1119      1121404 :      rdispls(icpu) = rdispls(icpu-1)+recvcounts(icpu-1)
    1120              :    end do
    1121              :    !recvcounts(:) = 2*nrowsLinalg(me+1:me+ncpu)*ncolsColsRows
    1122              :    !rdispls(1) = 0
    1123              :    !do icpu = 2, ncpu
    1124              :    !  rdispls(icpu) = rdispls(icpu-1)+recvcounts(icpu-1)
    1125              :    !end do
    1126              : 
    1127       880580 :    select case(xgTransposer%mpiAlgo)
    1128              :    case (TRANS_ALL2ALL)
    1129       880580 :      ABI_MALLOC(sendcounts,(ncpu_cols))
    1130       880580 :      ABI_MALLOC(sdispls,(ncpu_cols))
    1131              :      !ABI_MALLOC(request,(1))
    1132              :      !myrequest = 1
    1133              : 
    1134              :      ! 2 * ncolsColsRows_sub(:) * nrowsLinalgMe
    1135       440290 :      if (xgTransposer%custom_ncolsColsRows) then ! non uniform sendcounts
    1136           80 :         sendcounts(:) = 2*nrowsLinalgMe*ncolsColsRows_sub(:)
    1137              :      else
    1138      1561614 :         sendcounts(:) = 2*nrowsLinalgMe*ncolsColsRows !! Thank you fortran for not starting at 0 !
    1139              :      end if
    1140       440290 :      sdispls(1) = 0
    1141      1121404 :      do icpu = 2, ncpu_cols
    1142      1121404 :        sdispls(icpu) = sdispls(icpu-1)+sendcounts(icpu-1)
    1143              :      end do
    1144              : 
    1145              :      call xgBlock_reverseMap(xgTransposer%xgBlock_linalg,sendbuf, &
    1146       440290 : &      rows=1,cols=cols(xgTransposer%xgBlock_linalg)*nrowsLinalgMe)
    1147              :      !write(*,*) "Before ialltoall"
    1148              : 
    1149              :      ABI_NVTX_START_RANGE(NVTX_TRANSPOSER_MPI_ALL2ALL)
    1150              : 
    1151              :     ! if gpu is enabled, data are located in GPU memory, so we copy them on a host buffer
    1152       440290 :     if( xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1153              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1154              :       ABI_MALLOC(sendbuf_mpi, (size(sendbuf,1), size(sendbuf,2)) )
    1155              : 
    1156              :       ! sync sendbuf on host and then copy to sendbuf_mpi
    1157              :       buffer_size = size(sendbuf) * dp
    1158              :       call gpu_data_prefetch_async(C_LOC(sendbuf), buffer_size, CPU_DEVICE_ID)
    1159              :       call gpu_device_synchronize()
    1160              : 
    1161              :       sendbuf_mpi(:,:) = sendbuf(:,:)
    1162              : 
    1163              :       call timab(tim_all2allv,1,tsec)
    1164              :       ! this is a cpu mpi comm
    1165              :       call xmpi_alltoallv(sendbuf_mpi, sendcounts, sdispls, &
    1166              :                           recvbuf,     recvcounts, rdispls, &
    1167              :                           comm, ierr)
    1168              :       call timab(tim_all2allv,2,tsec)
    1169              :       !call xmpi_ialltoallv(sendbuf, sendcounts, sdispls, &
    1170              :       !                    recvbuf, recvcounts, rdispls, &
    1171              :       !                    comm, request(myrequest))
    1172              :       !write(*,*) "After ialltoall"
    1173              : 
    1174              :       ABI_FREE(sendbuf_mpi)
    1175              : #endif
    1176              :     else
    1177              : 
    1178              :       !write(std_out,'(a,i4,i4,i4)') '@xgTransposer_toColsRows for MPI proc in comm=', &
    1179              :       !    xgTransposer%mpiData(MPI_LINALG)%rank, xgTransposer%mpiData(MPI_LINALG)%comm, comm
    1180              :       !if (xgTransposer%custom_ncolsColsRows) then
    1181              :       !    write(std_out,*) 'db ncolsColsRows_sub', ncolsColsRows_sub(:)
    1182              :       !end if
    1183              :       !write(std_out,*) 'db ncolsColsMe', ncolsColsRows
    1184              :       !write(std_out,*) 'db nrowsLinalg', nrowsLinalg(1+me_rows:1+me_rows+(ncpu_cols-1)*ncpu_rows:ncpu_rows)
    1185              :       !write(std_out,*) 'db nrowsLinalgMe', nrowsLinalgMe
    1186              :       !write(std_out,*) 'db sendbuf', cols(xgTransposer%xgBlock_linalg), nrowsLinalgMe
    1187              :       !write(std_out,*) 'db recvbuf', nrowsColsRows, ncolsColsRows
    1188              :       !write(std_out,*) 'db sendcounts', sendcounts(:)
    1189              :       !write(std_out,*) 'db recvcounts', recvcounts(:)
    1190              :       !write(std_out,*) 'db sdispls', sdispls(:)
    1191              :       !write(std_out,*) 'db rdispls', rdispls(:)
    1192              :       !call flush_unit(std_out)
    1193              : 
    1194       440290 :       call timab(tim_all2allv,1,tsec)
    1195              :       call xmpi_alltoallv(sendbuf, sendcounts, sdispls, &
    1196              :                           recvbuf, recvcounts, rdispls, &
    1197       440290 :                           comm, ierr, use_omp_map=(xgTransposer%gpu_option == ABI_GPU_OPENMP))
    1198       440290 :       call timab(tim_all2allv,2,tsec)
    1199              :       !call xmpi_ialltoallv(sendbuf, sendcounts, sdispls, &
    1200              :       !                    recvbuf, recvcounts, rdispls, &
    1201              :       !                    comm, request(myrequest))
    1202              :       !write(*,*) "After ialltoall"
    1203              :     end if
    1204              : 
    1205              :     ABI_NVTX_END_RANGE()
    1206              : 
    1207              :    case (TRANS_GATHER)
    1208              : 
    1209              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1210              :      !$OMP TARGET UPDATE FROM(sendbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1211              : #endif
    1212              :      !ABI_MALLOC(request,(ncpu))
    1213            0 :      me_cols = xgTransposer%mpiData(MPI_COLS)%rank
    1214              :      !myrequest = me+1
    1215              : 
    1216            0 :      ABI_MALLOC(sendptrbuf,(1:ncpu_cols))
    1217              :      !call flush(6)
    1218              :      !call xmpi_barrier(xgTransposer%mpiData(MPI_LINALG)%comm)
    1219            0 :      do icpu = 0, ncpu_cols-1
    1220              :        !write(*,*) me, "->", icpu, "from col ",icpu*ncolsColsRows+1, " number of rows:", nrowsLinalgMe
    1221            0 :        call xgBlock_setBlock(xgTransposer%xgBlock_linalg,xgBlock_toTransposed,nrowsLinalgMe,ncolsColsRows,fcol=icpu*ncolsColsRows+1)
    1222              :        call xgBlock_reverseMap(xgBlock_toTransposed,sendptrbuf(icpu+1)%ptr,&
    1223            0 :          rows=1,cols=ncolsColsRows*nrowsLinalgMe)
    1224            0 :        call timab(tim_gatherv,1,tsec)
    1225            0 :        call xmpi_gatherv(sendptrbuf(icpu+1)%ptr,2*ncolsColsRows*nrowsLinalgMe,recvbuf,recvcounts,rdispls,icpu,comm,ierr)
    1226            0 :        call timab(tim_gatherv,2,tsec)
    1227              :        !call mpi_igatherv(sendptrbuf(me+1)%ptr,2*ncolsColsRows*nrowsLinalgMe,MPI_DOUBLE_PRECISION,&
    1228              :        !  recvbuf,recvcounts,rdispls,MPI_DOUBLE_PRECISION,icpu,comm,request(icpu+1),ierr)
    1229              :      end do
    1230              :      !call xmpi_barrier(xgTransposer%mpiData(MPI_LINALG)%comm)
    1231              :      !call flush(6)
    1232              :      !write(*,*) me, request
    1233              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1234              :      !$OMP TARGET UPDATE TO(recvbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1235              : #endif
    1236              : 
    1237              :    case default
    1238       440290 :      ABI_BUG("This algo does not exist")
    1239              :    end select
    1240              : 
    1241              :    !ABI_MALLOC(status,(MPI_STATUS_SIZE))
    1242              :    !call mpi_wait(request(myrequest),status,ierr)
    1243              :    !write(*,*) "Request ended"
    1244       440290 :    if ( ierr /= xmpi_success ) then
    1245            0 :      ABI_ERROR("Error while waiting for mpi")
    1246              :    end if
    1247              :    !write(*,*) "with success"
    1248              : 
    1249       440290 :    call xgTransposer_reorganizeData(xgTransposer,recvbuf)
    1250              : 
    1251       440290 :    if ( allocated(sendcounts) ) then
    1252       440290 :      ABI_FREE(sendcounts)
    1253              :    end if
    1254       440290 :    if ( allocated(sdispls) ) then
    1255       440290 :      ABI_FREE(sdispls)
    1256              :    end if
    1257              : 
    1258       440290 :    ABI_FREE(recvcounts)
    1259       440290 :    ABI_FREE(rdispls)
    1260              : 
    1261              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1262              :    !$OMP TARGET EXIT DATA MAP(delete:recvbuf) if(xgTransposer%gpu_option == ABI_GPU_OPENMP)
    1263              : #endif
    1264       440290 :    ABI_FREE(recvbuf)
    1265              : 
    1266       440290 :    if ( allocated(sendptrbuf) ) then
    1267            0 :      ABI_FREE(sendptrbuf)
    1268              :    end if
    1269              : 
    1270       440290 :    xgTransposer%state = STATE_COLSROWS
    1271              : 
    1272              :    !do icpu = 1, size(request)
    1273              :    !  if ( icpu /= myrequest ) then
    1274              :    !    call mpi_wait(request(icpu),status,ierr)
    1275              :    !    if ( ierr /= MPI_SUCCESS ) then
    1276              :    !      ABI_ERROR("Error while waiting for other mpi")
    1277              :    !    end if
    1278              :    !  end if
    1279              :    !end do
    1280              :    !ABI_FREE(status)
    1281              :    !ABI_FREE(request)
    1282              : 
    1283       440290 :     call timab(tim_toColsRows,2,tsec)
    1284              : 
    1285       880580 :   end subroutine xgTransposer_toColsRows
    1286              : !!***
    1287              : 
    1288              : !!****f* m_xgTransposer/xgTransposer_reorganizeData
    1289              : !!
    1290              : !! NAME
    1291              : !! xgTransposer_reorganizeData
    1292              : 
    1293      1652876 :   subroutine xgTransposer_reorganizeData(xgTransposer,bufferMess)
    1294              : 
    1295              :     type(xgTransposer_t), intent(inout) :: xgTransposer
    1296              :     double precision    , intent(inout) :: bufferMess(:,:)
    1297              :     double precision, pointer :: bufferOrdered(:,:) => null()
    1298              :     integer :: nrowsColsRows,nthreads_bak
    1299              :     integer :: ncolsColsRows
    1300              :     integer :: tos,toe,froms,frome
    1301              :     integer :: col, icpu
    1302              :     integer :: me_rows,ncpu_cols,ncpu_rows
    1303              :     integer :: nPair,ispinor,nspinor
    1304              :     integer :: nrowsLinalgMe,nrowsLinalgMeSum
    1305              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1306              :     integer :: irow
    1307              :     integer, ABI_CONTIGUOUS pointer :: nrowsLinalg(:)
    1308              : #else
    1309      1652876 :     integer, pointer :: nrowsLinalg(:)
    1310              : #endif
    1311              :     double precision :: tsec(2)
    1312              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1313              :     integer(c_size_t) :: buffer_size
    1314              : #endif
    1315              : 
    1316      1652876 :     call timab(tim_reorganize,1,tsec)
    1317              : 
    1318      1652876 :     me_rows = xgTransposer%mpiData(MPI_ROWS)%rank!*xgTransposer%mpiData(MPI_COLS)%size
    1319      1652876 :     ncpu_rows = xgTransposer%mpiData(MPI_ROWS)%size
    1320      1652876 :     ncpu_cols = xgTransposer%mpiData(MPI_COLS)%size
    1321              : 
    1322              :     ! These arrays are stored as
    1323              :     ! 1 2 3
    1324              :     ! 4 5 6
    1325              :     ! 7 8 9
    1326              :     !
    1327              :     ! stored as
    1328              :     !
    1329              :     ! column-major, one-base indexing  : 1 4 7 2 5 8 3 6 9    | y + N_y*(x-1)
    1330              :     ! row-major   , zero-based indexing: 1 2 3 4 5 6 7 8 9    | x + N_x*y
    1331      1652876 :     nspinor = xgTransposer%nspinor
    1332      1652876 :     nrowsLinalg => xgTransposer%nrowsLinalg
    1333              : 
    1334      1652876 :     nrowsColsRows = xgTransposer%nrowsColsRows
    1335      1652876 :     ncolsColsRows = xgTransposer%ncolsColsRows
    1336              : 
    1337              :     ! number of pairs depends on current MPI process
    1338      1652876 :     nPair = nrowsColsRows*ncolsColsRows
    1339      1652876 :     call xgBlock_reverseMap(xgTransposer%xgBlock_colsrows,bufferOrdered,rows=1,cols=nPair)
    1340              : 
    1341              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1342              :     ! if gpu is enabled, data are located in GPU memory, so we prefetch them on host
    1343              :     ! to do the following reorganization.
    1344              :     ! Alternatively, we should provide a GPU implementation of this data layout reorganization
    1345              :     if( xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1346              :        buffer_size = size(bufferOrdered) * dp
    1347              :        call gpu_data_prefetch_async(C_LOC(bufferOrdered), buffer_size, CPU_DEVICE_ID)
    1348              :        call gpu_device_synchronize()
    1349              :     end if
    1350              : 
    1351              :     ! if gpu enabled increase locally OpenMP num threads
    1352              :     if (xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1353              :        call xomp_set_num_threads(xgTransposer%gpu_kokkos_nthrd)
    1354              :     end if
    1355              : #endif
    1356              : 
    1357      1652876 :     if (xgTransposer%gpu_option /= ABI_GPU_DISABLED .and. xgTransposer%gpu_thread_limit /= 0) then
    1358            0 :       nthreads_bak=xomp_get_max_threads()
    1359            0 :       call xomp_set_num_threads(min(xgTransposer%gpu_thread_limit,nthreads_bak))
    1360              :     end if
    1361              : 
    1362      1652876 :     select case (xgTransposer%state)
    1363              :     case (STATE_LINALG)
    1364              :       ! We are going to STATE_COLSROWS so we are after all2all
    1365              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1366              :       if (xgTransposer%gpu_option == ABI_GPU_OPENMP) then
    1367              :         ! bufferMess and bufferOrdered already live on the device: reorganize them there directly,
    1368              :         ! no CPU<->GPU round trip needed. nrowsLinalg is small and mapped just for this kernel.
    1369              :         ! Array-section assignment is not usable in device kernel bodies: loop explicitly instead.
    1370              :         !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
    1371              :         !$OMP& PRIVATE(nrowsLinalgMe,nrowsLinalgMeSum,toe,tos,frome,froms,irow) &
    1372              :         !$OMP& MAP(to:bufferMess) MAP(to:bufferOrdered) MAP(to:nrowsLinalg)
    1373              :         do col = 1, ncolsColsRows
    1374              :           do icpu = 0, ncpu_cols-1
    1375              :             do ispinor = 1, nspinor
    1376              :               nrowsLinalgMe = nrowsLinalg(1+me_rows+icpu*ncpu_rows)
    1377              :               nrowsLinalgMeSum = sum(nrowsLinalg(1+me_rows:1+me_rows+(icpu-1)*ncpu_rows:ncpu_rows))
    1378              :               froms=1+(ispinor-1)*nrowsLinalgMe/nspinor+(col-1)*nrowsLinalgMe+nrowsLinalgMeSum*ncolsColsRows
    1379              :               frome=froms-1+nrowsLinalgMe/nspinor
    1380              :               tos=1+nrowsLinalgMeSum/nspinor+(ispinor-1)*nrowsColsRows/nspinor+(col-1)*nrowsColsRows
    1381              :               toe=tos-1+nrowsLinalgMe/nspinor
    1382              :               do irow = 0, toe-tos
    1383              :                 bufferOrdered(1,tos+irow) = bufferMess(1,froms+irow)
    1384              :                 bufferOrdered(2,tos+irow) = bufferMess(2,froms+irow)
    1385              :               end do
    1386              :             end do
    1387              :           end do
    1388              :         end do
    1389              :       else
    1390              : #endif
    1391              :         !$omp parallel do private(nrowsLinalgMe,nrowsLinalgMeSum,toe,tos,frome,froms), collapse(3)
    1392      1099232 :         do col = 1, ncolsColsRows
    1393      2795640 :           do icpu = 0, ncpu_cols-1
    1394      4264606 :             do ispinor = 1, nspinor
    1395      1909256 :               nrowsLinalgMe = nrowsLinalg(1+me_rows+icpu*ncpu_rows)
    1396      3833780 :               nrowsLinalgMeSum = sum(nrowsLinalg(1+me_rows:1+me_rows+(icpu-1)*ncpu_rows:ncpu_rows))
    1397      1909256 :               froms=1+(ispinor-1)*nrowsLinalgMe/nspinor+(col-1)*nrowsLinalgMe+nrowsLinalgMeSum*ncolsColsRows
    1398      1909256 :               frome=froms-1+nrowsLinalgMe/nspinor
    1399      1909256 :               tos=1+nrowsLinalgMeSum/nspinor+(ispinor-1)*nrowsColsRows/nspinor+(col-1)*nrowsColsRows
    1400      1909256 :               toe=tos-1+nrowsLinalgMe/nspinor
    1401    519291222 :               bufferOrdered(:,tos:toe) = bufferMess(:,froms:frome)
    1402              :             end do
    1403              :           end do
    1404              :         end do
    1405              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1406              :       end if
    1407              : #endif
    1408              :     case (STATE_COLSROWS)
    1409              :       ! We are going to STATE_LINALG so we are before all2all
    1410              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1411              :       if (xgTransposer%gpu_option == ABI_GPU_OPENMP) then
    1412              :         !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) &
    1413              :         !$OMP& PRIVATE(nrowsLinalgMe,nrowsLinalgMeSum,toe,tos,frome,froms,irow) &
    1414              :         !$OMP& MAP(to:bufferMess) MAP(to:bufferOrdered) MAP(to:nrowsLinalg)
    1415              :         do col = 1, ncolsColsRows
    1416              :           do icpu = 0, ncpu_cols-1
    1417              :             do ispinor = 1, nspinor
    1418              :               nrowsLinalgMe = nrowsLinalg(1+me_rows+icpu*ncpu_rows)
    1419              :               nrowsLinalgMeSum = sum(nrowsLinalg(1+me_rows:1+me_rows+(icpu-1)*ncpu_rows:ncpu_rows))
    1420              :               froms=1+(ispinor-1)*nrowsLinalgMe/nspinor+(col-1)*nrowsLinalgMe+nrowsLinalgMeSum*ncolsColsRows
    1421              :               frome=froms-1+nrowsLinalgMe/nspinor
    1422              :               tos=1+nrowsLinalgMeSum/nspinor+(ispinor-1)*nrowsColsRows/nspinor+(col-1)*nrowsColsRows
    1423              :               toe=tos-1+nrowsLinalgMe/nspinor
    1424              :               do irow = 0, toe-tos
    1425              :                 bufferMess(1,froms+irow) = bufferOrdered(1,tos+irow)
    1426              :                 bufferMess(2,froms+irow) = bufferOrdered(2,tos+irow)
    1427              :               end do
    1428              :             end do
    1429              :           end do
    1430              :         end do
    1431              :       else
    1432              : #endif
    1433              :         !$omp parallel do private(nrowsLinalgMe,nrowsLinalgMeSum,toe,tos,frome,froms), collapse(3)
    1434      3490332 :         do col = 1, ncolsColsRows
    1435      7607026 :           do icpu = 0, ncpu_cols-1
    1436     11443888 :             do ispinor = 1, nspinor
    1437      5049448 :               nrowsLinalgMe = nrowsLinalg(1+me_rows+icpu*ncpu_rows)
    1438      9830780 :               nrowsLinalgMeSum = sum(nrowsLinalg(1+me_rows:1+me_rows+(icpu-1)*ncpu_rows:ncpu_rows))
    1439      5049448 :               froms=1+(ispinor-1)*nrowsLinalgMe/nspinor+(col-1)*nrowsLinalgMe+nrowsLinalgMeSum*ncolsColsRows
    1440      5049448 :               frome=froms-1+nrowsLinalgMe/nspinor
    1441      5049448 :               tos=1+nrowsLinalgMeSum/nspinor+(ispinor-1)*nrowsColsRows/nspinor+(col-1)*nrowsColsRows
    1442      5049448 :               toe=tos-1+nrowsLinalgMe/nspinor
    1443   1435687332 :               bufferMess(:,froms:frome) = bufferOrdered(:,tos:toe)
    1444              :             end do
    1445              :           end do
    1446              :         end do
    1447              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1448              :       end if
    1449              : #endif
    1450              :     end select
    1451              : 
    1452      1652876 :     if (xgTransposer%gpu_option /= ABI_GPU_DISABLED .and. xgTransposer%gpu_thread_limit /= 0) then
    1453            0 :       call xomp_set_num_threads(nthreads_bak)
    1454              :     end if
    1455              : 
    1456              : #if defined(HAVE_GPU_CUDA) && defined(HAVE_KOKKOS) && defined(HAVE_YAKL)
    1457              :     ! if gpu enable restore OpenMP num threads to 1
    1458              :     if (xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1459              :        ! restore OMP_NUM_THREADS=1
    1460              :        call xomp_set_num_threads(1)
    1461              :     end if
    1462              : 
    1463              :     ! if gpu is enabled, transfer back data on GPU
    1464              :     if (xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1465              :        buffer_size = size(bufferOrdered) * dp
    1466              :        call gpu_data_prefetch_async(C_LOC(bufferOrdered), buffer_size)
    1467              :        call gpu_device_synchronize()
    1468              :     end if
    1469              : #endif
    1470              : 
    1471      1652876 :     call timab(tim_reorganize,2,tsec)
    1472              : 
    1473      1652876 :   end subroutine xgTransposer_reorganizeData
    1474              : !!***
    1475              : 
    1476              : !!****f* m_xgTransposer/xgTransposer_getRank
    1477              : !!
    1478              : !! NAME
    1479              : !! xgTransposer_getRank
    1480              : 
    1481            0 :   function xgTransposer_getRank(xgTransposer, comm) result(rank)
    1482              :     type(xgTransposer_t), intent(in   ) :: xgTransposer
    1483              :     integer             , intent(in   ) :: comm
    1484              :     integer :: rank
    1485            0 :     if ( (comm > ubound(xgTransposer%mpiData,1)) .or.  (comm < lbound(xgTransposer%mpiData,1)) ) then
    1486            0 :       ABI_ERROR("Value for communicator is wrong")
    1487              :     end if
    1488            0 :     rank = xgTransposer%mpiData(comm)%rank
    1489            0 :   end function xgTransposer_getRank
    1490              : !!***
    1491              : 
    1492              : !!****f* m_xgTransposer/xgTransposer_getComm
    1493              : !!
    1494              : !! NAME
    1495              : !! xgTransposer_getComm
    1496              : 
    1497            0 :   function xgTransposer_getComm(xgTransposer, comm1) result(communicator)
    1498              :     type(xgTransposer_t), intent(in   ) :: xgTransposer
    1499              :     integer             , intent(in   ) :: comm1
    1500              :     integer :: communicator
    1501            0 :     if ( (comm1 > ubound(xgTransposer%mpiData,1)) .or.  (comm1 < lbound(xgTransposer%mpiData,1)) ) then
    1502            0 :       ABI_ERROR("Value for communicator is wrong")
    1503              :     end if
    1504            0 :     communicator = xgTransposer%mpiData(comm1)%comm
    1505            0 :   end function xgTransposer_getComm
    1506              : !!***
    1507              : 
    1508              : !!****f* m_xgTransposer/xgTransposer_free
    1509              : !!
    1510              : !! NAME
    1511              : !! xgTransposer_free
    1512              : 
    1513       189878 :   subroutine xgTransposer_free(xgTransposer)
    1514              : 
    1515              :     type(xgTransposer_t), intent(inout) :: xgTransposer
    1516              :     double precision :: tsec(2)
    1517              :     integer :: i
    1518              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD && !defined HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
    1519              :     real(dp), ABI_CONTIGUOUS pointer :: xgTransposer__buffer(:,:)
    1520              : #endif
    1521              : 
    1522       189878 :     call timab(tim_free,1,tsec)
    1523              : #ifdef HAVE_MPI
    1524       189878 :     if ( xgTransposer%type == TRANS_TYPE_CONSTRUCTED_NULL_COMM ) then
    1525           10 :       call mpi_comm_free(xgTransposer%mpiData(MPI_ROWS)%comm,i)
    1526           10 :       call mpi_comm_free(xgTransposer%mpiData(MPI_COLS)%comm,i)
    1527           10 :       call mpi_comm_free(xgTransposer%mpiData(MPI_2DCART)%comm,i)
    1528              :     end if
    1529              : #else
    1530              :     ABI_UNUSED(i)
    1531              : #endif
    1532              : 
    1533       189878 :     if ( allocated(xgTransposer%lookup) ) then
    1534       189878 :       ABI_FREE(xgTransposer%lookup)
    1535              :     end if
    1536              : 
    1537       189878 :     if ( associated(xgTransposer%nrowsLinalg) ) then
    1538       189878 :       ABI_FREE(xgTransposer%nrowsLinalg)
    1539              :     end if
    1540              : 
    1541       189878 :     if ( associated(xgTransposer%buffer) ) then
    1542       151952 :       if(xgTransposer%gpu_option == ABI_GPU_KOKKOS) then
    1543              : #if defined HAVE_GPU && defined HAVE_YAKL
    1544              :         ABI_FREE_MANAGED(xgTransposer%buffer)
    1545              : #endif
    1546              :       else
    1547              :         if(xgTransposer%gpu_option == ABI_GPU_OPENMP) then
    1548              : #if defined HAVE_GPU && defined HAVE_OPENMP_OFFLOAD
    1549              : #ifdef HAVE_OPENMP_OFFLOAD_DATASTRUCTURE
    1550              :           !$OMP TARGET EXIT DATA MAP(delete:xgTransposer%buffer)
    1551              : #else
    1552              :           xgTransposer__buffer => xgTransposer%buffer
    1553              :           !$OMP TARGET EXIT DATA MAP(delete:xgTransposer__buffer)
    1554              : #endif
    1555              : #endif
    1556              :         end if
    1557       151952 :         ABI_FREE(xgTransposer%buffer)
    1558              :       end if
    1559              :     end if
    1560              : 
    1561       189878 :     call timab(tim_free,2,tsec)
    1562              : 
    1563       189878 :   end subroutine xgTransposer_free
    1564              : !!***
    1565              : 
    1566            0 : end module m_xgTransposer
    1567              : !!***
        

Generated by: LCOV version 2.3-1