LCOV - code coverage report
Current view: top level - shared/common/src/12_hide_mpi - m_xmpi.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 37.6 % 1245 468
Test Date: 2026-09-19 15:24:51 Functions: 53.8 % 91 49

            Line data    Source code
       1              : !!****m* ABINIT/m_xmpi
       2              : !! NAME
       3              : !!  m_xmpi
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module provides MPI named constants, tools for inquiring the MPI environment
       7              : !!  and a set of generic interfaces wrapping the most commonly used MPI primitives.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2009-2026 ABINIT group (MG, MB, XG, YP, MT)
      11              : !! This file is distributed under the terms of the
      12              : !! GNU General Public License, see ~abinit/COPYING
      13              : !! or http://www.gnu.org/copyleft/gpl.txt .
      14              : !!
      15              : !! TODO
      16              : !!  Get rid of xmpi_paral. Sequential code is the **exception**. Developers should code parallel
      17              : !!  code or code that is compatible both with MPI and seq (thanks to the wrappers provided by this module)
      18              : !!
      19              : !! SOURCE
      20              : 
      21              : #if defined HAVE_CONFIG_H
      22              : #include "config.h"
      23              : #endif
      24              : 
      25              : #include "abi_common.h"
      26              : 
      27              : module m_xmpi
      28              : 
      29              :  use, intrinsic :: iso_c_binding
      30              : #ifdef HAVE_FC_ISO_FORTRAN_2008
      31              :  use ISO_FORTRAN_ENV, only : int16, int32, int64
      32              : #endif
      33              :  USE_MPI
      34              :  use defs_basis
      35              :  use m_profiling_abi
      36              : #ifdef FC_NAG
      37              :  use f90_unix_proc
      38              : #endif
      39              :  use m_clib
      40              : 
      41              :  implicit none
      42              : 
      43              :  private
      44              : !!***
      45              : 
      46              : #ifdef HAVE_MPI1
      47              :  include 'mpif.h'
      48              : #endif
      49              : 
      50              : #ifndef HAVE_FC_ISO_FORTRAN_2008
      51              :  integer,parameter :: int16=2,int32=4,int64=8
      52              : #endif
      53              : 
      54              : #ifdef HAVE_MPI
      55              :  ! MPI constants used in abinit. Make sure that a corresponding fake value is provided for the sequential version.
      56              :  integer,public,parameter :: xmpi_paral          = 1
      57              :  integer,public,parameter :: xmpi_world          = MPI_COMM_WORLD
      58              :  integer,public,parameter :: xmpi_comm_self      = MPI_COMM_SELF
      59              :  integer,public,parameter :: xmpi_undefined      = MPI_UNDEFINED
      60              :  integer,public,parameter :: xmpi_undefined_rank = MPI_UNDEFINED  ! MPI_UNDEFINED_RANK is not portable.
      61              :  integer,public,parameter :: xmpi_comm_null      = MPI_COMM_NULL
      62              :  integer,public,parameter :: xmpi_group_null     = MPI_GROUP_NULL
      63              :  integer,public,parameter :: xmpi_any_source     = MPI_ANY_SOURCE
      64              :  integer,public,parameter :: xmpi_request_null   = MPI_REQUEST_NULL
      65              :  integer,public,parameter :: xmpi_msg_len        = MPI_MAX_ERROR_STRING ! Length of fortran string used to store MPI error strings.
      66              :  integer,public,parameter :: xmpi_info_null      = MPI_INFO_NULL
      67              :  integer,public,parameter :: xmpi_success        = MPI_SUCCESS
      68              :  integer,public,parameter :: xmpi_max_processor_name = MPI_MAX_PROCESSOR_NAME
      69              :  integer,public,parameter :: XMPI_MODE_NOPRECEDE = MPI_MODE_NOPRECEDE
      70              :  integer,public,parameter :: XMPI_MODE_NOSTORE   = MPI_MODE_NOSTORE
      71              :  integer,public,parameter :: XMPI_MODE_NOPUT     = MPI_MODE_NOPUT
      72              :  integer,public,parameter :: XMPI_MODE_NOSUCCEED = MPI_MODE_NOSUCCEED
      73              : 
      74              : #else
      75              :  ! Fake replacements for the sequential version. Values are taken from
      76              :  ! http://www.mit.edu/course/13/13.715/sun-hpc-ct-8.2.1/Linux/sun/include/mpif-common.h
      77              :  ! Please use these conventions when adding new replacements in order to avoid collisions between values.
      78              :  integer,public,parameter :: xmpi_paral          = 0
      79              :  integer,public,parameter :: xmpi_world          = 0
      80              :  integer,public,parameter :: xmpi_comm_self      = 1
      81              :  integer,public,parameter :: xmpi_undefined      =-32766
      82              :  integer,public,parameter :: xmpi_undefined_rank =-32766
      83              :  integer,public,parameter :: xmpi_comm_null      = 2
      84              :  integer,public,parameter :: xmpi_group_null     = 0
      85              :  integer,public,parameter :: xmpi_any_source     = -1
      86              :  integer,public,parameter :: xmpi_request_null   = 0
      87              :  integer,public,parameter :: xmpi_msg_len        = 1000
      88              :  integer,public,parameter :: xmpi_info_null      = 0
      89              :  integer,public,parameter :: xmpi_success        = 0
      90              :  integer,public,parameter :: xmpi_max_processor_name = 128
      91              :  integer,public,parameter :: XMPI_MODE_NOPRECEDE = 1
      92              :  integer,public,parameter :: XMPI_MODE_NOSTORE   = 2
      93              :  integer,public,parameter :: XMPI_MODE_NOPUT     = 8
      94              :  integer,public,parameter :: XMPI_MODE_NOSUCCEED = 32
      95              : #endif
      96              : 
      97              : #ifdef HAVE_MPI
      98              :  integer,save,private  :: xmpi_tag_ub=32767
      99              :  ! The tag upper bound value must be at least 32767. An MPI implementation is free to make
     100              :  ! the value of MPI_TAG_UB larger than this hence xmpi_tag_ub is redefined when MPI is init in xmpi_init.
     101              : #endif
     102              : 
     103              :  ! Size in bytes of the entries used in MPI datatypes.
     104              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_ch  = 0
     105              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_int = 0
     106              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_sp  = 0
     107              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_dp  = 0
     108              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_spc = 0
     109              :  integer,save, public ABI_PROTECTED:: xmpi_bsize_dpc = 0
     110              : 
     111              :  ! kind of the offset used for MPI-IO.
     112              : #ifdef HAVE_MPI_IO
     113              :  integer,public,parameter :: xmpi_offset_kind  = MPI_OFFSET_KIND
     114              :  integer,public,parameter :: xmpi_address_kind = MPI_ADDRESS_KIND
     115              :  integer,public,parameter :: xmpi_mpiio = 1
     116              : #else
     117              :  integer,public,parameter :: xmpi_offset_kind = i8b
     118              :  integer,public,parameter :: xmpi_address_kind = i8b
     119              :  integer,public,parameter :: xmpi_mpiio = 0
     120              : #endif
     121              : 
     122              :  ! The byte size and the MPI type of the Fortran record marker.
     123              :  ! These quantities are compiler-dependent and are initalized here
     124              :  ! for selected compilers or in xmpio_get_info_frm that is called by xmpi_init (only if MPI-IO is on).
     125              : #if defined HAVE_MPI && (defined FC_INTEL || defined FC_GNU || defined FC_IBM)
     126              :  integer,save,public ABI_PROTECTED :: xmpio_bsize_frm   = 4
     127              :  integer,save,public ABI_PROTECTED :: xmpio_mpi_type_frm= MPI_INTEGER4
     128              : #else
     129              :  integer,save,public ABI_PROTECTED :: xmpio_bsize_frm    = 0
     130              :  integer,save,public ABI_PROTECTED :: xmpio_mpi_type_frm = 0
     131              : #endif
     132              : 
     133              :  integer,save, public ABI_PROTECTED :: xmpio_info = xmpi_info_null
     134              :  ! Global variable used to pass hints to the MPI-IO routines.
     135              : 
     136              :  integer(XMPI_OFFSET_KIND),public,parameter :: xmpio_chunk_bsize = 2000 * (1024.0_dp**2)
     137              :  ! Defines the chunk size (in bytes) used to (read|write) data in a single MPI-IO call.
     138              :  ! MPI-IO, indeed, crashes if we try to do the IO of a large array with a single call.
     139              :  ! We use a value <= 2  Gb to avoid wraparound errors with standard integers.
     140              : 
     141              :  ! Options used for the MPI-IO wrappers used in abinit.
     142              :  integer,public,parameter :: xmpio_single     = 1  ! Individual IO.
     143              :  integer,public,parameter :: xmpio_collective = 2  ! Collective IO.
     144              : 
     145              :  integer,save, public ABI_PROTECTED :: xmpi_count_requests = 0
     146              :  ! Count number of requests (+1 for each call to non-blocking API, -1 for each call to xmpi_wait)
     147              :  ! This counter should be zero at the end of the run if all requests have been released.
     148              : 
     149              :  integer,save, public ABI_PROTECTED :: xmpi_count_wins = 0
     150              :  ! Count number of windows created
     151              :  ! This counter should be zero at the end of the run if all windows have been released.
     152              : 
     153              :  logical,save, private :: xmpi_use_inplace_operations = .True.
     154              :  ! Enable/disable usage of MPI_IN_PLACE in e.g. xmpi_sum
     155              : 
     156              :  ! For MPI < v4, collective communication routines accept only a 32bit integer as data count.
     157              :  ! To exchange more than 2^32 data we need to create specific user-defined datatypes
     158              :  ! For this, we need some parameters:
     159              :  integer(KIND=int32),public,parameter :: xmpi_maxint32 = huge(0_int32)
     160              :  integer(KIND=int64),public,parameter :: xmpi_maxint32_64 = int(xmpi_maxint32,kind=int64)
     161              :  ! Max. integer that can be represented with 32 bits
     162              :  integer(KIND=int64),public,save :: xmpi_largetype_size = 0
     163              :  ! Number of data to be used in user-defined operations related to user-defined "largetype" type
     164              : !!***
     165              : 
     166              : !----------------------------------------------------------------------
     167              : 
     168              : !!****t* m_xmpi/xcomm_t
     169              : !! NAME
     170              : !! xcomm_t
     171              : !!
     172              : !! FUNCTION
     173              : !!  A small object storing the MPI communicator, the rank of the process and the size of the communicator.
     174              : !!  Provides helper functions to perform typical operations and parallelize loops.
     175              : !!  The datatype is initialized with xmpi_comm_self.
     176              : !!
     177              : !! SOURCE
     178              : 
     179              :  type, public :: xcomm_t
     180              :    integer :: value = xmpi_comm_self
     181              :    integer :: nproc = 1
     182              :    integer :: me = 0
     183              :    integer,private :: can_use_shmem__ = -1
     184              :     ! -1 --> unitialized, 0 if ranks do not belong to a shared memory region else 1
     185              : 
     186              :  contains
     187              :    procedure :: skip => xcomm_skip                     ! Skip iteration according to rank
     188              :    procedure :: set_to_null => xcomm_set_to_null       ! Init object using xmpi_comm_null.
     189              :    procedure :: set_to_self => xcomm_set_to_self       ! Init object using xmpi_comm_self.
     190              :    procedure :: free => xcomm_free                     ! Free the communicator.
     191              :    procedure :: from_cart_sub => xcomm_from_cart_sub   ! Build sub-communicators in a Cartesian grid.
     192              :    procedure :: split_type => xcomm_split_type         ! Creates new communicators based on split types and keys
     193              :    procedure :: prep_gatherv => xcomm_prep_gatherv     ! Prepare a typical gatherv operation.
     194              :    procedure :: print_names => xcomm_print_names
     195              :    procedure :: can_use_shmem => xcomm_can_use_shmem   ! true if communicator can use shared memory.
     196              :    procedure :: allocate_shared_master => xcomm_allocate_shared_master  ! Allocate MPI shared memory
     197              :  end type xcomm_t
     198              : 
     199              :  public :: xcomm_from_mpi_int
     200              : !!***
     201              : 
     202              : !----------------------------------------------------------------------
     203              : 
     204              : !!****t* m_xmpi/xmpi_pool2d_t
     205              : !! NAME
     206              : !! xmpi_pool2d_t
     207              : !!
     208              : !! FUNCTION
     209              : !!  Pool of MPI processors operating on a 2D problem of shape (n1, n2).
     210              : !!  Each item in the (n1, n2) matrix is assigned to a single pool.
     211              : !!  Note that differerent pools do not necessarily have the same number of procs,
     212              : !!  thus a pool is more flexibile than a Cartesian grid although inter-pool communication becomes more complex.
     213              : !!
     214              : !! SOURCE
     215              : 
     216              :  type, public :: xmpi_pool2d_t
     217              : 
     218              :    integer :: n1 = -1, n2 = -1
     219              :    ! Dimensions of the 2d problem
     220              : 
     221              :    type(xcomm_t) :: comm
     222              :    ! MPI communicator.
     223              : 
     224              :    logical,allocatable :: treats(:,:)
     225              :    ! (n1, n2)
     226              :    ! True if this pool treats (i1, i2)
     227              : 
     228              :  contains
     229              :    procedure :: from_dims => pool2d_from_dims     ! Init pool from problem dims.
     230              :    procedure :: free => pool2d_free               ! Free memory.
     231              :  end type xmpi_pool2d_t
     232              : !!***
     233              : 
     234              : ! Public procedures.
     235              :  public :: xmpi_init                  ! Initialize the MPI environment.
     236              :  public :: xmpi_set_inplace_operations! Set internal flag to use MPI_IN_PLACE whenever possible.
     237              :  public :: xmpi_end                   ! Terminate the MPI environment.
     238              :  public :: xmpi_abort                 ! Hides MPI_ABORT from MPI library.
     239              :  public :: xmpi_show_info             ! Printout of the basic variables stored in this module (useful for debugging).
     240              :  public :: xmpi_group_free            ! Hides MPI_GROUP_FREE from MPI library.
     241              :  public :: xmpi_group_incl            ! Hides MPI_GROUP_INCL from MPI library.
     242              :  public :: xmpi_group_translate_ranks ! Hides MPI_GROUP_TRANSLATE_RANKS from MPI library.
     243              :  public :: xmpi_comm_create           ! Hides MPI_COMM_CREATE from MPI library.
     244              :  public :: xmpi_comm_rank             ! Hides MPI_COMM_RANK from MPI library.
     245              :  public :: xmpi_comm_size             ! Hides MPI_COMM_SIZE from MPI library.
     246              :  public :: xmpi_comm_free             ! Hides MPI_COMM_FREE from MPI library.
     247              :  public :: xmpi_comm_dup              ! Hides MPI_COMM_DUP from MPI library.
     248              :  public :: xmpi_comm_group            ! Hides MPI_COMM_GROUP from MPI library.
     249              :  public :: xmpi_comm_translate_ranks  ! Hides MPI_GROUP_TRANSLATE_RANKS from MPI library.
     250              :  public :: xmpi_comm_translate_rank   ! Translate one rank
     251              :  public :: xmpi_comm_split            ! Hides MPI_COMM_SPLIT from MPI library.
     252              :  public :: xmpi_subcomm               ! Creates a sub-communicator from an input communicator.
     253              :  public :: xmpi_comm_multiple_of      ! Creates sub-communicator with number of procs multiple of a certain number.
     254              :  public :: xmpi_barrier               ! Hides MPI_BARRIER from MPI library.
     255              :  public :: xmpi_name                  ! Hides MPI_NAME from MPI library.
     256              :  public :: xmpi_iprobe                ! Hides MPI_IPROBE from MPI library.
     257              :  public :: xmpi_wait                  ! Hides MPI_WAIT from MPI library.
     258              :  public :: xmpi_waitall               ! Hides MPI_WAITALL from MPI library.
     259              :  public :: xmpi_request_free          ! Hides MPI_REQUEST_FREE from MPI library.
     260              :  public :: xmpi_requests_add          ! Increase/decrement xmpi_count_requests internal counter
     261              :  public :: xmpi_comm_set_errhandler   ! Hides MPI_COMM_SET_ERRHANDLER from MPI library.
     262              :  public :: xmpi_error_string          ! Return a string describing the error from ierr.
     263              :  public :: xmpi_split_work            ! Splits tasks inside communicator using blocks
     264              :  public :: xmpi_split_block           ! Splits tasks inside communicator using block distribution.
     265              :  public :: xmpi_split_cyclic          ! Splits tasks inside communicator using cyclic distribution.
     266              :  public :: xmpi_split_list            ! Splits list of indices inside communicator using block distribution.
     267              :  public :: xmpi_distab                ! Fill table defining the distribution of the tasks according to the # of processors
     268              :  public :: xmpi_distrib_with_replicas ! Distribute tasks among MPI ranks (replicas are allowed)
     269              :  public :: xmpi_distrib_2d            ! Try to optimally distribute nprocs in a 2d grid of shape (n1, n2)
     270              :  public :: xmpi_split_nsppol          ! Distribute spins. Also create and return indirect mapping to spin index.
     271              : 
     272              : ! Private procedures.
     273              :  private :: xmpi_largetype_create      ! Build a large-count contiguous datatype (to handle a very large # of data)
     274              :  private :: xmpi_largetype_free        ! Release a large-count contiguous datatype
     275              : 
     276              :  interface xmpi_comm_free
     277              :    module procedure xmpi_comm_free_0D
     278              :    module procedure xmpi_comm_free_1D
     279              :    module procedure xmpi_comm_free_2D
     280              :    module procedure xmpi_comm_free_3D
     281              :  end interface xmpi_comm_free
     282              : 
     283              :  interface xmpi_waitall
     284              :    module procedure xmpi_waitall_1d
     285              :    module procedure xmpi_waitall_2d
     286              :  end interface xmpi_waitall
     287              : 
     288              :  interface xmpi_split_work
     289              :    module procedure xmpi_split_work_i4b
     290              :  end interface xmpi_split_work
     291              : 
     292              :  public :: xmpi_split_work2_i4b
     293              :  public :: xmpi_split_work2_i8b
     294              :  !public :: xmpi_split_work2
     295              :  !
     296              :  ! g95@green v0.93 is not able to resolve the interface.
     297              :  ! For the time being, this generic interface has been disabled.
     298              :  !interface xmpi_split_work2
     299              :  !  module procedure xmpi_split_work2_i4b
     300              :  !  module procedure xmpi_split_work2_i8b
     301              :  !end interface xmpi_split_work2
     302              : 
     303              :  interface xmpi_distab
     304              :    module procedure xmpi_distab_4D
     305              :  end interface xmpi_distab
     306              : 
     307              :  ! MPI generic interfaces.
     308              :  public :: xmpi_allgather
     309              :  public :: xmpi_iallgather
     310              :  public :: xmpi_allgatherv
     311              :  public :: xmpi_alltoall
     312              :  public :: xmpi_ialltoall
     313              :  public :: xmpi_alltoallv
     314              :  public :: xmpi_ialltoallv
     315              :  public :: xmpi_bcast
     316              :  public :: xmpi_ibcast
     317              :  public :: xmpi_exch
     318              :  public :: xmpi_gather
     319              :  public :: xmpi_gatherv
     320              :  public :: xmpi_max
     321              :  public :: xmpi_max_ip
     322              :  public :: xmpi_min         ! Out-of-place version
     323              :  public :: xmpi_min_ip      ! In-place version
     324              :  public :: xmpi_recv
     325              :  public :: xmpi_irecv
     326              :  public :: xmpi_scatterv
     327              :  public :: xmpi_send
     328              :  public :: xmpi_isend
     329              :  public :: xmpi_sum_master
     330              :  public :: xmpi_sum
     331              :  public :: xmpi_isum
     332              :  public :: xmpi_isum_ip
     333              :  public :: xmpi_land              ! allreduce with MPI_LAND
     334              :  public :: xmpi_lor               ! allreduce with MPI_LOR
     335              : 
     336              :  public :: xmpi_win_fence
     337              :  public :: xmpi_win_free
     338              : 
     339              : #ifdef HAVE_MPI_IO
     340              :  public :: xmpio_max_address      !  Returns .TRUE. if offset cannot be stored in integer(kind=XMPI_ADDRESS_KIND).
     341              :  public :: xmpio_type_struct
     342              :  public :: xmpio_get_info_frm
     343              :  public :: xmpio_check_frmarkers
     344              :  public :: xmpio_read_frm
     345              :  public :: xmpio_read_int
     346              :  public :: xmpio_read_dp
     347              :  public :: xmpio_write_frm
     348              :  public :: xmpio_write_frmarkers
     349              : 
     350              :  public :: xmpio_create_fstripes
     351              :  public :: xmpio_create_fsubarray_2D
     352              :  public :: xmpio_create_fsubarray_3D
     353              :  public :: xmpio_create_fsubarray_4D
     354              :  public :: xmpio_create_fherm_packed
     355              :  public :: xmpio_create_coldistr_from_fpacked
     356              :  public :: xmpio_create_coldistr_from_fp3blocks
     357              : #endif
     358              : 
     359              : !----------------------------------------------------------------------
     360              : 
     361              : interface xmpi_allgather
     362              :   module procedure xmpi_allgather_int
     363              :   module procedure xmpi_allgather_char
     364              :   module procedure xmpi_allgather_int1d_1b
     365              :   module procedure xmpi_allgather_int1d
     366              :   module procedure xmpi_allgather_int2d
     367              :   module procedure xmpi_allgather_dp1d
     368              :   module procedure xmpi_allgather_dp2d
     369              :   module procedure xmpi_allgather_dp3d
     370              :   module procedure xmpi_allgather_dp4d
     371              : end interface xmpi_allgather
     372              : 
     373              : !----------------------------------------------------------------------
     374              : 
     375              : ! non-blocking version (requires MPI3)
     376              : ! Prototype:
     377              : !
     378              : !   call xmpi_iallgather(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, COMM, REQUEST, IERROR)
     379              : !
     380              : ! If the MPI library does not provide ialltoall, we call the blocking version and
     381              : ! we return xmpi_request_null (see xmpi_iallgather.finc)
     382              : ! Client code should always test/wait the request so that code semantics is preserved.
     383              : 
     384              : interface xmpi_iallgather
     385              :   module procedure xmpi_iallgather_dp4d
     386              : end interface xmpi_iallgather
     387              : 
     388              : interface xmpi_allgatherv
     389              :   module procedure xmpi_allgatherv_int2d
     390              :   module procedure xmpi_allgatherv_int
     391              :   module procedure xmpi_allgatherv_int1_dp1
     392              :   module procedure xmpi_allgatherv_dp
     393              :   module procedure xmpi_allgatherv_dp2d
     394              :   module procedure xmpi_allgatherv_dp3d
     395              :   module procedure xmpi_allgatherv_dp4d
     396              :   module procedure xmpi_allgatherv_dp5d
     397              :   module procedure xmpi_allgatherv_dp6d
     398              :   module procedure xmpi_allgatherv_coeff2d
     399              :   module procedure xmpi_allgatherv_coeff2d_indx
     400              :   module procedure xmpi_allgatherv_dc
     401              : end interface xmpi_allgatherv
     402              : 
     403              : !----------------------------------------------------------------------
     404              : 
     405              : ! blocking
     406              : interface xmpi_alltoall
     407              :   module procedure xmpi_alltoall_int
     408              :   module procedure xmpi_alltoall_dp2d
     409              :   module procedure xmpi_alltoall_dp4d
     410              : end interface xmpi_alltoall
     411              : 
     412              : ! non-blocking version (requires MPI3)
     413              : ! Prototype:
     414              : !
     415              : !   call xmpi_ialltoall(xval, sendsize, recvbuf, recvsize, comm, request)
     416              : !
     417              : ! If the MPI library does not provide ialltoall, we call the blocking version and
     418              : ! we return xmpi_request_null (see xmpi_ialltoall.finc)
     419              : ! Client code should always test/wait the request so that code semantics is preserved.
     420              : 
     421              : interface xmpi_ialltoall
     422              :   module procedure xmpi_ialltoall_dp4d
     423              : end interface xmpi_ialltoall
     424              : 
     425              : !----------------------------------------------------------------------
     426              : 
     427              : interface xmpi_alltoallv
     428              :   module procedure xmpi_alltoallv_dp2d
     429              :   module procedure xmpi_alltoallv_int2d
     430              :   module procedure xmpi_alltoallv_dp1d
     431              :   module procedure xmpi_alltoallv_dp1d2
     432              : end interface xmpi_alltoallv
     433              : 
     434              : !----------------------------------------------------------------------
     435              : 
     436              : ! non-blocking version (requires MPI3)
     437              : ! Prototype:
     438              : !
     439              : !   call xmpi_ialltoallv(xval, sendcnts, sdispls, recvbuf, recvcnts, rdispls, comm, request)
     440              : !
     441              : ! If the MPI library does not provide ialltoallv, we call the blocking version and
     442              : ! we return xmpi_request_null (see xmpi_ialltoallv.finc)
     443              : ! Client code should always test/wait the request so that code semantics is preserved.
     444              : 
     445              : interface xmpi_ialltoallv
     446              :   module procedure xmpi_ialltoallv_dp2d
     447              :   module procedure xmpi_ialltoallv_int2d
     448              :   module procedure xmpi_ialltoallv_dp1d2
     449              : end interface xmpi_ialltoallv
     450              : 
     451              : !----------------------------------------------------------------------
     452              : 
     453              : interface xmpi_bcast
     454              :   module procedure xmpi_bcast_intv
     455              :   module procedure xmpi_bcast_int1d
     456              :   module procedure xmpi_bcast_int2d
     457              :   module procedure xmpi_bcast_int3d
     458              :   module procedure xmpi_bcast_int4d
     459              :   module procedure xmpi_bcast_dpv
     460              :   module procedure xmpi_bcast_dp1d
     461              :   module procedure xmpi_bcast_dp2d
     462              :   module procedure xmpi_bcast_dp3d
     463              :   module procedure xmpi_bcast_dp4d
     464              :   module procedure xmpi_bcast_dp5d
     465              :   module procedure xmpi_bcast_dp6d
     466              :   module procedure xmpi_bcast_spv
     467              :   module procedure xmpi_bcast_sp1d
     468              :   module procedure xmpi_bcast_sp2d
     469              :   module procedure xmpi_bcast_sp3d
     470              :   module procedure xmpi_bcast_sp4d
     471              :   module procedure xmpi_bcast_cplxv
     472              :   module procedure xmpi_bcast_cplx1d
     473              :   module procedure xmpi_bcast_cplx2d
     474              :   module procedure xmpi_bcast_cplx3d
     475              :   module procedure xmpi_bcast_cplx4d
     476              :   module procedure xmpi_bcast_dcv
     477              :   module procedure xmpi_bcast_dc1d
     478              :   module procedure xmpi_bcast_dc2d
     479              :   module procedure xmpi_bcast_dc3d
     480              :   module procedure xmpi_bcast_dc4d
     481              :   module procedure xmpi_bcast_ch0d
     482              :   module procedure xmpi_bcast_ch1d
     483              :   module procedure xmpi_bcast_log0d
     484              :   module procedure xmpi_bcast_coeffi2_1d
     485              :   module procedure xmpi_bcast_coeff2_1d
     486              : end interface xmpi_bcast
     487              : 
     488              : !----------------------------------------------------------------------
     489              : 
     490              : interface xmpi_ibcast
     491              :   module procedure xmpi_ibcast_int1d
     492              :   module procedure xmpi_ibcast_int4d
     493              :   module procedure xmpi_ibcast_dp1d
     494              :   module procedure xmpi_ibcast_dp2d
     495              :   module procedure xmpi_ibcast_dp3d
     496              :   module procedure xmpi_ibcast_dp4d
     497              :   module procedure xmpi_ibcast_dpc2d
     498              :   module procedure xmpi_ibcast_spc2d
     499              : end interface xmpi_ibcast
     500              : 
     501              : !----------------------------------------------------------------------
     502              : 
     503              : interface xmpi_exch
     504              :   module procedure xmpi_exch_int1d
     505              :   module procedure xmpi_exch_int2d
     506              :   module procedure xmpi_exch_dp1d
     507              :   module procedure xmpi_exch_dp2d
     508              :   module procedure xmpi_exch_dp3d
     509              :   module procedure xmpi_exch_dp4d
     510              :   module procedure xmpi_exch_dp5d
     511              :   module procedure xmpi_exch_spc1d
     512              :   module procedure xmpi_exch_dpc1d
     513              :   module procedure xmpi_exch_dpc2d
     514              : end interface xmpi_exch
     515              : 
     516              : !----------------------------------------------------------------------
     517              : 
     518              : interface xmpi_gather
     519              :   module procedure xmpi_gather_int
     520              :   module procedure xmpi_gather_int2d
     521              :   module procedure xmpi_gather_dp
     522              :   module procedure xmpi_gather_dp2d
     523              :   module procedure xmpi_gather_dp3d
     524              :   module procedure xmpi_gather_dp4d
     525              : end interface xmpi_gather
     526              : 
     527              : !----------------------------------------------------------------------
     528              : 
     529              : interface xmpi_gatherv
     530              :   module procedure xmpi_gatherv_int
     531              :   module procedure xmpi_gatherv_int1_dp1
     532              :   module procedure xmpi_gatherv_int2d
     533              :   module procedure xmpi_gatherv_dp
     534              :   module procedure xmpi_gatherv_dp2d
     535              :   module procedure xmpi_gatherv_dp3d
     536              :   module procedure xmpi_gatherv_dp4d
     537              :   module procedure xmpi_gatherv_dp5d
     538              :   module procedure xmpi_gatherv_dp6d
     539              :   module procedure xmpi_gatherv_dc
     540              : end interface xmpi_gatherv
     541              : 
     542              : !----------------------------------------------------------------------
     543              : 
     544              : interface xmpi_max
     545              :   module procedure xmpi_max_int0d_i4b
     546              :   module procedure xmpi_max_int0d_i8b
     547              :   module procedure xmpi_max_int
     548              :   module procedure xmpi_max_dpv
     549              :   module procedure xmpi_max_dp0d_ip
     550              :   module procedure xmpi_max_dp1d_ip
     551              : end interface xmpi_max
     552              : 
     553              : interface xmpi_max_ip
     554              :   module procedure xmpi_max_int0d_ip
     555              :   module procedure xmpi_max_int1d_ip
     556              :   module procedure xmpi_max_dp0d_ip
     557              :   module procedure xmpi_max_dp1d_ip
     558              : end interface xmpi_max_ip
     559              : 
     560              : !----------------------------------------------------------------------
     561              : 
     562              : interface xmpi_min
     563              :   module procedure xmpi_min_intv
     564              :   module procedure xmpi_min_dpv
     565              :   module procedure xmpi_min_dp
     566              : end interface xmpi_min
     567              : 
     568              : ! In-place version of xmpi_min
     569              : interface xmpi_min_ip
     570              :   module procedure xmpi_min_int1d
     571              :   module procedure xmpi_min_dp
     572              : end interface xmpi_min_ip
     573              : 
     574              : !----------------------------------------------------------------------
     575              : 
     576              : !interface xmpi_min_max
     577              : !  module procedure xmpi_min_max_int0d_i4b
     578              : !end interface xmpi_min_max
     579              : 
     580              : !----------------------------------------------------------------------
     581              : 
     582              : interface xmpi_recv
     583              :   module procedure xmpi_recv_char
     584              :   module procedure xmpi_recv_intv
     585              :   module procedure xmpi_recv_int1d
     586              :   module procedure xmpi_recv_int2d
     587              :   module procedure xmpi_recv_int3d
     588              :   module procedure xmpi_recv_dp
     589              :   module procedure xmpi_recv_dp1d
     590              :   module procedure xmpi_recv_dp2d
     591              :   module procedure xmpi_recv_dp3d
     592              :   module procedure xmpi_recv_dp4d
     593              : end interface xmpi_recv
     594              : 
     595              : !----------------------------------------------------------------------
     596              : 
     597              : interface xmpi_irecv
     598              :   module procedure xmpi_irecv_intv
     599              :   module procedure xmpi_irecv_int1d
     600              :   module procedure xmpi_irecv_dp1d
     601              :   module procedure xmpi_irecv_dp2d
     602              :   module procedure xmpi_irecv_dp3d
     603              : end interface xmpi_irecv
     604              : 
     605              : !----------------------------------------------------------------------
     606              : 
     607              : interface xmpi_scatterv
     608              :   module procedure xmpi_scatterv_int
     609              :   module procedure xmpi_scatterv_int2d
     610              :   module procedure xmpi_scatterv_dp
     611              :   module procedure xmpi_scatterv_dp2d
     612              :   module procedure xmpi_scatterv_dp3d
     613              :   module procedure xmpi_scatterv_dp4d
     614              : end interface xmpi_scatterv
     615              : 
     616              : !----------------------------------------------------------------------
     617              : 
     618              : interface xmpi_isend
     619              :   module procedure xmpi_isend_int1d
     620              :   module procedure xmpi_isend_dp1d
     621              :   module procedure xmpi_isend_dp2d
     622              :   module procedure xmpi_isend_dp3d
     623              : end interface xmpi_isend
     624              : 
     625              : !----------------------------------------------------------------------
     626              : 
     627              : interface xmpi_send
     628              :   module procedure xmpi_send_char
     629              :   module procedure xmpi_send_intv
     630              :   module procedure xmpi_send_int1d
     631              :   module procedure xmpi_send_int2d
     632              :   module procedure xmpi_send_int3d
     633              :   module procedure xmpi_send_dp
     634              :   module procedure xmpi_send_dp1d
     635              :   module procedure xmpi_send_dp2d
     636              :   module procedure xmpi_send_dp3d
     637              :   module procedure xmpi_send_dp4d
     638              : end interface xmpi_send
     639              : 
     640              : !----------------------------------------------------------------------
     641              : 
     642              : interface xmpi_sum_master
     643              :   module procedure xmpi_sum_master_int
     644              :   module procedure xmpi_sum_master_int2d
     645              :   module procedure xmpi_sum_master_int4d
     646              :   module procedure xmpi_sum_master_dp
     647              :   module procedure xmpi_sum_master_dp1d
     648              :   module procedure xmpi_sum_master_dp2d
     649              :   module procedure xmpi_sum_master_dp3d
     650              :   module procedure xmpi_sum_master_dp4d
     651              :   module procedure xmpi_sum_master_dp5d
     652              :   module procedure xmpi_sum_master_dp6d
     653              :   module procedure xmpi_sum_master_dp7d
     654              :   module procedure xmpi_sum_master_c1cplx
     655              :   module procedure xmpi_sum_master_c2cplx
     656              :   module procedure xmpi_sum_master_c3cplx
     657              :   module procedure xmpi_sum_master_c4cplx
     658              :   module procedure xmpi_sum_master_c5cplx
     659              :   module procedure xmpi_sum_master_c1dpc
     660              :   module procedure xmpi_sum_master_c2dpc
     661              :   module procedure xmpi_sum_master_c3dpc
     662              :   module procedure xmpi_sum_master_c4dpc
     663              :   module procedure xmpi_sum_master_c5dpc
     664              : end interface xmpi_sum_master
     665              : 
     666              : !----------------------------------------------------------------------
     667              : 
     668              : !MG:TODO procedure marked with !? are considered obsolete.
     669              : !   and will be removed in future versions.
     670              : !   Please use interfaces where array dimensions are not passed explicitly.
     671              : !   Rationale: The array descriptor is already passed to the routine
     672              : !   so it does not make sense to pass the dimension explicitly.
     673              : 
     674              : interface xmpi_sum
     675              :   module procedure xmpi_sum_int
     676              :   module procedure xmpi_sum_intv
     677              :   module procedure xmpi_sum_intv2
     678              :   module procedure xmpi_sum_intn   !?
     679              :   module procedure xmpi_sum_int2t  !?
     680              :   module procedure xmpi_sum_int2d
     681              :   module procedure xmpi_sum_int3d
     682              :   module procedure xmpi_sum_int4d
     683              :   module procedure xmpi_sum_dp
     684              :   module procedure xmpi_sum_dpvt
     685              :   module procedure xmpi_sum_dpv
     686              :   module procedure xmpi_sum_dpn    !?
     687              :   module procedure xmpi_sum_sp2d
     688              :   module procedure xmpi_sum_sp3d
     689              :   module procedure xmpi_sum_sp4d
     690              :   module procedure xmpi_sum_sp5d
     691              :   module procedure xmpi_sum_sp6d
     692              :   module procedure xmpi_sum_sp7d
     693              :   module procedure xmpi_sum_dp2d
     694              :   module procedure xmpi_sum_dp3d
     695              :   module procedure xmpi_sum_dp4d
     696              :   module procedure xmpi_sum_dp5d
     697              :   module procedure xmpi_sum_dp6d
     698              :   module procedure xmpi_sum_dp7d
     699              :   module procedure xmpi_sum_dp2t   !?
     700              :   module procedure xmpi_sum_dp2d2t
     701              :   module procedure xmpi_sum_dp3d2t !?
     702              :   module procedure xmpi_sum_dp4d2t !?
     703              :   module procedure xmpi_sum_c0dc
     704              :   module procedure xmpi_sum_c0sc
     705              :   module procedure xmpi_sum_c1dc
     706              :   module procedure xmpi_sum_c2dc
     707              :   module procedure xmpi_sum_c3dc
     708              :   module procedure xmpi_sum_c4dc
     709              :   module procedure xmpi_sum_c5dc
     710              :   module procedure xmpi_sum_c6dc
     711              :   module procedure xmpi_sum_c7dc
     712              :   module procedure xmpi_sum_c1cplx
     713              :   module procedure xmpi_sum_c2cplx
     714              :   module procedure xmpi_sum_c3cplx
     715              :   module procedure xmpi_sum_c4cplx
     716              :   module procedure xmpi_sum_c5cplx
     717              :   module procedure xmpi_sum_c6cplx
     718              :   module procedure xmpi_sum_coeff5d1
     719              :  end interface xmpi_sum
     720              : !!***
     721              : 
     722              : ! Non-blocking version
     723              : interface xmpi_isum
     724              :   module procedure xmpi_isum_int0d
     725              : end interface xmpi_isum
     726              : !!***
     727              : 
     728              : ! Non-blocking in-place version
     729              : interface xmpi_isum_ip
     730              :   module procedure xmpi_isum_ip_dp2d
     731              :   module procedure xmpi_isum_ip_dp3d
     732              :   module procedure xmpi_isum_ip_dp4d
     733              :   module procedure xmpi_isum_ip_spc1d
     734              :   module procedure xmpi_isum_ip_dpc1d
     735              :   module procedure xmpi_isum_ip_spc2d
     736              :   module procedure xmpi_isum_ip_dpc2d
     737              :   module procedure xmpi_isum_ip_spc3d
     738              :   module procedure xmpi_isum_ip_dpc3d
     739              : end interface xmpi_isum_ip
     740              : !!***
     741              : 
     742              : interface xmpi_land
     743              :   module procedure xmpi_land_log0d
     744              :   module procedure xmpi_land_log1d
     745              : end interface xmpi_land
     746              : !!***
     747              : 
     748              : interface xmpi_lor
     749              :   module procedure xmpi_lor_log1d
     750              :   module procedure xmpi_lor_log2d
     751              :   module procedure xmpi_lor_log3d
     752              : end interface xmpi_lor
     753              : !!!***
     754              : 
     755              : !----------------------------------------------------------------------
     756              : 
     757              : CONTAINS  !===========================================================
     758              : !!***
     759              : 
     760              : !!****f* m_xmpi/xmpi_init
     761              : !! NAME
     762              : !!  xmpi_init
     763              : !!
     764              : !! FUNCTION
     765              : !!  Hides MPI_INIT from MPI library. Perform the initialization of some basic variables
     766              : !!  used by the MPI routines employed in abinit.
     767              : !!
     768              : !! SOURCE
     769              : 
     770         3576 : subroutine xmpi_init()
     771              : 
     772              : !Local variables-------------------
     773              :  integer :: mpierr, ierr, unt
     774              :  integer(c_long) :: rlim_cur, rlim_max
     775              :  logical :: exists
     776              : #ifdef HAVE_MPI
     777              :  integer :: attribute_val
     778              :  logical :: lflag
     779              : #ifdef HAVE_OPENMP
     780              :  integer :: required,provided
     781              : #endif
     782              : #endif
     783              : ! *************************************************************************
     784              : 
     785              :  call set_num_threads_if_undef()
     786              : 
     787         1788 :  mpierr=0
     788              : #ifdef HAVE_MPI
     789              : 
     790              : #ifndef HAVE_OPENMP
     791         1788 :  call MPI_INIT(mpierr)
     792              : #else
     793              :  required = MPI_THREAD_SINGLE
     794              :  !required = MPI_THREAD_FUNNELED
     795              :  !required = MPI_THREAD_SERIALIZED
     796              :  !required = MPI_THREAD_MULTIPLE
     797              :  call MPI_INIT_THREAD(required,provided,mpierr)
     798              :  if (provided /= required) call xmpi_abort(msg="MPI_INIT_THREADS: provided /= required")
     799              : #endif
     800              : 
     801              :  !%comm_world = xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
     802              :  !%call xmpi_comm_set_errhandler(comm_world, MPI_ERRORS_RETURN, err_handler_sav, mpierr)
     803              : 
     804              :  ! Deprecated in MPI2 but not all MPI2 implementations provide MPI_Comm_get_attr !
     805         1788 :  call MPI_ATTR_GET(xmpi_world, MPI_TAG_UB, attribute_val, lflag, mpierr)
     806              :  !call MPI_Comm_get_attr(xmpi_world, MPI_TAG_UB, attribute_val, lflag, mpierr)
     807              : 
     808         1788 :  if (lflag) xmpi_tag_ub = attribute_val
     809              : 
     810              :  ! Define type values.
     811         1788 :  call MPI_TYPE_SIZE(MPI_CHARACTER, xmpi_bsize_ch, mpierr)
     812         1788 :  call MPI_TYPE_SIZE(MPI_INTEGER, xmpi_bsize_int, mpierr)
     813         1788 :  call MPI_TYPE_SIZE(MPI_REAL, xmpi_bsize_sp, mpierr)
     814         1788 :  call MPI_TYPE_SIZE(MPI_DOUBLE_PRECISION, xmpi_bsize_dp, mpierr)
     815         1788 :  call MPI_TYPE_SIZE(MPI_COMPLEX, xmpi_bsize_spc, mpierr)
     816         1788 :  call MPI_TYPE_SIZE(MPI_DOUBLE_COMPLEX, xmpi_bsize_dpc, mpierr)
     817              : 
     818              :  ! Find the byte size of Fortran record marker used in MPI-IO routines.
     819         1788 :  if (xmpio_bsize_frm == 0) call xmpio_get_info_frm(xmpio_bsize_frm, xmpio_mpi_type_frm, xmpi_world)
     820              : #endif
     821              : 
     822              :  ! Try to increase stack size.
     823         1788 :  call clib_ulimit_stack(rlim_cur, rlim_max, ierr)
     824              : 
     825         1788 :  if (xmpi_comm_rank(xmpi_world) == 0) then
     826              : 
     827         1486 :    if (ierr /= 0) then
     828            0 :      write(std_out, "(a)")" WARNING: cannot increase stack size limit. "
     829              :      !write(std_out, *)"rlim_cur, rlim_max, ierr", rlim_cur, rlim_max, ierr
     830              :    end if
     831              : 
     832              :    ! Master Removes the ABI_MPIABORTFILE if present so that we start with a clean environment.
     833         1486 :    inquire(file=ABI_MPIABORTFILE, exist=exists)
     834         1486 :    if (exists) then
     835              :      ! Get free unit (emulate F2008 newunit for portability reasons)
     836            0 :      unt = xmpi_get_unit()
     837            0 :      if (unt == -1) call xmpi_abort(msg="Cannot find free unit!!")
     838            0 :      open(unit=unt, file=trim(ABI_MPIABORTFILE), status="old", iostat=ierr)
     839            0 :      if (ierr == 0) close(unit=unt, status="delete", iostat=ierr)
     840            0 :      if (ierr /= 0) call xmpi_abort(msg="Cannot remove ABI_MPIABORTFILE")
     841              :    end if
     842              : 
     843              :    ! If MPI interfaces are buggy, MPI_IN_PLACE is not allowed
     844              : #if defined HAVE_MPI2_INPLACE && defined HAVE_MPI_BUGGY_INTERFACES
     845              :    write(std_out, "(a)")"ERROR: Cannot use MPI_IN_PLACE with this buggy MPI version!"
     846              :    write(ab_out , "(a)")"ERROR: Cannot use MPI_IN_PLACE with this buggy MPI version!"
     847              :    call xmpi_abort(msg="Stopping here!")
     848              : #endif
     849              : 
     850              :  end if
     851              : 
     852         1788 : end subroutine xmpi_init
     853              : !!***
     854              : 
     855              : !----------------------------------------------------------------------
     856              : 
     857              : !!****f* m_xmpi/set_num_threads_if_undef
     858              : !! NAME
     859              : !!  set_num_threads_if_undef
     860              : !!
     861              : !! FUNCTION
     862              : !!  sets OMP_NUM_THREADS to 1 is the env variable is undefined.
     863              : !!
     864              : !! SOURCE
     865              : 
     866              : subroutine set_num_threads_if_undef()
     867              : 
     868              : #ifdef HAVE_OPENMP
     869              : !Local variables-------------------
     870              :  integer :: ierr
     871              :  character(len=100) :: omp_num_threads
     872              : ! *************************************************************************
     873              : 
     874              :  ! Get the value of OMP_NUM_THREADS environment variable
     875              :  call get_environment_variable('OMP_NUM_THREADS', omp_num_threads, status=ierr)
     876              : 
     877              :  ! If OMP_NUM_THREADS is not defined (ierr != 0), set it to 1
     878              :  if (ierr /= 0) then
     879              :    ierr = clib_setenv('OMP_NUM_THREADS', '1', 1)
     880              :    if (ierr == 0) then
     881              :      write(std_out,"(a)")'- OMP_NUM_THREADS was not defined. It has been set to 1.'
     882              :    else
     883              :      write(std_out,"(a)")'- WARNING: Failed to set OMP_NUM_THREADS.'
     884              :    end if
     885              :  else
     886              :    !write(std_out,*)'- OMP_NUM_THREADS is already set to: ', trim(omp_num_threads)
     887              :  end if
     888              : #endif
     889              : 
     890              : end subroutine set_num_threads_if_undef
     891              : !!***
     892              : 
     893              : !----------------------------------------------------------------------
     894              : 
     895              : !!****f* m_xmpi/xmpi_set_inplace_operations
     896              : !! NAME
     897              : !!  xmpi_set_inplace_operations
     898              : !!
     899              : !! FUNCTION
     900              : !!  Set internal flag to use MPI_IN_PLACE whenever possible.
     901              : !!
     902              : !! SOURCE
     903              : 
     904            0 : subroutine xmpi_set_inplace_operations(bool)
     905              : 
     906              : !Local variables-------------------
     907              :  logical,intent(in) :: bool
     908              : ! *************************************************************************
     909              : 
     910            0 :  xmpi_use_inplace_operations = bool
     911              : 
     912            0 : end subroutine xmpi_set_inplace_operations
     913              : !!***
     914              : 
     915              : !----------------------------------------------------------------------
     916              : 
     917              : !!****f* m_xmpi/xmpi_get_unit
     918              : !! NAME
     919              : !!  xmpi_get_unit
     920              : !!
     921              : !! FUNCTION
     922              : !! Get free unit (emulate F2008 newunit for portability reasons)
     923              : !! Return -1 if no unit is found.
     924              : !!
     925              : !! SOURCE
     926              : 
     927            0 : integer function xmpi_get_unit() result(unt)
     928              : 
     929              : !Local variables-------------------
     930              :  logical :: isopen
     931              : ! *************************************************************************
     932              : 
     933            0 :  do unt=1024,-1,-1
     934            0 :    inquire(unit=unt, opened=isopen)
     935            0 :    if (.not.isopen) exit
     936              :  end do
     937              : 
     938            0 : end function xmpi_get_unit
     939              : !!***
     940              : 
     941              : !----------------------------------------------------------------------
     942              : 
     943              : !!****f* m_xmpi/xmpi_end
     944              : !! NAME
     945              : !!  xmpi_end
     946              : !!
     947              : !! FUNCTION
     948              : !!  Hides MPI_FINALIZE from MPI library.
     949              : !!
     950              : !! SOURCE
     951              : 
     952         1772 : subroutine xmpi_end()
     953              : 
     954              : !Local variables-------------------
     955              :  integer :: mpierr
     956              : ! *************************************************************************
     957              : 
     958         1772 :  mpierr=0
     959              : #ifdef HAVE_MPI
     960         1772 :  call MPI_BARRIER(MPI_COMM_WORLD,mpierr)  !  Needed by some HPC architectures (MT, 20110315)
     961         1772 :  call MPI_FINALIZE(mpierr)
     962              : #endif
     963              : 
     964              : #ifndef FC_IBM
     965              :  ! IBM8 returns 260. 320 ...
     966              :  call sys_exit(0)
     967              : #endif
     968              : 
     969              : end subroutine xmpi_end
     970              : !!***
     971              : 
     972              : !----------------------------------------------------------------------
     973              : 
     974              : !!****f* m_xmpi/xmpi_abort
     975              : !! NAME
     976              : !!  xmpi_abort
     977              : !!
     978              : !! FUNCTION
     979              : !!  Hides MPI_ABORT from MPI library.
     980              : !!
     981              : !! INPUTS
     982              : !!  [comm]=communicator of tasks to abort.
     983              : !!  [mpierr]=Error code to return to invoking environment.
     984              : !!  [msg]=User message
     985              : !!  [exit_status]=optional, shell return code, default 1
     986              : !!
     987              : !! SOURCE
     988              : 
     989           16 : subroutine xmpi_abort(comm, mpierr, msg, exit_status)
     990              : 
     991              : !Arguments-------------------------
     992              :  integer,optional,intent(in) :: comm,mpierr,exit_status
     993              :  character(len=*),optional,intent(in) :: msg
     994              : 
     995              : !Local variables-------------------
     996              :  integer :: ierr,my_comm,my_errorcode,ilen,ierr2
     997              :  logical :: testopen
     998              :  character(len=xmpi_msg_len) :: mpi_msg_error
     999              : ! *************************************************************************
    1000              : 
    1001           16 :  ierr=0
    1002           16 :  my_comm = xmpi_world; if (PRESENT(comm)) my_comm = comm
    1003              : 
    1004           16 :  if (PRESENT(msg)) then
    1005            0 :    write(std_out,'(2a)')"User message: ",TRIM(msg)
    1006              :  end if
    1007              : 
    1008              :  ! Close std_out and ab_out and flush units.
    1009              :  ! Note that flush does not guarantee that the data is committed to disk.
    1010              :  ! This is rather annoying because we may end up with incomplete log files
    1011              :  ! that cannot be parsed by Abipy
    1012              :  ! For a possible approach based on fsync, see
    1013              :  ! https://gcc.gnu.org/onlinedocs/gcc-4.7.4/gfortran/FLUSH.html
    1014              : 
    1015           16 :  inquire(std_out, opened=testopen)
    1016           16 :  if (testopen) then
    1017              : #if defined HAVE_FC_FLUSH
    1018           16 :    call flush(std_out)
    1019              : #endif
    1020           16 :    close(std_out)
    1021              :  end if
    1022              : 
    1023           16 :  inquire(ab_out,opened=testopen)
    1024           16 :  if (testopen) then
    1025              : #if defined HAVE_FC_FLUSH
    1026           16 :    call flush(ab_out)
    1027              : #endif
    1028           16 :    close(ab_out)
    1029              :  end if
    1030              : 
    1031              :  ! exit_status=0 signals a deliberate, non-error termination (e.g. testkgrid
    1032              :  ! stopping after dumping k-grids for prtkpt/=0), not a real abort. MPI_ABORT
    1033              :  ! never returns, so it would discard exit_status: under some MPI/job-scheduler
    1034              :  ! combinations (e.g. Slurm srun) the step then gets reported as killed by
    1035              :  ! SIGKILL (retcode 137) instead of exiting 0. This code path is reached
    1036              :  ! identically by every rank, so exiting the calling process directly is safe.
    1037           16 :  if (present(exit_status)) then
    1038           14 :    if (exit_status == 0) call sys_exit(0)
    1039              :  end if
    1040              : 
    1041              : #ifdef HAVE_MPI
    1042            2 :  my_errorcode=MPI_ERR_UNKNOWN; if (PRESENT(mpierr)) my_errorcode=mpierr
    1043              : 
    1044            2 :  call MPI_ERROR_STRING(my_errorcode, mpi_msg_error, ilen, ierr2)
    1045              : 
    1046              :  !if (ilen>xmpi_msg_len) write(std_out,*)" WARNING: MPI message has been truncated!"
    1047              :  !if (ierr2/=MPI_SUCCESS) then
    1048              :  !  write(std_out,'(a,i0)')" WARNING: MPI_ERROR_STRING returned ierr2= ",ierr2
    1049              :  !else
    1050              :  !  write(std_out,'(2a)')" MPI_ERROR_STRING: ",TRIM(mpi_msg_error)
    1051              :  !end if
    1052              : 
    1053            2 :  call MPI_ABORT(my_comm, my_errorcode, ierr)
    1054              : #endif
    1055              : 
    1056            0 :  if (present(exit_status)) then
    1057              :    call sys_exit(exit_status)
    1058              :  else
    1059              :    call sys_exit(1)
    1060              :  end if
    1061              : 
    1062              : end subroutine xmpi_abort
    1063              : !!***
    1064              : 
    1065              : !----------------------------------------------------------------------
    1066              : 
    1067              : !!****f* m_xmpi/sys_exit
    1068              : !! NAME
    1069              : !! sys_exit
    1070              : !!
    1071              : !! FUNCTION
    1072              : !! Routine for clean exit of f90 code by one processor
    1073              : !!
    1074              : !! INPUTS
    1075              : !!   exit_status: return code.
    1076              : !!
    1077              : !! NOTES
    1078              : !!  By default, it uses "call exit(1)", that is not completely portable.
    1079              : !!
    1080              : !! SOURCE
    1081              : 
    1082         1786 : subroutine sys_exit(exit_status)
    1083              : 
    1084              : !Arguments ------------------------------------
    1085              : !scalars
    1086              :  integer,intent(in) :: exit_status
    1087              : ! **********************************************************************
    1088              : 
    1089              : #if defined FC_NAG
    1090              :  call exit(exit_status)
    1091              : #elif defined HAVE_FC_EXIT
    1092           14 :  call exit(exit_status)
    1093              : #else
    1094              :  ! stop with exit_status
    1095              :  ! MT 06-2013:stop function only accept parameters!
    1096              :  if (exit_status== 0) stop  "0"
    1097              :  if (exit_status== 1) stop  "1"
    1098              :  if (exit_status==-1) stop "-1"
    1099              : #endif
    1100              :  stop 1
    1101              : 
    1102              : end subroutine sys_exit
    1103              : !!***
    1104              : 
    1105              : !----------------------------------------------------------------------
    1106              : 
    1107              : !!****f* m_xmpi/xmpi_show_info
    1108              : !! NAME
    1109              : !!  xmpi_show_info
    1110              : !!
    1111              : !! FUNCTION
    1112              : !!  Printout of the most important variables stored in this module (useful for debugging).
    1113              : !!
    1114              : !! INPUTS
    1115              : !!  unt=Unit number for formatted output.
    1116              : !!
    1117              : !! SOURCE
    1118              : 
    1119         1150 : subroutine xmpi_show_info(unit)
    1120              : 
    1121              : !Arguments-------------------------
    1122              :  integer,optional,intent(in) :: unit
    1123              : 
    1124              : !Local variables-------------------
    1125              :  integer :: my_unt
    1126              : ! *************************************************************************
    1127              : 
    1128         1150 :  my_unt = std_out; if (PRESENT(unit)) my_unt=unit
    1129              : 
    1130              : #ifdef HAVE_MPI1
    1131              :   write(my_unt,*)" ==== Using MPI-1 specifications ==== "
    1132              : #endif
    1133              : #ifdef HAVE_MPI2
    1134         1150 :   write(my_unt,*)" ==== Using MPI-2 specifications ==== "
    1135              : #endif
    1136              : 
    1137              : #ifdef HAVE_MPI_IO
    1138         1150 :   write(my_unt,*)" MPI-IO support is ON"
    1139              : #else
    1140              :   write(my_unt,*)" MPI-IO support is OFF"
    1141              : #endif
    1142              : 
    1143              : #ifdef HAVE_MPI
    1144         1150 :  write(my_unt,*)" xmpi_tag_ub ................ ",xmpi_tag_ub
    1145         1150 :  write(my_unt,*)" xmpi_bsize_ch .............. ",xmpi_bsize_ch
    1146         1150 :  write(my_unt,*)" xmpi_bsize_int ............. ",xmpi_bsize_int
    1147         1150 :  write(my_unt,*)" xmpi_bsize_sp .............. ",xmpi_bsize_sp
    1148         1150 :  write(my_unt,*)" xmpi_bsize_dp .............. ",xmpi_bsize_dp
    1149         1150 :  write(my_unt,*)" xmpi_bsize_spc ............. ",xmpi_bsize_spc
    1150         1150 :  write(my_unt,*)" xmpi_bsize_dpc ............. ",xmpi_bsize_dpc
    1151         1150 :  write(my_unt,*)" xmpio_bsize_frm ............ ",xmpio_bsize_frm
    1152         1150 :  write(my_unt,*)" xmpi_address_kind .......... ",xmpi_address_kind
    1153         1150 :  write(my_unt,*)" xmpi_offset_kind ........... ",xmpi_offset_kind
    1154         1150 :  write(my_unt,*)" MPI_WTICK .................. ",MPI_WTICK()
    1155              : #endif
    1156              : 
    1157         1150 : end subroutine xmpi_show_info
    1158              : !!***
    1159              : 
    1160              : !----------------------------------------------------------------------
    1161              : 
    1162              : !!****f* m_xmpi/xmpi_comm_rank
    1163              : !! NAME
    1164              : !!  xmpi_comm_rank
    1165              : !!
    1166              : !! FUNCTION
    1167              : !!  Hides MPI_COMM_RANK from MPI library.
    1168              : !!
    1169              : !! INPUTS
    1170              : !!  comm=MPI communicator.
    1171              : !!
    1172              : !! OUTPUT
    1173              : !!  xmpi_comm_rank=The rank of the node inside comm
    1174              : !!
    1175              : !! SOURCE
    1176              : 
    1177     10381177 : integer function xmpi_comm_rank(comm)
    1178              : 
    1179              : !Arguments-------------------------
    1180              :  integer,intent(in) :: comm
    1181              : 
    1182              : !Local variables-------------------
    1183              :  integer :: mpierr
    1184              : ! *************************************************************************
    1185              : 
    1186     10381177 :  mpierr=0
    1187              : #ifdef HAVE_MPI
    1188     10381177 :  xmpi_comm_rank=-1  ! Return non-sense value if the proc does not belong to the comm
    1189     10381177 :  if (comm/=xmpi_comm_null) then
    1190     10381177 :    call MPI_COMM_RANK(comm,xmpi_comm_rank,mpierr)
    1191              :  end if
    1192              : #else
    1193              :  xmpi_comm_rank=0
    1194              : #endif
    1195              : 
    1196     10381177 : end function xmpi_comm_rank
    1197              : !!***
    1198              : 
    1199              : !----------------------------------------------------------------------
    1200              : 
    1201              : !!****f* m_xmpi/xmpi_comm_size
    1202              : !! NAME
    1203              : !!  xmpi_comm_size
    1204              : !!
    1205              : !! FUNCTION
    1206              : !!  Hides MPI_COMM_SIZE from MPI library.
    1207              : !!
    1208              : !! INPUTS
    1209              : !!  comm=MPI communicator.
    1210              : !!
    1211              : !! OUTPUT
    1212              : !!  xmpi_comm_size=The number of processors inside comm. Return 0 if comm = xmpi_comm_null
    1213              : !!
    1214              : !! SOURCE
    1215              : 
    1216    213868291 : integer function xmpi_comm_size(comm)
    1217              : 
    1218              : !Arguments-------------------------
    1219              :  integer,intent(in) :: comm
    1220              : 
    1221              : !Local variables-------------------------------
    1222              :  integer :: mpierr
    1223              : ! *************************************************************************
    1224              : 
    1225    213868291 :  mpierr=0; xmpi_comm_size=1
    1226              : #ifdef HAVE_MPI
    1227    213868291 :  xmpi_comm_size = 0
    1228    213868291 :  if (comm /= xmpi_comm_null) call MPI_COMM_SIZE(comm,xmpi_comm_size,mpierr)
    1229              : #endif
    1230              : 
    1231    213868291 : end function xmpi_comm_size
    1232              : !!***
    1233              : 
    1234              : !----------------------------------------------------------------------
    1235              : 
    1236              : !!****f* m_xmpi/xmpi_comm_free_0D
    1237              : !! NAME
    1238              : !!  xmpi_comm_free_0D
    1239              : !!
    1240              : !! FUNCTION
    1241              : !!  Hides MPI_COMM_FREE from MPI library.
    1242              : !!  Does not abort MPI in case of an invalid communicator
    1243              : !!
    1244              : !! INPUTS
    1245              : !!  comm=MPI communicator.
    1246              : !!
    1247              : !! SOURCE
    1248              : 
    1249        79673 : subroutine xmpi_comm_free_0D(comm)
    1250              : 
    1251              : !Arguments-------------------------
    1252              :  integer,intent(inout) :: comm
    1253              : 
    1254              : !Local variables-------------------------------
    1255              : #ifdef HAVE_MPI
    1256              :  integer :: comm_world,err_handler_dum,err_handler_sav,ierr,mpierr,mpierr_class
    1257              : ! *************************************************************************
    1258              : 
    1259        79673 :  if (comm/=xmpi_comm_null.and.comm/=xmpi_world.and.comm/=xmpi_comm_self) then
    1260              : 
    1261         7820 :    comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
    1262         7820 :    call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,ierr)
    1263         7820 :    call MPI_COMM_FREE(comm,mpierr)
    1264         7820 :    call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,ierr)
    1265              : 
    1266         7820 :    if (mpierr/=MPI_SUCCESS) then
    1267          396 :      call MPI_ERROR_CLASS(mpierr,mpierr_class,ierr)
    1268          396 :      if (mpierr_class/=MPI_ERR_COMM) then
    1269            0 :        write(std_out,*)" WARNING: MPI_COMM_FREE returned ierr= ",mpierr
    1270              :      end if
    1271              :    end if
    1272              : 
    1273              :  end if
    1274              : 
    1275              : #else
    1276              :  if (.false.) write(std_out,*) comm
    1277              : #endif
    1278              : 
    1279        79673 : end subroutine xmpi_comm_free_0D
    1280              : !!***
    1281              : 
    1282              : !----------------------------------------------------------------------
    1283              : 
    1284              : !!****f* m_xmpi/xmpi_comm_free_1D
    1285              : !! NAME
    1286              : !!  xmpi_comm_free_1D
    1287              : !!
    1288              : !! FUNCTION
    1289              : !!  Hides MPI_COMM_FREE from MPI library. Target 1D arrays
    1290              : !!  Does not abort MPI in case of an invalid communicator
    1291              : !!
    1292              : !! INPUTS
    1293              : !!  comms(:)=MPI communicators
    1294              : !!
    1295              : !! SOURCE
    1296              : 
    1297           24 : subroutine xmpi_comm_free_1D(comms)
    1298              : 
    1299              : !Arguments-------------------------
    1300              :  integer,intent(inout) :: comms(:)
    1301              : 
    1302              : !Local variables-------------------------------
    1303              : !scalars
    1304              : #ifdef HAVE_MPI
    1305              :  integer :: comm_world,err_handler_dum,err_handler_sav,ii,mpierr
    1306              : ! *************************************************************************
    1307              : 
    1308           24 :  comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
    1309           24 :  call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr)
    1310              : 
    1311           72 :  do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1)
    1312           48 :    if (comms(ii)/=xmpi_comm_null.and.comms(ii)/=xmpi_world.and.comms(ii)/=xmpi_comm_self) then
    1313           24 :      call MPI_COMM_FREE(comms(ii),mpierr)
    1314              :    end if
    1315              :  end do
    1316              : 
    1317           24 :  call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr)
    1318              : 
    1319              : #else
    1320              :  if (.false.) write(std_out,*) comms(1)
    1321              : #endif
    1322              : 
    1323           24 : end subroutine xmpi_comm_free_1D
    1324              : !!***
    1325              : 
    1326              : !----------------------------------------------------------------------
    1327              : 
    1328              : !!****f* m_xmpi/xmpi_comm_free_2D
    1329              : !! NAME
    1330              : !!  xmpi_comm_free_2D
    1331              : !!
    1332              : !! FUNCTION
    1333              : !!  Hides MPI_COMM_FREE from MPI library. Target 2D arrays
    1334              : !!  Does not abort MPI in case of an invalid communicator
    1335              : !!
    1336              : !! INPUTS
    1337              : !!  comms=MPI communicator.
    1338              : !!
    1339              : !! SOURCE
    1340              : 
    1341            0 : subroutine xmpi_comm_free_2D(comms)
    1342              : 
    1343              : !Arguments-------------------------
    1344              :  integer,intent(inout) :: comms(:,:)
    1345              : 
    1346              : !Local variables-------------------------------
    1347              : !scalars
    1348              : #ifdef HAVE_MPI
    1349              :  integer :: comm_world,err_handler_dum,err_handler_sav,ii,jj,mpierr
    1350              : ! *************************************************************************
    1351              : 
    1352            0 :  comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
    1353            0 :  call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr)
    1354              : 
    1355            0 :  do jj=LBOUND(comms,DIM=2),UBOUND(comms,DIM=2)
    1356            0 :    do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1)
    1357            0 :      if (comms(ii,jj)/=xmpi_comm_null.and.comms(ii,jj)/=xmpi_world.and. comms(ii,jj)/=xmpi_comm_self) then
    1358            0 :        call MPI_COMM_FREE(comms(ii,jj),mpierr)
    1359              :      end if
    1360              :    end do
    1361              :  end do
    1362              : 
    1363            0 :  call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr)
    1364              : 
    1365              : #else
    1366              :  if (.false.) write(std_out,*) comms(1,1)
    1367              : #endif
    1368              : 
    1369            0 : end subroutine xmpi_comm_free_2D
    1370              : !!***
    1371              : 
    1372              : !----------------------------------------------------------------------
    1373              : 
    1374              : !!****f* m_xmpi/xmpi_comm_free_3D
    1375              : !! NAME
    1376              : !!  xmpi_comm_free_3D
    1377              : !!
    1378              : !! FUNCTION
    1379              : !!  Hides MPI_COMM_FREE from MPI library. Target 3D arrays
    1380              : !!  Does not abort MPI in case of an invalid communicator
    1381              : !!
    1382              : !! INPUTS
    1383              : !!  comms=MPI communicator.
    1384              : !!
    1385              : !! SOURCE
    1386              : 
    1387            0 : subroutine xmpi_comm_free_3D(comms)
    1388              : 
    1389              : !Arguments-------------------------
    1390              :  integer,intent(inout) :: comms(:,:,:)
    1391              : 
    1392              : !Local variables-------------------------------
    1393              : !scalars
    1394              : #ifdef HAVE_MPI
    1395              :  integer :: comm_world,err_handler_dum,err_handler_sav,ii,jj,kk,mpierr
    1396              : ! *************************************************************************
    1397              : 
    1398            0 :  comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
    1399            0 :  call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,mpierr)
    1400              : 
    1401            0 :  do kk=LBOUND(comms,DIM=3),UBOUND(comms,DIM=3)
    1402            0 :    do jj=LBOUND(comms,DIM=2),UBOUND(comms,DIM=2)
    1403            0 :      do ii=LBOUND(comms,DIM=1),UBOUND(comms,DIM=1)
    1404            0 :        if (comms(ii,jj,kk)/=xmpi_comm_null.and.comms(ii,jj,kk)/=xmpi_world.and. comms(ii,jj,kk)/=xmpi_comm_self) then
    1405            0 :          call MPI_COMM_FREE(comms(ii,jj,kk),mpierr)
    1406              :        end if
    1407              :      end do
    1408              :    end do
    1409              :  end do
    1410              : 
    1411            0 :  call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,mpierr)
    1412              : 
    1413              : #else
    1414              :  if (.false.) write(std_out,*) comms(1,1,1)
    1415              : #endif
    1416              : 
    1417            0 : end subroutine xmpi_comm_free_3D
    1418              : !!***
    1419              : 
    1420              : !----------------------------------------------------------------------
    1421              : 
    1422              : !!****f* m_xmpi/xmpi_group_free
    1423              : !! NAME
    1424              : !!  xmpi_group_free
    1425              : !!
    1426              : !! FUNCTION
    1427              : !!  Hides MPI_GROUP_FREE from MPI library.
    1428              : !!  Does not abort MPI in case of an invalid group
    1429              : !!
    1430              : !! INPUTS
    1431              : !!  spaceGroup=MPI group
    1432              : !!
    1433              : !! SOURCE
    1434              : 
    1435         1166 : subroutine xmpi_group_free(spaceGroup)
    1436              : 
    1437              : !Arguments-------------------------
    1438              :  integer,intent(inout) :: spaceGroup
    1439              : 
    1440              : !Local variables-------------------------------
    1441              : !scalars
    1442              : #ifdef HAVE_MPI
    1443              :  integer :: comm_world,err_handler_dum,err_handler_sav,ierr,mpierr,mpierr_class
    1444              : ! *************************************************************************
    1445              : 
    1446         1166 :  if (spaceGroup/=xmpi_group_null) then
    1447              : 
    1448         1166 :    comm_world=xmpi_world ! Needed to bypass a bug in some OMPI implementations (intent(inout))
    1449         1166 :    call xmpi_comm_set_errhandler(comm_world,MPI_ERRORS_RETURN,err_handler_sav,ierr)
    1450         1166 :    call MPI_GROUP_FREE(spaceGroup,mpierr)
    1451         1166 :    call xmpi_comm_set_errhandler(comm_world,err_handler_sav,err_handler_dum,ierr)
    1452              : 
    1453         1166 :    if (mpierr/=MPI_SUCCESS) then
    1454            0 :      call MPI_ERROR_CLASS(mpierr,mpierr_class,ierr)
    1455            0 :      if (mpierr_class/=MPI_ERR_GROUP) write(std_out,*)" WARNING: MPI_GROUP_FREE returned ierr= ",mpierr
    1456              :    end if
    1457              : 
    1458              :  end if
    1459              : 
    1460              : #else
    1461              :  if (.false.) write(std_out,*) spaceGroup
    1462              : #endif
    1463              : 
    1464         1166 : end subroutine xmpi_group_free
    1465              : !!***
    1466              : 
    1467              : !----------------------------------------------------------------------
    1468              : 
    1469              : !!****f* m_xmpi/xmpi_group_incl
    1470              : !! NAME
    1471              : !!  xmpi_group_incl
    1472              : !!
    1473              : !! FUNCTION
    1474              : !!  Hides MPI_GROUP_INCL from MPI library.
    1475              : !!
    1476              : !! INPUTS
    1477              : !!  group=input group
    1478              : !!  nrank=number of elements in array ranks (size of newgroup)
    1479              : !!  ranks=ranks of processes in group to appear in newgroup
    1480              : !!
    1481              : !! OUTPUT
    1482              : !!  newgroup= new group derived from above, in the order defined by ranks
    1483              : !!
    1484              : !! SOURCE
    1485              : 
    1486            0 : subroutine xmpi_group_incl(group,nranks,ranks,newgroup,mpierr)
    1487              : 
    1488              : !Arguments-------------------------
    1489              : !scalars
    1490              :  integer,intent(in) :: group,nranks
    1491              :  integer,intent(out) :: mpierr
    1492              :  integer,intent(inout) :: newgroup
    1493              : !arrays
    1494              :  integer,intent(in) :: ranks(nranks)
    1495              : ! *************************************************************************
    1496              : 
    1497            0 :  mpierr=0 ; newgroup=xmpi_group_null
    1498              : #ifdef HAVE_MPI
    1499            0 :  if (group/=xmpi_group_null) then
    1500            0 :    call MPI_GROUP_INCL(group,nranks,ranks,newgroup,mpierr)
    1501              :  end if
    1502              : #endif
    1503              : 
    1504            0 : end subroutine xmpi_group_incl
    1505              : !!***
    1506              : 
    1507              : !----------------------------------------------------------------------
    1508              : 
    1509              : !!****f* m_xmpi/xmpi_comm_create
    1510              : !! NAME
    1511              : !!  xmpi_comm_create
    1512              : !!
    1513              : !! FUNCTION
    1514              : !!  Hides MPI_COMM_CREATE from MPI library.
    1515              : !!
    1516              : !! INPUTS
    1517              : !!  comm=communicator
    1518              : !!  group=group, which is a subset of the group of comm
    1519              : !!
    1520              : !! OUTPUT
    1521              : !!  newcomm=new communicator
    1522              : !!
    1523              : !! SOURCE
    1524              : 
    1525            0 : subroutine xmpi_comm_create(comm,group,newcomm,mpierr)
    1526              : 
    1527              : !Arguments-------------------------
    1528              : !scalars
    1529              :  integer,intent(in) :: comm,group
    1530              :  integer,intent(out) :: mpierr
    1531              :  integer,intent(inout) :: newcomm
    1532              : ! *************************************************************************
    1533              : 
    1534            0 :  mpierr=0
    1535              : #ifdef HAVE_MPI
    1536            0 :  if (group/=xmpi_group_null) then
    1537            0 :    call MPI_comm_create(comm,group,newcomm,mpierr)
    1538              :  else
    1539            0 :    newcomm=xmpi_comm_null
    1540              :  end if
    1541              : #else
    1542              :   newcomm=xmpi_comm_self
    1543              : #endif
    1544              : 
    1545            0 : end subroutine xmpi_comm_create
    1546              : !!***
    1547              : 
    1548              : !----------------------------------------------------------------------
    1549              : 
    1550              : !!****f* m_xmpi/xmpi_subcomm
    1551              : !! NAME
    1552              : !!  xmpi_subcomm
    1553              : !!
    1554              : !! FUNCTION
    1555              : !!  Return a sub-communicator from an input communicator and a given proc. ranks set.
    1556              : !!  (hides subgroup creation/destruction)
    1557              : !!
    1558              : !! INPUTS
    1559              : !!  comm=input communicator
    1560              : !!  nrank=number of elements in array ranks (size of subcomm)
    1561              : !!  ranks=ranks of processes in group to appear in subcomm
    1562              : !!
    1563              : !! OUTPUT
    1564              : !!  [my_rank_in_group]=optional: my rank in the group of new sub-communicator
    1565              : !!  xmpi_subcomm=new (sub-)communicator
    1566              : !!
    1567              : !! SOURCE
    1568              : 
    1569          148 : integer function xmpi_subcomm(comm,nranks,ranks,my_rank_in_group)
    1570              : 
    1571              : !Arguments-------------------------
    1572              : !scalars
    1573              :  integer,intent(in) :: comm,nranks
    1574              :  integer,intent(out),optional :: my_rank_in_group
    1575              : !arrays
    1576              :  integer,intent(in) :: ranks(nranks)
    1577              : 
    1578              : !Local variables-------------------------------
    1579              : #ifdef HAVE_MPI
    1580              :  integer :: group,ierr,subgroup
    1581              : #endif
    1582              : ! *************************************************************************
    1583              : 
    1584          148 :  xmpi_subcomm=xmpi_comm_null
    1585          148 :  if (present(my_rank_in_group)) my_rank_in_group=xmpi_undefined
    1586              : 
    1587              : #ifdef HAVE_MPI
    1588          148 :  if (comm/=xmpi_comm_null.and.nranks>=0) then
    1589          148 :    call MPI_COMM_GROUP(comm,group,ierr)
    1590          148 :    call MPI_GROUP_INCL(group,nranks,ranks,subgroup,ierr)
    1591          148 :    call MPI_COMM_CREATE(comm,subgroup,xmpi_subcomm,ierr)
    1592          148 :    if ( nranks == 0 )xmpi_subcomm=xmpi_comm_self
    1593          148 :    if (present(my_rank_in_group)) then
    1594           24 :      call MPI_Group_rank(subgroup,my_rank_in_group,ierr)
    1595              :    end if
    1596          148 :    call MPI_GROUP_FREE(subgroup,ierr)
    1597          148 :    call MPI_GROUP_FREE(group,ierr)
    1598              :  end if
    1599              : #else
    1600              :  if (nranks>0) then
    1601              :    if (ranks(1)==0) then
    1602              :      xmpi_subcomm=xmpi_comm_self
    1603              :      if (present(my_rank_in_group)) my_rank_in_group=0
    1604              :    end if
    1605              :  end if
    1606              : #endif
    1607              : 
    1608          148 : end function xmpi_subcomm
    1609              : !!***
    1610              : 
    1611              : !----------------------------------------------------------------------
    1612              : 
    1613              : !!****f* m_xmpi/xmpi_comm_multiple
    1614              : !! NAME
    1615              : !!  xmpi_comm_multiple
    1616              : !!
    1617              : !! FUNCTION
    1618              : !!  Given an input communicator `input_comm`, create a new communicator
    1619              : !!  with number of procs multiple of a certain number `ntasks`.
    1620              : !!  Use all procs if ntasks >= input_nprocs.
    1621              : !!
    1622              : !! INPUTS
    1623              : !!  ntasks=Number of tasks.
    1624              : !!  comm=input communicator
    1625              : !!
    1626              : !! OUTPUT
    1627              : !!  idle_proc=True if this proc is idle. In this case, output_comm contains all the idle procs.
    1628              : !!  output_comm=Output communicator
    1629              : !!
    1630              : !! SOURCE
    1631              : 
    1632            0 : subroutine xmpi_comm_multiple_of(ntasks, input_comm, idle_proc, output_comm)
    1633              : 
    1634              : !Arguments-------------------------
    1635              : !scalars
    1636              :  integer,intent(in) :: ntasks, input_comm
    1637              :  integer,intent(out) :: output_comm
    1638              :  logical,intent(out) :: idle_proc
    1639              : 
    1640              : !Local variables-------------------------------
    1641              :  integer :: color, my_rank, ierr, input_nproc
    1642              : ! *************************************************************************
    1643              : 
    1644            0 :  my_rank = xmpi_comm_rank(input_comm)
    1645            0 :  input_nproc = xmpi_comm_size(input_comm)
    1646              : 
    1647            0 :  if (input_nproc <= ntasks) then
    1648              :    ! Use all procs in input comm.
    1649            0 :    idle_proc = .False.; output_comm = input_comm
    1650              : #ifdef HAVE_MPI
    1651            0 :    call MPI_Comm_dup(input_comm, output_comm, ierr)
    1652              : #endif
    1653              :  else
    1654            0 :    color = merge(0, 1, my_rank + 1 <= (ntasks / input_nproc) * input_nproc)
    1655            0 :    idle_proc = color == 1
    1656            0 :    call xmpi_comm_split(input_comm, color, my_rank, output_comm, ierr)
    1657              :  end if
    1658              : 
    1659            0 : end subroutine xmpi_comm_multiple_of
    1660              : !!***
    1661              : 
    1662              : !----------------------------------------------------------------------
    1663              : 
    1664              : !!****f* m_xmpi/xmpi_comm_dup
    1665              : !! NAME
    1666              : !!  xmpi_comm_dup
    1667              : !!
    1668              : !! FUNCTION
    1669              : !!  Hides MPI_COMM_DUP from MPI library.
    1670              : !!
    1671              : !! INPUTS
    1672              : !!  in_comm=input MPI communicator.
    1673              : !!
    1674              : !! OUTPUT
    1675              : !!  out_comm=Output MPI communicator.
    1676              : !!  mpierr=error code returned
    1677              : !!
    1678              : !! SOURCE
    1679              : 
    1680            0 : subroutine xmpi_comm_dup(in_comm, out_comm, mpierr)
    1681              : 
    1682              : !Arguments-------------------------
    1683              :  integer,intent(in) :: in_comm
    1684              :  integer,intent(out) :: out_comm, mpierr
    1685              : 
    1686              : !----------------------------------------------------------------------
    1687              : 
    1688              : #ifdef HAVE_MPI
    1689            0 :   call MPI_Comm_dup(in_comm, out_comm, mpierr)
    1690              : #else
    1691              :   out_comm = in_comm
    1692              : #endif
    1693              : 
    1694            0 : end subroutine xmpi_comm_dup
    1695              : !!***
    1696              : 
    1697              : !----------------------------------------------------------------------
    1698              : 
    1699              : !!****f* m_xmpi/xmpi_comm_group
    1700              : !! NAME
    1701              : !!  xmpi_comm_group
    1702              : !!
    1703              : !! FUNCTION
    1704              : !!  Hides MPI_COMM_GROUP from MPI library.
    1705              : !!
    1706              : !! INPUTS
    1707              : !!  comm=MPI communicator.
    1708              : !!
    1709              : !! OUTPUT
    1710              : !!  spaceGroup=The group associated to comm.
    1711              : !!  mpierr=error code returned
    1712              : !!
    1713              : !! SOURCE
    1714              : 
    1715         1166 : subroutine xmpi_comm_group(comm,spaceGroup,mpierr)
    1716              : 
    1717              : !Arguments-------------------------
    1718              :  integer,intent(in) :: comm
    1719              :  integer,intent(out) :: mpierr,spaceGroup
    1720              : ! *************************************************************************
    1721              : 
    1722         1166 :  mpierr=0; spaceGroup=xmpi_group_null
    1723              : #ifdef HAVE_MPI
    1724         1166 :  if (comm/=xmpi_comm_null) then
    1725         1166 :    call MPI_COMM_GROUP(comm,spaceGroup,mpierr)
    1726              :  end if
    1727              : #endif
    1728              : 
    1729         1166 : end subroutine xmpi_comm_group
    1730              : !!***
    1731              : 
    1732              : !----------------------------------------------------------------------
    1733              : 
    1734              : !!****f* m_xmpi/xmpi_comm_split
    1735              : !! NAME
    1736              : !!  xmpi_comm_split
    1737              : !!
    1738              : !! FUNCTION
    1739              : !!  Hides MPI_COMM_SPLIT from MPI library.
    1740              : !!
    1741              : !! INPUTS
    1742              : !!  input_comm=Input MPI communicator (to be splitted)
    1743              : !!  color=Control of subset assignment (nonnegative integer).
    1744              : !!        Processes with the same color are in the same new communicator
    1745              : !!  key=Control of rank assigment (integer)
    1746              : !!
    1747              : !! OUTPUT
    1748              : !!  mpierr=error code returned
    1749              : !!  output_comm=new splitted communicator
    1750              : !!
    1751              : !! SOURCE
    1752              : 
    1753          713 : subroutine xmpi_comm_split(input_comm, color, key, output_comm, mpierr)
    1754              : 
    1755              : !Arguments-------------------------
    1756              :  integer,intent(in) :: color,input_comm,key
    1757              :  integer,intent(out) :: mpierr,output_comm
    1758              : ! *************************************************************************
    1759              : 
    1760          713 :  mpierr=0; output_comm=input_comm
    1761              : #ifdef HAVE_MPI
    1762          713 :  if (input_comm/=xmpi_comm_null.and.input_comm/=xmpi_comm_self) then
    1763          702 :    call MPI_COMM_SPLIT(input_comm,color,key,output_comm,mpierr)
    1764              :  end if
    1765              : #endif
    1766              : 
    1767          713 : end subroutine xmpi_comm_split
    1768              : !!***
    1769              : 
    1770              : !----------------------------------------------------------------------
    1771              : 
    1772              : !!****f* m_xmpi/xmpi_group_translate_ranks
    1773              : !! NAME
    1774              : !!  xmpi_group_translate_ranks
    1775              : !!
    1776              : !! FUNCTION
    1777              : !!  Hides MPI_GROUP_TRANSLATE_RANKS from MPI library.
    1778              : !!
    1779              : !! INPUTS
    1780              : !!  nrank=number of ranks in ranks1 and ranks2 arrays
    1781              : !!  ranks1(nrank)=array of zero or more valid ranks in group1
    1782              : !!  spaceGroup1=group1
    1783              : !!  spaceGroup2=group2
    1784              : !!
    1785              : !! OUTPUT
    1786              : !!  mpierr=error code returned
    1787              : !!  ranks2(nrank)=array of corresponding ranks in group2,
    1788              : !!                xmpi_undefined when no correspondence exists
    1789              : !!
    1790              : !! SOURCE
    1791              : 
    1792          583 : subroutine xmpi_group_translate_ranks(spaceGroup1,nrank,ranks1,&
    1793          583 : &                                     spaceGroup2,ranks2,mpierr)
    1794              : 
    1795              : !Arguments-------------------------
    1796              : !scalars
    1797              :  integer,intent(in) :: nrank,spaceGroup1,spaceGroup2
    1798              :  integer,intent(out) :: mpierr
    1799              : !arrays
    1800              :  integer,intent(in) :: ranks1(nrank)
    1801              :  integer,intent(out) :: ranks2(nrank)
    1802              : ! *************************************************************************
    1803              : 
    1804         1173 :  mpierr=0; ranks2(:)=xmpi_undefined
    1805              : #ifdef HAVE_MPI
    1806          583 :  if (spaceGroup1/=xmpi_group_null.and.spaceGroup2/=xmpi_group_null) then
    1807          583 :    call MPI_GROUP_TRANSLATE_RANKS(spaceGroup1,nrank,ranks1, spaceGroup2,ranks2,mpierr)
    1808              :  end if
    1809              : #else
    1810              :  ranks2(1)=0
    1811              : #endif
    1812              : 
    1813          583 : end subroutine xmpi_group_translate_ranks
    1814              : !!***
    1815              : 
    1816              : !----------------------------------------------------------------------
    1817              : 
    1818              : !!****f* m_xmpi/xmpi_comm_translate_ranks
    1819              : !! NAME
    1820              : !!  xmpi_comm_translate_ranks
    1821              : !!
    1822              : !! FUNCTION
    1823              : !!  Helper function that translate the ranks from a communicator to another one.
    1824              : !!  Wraps xmpi_group_translate_ranks but provides a more user-friendly interface
    1825              : !!
    1826              : !! INPUTS
    1827              : !!  from_comm=MPI communicator where from_ranks are defined.
    1828              : !!  nrank=number of ranks in from_ranks and to_ranks arrays
    1829              : !!  from_ranks(nrank)=array of zero or more valid ranks in from_comm
    1830              : !!
    1831              : !! OUTPUT
    1832              : !!  to_ranks(nrank)=array of corresponding ranks in to_comm
    1833              : !!                xmpi_undefined when no correspondence exists
    1834              : !!
    1835              : !! SOURCE
    1836              : 
    1837           75 : subroutine xmpi_comm_translate_ranks(from_comm, nrank, from_ranks, to_comm, to_ranks)
    1838              : 
    1839              : !Arguments-------------------------
    1840              : !scalars
    1841              :  integer,intent(in) :: nrank,from_comm,to_comm
    1842              : !arrays
    1843              :  integer,intent(in) :: from_ranks(nrank)
    1844              :  integer,intent(out) :: to_ranks(nrank)
    1845              : 
    1846              : !Local variables-------------------------------
    1847              : !scalars
    1848              :  integer :: ierr,from_group,to_group
    1849              : ! *************************************************************************
    1850              : 
    1851              :  ! Get the groups
    1852           25 :  call xmpi_comm_group(from_comm,from_group,ierr)
    1853           25 :  call xmpi_comm_group(to_comm,to_group,ierr)
    1854              : 
    1855           25 :  call xmpi_group_translate_ranks(from_group,nrank,from_ranks,to_group,to_ranks,ierr)
    1856              : 
    1857              :  ! Release the groups
    1858           25 :  call xmpi_group_free(from_group)
    1859           25 :  call xmpi_group_free(to_group)
    1860              : 
    1861           25 : end subroutine xmpi_comm_translate_ranks
    1862              : !!***
    1863              : 
    1864              : !----------------------------------------------------------------------
    1865              : 
    1866              : !!****f* m_xmpi/xmpi_comm_translate_rank
    1867              : !! NAME
    1868              : !!  xmpi_comm_translate_rank
    1869              : !!
    1870              : !! FUNCTION
    1871              : !!  Helper function to translate a single rank `from_rank` in communicator `from_rank` to
    1872              : !!  the rank in communicator `to_comm`.
    1873              : 
    1874            0 : integer function xmpi_comm_translate_rank(from_comm, from_rank, to_comm) result(to_rank)
    1875              : 
    1876              : !Arguments ------------------------------------
    1877              :  integer,intent(in) :: from_comm, from_rank, to_comm
    1878              : 
    1879              : !Local variables-------------------------------
    1880              :  integer :: from_ranks(1), to_ranks(1)
    1881              : ! *************************************************************************
    1882              : 
    1883            0 :  from_ranks(1) = from_rank
    1884            0 :  call xmpi_comm_translate_ranks(from_comm, 1, from_ranks, to_comm, to_ranks)
    1885            0 :  to_rank = to_ranks(1)
    1886              : 
    1887            0 : end function xmpi_comm_translate_rank
    1888              : !!***
    1889              : 
    1890              : !----------------------------------------------------------------------
    1891              : 
    1892              : !!****f* m_xmpi/xmpi_barrier
    1893              : !! NAME
    1894              : !!  xmpi_barrier
    1895              : !!
    1896              : !! FUNCTION
    1897              : !!  Hides MPI_BARRIER from MPI library.
    1898              : !!
    1899              : !! INPUTS
    1900              : !!  comm=MPI communicator
    1901              : !!
    1902              : !! SOURCE
    1903              : 
    1904       104271 : subroutine xmpi_barrier(comm)
    1905              : 
    1906              : !Arguments-------------------------
    1907              :  integer,intent(in) :: comm
    1908              : 
    1909              : !Local variables-------------------
    1910              :  integer :: ier
    1911              : #ifdef HAVE_MPI
    1912              :  integer :: nprocs
    1913              : #endif
    1914              : ! *************************************************************************
    1915              : 
    1916       104271 :  ier = 0
    1917              : #ifdef HAVE_MPI
    1918       104271 :  if (comm/=xmpi_comm_null) then
    1919       104271 :    call MPI_COMM_SIZE(comm,nprocs,ier)
    1920       104271 :    if(nprocs>1) call MPI_BARRIER(comm,ier)
    1921              :  end if
    1922              : #endif
    1923              : 
    1924       104271 : end subroutine xmpi_barrier
    1925              : !!***
    1926              : 
    1927              : !----------------------------------------------------------------------
    1928              : 
    1929              : !!****f* m_xmpi/xmpi_name
    1930              : !! NAME
    1931              : !!  xmpi_name
    1932              : !!
    1933              : !! FUNCTION
    1934              : !!  Returns the name of the processor
    1935              : !!  Hides MPI_GET_PROCESSOR_NAME from MPI library.
    1936              : !!
    1937              : !! For the MPI standard:
    1938              : !!    The name returned should identify a particular piece of hardware; the exact format is implementation defined.
    1939              : !!    This name may or may not be the same as might be returned by gethostname, uname, or sysinfo.
    1940              : !!
    1941              : !! SOURCE
    1942              : 
    1943            0 : subroutine xmpi_name(name_ch, ierr)
    1944              : 
    1945              : !Arguments-------------------------
    1946              :  character(xmpi_max_processor_name),intent(out) :: name_ch
    1947              :  integer,intent(out) ::  ierr
    1948              : 
    1949              : !Local variables-------------------
    1950              :  integer :: len
    1951              : ! *************************************************************************
    1952              : 
    1953              :  ! Get the name of this processor (usually the hostname)
    1954            0 :  ierr = 0
    1955              : #ifdef HAVE_MPI
    1956            0 :  call MPI_GET_PROCESSOR_NAME(name_ch, len, ierr)
    1957            0 :  name_ch = trim(name_ch(1:len))
    1958              : 
    1959              : #else
    1960              :  name_ch = '0'
    1961              : #endif
    1962              : 
    1963            0 : end subroutine xmpi_name
    1964              : !!***
    1965              : 
    1966              : !----------------------------------------------------------------------
    1967              : 
    1968              : !!****f* m_xmpi/xmpi_iprobe
    1969              : !! NAME
    1970              : !!  xmpi_iprobe
    1971              : !!
    1972              : !! FUNCTION
    1973              : !!  Hides MPI_IPROBE from MPI library.
    1974              : !!  Nonblocking test for a message.
    1975              : !!
    1976              : !! INPUTS
    1977              : !!  source= source processes
    1978              : !!  tag= tag value
    1979              : !!  mpicomm= communicator
    1980              : !!
    1981              : !! OUTPUT
    1982              : !!  flag= True if a message with the specified source, tag, and communicator is available
    1983              : !!  mpierr= status error
    1984              : !!
    1985              : !! SOURCE
    1986              : 
    1987         4977 : subroutine xmpi_iprobe(source,tag,mpicomm,flag,mpierr)
    1988              : 
    1989              : !Arguments-------------------------
    1990              :  integer,intent(in) :: mpicomm,source,tag
    1991              :  integer,intent(out) :: mpierr
    1992              :  logical,intent(out) :: flag
    1993              : 
    1994              : !Local variables-------------------
    1995              : #ifdef HAVE_MPI
    1996              :  integer :: ier,status(MPI_STATUS_SIZE)
    1997              : #endif
    1998              : ! *************************************************************************
    1999              : 
    2000         4977 :  mpierr = 0
    2001              : #ifdef HAVE_MPI
    2002         4977 :   call MPI_IPROBE(source,tag,mpicomm,flag,status,ier)
    2003         4977 :   mpierr=ier
    2004              : #endif
    2005              : 
    2006         4977 : end subroutine xmpi_iprobe
    2007              : !!***
    2008              : 
    2009              : !----------------------------------------------------------------------
    2010              : 
    2011              : !!****f* m_xmpi/xmpi_wait
    2012              : !! NAME
    2013              : !!  xmpi_wait
    2014              : !!
    2015              : !! FUNCTION
    2016              : !!  Hides MPI_WAIT from MPI library.
    2017              : !!  Waits for an MPI request to complete.
    2018              : !!
    2019              : !! INPUTS
    2020              : !!  request= MPI request handle to wait for
    2021              : !!
    2022              : !! OUTPUT
    2023              : !!  mpierr= status error
    2024              : !!
    2025              : !! SOURCE
    2026              : 
    2027      1594023 : subroutine xmpi_wait(request, mpierr)
    2028              : 
    2029              : !Arguments-------------------------
    2030              :  integer,intent(inout) :: request
    2031              :  integer,intent(out) :: mpierr
    2032              : 
    2033              : !Local variables-------------------
    2034              : #ifdef HAVE_MPI
    2035              :  integer :: ier,status(MPI_STATUS_SIZE)
    2036              : #endif
    2037              : ! *************************************************************************
    2038              : 
    2039      1594023 :  mpierr = 0
    2040              : #ifdef HAVE_MPI
    2041      1594023 :  if (request /= xmpi_request_null) xmpi_count_requests = xmpi_count_requests - 1
    2042      1594023 :  call MPI_WAIT(request,status,ier)
    2043      1594023 :  mpierr=ier
    2044              : #endif
    2045              : 
    2046      1594023 : end subroutine xmpi_wait
    2047              : !!***
    2048              : 
    2049              : !----------------------------------------------------------------------
    2050              : 
    2051              : !!****f* m_xmpi/xmpi_waitall_1d
    2052              : !! NAME
    2053              : !!  xmpi_waitall_1d
    2054              : !!
    2055              : !! FUNCTION
    2056              : !!  Hides MPI_WAITALL from MPI library.
    2057              : !!  Waits for all given MPI Requests to complete.
    2058              : !!
    2059              : !! INPUTS
    2060              : !!  array_of_requests= array of request handles
    2061              : !!
    2062              : !! OUTPUT
    2063              : !!  mpierr= status error
    2064              : !!
    2065              : !! SOURCE
    2066              : 
    2067         9016 : subroutine xmpi_waitall_1d(array_of_requests, mpierr)
    2068              : 
    2069              : !Arguments-------------------------
    2070              :  integer,intent(inout) :: array_of_requests(:)
    2071              :  integer,intent(out) :: mpierr
    2072              : 
    2073              : !Local variables-------------------
    2074              : #ifdef HAVE_MPI
    2075        18032 :  integer :: ier,status(MPI_STATUS_SIZE,size(array_of_requests))
    2076              : #endif
    2077              : ! *************************************************************************
    2078              : 
    2079         9016 :  mpierr = 0
    2080              : #ifdef HAVE_MPI
    2081        42442 :  xmpi_count_requests = xmpi_count_requests - count(array_of_requests /= xmpi_request_null)
    2082         9016 :  call MPI_WAITALL(size(array_of_requests), array_of_requests, status, ier)
    2083         9016 :  mpierr=ier
    2084              : #endif
    2085              : 
    2086         9016 : end subroutine xmpi_waitall_1d
    2087              : !!***
    2088              : 
    2089              : !----------------------------------------------------------------------
    2090              : 
    2091              : !!****f* m_xmpi/xmpi_waitall_2d
    2092              : !! NAME
    2093              : !!  xmpi_waitall_2d
    2094              : !!
    2095              : !! FUNCTION
    2096              : !!  Hides MPI_WAITALL from MPI library.
    2097              : !!  Waits for all given MPI Requests to complete.
    2098              : !!
    2099              : !! INPUTS
    2100              : !!  array_of_requests= array of request handles
    2101              : !!
    2102              : !! OUTPUT
    2103              : !!  mpierr= status error
    2104              : !!
    2105              : !! SOURCE
    2106              : 
    2107         2050 : subroutine xmpi_waitall_2d(array_of_requests, mpierr)
    2108              : 
    2109              : !Arguments-------------------------
    2110              :  integer,intent(inout) :: array_of_requests(:,:)
    2111              :  integer,intent(out) :: mpierr
    2112              : 
    2113              : !Local variables-------------------
    2114         6150 :  integer :: flat_requests(product(shape(array_of_requests)))
    2115              : ! *************************************************************************
    2116              : 
    2117              :  ! MPI_WAITALL is a Fortran interface so cannot pass count and base address a la C
    2118              :  ! so flat 2d array and copy in-out. See https://github.com/open-mpi/ompi/issues/587
    2119         2050 :  flat_requests = pack(array_of_requests, mask=.True.)
    2120         2050 :  call xmpi_waitall_1d(flat_requests, mpierr)
    2121         6150 :  array_of_requests = reshape(flat_requests, shape(array_of_requests))
    2122              : 
    2123         2050 : end subroutine xmpi_waitall_2d
    2124              : !!***
    2125              : 
    2126              : !----------------------------------------------------------------------
    2127              : 
    2128              : !!****f* m_xmpi/xmpi_request_free
    2129              : !! NAME
    2130              : !!  xmpi_request_free
    2131              : !!
    2132              : !! FUNCTION
    2133              : !!  Hides MPI_REQUEST_FREE from MPI library.
    2134              : !!  Frees an array of communication request objects.
    2135              : !!
    2136              : !! INPUTS
    2137              : !!  requests(:)= communication request array (array of handles)
    2138              : !!
    2139              : !! OUTPUT
    2140              : !!  mpierr= status error
    2141              : !!
    2142              : !! SOURCE
    2143              : 
    2144            0 : subroutine xmpi_request_free(requests,mpierr)
    2145              : 
    2146              : !Arguments-------------------------
    2147              :  integer,intent(inout) :: requests(:)
    2148              :  integer,intent(out)  :: mpierr
    2149              : 
    2150              : !Local variables-------------------
    2151              : #ifdef HAVE_MPI
    2152              :  integer :: ier,ii
    2153              : #endif
    2154              : ! *************************************************************************
    2155              : 
    2156            0 :  mpierr = 0
    2157              : #ifdef HAVE_MPI
    2158            0 :  do ii=1,size(requests)
    2159            0 :    if (requests(ii) /= xmpi_request_null) xmpi_count_requests = xmpi_count_requests - 1
    2160            0 :    call MPI_REQUEST_FREE(requests(ii),ier)
    2161              :  end do
    2162            0 :  mpierr=ier
    2163              : #endif
    2164              : 
    2165            0 : end subroutine xmpi_request_free
    2166              : !!***
    2167              : 
    2168              : !!****f* m_xmpi/xmpi_requests_add
    2169              : !! NAME
    2170              : !!  xmpi_requests_add
    2171              : !!
    2172              : !! FUNCTION
    2173              : !!  Increase/decrement xmpi_count_requests internal counter
    2174              : !!
    2175              : !! SOURCE
    2176              : 
    2177            0 : subroutine xmpi_requests_add(count)
    2178              : 
    2179              : !Arguments-------------------------
    2180              :  integer,intent(in) :: count
    2181              : ! *************************************************************************
    2182              : 
    2183            0 :  xmpi_count_requests = xmpi_count_requests + count
    2184              : 
    2185            0 : end subroutine xmpi_requests_add
    2186              : !!***
    2187              : 
    2188              : !----------------------------------------------------------------------
    2189              : 
    2190              : !!****f* m_xmpi/xmpi_error_string
    2191              : !! NAME
    2192              : !!  xmpi_error_string
    2193              : !!
    2194              : !! FUNCTION
    2195              : !!  Hides MPI_ERROR_STRING from MPI library.
    2196              : !!
    2197              : !! INPUTS
    2198              : !!
    2199              : !! OUTPUT
    2200              : !!
    2201              : !! SOURCE
    2202              : 
    2203            0 : subroutine xmpi_error_string(mpierr,err_string,ilen,ierror)
    2204              : 
    2205              : !Arguments-------------------------
    2206              :  integer,intent(in) :: mpierr
    2207              :  integer,intent(out) :: ilen,ierror
    2208              :  character(len=*),intent(out) :: err_string
    2209              : ! *************************************************************************
    2210              : 
    2211            0 :  ilen=0
    2212              : #ifdef HAVE_MPI
    2213            0 :  call MPI_Error_string(mpierr,err_string,ilen,ierror)
    2214              : #else
    2215              :  ierror=1
    2216              :  err_string="Sorry, no MPI_Error_string routine is available to interpret the error message"
    2217              : #endif
    2218              : 
    2219            0 : end subroutine xmpi_error_string
    2220              : !!***
    2221              : 
    2222              : !----------------------------------------------------------------------
    2223              : 
    2224              : !!****f* m_xmpi/xmpi_comm_set_errhandler
    2225              : !! NAME
    2226              : !!  xmpi_set_errhandler
    2227              : !!
    2228              : !! FUNCTION
    2229              : !!  Hides MPI_COMM_SET_ERRHANDLER from MPI library.
    2230              : !!
    2231              : !! INPUTS
    2232              : !!  new_err_handler= new error handler
    2233              : !!
    2234              : !! OUTPUT
    2235              : !!  ierror=error code
    2236              : !!  old_err_handler= old error handler
    2237              : !!
    2238              : !! SIZE EFFECTS
    2239              : !!  comm= communicator (should be intent(in) but is intent(inout) in some
    2240              : !!             OMPI implementation ; known as a bug)
    2241              : !!
    2242              : !! SOURCE
    2243              : 
    2244        18020 : subroutine xmpi_comm_set_errhandler(comm,new_err_handler,old_err_handler,ierror)
    2245              : 
    2246              : !Arguments-------------------------
    2247              :  integer,intent(in) :: new_err_handler
    2248              :  integer,intent(in) :: comm
    2249              :  integer,intent(out) :: ierror,old_err_handler
    2250              : 
    2251              : !Local variables-------------------------
    2252              :  integer :: mpierr1,mpierr2,my_comm
    2253              : ! *************************************************************************
    2254              : 
    2255        18020 :  ierror=0
    2256        18020 :  my_comm = comm  !should be intent(in) but is intent(inout) in some OMPI implementation ; known as a bug)
    2257              : 
    2258              : #if defined HAVE_MPI
    2259              : 
    2260        18020 :  mpierr1=MPI_SUCCESS; mpierr2=MPI_SUCCESS
    2261              : 
    2262              : #if defined HAVE_MPI1
    2263              :    call MPI_Errhandler_get(my_comm,old_err_handler,mpierr1)
    2264              :    call MPI_Errhandler_set(my_comm,new_err_handler,mpierr2)
    2265              : #endif
    2266              : #if defined HAVE_MPI2
    2267        18020 :    call MPI_comm_get_Errhandler(my_comm,old_err_handler,mpierr1)
    2268        18020 :    call MPI_comm_set_Errhandler(my_comm,new_err_handler,mpierr2)
    2269              : #endif
    2270              : 
    2271        18020 :  ierror=MPI_SUCCESS
    2272        18020 :  if (mpierr1/=MPI_SUCCESS) then
    2273            0 :    ierror=mpierr1
    2274        18020 :  else if (mpierr2/=MPI_SUCCESS) then
    2275            0 :    ierror=mpierr2
    2276              :  end if
    2277              : #endif
    2278              : 
    2279        18020 : end subroutine xmpi_comm_set_errhandler
    2280              : !!***
    2281              : 
    2282              : !----------------------------------------------------------------------
    2283              : 
    2284              : !!****f* m_xmpi/xmpi_split_work_i4b
    2285              : !! NAME
    2286              : !!  xmpi_split_work_i4b
    2287              : !!
    2288              : !! FUNCTION
    2289              : !!  Splits the number of tasks, ntasks, among nprocs processors.
    2290              : !!  Used for the MPI parallelization of simple loops.
    2291              : !!
    2292              : !! INPUTS
    2293              : !!  ntasks=number of tasks
    2294              : !!  comm=MPI communicator.
    2295              : !!
    2296              : !! OUTPUT
    2297              : !!  my_start,my_stop= indices defining the initial and final task for this processor
    2298              : !!
    2299              : !! NOTES
    2300              : !!  If nprocs > ntasks then:
    2301              : !!
    2302              : !!    my_start = ntasks + 1
    2303              : !!    my_stop = ntask
    2304              : !!
    2305              : !!  In this particular case, loops of the form
    2306              : !!
    2307              : !!  do ii=my_start,my_stop
    2308              : !!   ...
    2309              : !!  end do
    2310              : !!
    2311              : !!  are not executed. Moreover allocation such as foo(my_start:my_stop) will generate a zero-sized array.
    2312              : !!
    2313              : !! SOURCE
    2314              : 
    2315        10513 : subroutine xmpi_split_work_i4b(ntasks, comm, my_start, my_stop)
    2316              : 
    2317              : !Arguments ------------------------------------
    2318              :  integer,intent(in)  :: ntasks,comm
    2319              :  integer,intent(out) :: my_start, my_stop
    2320              : 
    2321              : !Local variables-------------------------------
    2322              :  integer :: res,nprocs,my_rank,block_p1,block
    2323              : ! *************************************************************************
    2324              : 
    2325        10513 :  nprocs  = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2326              : 
    2327        10513 :  block   = ntasks / nprocs
    2328        10513 :  res     = MOD(ntasks, nprocs)
    2329        10513 :  block_p1= block + 1
    2330              : 
    2331        10513 :  if (my_rank < res) then
    2332           60 :    my_start =  my_rank   *block_p1+1
    2333           60 :    my_stop  = (my_rank+1)*block_p1
    2334              :  else
    2335        10453 :    my_start = res*block_p1 + (my_rank-res  )*block + 1
    2336        10453 :    my_stop  = res*block_p1 + (my_rank-res+1)*block
    2337              :  end if
    2338              : 
    2339        10513 : end subroutine xmpi_split_work_i4b
    2340              : !!***
    2341              : 
    2342              : !----------------------------------------------------------------------
    2343              : 
    2344              : !!****f* m_xmpi/xmpi_split_block
    2345              : !! NAME
    2346              : !!  xmpi_split_block
    2347              : !!
    2348              : !! FUNCTION
    2349              : !!  Splits tasks inside communicator using block distribution. Used for the MPI parallelization of simple loops.
    2350              : !!
    2351              : !! INPUTS
    2352              : !!  ntasks: number of tasks
    2353              : !!  comm: MPI communicator.
    2354              : !!
    2355              : !! OUTPUT
    2356              : !!  my_ntasks: Number of tasks received by this rank. May be zero if ntasks > nprocs.
    2357              : !!  my_inds(my_ntasks): List of tasks treated by this rank. Allocated by the routine. May be zero-sized.
    2358              : !!
    2359              : !! SOURCE
    2360              : 
    2361           96 : subroutine xmpi_split_block(ntasks, comm, my_ntasks, my_inds)
    2362              : 
    2363              : !Arguments ------------------------------------
    2364              :  integer,intent(in)  :: ntasks, comm
    2365              :  integer,intent(out) :: my_ntasks
    2366              :  integer,allocatable,intent(out) :: my_inds(:)
    2367              : 
    2368              : !Local variables-------------------------------
    2369              :  integer :: ii, istart, istop
    2370              : ! *************************************************************************
    2371              : 
    2372           96 :  call xmpi_split_work(ntasks, comm, istart, istop)
    2373           96 :  my_ntasks = istop - istart + 1
    2374          288 :  ABI_MALLOC(my_inds, (my_ntasks))
    2375        12507 :  if (my_ntasks > 0) my_inds = [(istart + (ii - 1), ii=1, my_ntasks)]
    2376              : 
    2377           96 : end subroutine xmpi_split_block
    2378              : !!***
    2379              : 
    2380              : !----------------------------------------------------------------------
    2381              : 
    2382              : !!****f* m_xmpi/xmpi_split_cyclic
    2383              : !! NAME
    2384              : !!  xmpi_split_cyclic
    2385              : !!
    2386              : !! FUNCTION
    2387              : !!  Splits tasks inside communicator using cyclic distribution.
    2388              : !!  Used for the MPI parallelization of simple loops.
    2389              : !!
    2390              : !! INPUTS
    2391              : !!  ntasks: number of tasks
    2392              : !!  comm: MPI communicator.
    2393              : !!
    2394              : !! OUTPUT
    2395              : !!  my_ntasks: Number of tasks received by this rank. May be zero if ntasks > nprocs.
    2396              : !!  my_inds(my_ntasks): List of tasks treated by this rank. Allocated by the routine. May be zero-sized.
    2397              : !!
    2398              : !! SOURCE
    2399              : 
    2400           68 : subroutine xmpi_split_cyclic(ntasks, comm, my_ntasks, my_inds)
    2401              : 
    2402              : !Arguments ------------------------------------
    2403              :  integer,intent(in)  :: ntasks, comm
    2404              :  integer,intent(out) :: my_ntasks
    2405              :  integer,allocatable,intent(out) :: my_inds(:)
    2406              : 
    2407              : !Local variables-------------------------------
    2408              :  integer :: ii, cnt, itask, my_rank, nprocs
    2409              : ! *************************************************************************
    2410              : 
    2411           68 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2412              : 
    2413          204 :  do ii=1,2
    2414          136 :    if (ii == 2) then
    2415          204 :      ABI_MALLOC(my_inds, (my_ntasks))
    2416              :    end if
    2417          136 :    cnt = 0
    2418          632 :    do itask=1,ntasks
    2419          632 :      if (mod(itask, nprocs) == my_rank) then
    2420          496 :        cnt = cnt + 1
    2421          496 :        if (ii == 2) my_inds(cnt) = itask
    2422              :      end if
    2423              :    end do
    2424          204 :    if (ii == 1) my_ntasks = cnt
    2425              :  end do
    2426              : 
    2427           68 : end subroutine xmpi_split_cyclic
    2428              : !!***
    2429              : 
    2430              : !----------------------------------------------------------------------
    2431              : 
    2432              : !!****f* m_xmpi/xmpi_split_list
    2433              : !! NAME
    2434              : !!  xmpi_split_list
    2435              : !!
    2436              : !! FUNCTION
    2437              : !!  Splits list of items inside communicator using block distribution.
    2438              : !!  Used for the MPI parallelization of simple loops.
    2439              : !!
    2440              : !! INPUTS
    2441              : !!  ntasks:Number of items in list (global)
    2442              : !!  list(ntasks): List of indices
    2443              : !!  comm: MPI communicator.
    2444              : !!
    2445              : !! OUTPUT
    2446              : !!  my_ntasks: Number of tasks received by this rank. May be zero if ntasks > nprocs.
    2447              : !!  my_inds(my_ntasks): List of tasks treated by this rank. Allocated by the routine. May be zero-sized.
    2448              : !!
    2449              : !! SOURCE
    2450              : 
    2451           61 : subroutine xmpi_split_list(ntasks, list, comm, my_ntasks, my_inds)
    2452              : 
    2453              : !Arguments ------------------------------------
    2454              :  integer,intent(in)  :: ntasks, comm
    2455              :  integer,intent(out) :: my_ntasks
    2456              :  integer,intent(in) :: list(ntasks)
    2457              :  integer,allocatable,intent(out) :: my_inds(:)
    2458              : 
    2459              : !Local variables-------------------------------
    2460              :  integer :: my_start, my_stop
    2461              : ! *************************************************************************
    2462              : 
    2463           61 :  call xmpi_split_work(ntasks, comm, my_start, my_stop)
    2464              : 
    2465           61 :  my_ntasks = my_stop - my_start + 1
    2466              : 
    2467           61 :  if (my_stop >= my_start) then
    2468          183 :    ABI_MALLOC(my_inds, (my_ntasks))
    2469         6326 :    my_inds = list(my_start:my_stop)
    2470              :  else
    2471            0 :    my_ntasks = 0
    2472            0 :    ABI_MALLOC(my_inds, (0))
    2473              :  end if
    2474              : 
    2475           61 : end subroutine xmpi_split_list
    2476              : !!***
    2477              : 
    2478              : !----------------------------------------------------------------------
    2479              : 
    2480              : !!****f* m_xmpi/xmpi_split_work2_i4b
    2481              : !! NAME
    2482              : !!  xmpi_split_work2_i4b
    2483              : !!
    2484              : !! FUNCTION
    2485              : !!  Splits a number of tasks, ntasks, among nprocs processors.
    2486              : !!  The output arrays istart(1:nprocs) and istop(1:nprocs)
    2487              : !!  report the starting and final task index for each CPU.
    2488              : !!  Namely CPU with rank ii has to perform all the tasks between
    2489              : !!  istart(ii+1) and istop(ii+1). Note the Fortran convention of using 1 as first index of the array.
    2490              : !!  Note, moreover, that if a proc has rank > ntasks then:
    2491              : !!
    2492              : !!   istart(rank+1)=ntasks+1
    2493              : !!   istop(rank+1)=ntask
    2494              : !!
    2495              : !!  In this particular case, loops of the form
    2496              : !!
    2497              : !!  do ii=istart(rank),istop(rank)
    2498              : !!   ...
    2499              : !!  end do
    2500              : !!
    2501              : !!  are not executed. Moreover allocation such as foo(istart(rank):istop(rank))
    2502              : !!  will generate a zero-sized array
    2503              : !!
    2504              : !! INPUTS
    2505              : !!  ntasks= number of tasks
    2506              : !!  nprocs=Number of processors.
    2507              : !!
    2508              : !! OUTPUT
    2509              : !!  istart(nprocs),istop(nprocs)= indices defining the initial and final task for each processor
    2510              : !!
    2511              : !! SOURCE
    2512              : 
    2513          480 : subroutine xmpi_split_work2_i4b(ntasks, nprocs, istart, istop)
    2514              : 
    2515              : !Arguments ------------------------------------
    2516              :  integer,intent(in) :: ntasks,nprocs
    2517              :  integer,intent(inout) :: istart(nprocs), istop(nprocs)
    2518              : 
    2519              : !Local variables-------------------------------
    2520              :  integer :: res,irank,block,block_tmp
    2521              : ! *************************************************************************
    2522              : 
    2523          480 :  block_tmp = ntasks/nprocs
    2524          480 :  res       = MOD(ntasks,nprocs)
    2525          480 :  block     = block_tmp+1
    2526              : 
    2527         1618 :  do irank=0,nprocs-1
    2528         1618 :    if (irank<res) then
    2529          380 :      istart(irank+1) = irank    *block+1
    2530          380 :      istop (irank+1) = (irank+1)*block
    2531              :    else
    2532          758 :      istart(irank+1) = res*block + (irank-res  )*block_tmp+1
    2533          758 :      istop (irank+1) = res*block + (irank-res+1)*block_tmp
    2534              :    end if
    2535              :  end do
    2536              : 
    2537          480 : end subroutine xmpi_split_work2_i4b
    2538              : !!***
    2539              : 
    2540              : !----------------------------------------------------------------------
    2541              : 
    2542              : !!****f* m_xmpi/xmpi_split_work2_i8b
    2543              : !! NAME
    2544              : !!  xmpi_split_work2_i8b
    2545              : !!
    2546              : !! FUNCTION
    2547              : !!  Same as xmpi_split_work2_i8b but accepts 8 bytes integer.
    2548              : !!
    2549              : !! INPUTS
    2550              : !!  ntasks= number of tasks
    2551              : !!  nprocs=Number of processors.
    2552              : !!
    2553              : !! OUTPUT
    2554              : !!  istart(nprocs),istop(nprocs)= indices defining the initial and final task for each processor
    2555              : !!
    2556              : !! SOURCE
    2557              : 
    2558           24 : subroutine xmpi_split_work2_i8b(ntasks,nprocs,istart,istop)
    2559              : 
    2560              : !Arguments ------------------------------------
    2561              :  integer,intent(in)  :: nprocs
    2562              :  integer(i8b),intent(in)  :: ntasks
    2563              :  integer(i8b),intent(inout) :: istart(nprocs),istop(nprocs)
    2564              : 
    2565              : !Local variables-------------------------------
    2566              :  integer(i8b) :: res,irank,block,block_tmp
    2567              : ! *************************************************************************
    2568              : 
    2569           24 :  block_tmp = ntasks/nprocs
    2570           24 :  res       = MOD(ntasks,INT(nprocs,KIND=i8b))
    2571           24 :  block     = block_tmp+1
    2572              : 
    2573           62 :  do irank=0,nprocs-1
    2574           62 :    if (irank<res) then
    2575            0 :      istart(irank+1)= irank   *block+1
    2576            0 :      istop (irank+1)=(irank+1)*block
    2577              :    else
    2578           38 :      istart(irank+1)=res*block+(irank-res  )*block_tmp+1
    2579           38 :      istop (irank+1)=res*block+(irank-res+1)*block_tmp
    2580              :    end if
    2581              :  end do
    2582              : 
    2583           24 : end subroutine xmpi_split_work2_i8b
    2584              : !!***
    2585              : 
    2586              : !----------------------------------------------------------------------
    2587              : 
    2588              : !!****f* m_xmpi/xmpi_distab_4D
    2589              : !! NAME
    2590              : !!  xmpi_distab_4D
    2591              : !!
    2592              : !! FUNCTION
    2593              : !!  Fill table defining the distribution of the tasks according to the number of processors involved in the
    2594              : !!  calculation. For each set of indices, the table contains the rank of the node in the MPI communicator.
    2595              : !!
    2596              : !! INPUTS
    2597              : !!  nprocs=The number of processors performing the calculation in parallel.
    2598              : !!
    2599              : !! OUTPUT
    2600              : !!  task_distrib(:,:,:,:) = Contains the rank of the node that is taking care of this particular set of loop indices.
    2601              : !!  Tasks are distributed across the nodes in column-major order.
    2602              : !!
    2603              : !! SOURCE
    2604              : 
    2605           27 : subroutine xmpi_distab_4D(nprocs, task_distrib)
    2606              : 
    2607              : !Arguments ------------------------------------
    2608              :  integer,intent(in) :: nprocs
    2609              : !arrays
    2610              :  integer,intent(inout) :: task_distrib(:,:,:,:)
    2611              : 
    2612              : !Local variables ------------------------------
    2613              : !scalars
    2614              :  integer :: ii,jj,n1,n2,n3,n4,ntasks,irank,remainder,ntpblock
    2615              :  integer,allocatable :: list(:)
    2616              : !************************************************************************
    2617              : 
    2618           27 :  n1= SIZE(task_distrib,DIM=1)
    2619           27 :  n2= SIZE(task_distrib,DIM=2)
    2620           27 :  n3= SIZE(task_distrib,DIM=3)
    2621           27 :  n4= SIZE(task_distrib,DIM=4)
    2622           27 :  ntasks = n1*n2*n3*n4
    2623              : 
    2624           81 :  ABI_MALLOC(list, (ntasks))
    2625        29915 :  list=-999
    2626              : 
    2627           27 :  ntpblock  = ntasks/nprocs
    2628           27 :  remainder = MOD(ntasks,nprocs)
    2629              : 
    2630           27 :  if (ntpblock==0) then ! nprocs > ntasks
    2631            0 :    do ii=1,ntasks
    2632            0 :      list(ii) = ii-1
    2633              :    end do
    2634              :  else
    2635           27 :    ii=1
    2636           68 :    do irank=nprocs-1,0,-1 ! If remainder/=0, master will get less tasks.
    2637           41 :      jj = ii+ntpblock-1
    2638           41 :      if (remainder>0) then
    2639            0 :        jj=jj+1
    2640            0 :        remainder = remainder-1
    2641              :      end if
    2642        29929 :      list(ii:jj)=irank
    2643           68 :      ii=jj+1
    2644              :    end do
    2645              :  end if
    2646              : 
    2647          135 :  task_distrib = RESHAPE(list, [n1,n2,n3,n4])
    2648              : 
    2649        35893 :  if (ANY(task_distrib==-999)) call xmpi_abort(msg="task_distrib == -999")
    2650              : 
    2651           27 :  ABI_FREE(list)
    2652              : 
    2653           27 : end subroutine xmpi_distab_4D
    2654              : !!***
    2655              : 
    2656              : !----------------------------------------------------------------------
    2657              : 
    2658              : !!****f* m_xmpi/xmpi_distrib_with_replicas
    2659              : !! NAME
    2660              : !!  xmpi_distrib_with_replicas
    2661              : !!
    2662              : !! FUNCTION
    2663              : !!  This function distributes the i-th task `itask` among `nprocs` inside a MPI communicator.
    2664              : !!  If nprocs > ntasks, multiple MPI ranks will be assigned to a given task.
    2665              : !!
    2666              : !! INPUTS
    2667              : !!  itask=Index of the task (must be <= ntasks)
    2668              : !!  ntasks= number of tasks
    2669              : !!  rank=MPI Rank of this processor in the MPI communicator.
    2670              : !!  nprocs=Number of processors in the MPI communicator.
    2671              : !!
    2672              : !! OUTPUT
    2673              : !!  True if this node will treat itask (replicas are possible if nprocs > ntasks)
    2674              : !!
    2675              : !! SOURCE
    2676              : 
    2677         5081 : pure logical function xmpi_distrib_with_replicas(itask, ntasks, rank, nprocs) result(bool)
    2678              : 
    2679              : !Arguments ------------------------------------
    2680              :  integer,intent(in) :: itask,rank,nprocs,ntasks
    2681              : 
    2682              : !Local variables-------------------------------
    2683              :  integer :: ii,mnp_pool,rk_base
    2684              : ! *************************************************************************
    2685              : 
    2686              :  ! If the number of processors is less than ntasks, we have max one processor per task
    2687              :  ! else we replicate the tasks inside a pool of max size mnp_pool
    2688         5081 :  if (nprocs <= ntasks) then
    2689         5081 :    bool = modulo(itask - 1, nprocs) == rank
    2690              :  else
    2691            0 :    mnp_pool = (nprocs / ntasks)
    2692              :    !write(std_out,*)"Will duplicate itask, mnp_pool", mnp_pool, "nprocs, ntasks", nprocs, ntasks
    2693              : 
    2694            0 :    rk_base = modulo(itask - 1, nprocs)
    2695            0 :    bool = .False.
    2696            0 :    do ii=1,mnp_pool+1
    2697            0 :      if (rank == rk_base + (ii - 1) * ntasks) then
    2698              :        bool = .True.; exit
    2699              :      end if
    2700              :    end do
    2701              :  end if
    2702              : 
    2703         5081 : end function xmpi_distrib_with_replicas
    2704              : !!***
    2705              : 
    2706              : !----------------------------------------------------------------------
    2707              : 
    2708              : !!****f* m_xmpi/xmpi_largetype_create
    2709              : !! NAME
    2710              : !!  xmpi_largetype_create
    2711              : !!
    2712              : !! FUNCTION
    2713              : !!  This function builds a large-count contiguous datatype made of "small" adjacent
    2714              : !!  chunks (of same original type). The new type can then be used in MPI
    2715              : !!  routines when the number of elements to communicate exceeds a 32bit integer.
    2716              : !!
    2717              : !! INPUTS
    2718              : !!  largecount= total number of elements expressed as a 64bit integer
    2719              : !!  inputtype= (INTEGER) input type (typically INTEGER, REAL(dp), ...)
    2720              : !!  op_type= type of operation that will be applied during collective comms
    2721              : !!           At present, MPI_SUM, MPI_LOR, MPI_LAND are implemented
    2722              : !!
    2723              : !! OUTPUT
    2724              : !!  largetype= (INTEGER) new MPI type made of a serie of adjacent chunks
    2725              : !!  largetype_op= (INTEGER) MPI user-defined operation associated to largetype type
    2726              : !!
    2727              : !! NOTE
    2728              : !!  This routine is partially inspired by https://github.com/jeffhammond/BigMPI
    2729              : !!  See: J.R. Hammond. A. Schafer, R. Latham,
    2730              : !!       "ToINT_MAX. . . and beyond. Exploring large-count support in MPI",
    2731              : !!       2014 Workshop on Exascale MPI at Supercomputing Conference
    2732              : !!       MIT License (MIT)
    2733              : !!       Permission is hereby granted, free of charge, to any person obtaining a copy
    2734              : !!       of this software and associated documentation files (the "Software"), to deal
    2735              : !!       in the Software without restriction, including without limitation the rights
    2736              : !!       to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    2737              : !!       copies of the Software, and to permit persons to whom the Software is
    2738              : !!       furnished to do so.
    2739              : !!
    2740              : !!  From MPI4 specification, this routine is useless as large-count MPI communications
    2741              : !!    can be called with the use of the MPI_count datatype (instead of INTEGER).
    2742              : !!
    2743              : !! SOURCE
    2744              : 
    2745            0 : subroutine xmpi_largetype_create(largecount,inputtype,largetype,largetype_op,op_type)
    2746              : 
    2747              : !Arguments ------------------------------------
    2748              : !scalars
    2749              :  integer(KIND=int64),intent(in) :: largecount
    2750              :  integer,intent(in) :: inputtype,op_type
    2751              :  integer,intent(out) :: largetype,largetype_op
    2752              : 
    2753              : !Local variables-------------------------------
    2754              : #ifdef HAVE_MPI
    2755              : !scalars
    2756              :  integer,parameter :: INT_MAX=max(1,xmpi_maxint32/2)
    2757              :  integer(KIND=int32) :: cc,rr,ierr
    2758              :  integer(KIND=XMPI_ADDRESS_KIND) :: extent,lb,remdisp
    2759              :  integer :: chunks,remainder
    2760              : !arrays
    2761              :  integer(KIND=int32) :: blklens(2)
    2762              :  integer(KIND=XMPI_ADDRESS_KIND) :: disps(2)
    2763              :  integer :: types(2)
    2764              : #endif
    2765              : ! *************************************************************************
    2766              : 
    2767              : #ifdef HAVE_MPI
    2768              :  if (XMPI_ADDRESS_KIND<int64) call xmpi_abort(msg="Too much data to communicate for this architecture!")
    2769              : 
    2770              : !Divide data in chunks
    2771            0 :  cc=int(largecount/INT_MAX,kind=int32)
    2772            0 :  rr=int(largecount-cc*INT_MAX,kind=int32)
    2773              : 
    2774              : !Create user-defined datatype
    2775            0 :  if (rr==0) then
    2776            0 :    call MPI_TYPE_VECTOR(cc,INT_MAX,INT_MAX,inputtype,largetype,ierr)
    2777            0 :    if (ierr==0) call MPI_TYPE_COMMIT(largetype,ierr)
    2778              :  else
    2779            0 :    call MPI_TYPE_VECTOR(cc,INT_MAX,INT_MAX,inputtype,chunks,ierr)
    2780            0 :    call MPI_TYPE_CONTIGUOUS(rr,inputtype,remainder,ierr)
    2781            0 :    if (ierr==0) then
    2782            0 :      call MPI_TYPE_GET_EXTENT(inputtype,lb,extent,ierr)
    2783            0 :      remdisp=cc*INT_MAX*extent
    2784            0 :      blklens(1:2)=1
    2785            0 :      disps(1)=0;disps(2)=remdisp
    2786            0 :      types(1)=chunks;types(2)=remainder
    2787              : #ifdef HAVE_MPI_TYPE_CREATE_STRUCT
    2788            0 :      call MPI_TYPE_CREATE_STRUCT(2,blklens,disps,types,largetype,ierr)
    2789              : #else
    2790              :      call MPI_TYPE_STRUCT(2,blklens,disps,types,largetype,ierr)
    2791              : #endif
    2792            0 :      if (ierr==0) then
    2793            0 :        call MPI_TYPE_COMMIT(largetype,ierr)
    2794            0 :        call MPI_TYPE_FREE(chunks,ierr)
    2795            0 :        call MPI_TYPE_FREE(remainder,ierr)
    2796              :      end if
    2797              :    end if
    2798              :  end if
    2799            0 :  if (ierr/=0) call xmpi_abort(msg="Cannot remove ABI_MPIABORTFILE")
    2800              : 
    2801              : !Associate user-defined MPI operation
    2802            0 :  xmpi_largetype_size=largecount ; largetype_op=-1111
    2803            0 :  if (op_type==MPI_SUM) then
    2804            0 :    select case(inputtype)
    2805              :      case(MPI_INTEGER)
    2806            0 :       call MPI_OP_CREATE(largetype_sum_int  ,.true.,largetype_op,ierr)
    2807              :      case(MPI_REAL)
    2808            0 :       call MPI_OP_CREATE(largetype_sum_real ,.true.,largetype_op,ierr)
    2809              :      case(MPI_DOUBLE_PRECISION)
    2810            0 :       call MPI_OP_CREATE(largetype_sum_dble ,.true.,largetype_op,ierr)
    2811              :      case(MPI_COMPLEX)
    2812            0 :       call MPI_OP_CREATE(largetype_sum_cplx ,.true.,largetype_op,ierr)
    2813              :      case(MPI_DOUBLE_COMPLEX)
    2814            0 :       call MPI_OP_CREATE(largetype_sum_dcplx,.true.,largetype_op,ierr)
    2815              :    end select
    2816            0 :  else if (op_type==MPI_LOR) then
    2817            0 :    select case(inputtype)
    2818              :      case(MPI_LOGICAL)
    2819            0 :       call MPI_OP_CREATE(largetype_lor_log,.true.,largetype_op,ierr)
    2820              :    end select
    2821            0 :  else if (op_type==MPI_LAND) then
    2822            0 :    select case(inputtype)
    2823              :      case(MPI_LOGICAL)
    2824            0 :       call MPI_OP_CREATE(largetype_land_log,.true.,largetype_op,ierr)
    2825              :    end select
    2826              :  else if (op_type==MPI_OP_NULL) then
    2827              :    largetype_op=-1111
    2828              :  end if
    2829              : #else
    2830              :  ABI_UNUSED(largecount)
    2831              :  ABI_UNUSED(inputtype)
    2832              :  ABI_UNUSED(largetype)
    2833              :  ABI_UNUSED(largetype_op)
    2834              :  ABI_UNUSED(op_type)
    2835              : #endif
    2836              : 
    2837            0 : end subroutine xmpi_largetype_create
    2838              : !!***
    2839              : 
    2840              : !--------------------------------------
    2841              : 
    2842              : !!****f* m_xmpi/largetype_sum_int
    2843              : !! NAME
    2844              : !!  largetype_sum_int
    2845              : !!
    2846              : !! FUNCTION
    2847              : !!  Routine used to overload MPI_SUM for integers
    2848              : 
    2849            0 :  subroutine largetype_sum_int(invec,inoutvec,len,datatype)
    2850              :   integer :: len,datatype
    2851              :   integer :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2852              :   integer(KIND=int64) :: ii,jj,kk
    2853            0 :   kk=0
    2854            0 :   do ii=1,len
    2855            0 :     do jj=1,xmpi_largetype_size
    2856            0 :       kk=kk+1
    2857            0 :       inoutvec(kk)=inoutvec(kk)+invec(kk)
    2858              :     end do
    2859              :   end do
    2860              :   ! this macro is being used befor m_errors is compiled, so work around it
    2861              :   ! ABI_UNUSED(datatype)
    2862              :   if (.FALSE.) write(std_out,*) datatype
    2863            0 :  end subroutine largetype_sum_int
    2864              : !!***
    2865              : 
    2866              : !--------------------------------------
    2867              : 
    2868              : !!****f* m_xmpi/largetype_sum_real
    2869              : !! NAME
    2870              : !!  largetype_sum_real
    2871              : !!
    2872              : !! FUNCTION
    2873              : !!  Routine used to overload MPI_SUM for reals
    2874              : 
    2875            0 :  subroutine largetype_sum_real(invec,inoutvec,len,datatype)
    2876              :   integer :: len,datatype
    2877              :   real(sp) :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2878              :   integer(KIND=int64) :: ii,jj,kk
    2879            0 :   kk=0
    2880            0 :   do ii=1,len
    2881            0 :     do jj=1,xmpi_largetype_size
    2882            0 :       kk=kk+1
    2883            0 :       inoutvec(kk)=inoutvec(kk)+invec(kk)
    2884              :     end do
    2885              :   end do
    2886              :   ! this macro is being used befor m_errors is compiled, so work around it
    2887              :   ! ABI_UNUSED(datatype)
    2888              :   if (.FALSE.) write(std_out,*) datatype
    2889            0 :  end subroutine largetype_sum_real
    2890              : !!***
    2891              : 
    2892              : !--------------------------------------
    2893              : 
    2894              : !!****f* m_xmpi/largetype_sum_dble
    2895              : !! NAME
    2896              : !!  largetype_sum_dble
    2897              : !!
    2898              : !! FUNCTION
    2899              : !!  Routine used to overload MPI_SUM for double precision reals
    2900              : 
    2901            0 :  subroutine largetype_sum_dble(invec,inoutvec,len,datatype)
    2902              :   integer :: len,datatype
    2903              :   real(dp) :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2904              :   integer(KIND=int64) :: ii,jj,kk
    2905            0 :   kk=0
    2906            0 :   do ii=1,len
    2907            0 :     do jj=1,xmpi_largetype_size
    2908            0 :       kk=kk+1
    2909            0 :       inoutvec(kk)=inoutvec(kk)+invec(kk)
    2910              :     end do
    2911              :   end do
    2912              :   ! this macro is being used befor m_errors is compiled, so work around it
    2913              :   ! ABI_UNUSED(datatype)
    2914              :   if (.FALSE.) write(std_out,*) datatype
    2915            0 :  end subroutine largetype_sum_dble
    2916              : !!***
    2917              : 
    2918              : !--------------------------------------
    2919              : 
    2920              : !!****f* m_xmpi/largetype_sum_cplx
    2921              : !! NAME
    2922              : !!  largetype_sum_cplx
    2923              : !!
    2924              : !! FUNCTION
    2925              : !!  Routine used to overload MPI_SUM for complex
    2926              : 
    2927            0 :  subroutine largetype_sum_cplx(invec,inoutvec,len,datatype)
    2928              :   integer :: len,datatype
    2929              :   complex(sp) :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2930              :   integer(KIND=int64) :: ii,jj,kk
    2931            0 :   kk=0
    2932            0 :   do ii=1,len
    2933            0 :     do jj=1,xmpi_largetype_size
    2934            0 :       kk=kk+1
    2935            0 :       inoutvec(kk)=inoutvec(kk)+invec(kk)
    2936              :     end do
    2937              :   end do
    2938              :   ! this macro is being used befor m_errors is compiled, so work around it
    2939              :   ! ABI_UNUSED(datatype)
    2940              :   if (.FALSE.) write(std_out,*) datatype
    2941            0 :  end subroutine largetype_sum_cplx
    2942              : !!***
    2943              : 
    2944              : !--------------------------------------
    2945              : 
    2946              : !!****f* m_xmpi/largetype_sum_dcplx
    2947              : !! NAME
    2948              : !!  largetype_sum_dcplx
    2949              : !!
    2950              : !! FUNCTION
    2951              : !!  Routine used to overload MPI_SUM for double complex
    2952              : 
    2953            0 :  subroutine largetype_sum_dcplx(invec,inoutvec,len,datatype)
    2954              :   integer :: len,datatype
    2955              :   complex(dp) :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2956              :   integer(KIND=int64) :: ii,jj,kk
    2957            0 :   kk=0
    2958            0 :   do ii=1,len
    2959            0 :     do jj=1,xmpi_largetype_size
    2960            0 :       kk=kk+1
    2961            0 :       inoutvec(kk)=inoutvec(kk)+invec(kk)
    2962              :     end do
    2963              :   end do
    2964              :   ! this macro is being used befor m_errors is compiled, so work around it
    2965              :   ! ABI_UNUSED(datatype)
    2966              :   if (.FALSE.) write(std_out,*) datatype
    2967            0 :  end subroutine largetype_sum_dcplx
    2968              : !!***
    2969              : 
    2970              : !--------------------------------------
    2971              : 
    2972              : !!****f* m_xmpi/largetype_lor_log
    2973              : !! NAME
    2974              : !!  largetype_lor_log
    2975              : !!
    2976              : !! FUNCTION
    2977              : !!  Routine used to overload MPI_LOR for logicals
    2978              : 
    2979            0 :  subroutine largetype_lor_log(invec,inoutvec,len,datatype)
    2980              :   integer :: len,datatype
    2981              :   logical :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    2982              :   integer(KIND=int64) :: ii,jj,kk
    2983            0 :   kk=0
    2984            0 :   do ii=1,len
    2985            0 :     do jj=1,xmpi_largetype_size
    2986            0 :       kk=kk+1
    2987            0 :       inoutvec(kk)=inoutvec(kk).or.invec(kk)
    2988              :     end do
    2989              :   end do
    2990              :   ! this macro is being used befor m_errors is compiled, so work around it
    2991              :   ! ABI_UNUSED(datatype)
    2992              :   if (.FALSE.) write(std_out,*) datatype
    2993            0 :  end subroutine largetype_lor_log
    2994              : !!***
    2995              : 
    2996              : !--------------------------------------
    2997              : 
    2998              : !!****f* m_xmpi/largetype_land_log
    2999              : !! NAME
    3000              : !!  largetype_land_log
    3001              : !!
    3002              : !! FUNCTION
    3003              : !!  Routine used to overload MPI_LANG for logicals
    3004              : 
    3005            0 :  subroutine largetype_land_log(invec,inoutvec,len,datatype)
    3006              :   integer :: len,datatype
    3007              :   logical :: invec(len*xmpi_largetype_size),inoutvec(len*xmpi_largetype_size)
    3008              :   integer(KIND=int64) :: ii,jj,kk
    3009            0 :   kk=0
    3010            0 :   do ii=1,len
    3011            0 :     do jj=1,xmpi_largetype_size
    3012            0 :       kk=kk+1
    3013            0 :       inoutvec(kk)=inoutvec(kk).and.invec(kk)
    3014              :     end do
    3015              :   end do
    3016              :   ! this macro is being used befor m_errors is compiled, so work around it
    3017              :   ! ABI_UNUSED(datatype)
    3018              :   if (.FALSE.) write(std_out,*) datatype
    3019            0 :  end subroutine largetype_land_log
    3020              : !!***
    3021              : 
    3022              : !----------------------------------------------------------------------
    3023              : 
    3024              : !!****f* m_xmpi/xmpi_largetype_free
    3025              : !! NAME
    3026              : !!  xmpi_largetype_free
    3027              : !!
    3028              : !! FUNCTION
    3029              : !!  This function release a large-count contiguous datatype.
    3030              : !!
    3031              : !! SIDE EFFECTS
    3032              : !!  largetype= (INTEGER) MPI type to release
    3033              : !!  largetype_op= (INTEGER) MPI user-defined operation associated to largetype type
    3034              : !!
    3035              : !! SOURCE
    3036              : 
    3037            0 : subroutine xmpi_largetype_free(largetype,largetype_op)
    3038              : 
    3039              : !Arguments ------------------------------------
    3040              : !scalars
    3041              :  integer,intent(inout) :: largetype,largetype_op
    3042              : !Local variables-------------------------------
    3043              : #ifdef HAVE_MPI
    3044              :  integer :: ierr
    3045              : #endif
    3046              : ! *************************************************************************
    3047              : 
    3048              : #ifdef HAVE_MPI
    3049            0 :    xmpi_largetype_size=0
    3050            0 :    if (largetype_op/=-1111) call MPI_OP_FREE(largetype_op,ierr)
    3051            0 :    call MPI_TYPE_FREE(largetype,ierr)
    3052              : #else
    3053              :  ABI_UNUSED(largetype)
    3054              :  ABI_UNUSED(largetype_op)
    3055              : #endif
    3056              : 
    3057            0 : end subroutine xmpi_largetype_free
    3058              : !!***
    3059              : 
    3060              : !----------------------------------------------------------------------
    3061              : 
    3062              : ! Include files providing wrappers for some of the most commonly used MPI primitives.
    3063              : 
    3064              : #include "xmpi_iallgather.finc"
    3065              : #include "xmpi_allgather.finc"
    3066              : #include "xmpi_allgatherv.finc"
    3067              : #include "xmpi_alltoall.finc"
    3068              : #include "xmpi_ialltoall.finc"
    3069              : #include "xmpi_alltoallv.finc"
    3070              : #include "xmpi_ialltoallv.finc"
    3071              : #include "xmpi_bcast.finc"
    3072              : #include "xmpi_ibcast.finc"
    3073              : #include "xmpi_exch.finc"
    3074              : #include "xmpi_gather.finc"
    3075              : #include "xmpi_gatherv.finc"
    3076              : #include "xmpi_max.finc"
    3077              : #include "xmpi_min.finc"
    3078              : #include "xmpi_recv.finc"
    3079              : #include "xmpi_irecv.finc"
    3080              : #include "xmpi_scatterv.finc"
    3081              : #include "xmpi_send.finc"
    3082              : #include "xmpi_isend.finc"
    3083              : #include "xmpi_sum_master.finc"
    3084              : #include "xmpi_sum.finc"
    3085              : #include "xmpi_isum.finc"
    3086              : #include "xmpi_land_lor.finc"
    3087              : 
    3088              : !------------------------------------------------------------------------------------
    3089              : 
    3090              : !!****f* m_xmpi/xmpio_type_struct
    3091              : !! NAME
    3092              : !!  xmpio_type_struct
    3093              : !!
    3094              : !! FUNCTION
    3095              : !!  Some highly non-standard MPI implementations support MPI-IO without
    3096              : !!  implementing the full set of MPI-2 extensions.
    3097              : !!  This wrapper will call the obsolete MPI_TYPE_STRUCT if MPI_TYPE_CREATE_STRUCT
    3098              : !!  is not supported. Note that MPI_TYPE_STRUCT requires the displacement arrays
    3099              : !!  to be an array of default integers whereas the argument block_displ is an array of kind XMPI_ADDRESS_KIND.
    3100              : !!  The routine will abort if the displacement cannot be represented with a default integer.
    3101              : !!
    3102              : !! INPUTS
    3103              : !! ncount= number of blocks (integer) --- also number of entries in arrays
    3104              : !!         array_of_types, array_of_displacements and array_of_blocklengths
    3105              : !! array_of_blocklength(ncount)=number of elements in each block (array of integer)
    3106              : !! array_of_displacements(ncount)=byte displacement of each block (array of integer)
    3107              : !! array_of_types(ncount)=type of elements in each block (array of handles to datatype objects)
    3108              : !!
    3109              : !! OUTPUT
    3110              : !! new_type=new datatype (handle)
    3111              : !! mpierr=MPI status error
    3112              : !!
    3113              : !! SOURCE
    3114              : 
    3115              : #ifdef HAVE_MPI_IO
    3116              : 
    3117          179 : subroutine xmpio_type_struct(ncount, block_length, block_displ, block_type, new_type, mpierr)
    3118              : 
    3119              : !Arguments ------------------------------------
    3120              : !scalars
    3121              :  integer,intent(in) :: ncount
    3122              :  integer,intent(out) :: new_type,mpierr
    3123              : !arrays
    3124              :  integer,intent(in) :: block_length(ncount),block_type(ncount)
    3125              :  integer(XMPI_ADDRESS_KIND),intent(in) :: block_displ(ncount)
    3126              : 
    3127              : !Local variables-------------------
    3128              : #ifndef HAVE_MPI_TYPE_CREATE_STRUCT
    3129              :  integer,allocatable :: tmp_displ(:)
    3130              : #endif
    3131              : !************************************************************************
    3132              : 
    3133              : #ifdef HAVE_MPI_TYPE_CREATE_STRUCT
    3134          174 :  call MPI_TYPE_CREATE_STRUCT(ncount,block_length,block_displ,block_type,new_type,mpierr)
    3135              : #else
    3136              : 
    3137              :  ABI_MALLOC(tmp_displ,(ncount))
    3138              :  tmp_displ = block_displ
    3139              :  if (ANY(block_displ > HUGE(tmp_displ(1)) ))then
    3140              :    call xmpi_abort(msg=" byte displacement cannot be represented with a default integer")
    3141              :  end if
    3142              : 
    3143              :  call MPI_TYPE_STRUCT(ncount,block_length,block_displ,block_type,new_type,mpierr)
    3144              :  ABI_FREE(tmp_displ)
    3145              : #endif
    3146              : 
    3147          174 : end subroutine xmpio_type_struct
    3148              : !!***
    3149              : 
    3150              : #endif
    3151              : 
    3152              : !----------------------------------------------------------------------
    3153              : 
    3154              : !!****f* m_xmpi/xmpio_get_info_frm
    3155              : !! NAME
    3156              : !!  xmpio_marker_info
    3157              : !!
    3158              : !! FUNCTION
    3159              : !!  Return the byte size of the Fortran record and its corresponding MPI_type (compiler-dependent).
    3160              : !!  These two values are needed to access sequential binary Fortran files with MPI/IO routines where
    3161              : !!  C-streams are used.
    3162              : !!
    3163              : !! INPUTS
    3164              : !! comm=MPI communicator. Only master will find the values for the record marker. The results
    3165              : !! are then broadcast to all the other nodes in comm.
    3166              : !!
    3167              : !! OUTPUT
    3168              : !!  bsize_frm=Byte size of the Fortran record marker.
    3169              : !!  mpi_type_frm=MPI type of the marker.
    3170              : !!
    3171              : !! SOURCE
    3172              : 
    3173            0 : subroutine xmpio_get_info_frm(bsize_frm, mpi_type_frm, comm)
    3174              : 
    3175              : !Arguments ------------------------------------
    3176              : !scalars
    3177              :  integer,intent(in) :: comm
    3178              :  integer,intent(out) :: mpi_type_frm,bsize_frm
    3179              : 
    3180              : !Local variables-------------------------------
    3181              :  integer :: my_rank
    3182              : #ifdef HAVE_MPI_IO
    3183              : !scalars
    3184              :  integer,parameter :: master=0
    3185              :  integer :: spt,ept,ii
    3186              :  integer :: f90_unt,iimax,mpio_fh,bsize_int,mpierr
    3187              :  integer(XMPI_OFFSET_KIND) :: offset,rml
    3188              :  character(len=fnlen) :: fname
    3189              :  character(len=500) :: errmsg
    3190              :  logical :: file_exists
    3191              : !arrays
    3192              :  integer :: xvals(2),ivals(100),read_5ivals(5),ref_5ivals(5)
    3193              :  integer :: rm_lengths(4)=(/4,8,2,16/)
    3194              :  integer :: statux(MPI_STATUS_SIZE)
    3195              :  real(dp) :: xrand(fnlen)
    3196              : #endif
    3197              : !************************************************************************
    3198              : 
    3199            0 :  bsize_frm=0; mpi_type_frm=0
    3200              : 
    3201            0 :  my_rank = xmpi_comm_rank(comm) !; RETURN
    3202              : 
    3203              : #ifdef HAVE_MPI_IO
    3204            0 :  if ( my_rank == master ) then
    3205              :    ! Fortran scratch files cannot have a name so have to generate a random one.
    3206              :    ! cannot use pick_aname since it is higher level.
    3207            0 :    fname = "__MPI_IO_FRM__"
    3208            0 :    spt=LEN(trim(fname))+1; ept=spt
    3209              : 
    3210            0 :    inquire(file=trim(fname),exist=file_exists)
    3211              : 
    3212            0 :    do while (file_exists)
    3213            0 :      call RANDOM_NUMBER(xrand(spt:ept))
    3214            0 :      xrand(spt:ept) = 64+xrand(spt:ept)*26
    3215            0 :      do ii=spt,ept
    3216            0 :        fname(ii:ii) = ACHAR(NINT(xrand(ii)))
    3217              :      end do
    3218            0 :      ept = MIN(ept+1,fnlen)
    3219            0 :      inquire(file=trim(fname),exist=file_exists)
    3220              :    end do
    3221              :    !
    3222              :    ! Write five integers on the binary file open in Fortran mode, then try
    3223              :    ! to reread the values with MPI-IO using different offsets for the record marker.
    3224              :    !
    3225            0 :    f90_unt = xmpi_get_unit()
    3226            0 :    if (f90_unt == -1) call xmpi_abort(msg="Cannot find free unit!!")
    3227              :    ! MT dec 2013: suppress the new attribute: often cause unwanted errors
    3228              :    !              and theoretically useless because of the previous inquire
    3229            0 :    open(unit=f90_unt,file=trim(fname),form="unformatted",err=10, iomsg=errmsg)
    3230              : 
    3231            0 :    ref_5ivals = (/(ii, ii=5,9)/)
    3232            0 :    ivals = HUGE(1); ivals(5:9)=ref_5ivals
    3233            0 :    write(f90_unt, err=10, iomsg=errmsg) ivals
    3234            0 :    close(f90_unt, err=10, iomsg=errmsg)
    3235              : 
    3236            0 :    call MPI_FILE_OPEN(xmpi_comm_self, trim(fname), MPI_MODE_RDONLY, MPI_INFO_NULL, mpio_fh,mpierr)
    3237              : 
    3238              :    iimax=3 ! Define number of INTEGER types to be tested
    3239              : #ifdef HAVE_FC_INT_QUAD
    3240            0 :    iimax=4
    3241              : #endif
    3242              :    !
    3243              :    ! Try to read ivals(5:9) from file.
    3244            0 :    ii=0; bsize_frm=-1
    3245            0 :    call MPI_TYPE_SIZE(MPI_INTEGER,bsize_int,mpierr)
    3246              : 
    3247            0 :    do while (bsize_frm<=0 .and. ii<iimax)
    3248            0 :      ii=ii+1
    3249            0 :      rml = rm_lengths(ii)
    3250            0 :      offset = rml + 4 * bsize_int
    3251            0 :      call MPI_FILE_READ_AT(mpio_fh,offset,read_5ivals,5,MPI_INTEGER,statux,mpierr)
    3252              :      !write(std_out,*)read_5ivals
    3253            0 :      if (mpierr==MPI_SUCCESS .and. ALL(read_5ivals==ref_5ivals) ) bsize_frm=rml
    3254              :    end do
    3255              : 
    3256            0 :    if (ii==iimax.and.bsize_frm<=0) then
    3257              :      write(std_out,'(7a)') &
    3258            0 :        'Error during FORTRAN file record marker detection:',ch10,&
    3259            0 :        'It was not possible to read/write a small file!',ch10,&
    3260            0 :        'ACTION: check your access permissions to the file system.',ch10,&
    3261            0 :        'Common sources of this problem: quota limit exceeded, R/W incorrect permissions, ...'
    3262            0 :      call xmpi_abort()
    3263              :    else
    3264              :      !write(std_out,'(a,i0)')' Detected FORTRAN record mark length: ',bsize_frm
    3265              :    end if
    3266              : 
    3267            0 :    call MPI_FILE_CLOSE(mpio_fh, mpierr)
    3268              :    !
    3269              :    ! Select MPI datatype corresponding to the Fortran marker.
    3270            0 :    SELECT CASE (bsize_frm)
    3271              :    CASE (4)
    3272            0 :      mpi_type_frm=MPI_INTEGER4
    3273              :    CASE (8)
    3274            0 :      mpi_type_frm=MPI_INTEGER8
    3275              : #if defined HAVE_FC_INT_QUAD && defined HAVE_MPI_INTEGER16
    3276              :    CASE (16)
    3277            0 :      mpi_type_frm=MPI_INTEGER16
    3278              : #endif
    3279              :    CASE (2)
    3280            0 :      mpi_type_frm=MPI_INTEGER2
    3281              :    CASE DEFAULT
    3282            0 :      write(std_out,'(a,i0)')" Wrong bsize_frm: ",bsize_frm
    3283            0 :      call xmpi_abort()
    3284              :    END SELECT
    3285              : 
    3286            0 :    open(unit=f90_unt,file=trim(fname), err=10, iomsg=errmsg)
    3287            0 :    close(f90_unt,status="delete", err=10, iomsg=errmsg)
    3288              :  end if
    3289              :  !
    3290              :  ! Broadcast data.
    3291            0 :  xvals = (/bsize_frm,mpi_type_frm/)
    3292            0 :  call xmpi_bcast(xvals,master,comm,mpierr)
    3293              : 
    3294            0 :  bsize_frm    = xvals(1)
    3295            0 :  mpi_type_frm = xvals(2)
    3296              : 
    3297            0 :  return
    3298              : 
    3299              : !HANDLE IO ERROR
    3300              : 10 continue
    3301            0 :  call xmpi_abort(msg=errmsg)
    3302              : #endif
    3303              : 
    3304              : end subroutine xmpio_get_info_frm
    3305              : !!***
    3306              : 
    3307              : !----------------------------------------------------------------------
    3308              : 
    3309              : !!****f* m_wffile/xmpio_read_frm
    3310              : !! NAME
    3311              : !!  xmpio_read_frm
    3312              : !!
    3313              : !! FUNCTION
    3314              : !!  Read the content of a single record marker in a FORTRAN file at a given offset using MPI-IO.
    3315              : !!  the file pointer is modified according to the value of advance.
    3316              : !!
    3317              : !! INPUTS
    3318              : !!  fh=MPI-IO file handler.
    3319              : !!  sc_mode=
    3320              : !!    xmpio_single     ==> for reading by current proc.
    3321              : !!    xmpio_collective ==> for collective reading.
    3322              : !!  offset=MPI/IO file pointer
    3323              : !!  [advance]=By default the routine will move the file pointer to the next record.
    3324              : !!    advance=.FALSE. can be used so that the next read will continue picking information
    3325              : !!    off of the currect record.
    3326              : !!
    3327              : !! OUTPUT
    3328              : !!  fmarker=Content of the Fortran record marker.
    3329              : !!  mpierr= MPI error code
    3330              : !!
    3331              : !! SIDE EFFECTS
    3332              : !!  offset=
    3333              : !!     input: file pointer used to access the Fortran marker.
    3334              : !!     output: new offset updated after the reading, depending on advance.
    3335              : !!
    3336              : !! SOURCE
    3337              : 
    3338              : #ifdef HAVE_MPI_IO
    3339              : 
    3340         1042 : subroutine xmpio_read_frm(fh, offset, sc_mode, fmarker, mpierr, advance)
    3341              : 
    3342              : !Arguments ------------------------------------
    3343              : !scalars
    3344              :  integer,intent(in) :: fh,sc_mode
    3345              :  integer(XMPI_OFFSET_KIND),intent(inout) :: offset
    3346              :  integer(XMPI_OFFSET_KIND),intent(out) :: fmarker
    3347              :  integer,intent(out) :: mpierr
    3348              :  logical,optional,intent(in) :: advance
    3349              : 
    3350              : !Local variables-------------------------------
    3351              : !scalars
    3352              :  integer :: bsize_frm,mpi_type_frm,myfh
    3353              :  integer(kind=int16) :: delim_record2(1)
    3354              :  integer(kind=int32) :: delim_record4(1)
    3355              :  integer(kind=int64) :: delim_record8(1)
    3356              : #if defined HAVE_FC_INT_QUAD
    3357              :  integer*16 :: delim_record16(1)
    3358              : #endif
    3359              :  character(len=500) :: msg
    3360              : !arrays
    3361              :  integer :: statux(MPI_STATUS_SIZE)
    3362              : !************************************************************************
    3363              : 
    3364              :  !Workaround for XLF.
    3365         1042 :  myfh = fh
    3366              : 
    3367         1042 :  bsize_frm    = xmpio_bsize_frm    ! Byte size of the Fortran record marker.
    3368         1042 :  mpi_type_frm = xmpio_mpi_type_frm ! MPI type of the record marker.
    3369              : 
    3370         2084 :  SELECT CASE (sc_mode)
    3371              : 
    3372              :  CASE (xmpio_single)
    3373              : 
    3374         1042 :    if (bsize_frm==4) then
    3375         1042 :      call MPI_FILE_READ_AT(myfh,offset,delim_record4,1,mpi_type_frm,statux,mpierr)
    3376         1042 :      fmarker = delim_record4(1)
    3377            0 :    else if (bsize_frm==8) then
    3378            0 :      call MPI_FILE_READ_AT(myfh,offset,delim_record8,1,mpi_type_frm,statux,mpierr)
    3379            0 :      fmarker = delim_record8(1)
    3380              : #if defined HAVE_FC_INT_QUAD
    3381            0 :    else if (bsize_frm==16) then
    3382            0 :      call MPI_FILE_READ_AT(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr)
    3383            0 :      fmarker = delim_record16(1)
    3384              : #endif
    3385            0 :    else if (bsize_frm==2) then
    3386            0 :      call MPI_FILE_READ_AT(myfh,offset,delim_record2,1,mpi_type_frm,statux,mpierr)
    3387            0 :      fmarker = delim_record2(1)
    3388              :    else
    3389            0 :      call xmpi_abort(msg='Wrong record marker length!')
    3390              :    end if
    3391              : 
    3392              :  CASE (xmpio_collective)
    3393              : 
    3394            0 :    if (bsize_frm==4) then
    3395            0 :      call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record4,1,mpi_type_frm,statux,mpierr)
    3396            0 :      fmarker = delim_record4(1)
    3397            0 :    else if (bsize_frm==8) then
    3398            0 :      call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record8,1,mpi_type_frm,statux,mpierr)
    3399            0 :      fmarker = delim_record8(1)
    3400              : #if defined HAVE_FC_INT_QUAD
    3401            0 :    else if (bsize_frm==16) then
    3402            0 :      call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record16,1,mpi_type_frm,statux,mpierr)
    3403            0 :      fmarker = delim_record16(1)
    3404              : #endif
    3405            0 :    else if (bsize_frm==2) then
    3406            0 :      call MPI_FILE_READ_AT_ALL(myfh,offset,delim_record2,1,mpi_type_frm,statux,mpierr)
    3407            0 :      fmarker = delim_record2(1)
    3408              :    else
    3409            0 :      call xmpi_abort(msg='Wrong record marker length!')
    3410              :    end if
    3411              : 
    3412              :  CASE DEFAULT
    3413            0 :    write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode
    3414         1042 :    call xmpi_abort(msg=msg)
    3415              :  END SELECT
    3416              : 
    3417         1042 :  if (PRESENT(advance)) then
    3418            0 :    if (advance) then
    3419            0 :      offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record.
    3420              :    else
    3421            0 :      offset = offset + bsize_frm  ! Move the pointer after the marker.
    3422              :    end if
    3423              :  else
    3424         1042 :    offset = offset + fmarker + 2*bsize_frm
    3425              :  end if
    3426              : 
    3427         1042 : end subroutine xmpio_read_frm
    3428              : !!***
    3429              : 
    3430              : #endif
    3431              : 
    3432              : !------------------------------------------------------------------------------------
    3433              : 
    3434              : !!****f* m_wffile/xmpio_write_frm
    3435              : !! NAME
    3436              : !!  xmpio_write_frm
    3437              : !!
    3438              : !! FUNCTION
    3439              : !!  Write a single record marker in a FORTRAN file at a given offset using MPI-IO.
    3440              : !!  The file pointer is modified according to the value of advance.
    3441              : !!
    3442              : !! INPUTS
    3443              : !!  fh=MPI-IO file handler.
    3444              : !!  sc_mode=
    3445              : !!         xmpio_single     ==> for reading by current proc.
    3446              : !!         xmpio_collective ==> for collective reading.
    3447              : !!  fmarker=The content of the Fortran marker i.e. the size of the record in bytes.
    3448              : !!  [advance]=By default the routine will move the file pointer to the next record.
    3449              : !!    advance=.FALSE. can be used so that the next write will continue writing data
    3450              : !!    on the currect record.
    3451              : !!
    3452              : !! OUTPUT
    3453              : !!  mpierr= error code
    3454              : !!
    3455              : !! SIDE EFFECTS
    3456              : !!  offset=
    3457              : !!     input: offset of  the Fortran marker.
    3458              : !!     output: new offset updated after the writing, depending on advance.
    3459              : !!
    3460              : !! SOURCE
    3461              : 
    3462              : #ifdef HAVE_MPI_IO
    3463              : 
    3464          111 : subroutine xmpio_write_frm(fh, offset, sc_mode, fmarker, mpierr, advance)
    3465              : 
    3466              : !Arguments ------------------------------------
    3467              : !scalars
    3468              :  integer,intent(in) :: fh,sc_mode
    3469              :  integer(XMPI_OFFSET_KIND),intent(in) :: fmarker
    3470              :  integer(XMPI_OFFSET_KIND),intent(inout) :: offset
    3471              :  integer,intent(out) :: mpierr
    3472              :  logical,optional,intent(in) :: advance
    3473              : 
    3474              : !Local variables-------------------------------
    3475              : !scalars
    3476              :  integer :: myfh,bsize_frm,mpi_type_frm
    3477              :  integer(XMPI_OFFSET_KIND) :: last
    3478              :  integer(kind=int16)  :: delim_record2
    3479              :  integer(kind=int32)  :: delim_record4
    3480              :  integer(kind=int64)  :: delim_record8
    3481              : #if defined HAVE_FC_INT_QUAD
    3482              :  integer*16 :: delim_record16
    3483              : #endif
    3484              :  character(len=500) :: msg
    3485              : !arrays
    3486              :  integer :: statux(MPI_STATUS_SIZE)
    3487              : !************************************************************************
    3488              : 
    3489              :  ! Workaround for XLF
    3490          111 :  myfh = fh
    3491              : 
    3492          111 :  bsize_frm    = xmpio_bsize_frm      ! Byte size of the Fortran record marker.
    3493          111 :  mpi_type_frm = xmpio_mpi_type_frm   ! MPI type of the record marker.
    3494          111 :  last = offset + bsize_frm + fmarker ! position of the end marker
    3495              : 
    3496          222 :  SELECT CASE (sc_mode)
    3497              : 
    3498              :  CASE (xmpio_single)
    3499          111 :    if (bsize_frm==4) then
    3500          111 :      delim_record4 = fmarker
    3501          222 :      call MPI_FILE_WRITE_AT(myfh,offset,[delim_record4],1,mpi_type_frm,statux,mpierr)
    3502          222 :      call MPI_FILE_WRITE_AT(myfh,last,[delim_record4],1,mpi_type_frm,statux,mpierr)
    3503              : 
    3504            0 :    else if (bsize_frm==8) then
    3505            0 :      delim_record8 = fmarker
    3506            0 :      call MPI_FILE_WRITE_AT(myfh,offset,[delim_record8],1,mpi_type_frm,statux,mpierr)
    3507            0 :      call MPI_FILE_WRITE_AT(myfh,last,[delim_record8],1,mpi_type_frm,statux,mpierr)
    3508              : #if defined HAVE_FC_INT_QUAD
    3509            0 :    else if (bsize_frm==16) then
    3510            0 :      delim_record16 = fmarker
    3511            0 :      call MPI_FILE_WRITE_AT(myfh,offset,[delim_record16],1,mpi_type_frm,statux,mpierr)
    3512            0 :      call MPI_FILE_WRITE_AT(myfh,last,[delim_record16],1,mpi_type_frm,statux,mpierr)
    3513              : #endif
    3514            0 :    else if (bsize_frm==2) then
    3515            0 :      delim_record2 = fmarker
    3516            0 :      call MPI_FILE_WRITE_AT(myfh,offset,[delim_record2], 1,mpi_type_frm,statux,mpierr)
    3517            0 :      call MPI_FILE_WRITE_AT(myfh,last,[delim_record2],1,mpi_type_frm,statux,mpierr)
    3518              :    else
    3519            0 :      call xmpi_abort(msg='Wrong record marker length!')
    3520              :    end if
    3521              : 
    3522              :  CASE (xmpio_collective)
    3523            0 :    if (bsize_frm==4) then
    3524            0 :      delim_record4 = fmarker
    3525            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,offset,[delim_record4],1,mpi_type_frm,statux,mpierr)
    3526            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,last,[delim_record4],1,mpi_type_frm,statux,mpierr)
    3527            0 :    else if (bsize_frm==8) then
    3528            0 :      delim_record8 = fmarker
    3529            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,offset,[delim_record8],1,mpi_type_frm,statux,mpierr)
    3530            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,last,[delim_record8],1,mpi_type_frm,statux,mpierr)
    3531              : #if defined HAVE_FC_INT_QUAD
    3532            0 :    else if (bsize_frm==16) then
    3533            0 :      delim_record16 = fmarker
    3534            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,offset,[delim_record16],1,mpi_type_frm,statux,mpierr)
    3535            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,last,[delim_record16],1,mpi_type_frm,statux,mpierr)
    3536              : #endif
    3537            0 :    else if (bsize_frm==2) then
    3538            0 :      delim_record2 = fmarker
    3539            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,offset,[delim_record2],1,mpi_type_frm,statux,mpierr)
    3540            0 :      call MPI_FILE_WRITE_AT_ALL(myfh,last,[delim_record2],1,mpi_type_frm,statux,mpierr)
    3541              :    else
    3542            0 :      call xmpi_abort(msg='Wrong record marker length!')
    3543              :    end if
    3544              : 
    3545              :  CASE DEFAULT
    3546            0 :    write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode
    3547          111 :    call xmpi_abort(msg=msg)
    3548              :  END SELECT
    3549              : 
    3550          111 :  if (PRESENT(advance)) then
    3551            0 :    if (advance) then
    3552            0 :      offset = offset + fmarker + 2*bsize_frm  ! Move the file pointer to the next record.
    3553              :    else
    3554            0 :      offset = offset + bsize_frm              ! Move the pointer after the marker.
    3555              :    end if
    3556              :  else
    3557          111 :    offset = offset + fmarker + 2*bsize_frm
    3558              :  end if
    3559              : 
    3560          111 : end subroutine xmpio_write_frm
    3561              : !!***
    3562              : #endif
    3563              : 
    3564              : !------------------------------------------------------------------------------------
    3565              : 
    3566              : !!****f* m_xmpi/xmpio_create_fstripes
    3567              : !! NAME
    3568              : !!  xmpio_create_fstripes
    3569              : !!
    3570              : !! FUNCTION
    3571              : !!  Return a MPI type that can be used to (read|write) a set of interleaved Fortran records.
    3572              : !!
    3573              : !!  <FRM> type(1), type(1), ... <FRM>  ! size(1) elements
    3574              : !!  <FRM> type(2), type(2), ... <FRM>  ! size(2) elements
    3575              : !!  <FRM> type(1), type(1), ... <FRM>  ! size(1) elements
    3576              : !!  ....
    3577              : !!
    3578              : !! INPUTS
    3579              : !!  ncount = Number of records with elements of type types(1) to (read|write)
    3580              : !!  sizes(1:2) = Number of elements of each type in the two sets of record
    3581              : !!  type(1:2) = MPI Type of the elements in the first and in the second record.
    3582              : !!
    3583              : !! OUTPUT
    3584              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    3585              : !!    marker individuating the beginning of the matrix. (lets call it "base").
    3586              : !!    Each node should (read|write) using my_offset = base + my_offpad.
    3587              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    3588              : !!    to make it more efficient) without having to change the client code.
    3589              : !!  new_type=New MPI type.
    3590              : !!  mpierr= MPI error code
    3591              : !!
    3592              : !! SOURCE
    3593              : 
    3594              : #ifdef HAVE_MPI_IO
    3595              : 
    3596            0 : subroutine xmpio_create_fstripes(ncount, sizes, types, new_type, my_offpad, mpierr)
    3597              : 
    3598              : !Arguments ------------------------------------
    3599              : !scalars
    3600              :  integer,intent(in) :: ncount
    3601              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    3602              :  integer,intent(out) :: new_type,mpierr
    3603              : !arrays
    3604              :  integer,intent(in) :: types(2),sizes(2)
    3605              : 
    3606              : !Local variables-------------------------------
    3607              : !scalars
    3608              :  integer :: type_x,type_y,bsize_frm,bsize_x,bsize_y,nx,ny,column_type
    3609              :  integer(MPI_ADDRESS_KIND) :: stride
    3610              : !************************************************************************
    3611              : 
    3612              :  ! Byte size of the Fortran record marker.
    3613            0 :  bsize_frm = xmpio_bsize_frm
    3614              : 
    3615              :  ! Number of elements in the two stripes.
    3616            0 :  nx = sizes(1)
    3617            0 :  ny = sizes(2)
    3618              : 
    3619            0 :  type_x = types(1)
    3620            0 :  type_y = types(2)
    3621              : 
    3622              :  ! Byte size of type_x and type_y
    3623            0 :  call MPI_TYPE_SIZE(type_x,bsize_x,mpierr)
    3624            0 :  ABI_HANDLE_MPIERR(mpierr)
    3625              : 
    3626            0 :  call MPI_TYPE_SIZE(type_y,bsize_y,mpierr)
    3627            0 :  ABI_HANDLE_MPIERR(mpierr)
    3628              : 
    3629              :  ! The view starts at the first element of the first stripe.
    3630            0 :  my_offpad = xmpio_bsize_frm
    3631              : 
    3632            0 :  call MPI_Type_contiguous(nx,type_x,column_type,mpierr)
    3633            0 :  ABI_HANDLE_MPIERR(mpierr)
    3634              : 
    3635              :  ! Byte size of the Fortran record + the two markers.
    3636            0 :  stride = nx*bsize_x + 2*bsize_frm  + ny*bsize_y + 2*bsize_frm
    3637              : 
    3638              :  ! ncount colum_type separated by stride bytes
    3639            0 :  if (ncount>0) then
    3640            0 :    call MPI_Type_create_hvector(ncount,1,stride,column_type,new_type,mpierr)
    3641              :  else
    3642            0 :    call MPI_Type_create_hvector(1,1,stride,column_type,new_type,mpierr)
    3643              :  end if
    3644            0 :  ABI_HANDLE_MPIERR(mpierr)
    3645              : 
    3646            0 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    3647            0 :  ABI_HANDLE_MPIERR(mpierr)
    3648              : 
    3649            0 :  call MPI_TYPE_FREE(column_type,mpierr)
    3650            0 :  ABI_HANDLE_MPIERR(mpierr)
    3651              : 
    3652              : end subroutine xmpio_create_fstripes
    3653              : !!***
    3654              : #endif
    3655              : 
    3656              : !------------------------------------------------------------------------------------
    3657              : 
    3658              : !!****f* m_xmpi/xmpio_create_fsubarray_2D
    3659              : !! NAME
    3660              : !!  xmpio_create_fsubarray_2D
    3661              : !!
    3662              : !! FUNCTION
    3663              : !!  Return a MPI type that can be used to (read|write) a 2D matrix of elements of type old_type stored in a Fortran file.
    3664              : !!
    3665              : !! INPUTS
    3666              : !!  sizes(2)=number of elements of type old_type in each dimension of the full array (array of positive integers)
    3667              : !!  subsizes(2)=number of elements of type old_type in each dimension of the subarray (array of positive integers)
    3668              : !!  array_of_starts(2)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes)
    3669              : !!  old_type=Old MPI type.
    3670              : !!
    3671              : !! OUTPUT
    3672              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    3673              : !!    marker individuating the beginning of the matrix. (lets call it "base").
    3674              : !!    Each node should (read|write) using my_offset = base + my_offpad.
    3675              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    3676              : !!    to make it more efficient) without having to change the client code.
    3677              : !!  new_type=New MPI type.
    3678              : !!  mpierr= MPI error code
    3679              : !!
    3680              : !! SOURCE
    3681              : 
    3682              : #ifdef HAVE_MPI_IO
    3683              : 
    3684           30 : subroutine xmpio_create_fsubarray_2D(sizes, subsizes, array_of_starts, old_type, new_type, my_offpad, mpierr)
    3685              : 
    3686              : !Arguments ------------------------------------
    3687              : !scalars
    3688              :  integer,intent(in) :: old_type
    3689              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    3690              :  integer,intent(out) :: mpierr,new_type
    3691              : !arrays
    3692              :  integer,intent(in) :: sizes(2),subsizes(2),array_of_starts(2)
    3693              : !Local variables-------------------------------
    3694              : !scalars
    3695              :  integer :: bsize_frm,bsize_old,nx,ny,column_type,ldx
    3696              :  integer(XMPI_OFFSET_KIND) :: st_x,st_y
    3697              :  integer(MPI_ADDRESS_KIND) :: stride_x
    3698              :  !character(len=500) :: msg
    3699              : !************************************************************************
    3700              : 
    3701              :  ! Byte size of the Fortran record marker.
    3702           30 :  bsize_frm = xmpio_bsize_frm
    3703              : 
    3704              :  ! Byte size of old_type.
    3705           30 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    3706           30 :  ABI_HANDLE_MPIERR(mpierr)
    3707              :  !
    3708              :  ! Number of columns and rows of the submatrix.
    3709           30 :  nx = subsizes(1)
    3710           30 :  ny = subsizes(2)
    3711              : 
    3712           30 :  ldx = sizes(1)
    3713           30 :  st_x = array_of_starts(1)
    3714           30 :  st_y = array_of_starts(2)
    3715              : 
    3716              :  ! The view starts at the first element of the submatrix.
    3717           30 :  my_offpad = (st_x-1)*bsize_old + (st_y-1)*(ldx*bsize_old+2*xmpio_bsize_frm) + xmpio_bsize_frm
    3718              : 
    3719              :  ! Byte size of the Fortran record + the two markers.
    3720           30 :  stride_x = ldx*bsize_old + 2*bsize_frm
    3721              : 
    3722           30 :  call MPI_Type_contiguous(nx,old_type,column_type,mpierr)
    3723           30 :  ABI_HANDLE_MPIERR(mpierr)
    3724              : 
    3725           30 :  call MPI_Type_create_hvector(ny,1,stride_x,column_type,new_type,mpierr)
    3726           30 :  ABI_HANDLE_MPIERR(mpierr)
    3727              : 
    3728           30 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    3729           30 :  ABI_HANDLE_MPIERR(mpierr)
    3730              : 
    3731           30 :  call MPI_TYPE_FREE(column_type, mpierr)
    3732           30 :  ABI_HANDLE_MPIERR(mpierr)
    3733              : 
    3734              : end subroutine xmpio_create_fsubarray_2D
    3735              : !!***
    3736              : #endif
    3737              : 
    3738              : !------------------------------------------------------------------------------------
    3739              : 
    3740              : !!****f* m_xmpi/xmpio_create_fsubarray_3D
    3741              : !! NAME
    3742              : !!  xmpio_create_fsubarray_3D
    3743              : !!
    3744              : !! FUNCTION
    3745              : !!  Return a MPI type that can be used to (read|write) a 3D matrix of elements of type old_type stored in a Fortran file.
    3746              : !!
    3747              : !! INPUTS
    3748              : !!  sizes(3)=number of elements of type old_type in each dimension of the full array (array of positive integers)
    3749              : !!  subsizes(3)=number of elements of type old_type in each dimension of the subarray (array of positive integers)
    3750              : !!  array_of_starts(3)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes)
    3751              : !!  old_type=Old MPI type.
    3752              : !!
    3753              : !! OUTPUT
    3754              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    3755              : !!    marker individuating the beginning of the matrix. (lets call it "base").
    3756              : !!    Each node should (read|write) using my_offset = base + my_offpad.
    3757              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    3758              : !!    to make it more efficient) without having to change the client code.
    3759              : !!  new_type=New MPI type.
    3760              : !!  mpierr= MPI error code
    3761              : !!
    3762              : !! SOURCE
    3763              : 
    3764              : #ifdef HAVE_MPI_IO
    3765              : 
    3766            0 : subroutine xmpio_create_fsubarray_3D(sizes, subsizes, array_of_starts, old_type, new_type, my_offpad, mpierr)
    3767              : 
    3768              : !Arguments ------------------------------------
    3769              : !scalars
    3770              :  integer,intent(in) :: old_type
    3771              :  integer,intent(out) :: mpierr,new_type
    3772              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    3773              : !arrays
    3774              :  integer,intent(in) :: sizes(3),subsizes(3),array_of_starts(3)
    3775              : !Local variables-------------------------------
    3776              : !scalars
    3777              :  integer :: bsize_frm,bsize_old,nx,ny,nz
    3778              :  integer :: column_type,plane_type,ldx,ldy,ldz
    3779              :  integer(XMPI_OFFSET_KIND) :: st_x,st_y,st_z
    3780              :  integer(MPI_ADDRESS_KIND) :: stride_x
    3781              :  !character(len=500) :: msg
    3782              : !************************************************************************
    3783              : 
    3784            0 :  bsize_frm = xmpio_bsize_frm    ! Byte size of the Fortran record marker.
    3785              : 
    3786              :  ! Byte size of old_type.
    3787            0 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    3788            0 :  ABI_HANDLE_MPIERR(mpierr)
    3789              :  !
    3790              :  ! Number of columns and rows of the submatrix.
    3791            0 :  nx = subsizes(1)
    3792            0 :  ny = subsizes(2)
    3793            0 :  nz = subsizes(3)
    3794              : 
    3795            0 :  ldx = sizes(1)
    3796            0 :  ldy = sizes(2)
    3797            0 :  ldz = sizes(3)
    3798              : 
    3799            0 :  st_x = array_of_starts(1)
    3800            0 :  st_y = array_of_starts(2)
    3801            0 :  st_z = array_of_starts(3)
    3802              : 
    3803              :  ! The view starts at the first element of the submatrix.
    3804              :  my_offpad = (st_x-1)*bsize_old + &
    3805              :              (st_y-1)*    (ldx*bsize_old+2*xmpio_bsize_frm) + &
    3806              :              (st_z-1)*ldy*(ldx*bsize_old+2*xmpio_bsize_frm) + &
    3807            0 :               xmpio_bsize_frm
    3808              : 
    3809              :  ! Byte size of the Fortran record + the two markers.
    3810            0 :  stride_x = ldx*bsize_old + 2*bsize_frm
    3811              : 
    3812            0 :  call MPI_Type_contiguous(nx,old_type,column_type,mpierr)
    3813            0 :  ABI_HANDLE_MPIERR(mpierr)
    3814              : 
    3815            0 :  call MPI_Type_create_hvector(ny,1,stride_x,column_type,plane_type,mpierr)
    3816            0 :  ABI_HANDLE_MPIERR(mpierr)
    3817              : 
    3818            0 :  call MPI_Type_create_hvector(nz,1,ldy*stride_x,plane_type,new_type,mpierr)
    3819            0 :  ABI_HANDLE_MPIERR(mpierr)
    3820              : 
    3821              :  ! Commit the datatype
    3822            0 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    3823            0 :  ABI_HANDLE_MPIERR(mpierr)
    3824              : 
    3825              :  ! Free memory
    3826            0 :  call MPI_TYPE_FREE(plane_type, mpierr)
    3827            0 :  ABI_HANDLE_MPIERR(mpierr)
    3828              : 
    3829              : end subroutine xmpio_create_fsubarray_3D
    3830              : !!***
    3831              : #endif
    3832              : 
    3833              : !------------------------------------------------------------------------------------
    3834              : 
    3835              : !!****f* m_xmpi/xmpio_create_fsubarray_4D
    3836              : !! NAME
    3837              : !!  xmpio_create_fsubarray_4D
    3838              : !!
    3839              : !! FUNCTION
    3840              : !!  Return a MPI type that can be used to (read|write) a 2D matrix of elements of type old_type stored in a Fortran file.
    3841              : !!
    3842              : !! INPUTS
    3843              : !!  sizes(4)=number of elements of type old_type in each dimension of the full array (array of positive integers)
    3844              : !!  subsizes(4)=number of elements of type old_type in each dimension of the subarray (array of positive integers)
    3845              : !!  array_of_starts(4)=starting coordinates of the subarray in each dimension (array of nonnegative integers >=1, <=sizes)
    3846              : !!  old_type=Old MPI type.
    3847              : !!
    3848              : !! OUTPUT
    3849              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    3850              : !!    marker individuating the beginning of the matrix. (lets call it "base").
    3851              : !!    Each node should (read|write) using my_offset = base + my_offpad.
    3852              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    3853              : !!    to make it more efficient) without having to change the client code.
    3854              : !!  new_type=New MPI type.
    3855              : !!  mpierr= MPI error code
    3856              : !!
    3857              : !! SOURCE
    3858              : 
    3859              : #ifdef HAVE_MPI_IO
    3860              : 
    3861            0 : subroutine xmpio_create_fsubarray_4D(sizes, subsizes, array_of_starts, old_type, new_type, my_offpad, mpierr)
    3862              : 
    3863              : !Arguments ------------------------------------
    3864              : !scalars
    3865              :  integer,intent(in) :: old_type
    3866              :  integer,intent(out) :: mpierr,new_type
    3867              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    3868              : !arrays
    3869              :  integer,intent(in) :: sizes(4),subsizes(4),array_of_starts(4)
    3870              : 
    3871              : !Local variables-------------------------------
    3872              : !scalars
    3873              :  integer :: bsize_frm,bsize_old,nx,ny,nz,na
    3874              :  integer :: column_type,plane_type,ldx,ldy,ldz,lda,vol_type
    3875              :  integer(XMPI_OFFSET_KIND) :: st_x,st_y,st_z,st_a
    3876              :  integer(MPI_ADDRESS_KIND) :: stride_x
    3877              : !************************************************************************
    3878              : 
    3879            0 :  bsize_frm = xmpio_bsize_frm    ! Byte size of the Fortran record marker.
    3880              : 
    3881              :  ! Byte size of old_type.
    3882            0 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    3883            0 :  ABI_HANDLE_MPIERR(mpierr)
    3884              :  !
    3885              :  ! Number of columns and rows of the submatrix.
    3886            0 :  nx = subsizes(1)
    3887            0 :  ny = subsizes(2)
    3888            0 :  nz = subsizes(3)
    3889            0 :  na = subsizes(4)
    3890              : 
    3891            0 :  ldx = sizes(1)
    3892            0 :  ldy = sizes(2)
    3893            0 :  ldz = sizes(3)
    3894            0 :  lda = sizes(4)
    3895              : 
    3896            0 :  st_x = array_of_starts(1)
    3897            0 :  st_y = array_of_starts(2)
    3898            0 :  st_z = array_of_starts(3)
    3899            0 :  st_a = array_of_starts(4)
    3900              : 
    3901              :  ! The view starts at the first element of the submatrix.
    3902              :  my_offpad = (st_x-1)*bsize_old + &
    3903              :              (st_y-1)*        (ldx*bsize_old+2*xmpio_bsize_frm) + &
    3904              :              (st_z-1)*ldy*    (ldx*bsize_old+2*xmpio_bsize_frm) + &
    3905              :              (st_a-1)*lda*ldy*(ldx*bsize_old+2*xmpio_bsize_frm) + &
    3906            0 :              xmpio_bsize_frm
    3907              : 
    3908              :  ! Byte size of the Fortran record + the two markers.
    3909            0 :  stride_x = ldx*bsize_old + 2*bsize_frm
    3910              : 
    3911            0 :  call MPI_Type_contiguous(nx,old_type,column_type,mpierr)
    3912            0 :  ABI_HANDLE_MPIERR(mpierr)
    3913              : 
    3914            0 :  call MPI_Type_create_hvector(ny,1,stride_x,column_type,plane_type,mpierr)
    3915            0 :  ABI_HANDLE_MPIERR(mpierr)
    3916              : 
    3917            0 :  call MPI_Type_create_hvector(nz,1,ldy*stride_x,plane_type,vol_type,mpierr)
    3918            0 :  ABI_HANDLE_MPIERR(mpierr)
    3919              : 
    3920            0 :  call MPI_Type_create_hvector(na,1,ldz*ldy*stride_x,vol_type,new_type,mpierr)
    3921            0 :  ABI_HANDLE_MPIERR(mpierr)
    3922              : 
    3923              :  ! Commit the datatype
    3924            0 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    3925            0 :  ABI_HANDLE_MPIERR(mpierr)
    3926              : 
    3927              :  ! Free memory
    3928            0 :  call MPI_TYPE_FREE(column_type, mpierr)
    3929            0 :  ABI_HANDLE_MPIERR(mpierr)
    3930              : 
    3931            0 :  call MPI_TYPE_FREE(plane_type, mpierr)
    3932            0 :  ABI_HANDLE_MPIERR(mpierr)
    3933              : 
    3934            0 :  call MPI_TYPE_FREE(vol_type, mpierr)
    3935            0 :  ABI_HANDLE_MPIERR(mpierr)
    3936              : 
    3937              : end subroutine xmpio_create_fsubarray_4D
    3938              : !!***
    3939              : #endif
    3940              : 
    3941              : !------------------------------------------------------------------------------------
    3942              : 
    3943              : !!****f* m_xmpi/xmpio_check_frmarkers
    3944              : !! NAME
    3945              : !!  xmpio_check_frmarkers
    3946              : !!
    3947              : !! FUNCTION
    3948              : !!  Check a set of Fortran record markers starting at a given offset using MPI-IO.
    3949              : !!
    3950              : !! INPUTS
    3951              : !!  fh=MPI-IO file handler.
    3952              : !!  offset=MPI-IO file pointer
    3953              : !!  sc_mode=Option for individual or collective reading.
    3954              : !!  nfrec=Number of Fortran records to be checked.
    3955              : !!  bsize_frecord(nfrec)=Byte size of the Fortran records (markers are NOT included)
    3956              : !!    These values will be compared with the markers reported in the file.
    3957              : !!
    3958              : !! OUTPUT
    3959              : !!  ierr=A non-zero error code signals failure.
    3960              : !!
    3961              : !! SOURCE
    3962              : 
    3963              : #ifdef HAVE_MPI_IO
    3964              : 
    3965            0 : subroutine xmpio_check_frmarkers(fh, offset, sc_mode, nfrec, bsize_frecord, ierr)
    3966              : 
    3967              : !Arguments ------------------------------------
    3968              : !scalars
    3969              :  integer,intent(in) :: fh,nfrec,sc_mode
    3970              :  integer(XMPI_OFFSET_KIND),intent(in) :: offset
    3971              :  integer,intent(out) :: ierr
    3972              : !arrays
    3973              :  integer(XMPI_OFFSET_KIND),intent(in) :: bsize_frecord(nfrec)
    3974              : 
    3975              : !Local variables-------------------------------
    3976              : !scalars
    3977              :  integer :: nb,irec,frmarkers_type,jj,bsize_frm,mpi_type_frm,mpierr,myfh
    3978              :  integer(XMPI_OFFSET_KIND) :: displ
    3979              : !arrays
    3980            0 :  integer(kind=int16),allocatable :: bufdelim2(:)
    3981            0 :  integer(kind=int32),allocatable :: bufdelim4(:)
    3982            0 :  integer(kind=int64),allocatable :: bufdelim8(:)
    3983              : #ifdef HAVE_FC_INT_QUAD
    3984            0 :  integer*16,allocatable :: bufdelim16(:)
    3985              : #endif
    3986              : !integer :: statux(MPI_STATUS_SIZE)
    3987            0 :  integer,allocatable :: block_length(:),block_type(:)
    3988            0 :  integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
    3989            0 :  integer(XMPI_OFFSET_KIND),allocatable :: delim_record(:)
    3990              : !************************************************************************
    3991              : 
    3992              :  ! Workaround for XLF
    3993            0 :  myfh = fh
    3994            0 :  ierr=0
    3995              : 
    3996            0 :  bsize_frm    = xmpio_bsize_frm     ! Byte size of the Fortran record marker.
    3997            0 :  mpi_type_frm = xmpio_mpi_type_frm  ! MPI type of the record marker.
    3998              : 
    3999              :  ! Define the view for the file.
    4000            0 :  nb=2*nfrec
    4001            0 :  ABI_MALLOC(block_length,(nb+2))
    4002            0 :  ABI_MALLOC(block_displ,(nb+2))
    4003            0 :  ABI_MALLOC(block_type,(nb+2))
    4004            0 :  block_length(1)=1
    4005            0 :  block_displ (1)=0
    4006            0 :  block_type  (1)=MPI_LB
    4007              : 
    4008            0 :  jj=2; displ=0
    4009            0 :  do irec=1,nfrec
    4010            0 :    block_type (jj:jj+1) =mpi_type_frm
    4011            0 :    block_length(jj:jj+1)=1
    4012            0 :    block_displ(jj  )     = displ
    4013            0 :    block_displ(jj+1)     = bsize_frm + displ + bsize_frecord(irec)
    4014            0 :    jj=jj+2
    4015            0 :    displ = displ + bsize_frecord(irec) + 2*bsize_frm ! Move to the beginning of the next column.
    4016            0 :    if (xmpio_max_address(displ)) ierr=-1  ! Check for wraparound.
    4017              :  end do
    4018              : 
    4019            0 :  block_length(nb+2)=1
    4020            0 :  block_displ (nb+2)=displ
    4021            0 :  block_type  (nb+2)=MPI_UB
    4022              : 
    4023            0 :  call xmpio_type_struct(nb+2,block_length,block_displ,block_type,frmarkers_type,mpierr)
    4024            0 :  ABI_FREE(block_length)
    4025            0 :  ABI_FREE(block_displ)
    4026            0 :  ABI_FREE(block_type)
    4027              : 
    4028            0 :  call MPI_TYPE_COMMIT(frmarkers_type,mpierr)
    4029            0 :  call MPI_FILE_SET_VIEW(myfh,offset,MPI_BYTE,frmarkers_type,"native",MPI_INFO_NULL,mpierr)
    4030              : 
    4031            0 :  jj=1
    4032            0 :  ABI_MALLOC(delim_record,(nb))
    4033            0 :  do irec=1,nfrec
    4034            0 :    delim_record(jj:jj+1)=bsize_frecord(irec)
    4035            0 :    jj=jj+2
    4036              :  end do
    4037              : 
    4038              :  ! Read markers according to the MPI type of the Fortran marker.
    4039            0 :  SELECT CASE (bsize_frm)
    4040              : 
    4041              :  CASE (4)
    4042            0 :    ABI_MALLOC(bufdelim4,(nb))
    4043            0 :    if (sc_mode==xmpio_single) then
    4044            0 :      call MPI_FILE_READ    (myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4045            0 :    else if (sc_mode==xmpio_collective) then
    4046            0 :      call MPI_FILE_READ_ALL(myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4047              :    else
    4048            0 :      ierr=2
    4049              :    end if
    4050            0 :    if (ANY(bufdelim4/=delim_record)) ierr=1
    4051            0 :    if (ierr==1) then
    4052            0 :      do irec=1,2*nfrec
    4053            0 :        write(std_out,*)"irec, bufdelim4, delim_record: ",irec,bufdelim4(irec),delim_record(irec)
    4054              :      end do
    4055              :    end if
    4056            0 :    ABI_FREE(bufdelim4)
    4057              : 
    4058              :  CASE (8)
    4059            0 :    ABI_MALLOC(bufdelim8,(nb))
    4060            0 :    if (sc_mode==xmpio_single) then
    4061            0 :      call MPI_FILE_READ    (myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4062            0 :    else if (sc_mode==xmpio_collective) then
    4063            0 :      call MPI_FILE_READ_ALL(myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4064              :    else
    4065            0 :      ierr=2
    4066              :    end if
    4067            0 :    if (ANY(bufdelim8/=delim_record)) ierr=1
    4068            0 :    ABI_FREE(bufdelim8)
    4069              : 
    4070              : #ifdef HAVE_FC_INT_QUAD
    4071              :  CASE (16)
    4072            0 :    ABI_MALLOC(bufdelim16,(nb))
    4073            0 :    if (sc_mode==xmpio_single) then
    4074            0 :      call MPI_FILE_READ    (myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4075            0 :    else if (sc_mode==xmpio_collective) then
    4076            0 :      call MPI_FILE_READ_ALL(myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4077              :    else
    4078            0 :      ierr=2
    4079              :    end if
    4080            0 :    if (ANY(bufdelim16/=delim_record)) ierr=1
    4081            0 :    ABI_FREE(bufdelim16)
    4082              : #endif
    4083              : 
    4084              :  CASE (2)
    4085            0 :    ABI_MALLOC(bufdelim2,(nb))
    4086            0 :    if (sc_mode==xmpio_single) then
    4087            0 :      call MPI_FILE_READ    (myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4088            0 :    else if (sc_mode==xmpio_collective) then
    4089            0 :      call MPI_FILE_READ_ALL(myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4090              :    else
    4091            0 :      ierr=2
    4092              :    end if
    4093            0 :    if (ANY(bufdelim2/=delim_record)) ierr=1
    4094            0 :    ABI_FREE(bufdelim2)
    4095              : 
    4096              :  CASE DEFAULT
    4097            0 :    ierr=-2
    4098              :  END SELECT
    4099              : 
    4100              :  ! Free memory
    4101            0 :  call MPI_TYPE_FREE(frmarkers_type,mpierr)
    4102            0 :  ABI_FREE(delim_record)
    4103              : 
    4104            0 : end subroutine xmpio_check_frmarkers
    4105              : !!***
    4106              : #endif
    4107              : 
    4108              : !----------------------------------------------------------------------
    4109              : 
    4110              : !!****f* m_xmpi/xmpio_read_int
    4111              : !! NAME
    4112              : !!  xmpio_read_int
    4113              : !!
    4114              : !! FUNCTION
    4115              : !!  Read the content of a single record marker in a FORTRAN file at a given offset using MPI-IO.
    4116              : !!  the file pointer is modified according to the value of advance.
    4117              : !!  target: integer array
    4118              : !!
    4119              : !! INPUTS
    4120              : !!  fh=MPI-IO file handler.
    4121              : !!  offset=MPI-IO file pointer
    4122              : !!  sc_mode=
    4123              : !!         xmpio_single     ==> for reading by current proc.
    4124              : !!         xmpio_collective ==> for collective reading.
    4125              : !!  ncount=Number of elements in the buffer
    4126              : !!  [advance]=By default the routine will move the file pointer to the next record.
    4127              : !!    advance=.FALSE. can be used so that the next read will continue picking information
    4128              : !!    off of the currect record.
    4129              : !!
    4130              : !! OUTPUT
    4131              : !!  buf(ncount)=array with the values read from file
    4132              : !!  fmarker=Content of the Fortran record marker.
    4133              : !!  mpierr= MPI error code
    4134              : !!
    4135              : !! SIDE EFFECTS
    4136              : !!  offset=
    4137              : !!     input: file pointer used to access the Fortran marker.
    4138              : !!     output: new offset updated after the reading, depending on advance.
    4139              : !!
    4140              : !! SOURCE
    4141              : 
    4142              : #ifdef HAVE_MPI_IO
    4143              : 
    4144            0 : subroutine xmpio_read_int(fh, offset, sc_mode, ncount, buf, fmarker, mpierr, advance)
    4145              : 
    4146              : !Arguments ------------------------------------
    4147              : !scalars
    4148              :  integer,intent(in) :: fh,sc_mode,ncount
    4149              :  integer(XMPI_OFFSET_KIND),intent(inout) :: offset
    4150              :  integer(XMPI_OFFSET_KIND),intent(out) :: fmarker
    4151              :  integer,intent(out) :: mpierr
    4152              :  logical,optional,intent(in) :: advance
    4153              : !arrays
    4154              :  integer,intent(out) :: buf(ncount)
    4155              : 
    4156              : !Local variables-------------------------------
    4157              : !scalars
    4158              :  integer :: myfh,bsize_frm
    4159              :  integer(XMPI_OFFSET_KIND) :: my_offset
    4160              :  character(len=500) :: msg
    4161              : !arrays
    4162              :  integer :: statux(MPI_STATUS_SIZE)
    4163              : !************************************************************************
    4164              : 
    4165              :  ! Workaround for XLF
    4166            0 :  myfh = fh
    4167              : 
    4168            0 :  my_offset = offset
    4169            0 :  bsize_frm = xmpio_bsize_frm  ! Byte size of the Fortran record marker.
    4170              : 
    4171            0 :  call xmpio_read_frm(myfh,my_offset,sc_mode,fmarker,mpierr,advance=.FALSE.)
    4172              : 
    4173            0 :  SELECT CASE (sc_mode)
    4174              :  CASE (xmpio_single)
    4175            0 :    call MPI_FILE_READ_AT(myfh, my_offset, buf, ncount, MPI_INTEGER, statux, mpierr)
    4176              : 
    4177              :  CASE (xmpio_collective)
    4178            0 :    call MPI_FILE_READ_AT_ALL(myfh, my_offset, buf, ncount, MPI_INTEGER, statux, mpierr)
    4179              : 
    4180              :  CASE DEFAULT
    4181            0 :    write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode
    4182            0 :    call xmpi_abort(msg=msg)
    4183              :  END SELECT
    4184              : 
    4185            0 :  if (PRESENT(advance)) then
    4186            0 :    if (advance) then
    4187            0 :      offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record.
    4188              :    else
    4189            0 :      offset = offset + bsize_frm  ! Move the pointer after the marker.
    4190              :    end if
    4191              :  else
    4192            0 :    offset = offset + fmarker + 2*bsize_frm
    4193              :  end if
    4194              : 
    4195            0 : end subroutine xmpio_read_int
    4196              : !!***
    4197              : #endif
    4198              : 
    4199              : !----------------------------------------------------------------------
    4200              : 
    4201              : !!****f* m_xmpi/xmpio_read_dp
    4202              : !! NAME
    4203              : !!  xmpio_read_dp
    4204              : !!
    4205              : !! FUNCTION
    4206              : !!  Read the content of a single record marker in a FORTRAN file at a given offset using MPI-IO.
    4207              : !!  the file pointer is modified according to the value of advance.
    4208              : !!  targer: double precision real array
    4209              : !!
    4210              : !! INPUTS
    4211              : !!  fh=MPI-IO file handler.
    4212              : !!  offset=MPI-IO file pointer
    4213              : !!  sc_mode=
    4214              : !!         xmpio_single     ==> for reading by current proc.
    4215              : !!         xmpio_collective ==> for collective reading.
    4216              : !!  ncount=Number of elements in the buffer
    4217              : !!  [advance]=By default the routine will move the file pointer to the next record.
    4218              : !!    advance=.FALSE. can be used so that the next read will continue picking information
    4219              : !!    off of the currect record.
    4220              : !!
    4221              : !! OUTPUT
    4222              : !!  buf(ncount)=array with the values read from file
    4223              : !!  fmarker=Content of the Fortran record marker.
    4224              : !!  mpierr= MPI error code
    4225              : !!
    4226              : !! SIDE EFFECTS
    4227              : !!  offset=
    4228              : !!     input: file pointer used to access the Fortran marker.
    4229              : !!     output: new offset updated after the reading, depending on advance.
    4230              : !!
    4231              : !! SOURCE
    4232              : 
    4233              : #ifdef HAVE_MPI_IO
    4234              : 
    4235            0 : subroutine xmpio_read_dp(fh, offset, sc_mode, ncount, buf, fmarker, mpierr, advance)
    4236              : 
    4237              : !Arguments ------------------------------------
    4238              : !scalars
    4239              :  integer,intent(in) :: fh,sc_mode,ncount
    4240              :  integer(XMPI_OFFSET_KIND),intent(inout) :: offset
    4241              :  integer(XMPI_OFFSET_KIND),intent(out) :: fmarker
    4242              :  integer,intent(out) :: mpierr
    4243              :  logical,optional,intent(in) :: advance
    4244              : !arrays
    4245              :  real(dp),intent(out) :: buf(ncount)
    4246              : 
    4247              : !Local variables-------------------------------
    4248              : !scalars
    4249              :  integer :: bsize_frm,myfh
    4250              :  integer(XMPI_OFFSET_KIND) :: my_offset
    4251              :  character(len=500) :: msg
    4252              : !arrays
    4253              :  integer :: statux(MPI_STATUS_SIZE)
    4254              : !************************************************************************
    4255              : 
    4256              :  ! Workaround for XLF
    4257            0 :  myfh = fh
    4258              : 
    4259            0 :  my_offset = offset
    4260            0 :  bsize_frm = xmpio_bsize_frm  ! Byte size of the Fortran record marker.
    4261              : 
    4262            0 :  call xmpio_read_frm(myfh,my_offset,sc_mode,fmarker,mpierr,advance=.FALSE.)
    4263              : 
    4264            0 :  SELECT CASE (sc_mode)
    4265              :  CASE (xmpio_single)
    4266            0 :    call MPI_FILE_READ_AT(myfh, my_offset, buf, ncount, MPI_DOUBLE_PRECISION, statux, mpierr)
    4267              : 
    4268              :  CASE (xmpio_collective)
    4269            0 :    call MPI_FILE_READ_AT_ALL(myfh, my_offset, buf, ncount, MPI_DOUBLE_PRECISION, statux, mpierr)
    4270              : 
    4271              :  CASE DEFAULT
    4272            0 :    write(msg,"(a,i0)")" Wrong value for sc_mode: ",sc_mode
    4273            0 :    call xmpi_abort(msg=msg)
    4274              :  END SELECT
    4275              : 
    4276            0 :  if (PRESENT(advance)) then
    4277            0 :    if (advance) then
    4278            0 :      offset = offset + fmarker + 2*bsize_frm ! Move the file pointer to the next record.
    4279              :    else
    4280            0 :      offset = offset + bsize_frm  ! Move the pointer after the marker.
    4281              :    end if
    4282              :  else
    4283            0 :    offset = offset + fmarker + 2*bsize_frm
    4284              :  end if
    4285              : 
    4286            0 : end subroutine xmpio_read_dp
    4287              : !!***
    4288              : #endif
    4289              : 
    4290              : !------------------------------------------------------------------------------------
    4291              : 
    4292              : !!****f* m_xmpi/xmpio_max_address
    4293              : !! NAME
    4294              : !!  xmpio_max_address
    4295              : !!
    4296              : !! FUNCTION
    4297              : !!  Returns .TRUE. if offset cannot be stored in a Fortran integer of kind XMPI_ADDRESS_KIND.
    4298              : !!
    4299              : !! SOURCE
    4300              : 
    4301              : #ifdef HAVE_MPI_IO
    4302              : 
    4303            0 : function xmpio_max_address(offset)
    4304              : 
    4305              : !Arguments ------------------------------------
    4306              : !scalars
    4307              :  logical :: xmpio_max_address
    4308              :  integer(XMPI_OFFSET_KIND),intent(in) :: offset
    4309              : !arrays
    4310              : 
    4311              : !Local variables-------------------------------
    4312              : !scalars
    4313              :  integer(XMPI_ADDRESS_KIND) :: address
    4314              :  integer(XMPI_OFFSET_KIND),parameter :: max_address=HUGE(address)-100
    4315              : !************************************************************************
    4316              : 
    4317            0 :  xmpio_max_address = (offset >= max_address)
    4318              : 
    4319            0 : end function xmpio_max_address
    4320              : !!***
    4321              : #endif
    4322              : 
    4323              : !------------------------------------------------------------------------------------
    4324              : 
    4325              : !!****f* m_xmpi/xmpio_write_frmarkers
    4326              : !! NAME
    4327              : !!  xmpio_write_frmarkers
    4328              : !!
    4329              : !! FUNCTION
    4330              : !!  Write a set of Fortran record markers starting at a given offset using MPI-IO.
    4331              : !!
    4332              : !! INPUTS
    4333              : !!  fh=MPI-IO file handler.
    4334              : !!  offset=MPI-IO file pointer
    4335              : !!  sc_mode=Option for individual or collective reading.
    4336              : !!  nfrec=Number of Fortran records to be written.
    4337              : !!  bsize_frecord(nfrec)=Byte size of the Fortran records to be written (markers are NOT included in the size)
    4338              : !!
    4339              : !! OUTPUT
    4340              : !!  ierr=A non-zero error code signals failure.
    4341              : !!
    4342              : !! SOURCE
    4343              : 
    4344              : #ifdef HAVE_MPI_IO
    4345              : 
    4346            5 : subroutine xmpio_write_frmarkers(fh, offset, sc_mode, nfrec, bsize_frecord, ierr)
    4347              : 
    4348              : !Arguments ------------------------------------
    4349              : !scalars
    4350              :  integer,intent(in) :: fh,nfrec,sc_mode
    4351              :  integer(XMPI_OFFSET_KIND),intent(in) :: offset
    4352              :  integer,intent(out) :: ierr
    4353              : !arrays
    4354              :  integer(XMPI_OFFSET_KIND),intent(in) :: bsize_frecord(nfrec)
    4355              : 
    4356              : !Local variables-------------------------------
    4357              : !scalars
    4358              :  integer :: nb,irec,frmarkers_type,jj,bsize_frm,mpi_type_frm,mpierr,myfh
    4359              :  integer(XMPI_OFFSET_KIND) :: displ
    4360              : !integer(XMPI_OFFSET_KIND) :: my_offset
    4361              : !character(len=500) :: msg
    4362              : !arrays
    4363            5 :  integer(kind=int16),allocatable :: bufdelim2(:)
    4364            5 :  integer(kind=int32),allocatable :: bufdelim4(:)
    4365            5 :  integer(kind=int64),allocatable :: bufdelim8(:)
    4366              : #ifdef HAVE_FC_INT_QUAD
    4367            5 :  integer*16,allocatable :: bufdelim16(:)
    4368              : #endif
    4369              : !integer :: statux(MPI_STATUS_SIZE)
    4370            5 :  integer,allocatable :: block_length(:),block_type(:)
    4371            5 :  integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
    4372            5 :  integer(XMPI_OFFSET_KIND),allocatable :: delim_record(:)
    4373              : !************************************************************************
    4374              : 
    4375              :  ! Workaround for XLF
    4376            5 :  myfh = fh; ierr=0
    4377              : 
    4378              :  !my_offset = offset
    4379              :  !do irec=1,nfrec
    4380              :  !  call xmpio_write_frm(myfh,my_offset,sc_mode,bsize_frecord(irec),mpierr)
    4381              :  !end do
    4382              :  !return
    4383              : 
    4384              :  ! FIXME: This is buggy
    4385            5 :  bsize_frm    = xmpio_bsize_frm     ! Byte size of the Fortran record marker.
    4386            5 :  mpi_type_frm = xmpio_mpi_type_frm  ! MPI type of the record marker.
    4387              : 
    4388              :  ! Define the view for the file
    4389            5 :  nb=2*nfrec
    4390           15 :  ABI_MALLOC(block_length,(nb+2))
    4391           15 :  ABI_MALLOC(block_displ,(nb+2))
    4392           10 :  ABI_MALLOC(block_type,(nb+2))
    4393            5 :  block_length(1)=1
    4394            5 :  block_displ (1)=0
    4395            5 :  block_type  (1)=MPI_LB
    4396              : 
    4397            5 :  jj=2; displ=0
    4398          335 :  do irec=1,nfrec
    4399          990 :    block_type (jj:jj+1)  = mpi_type_frm
    4400          990 :    block_length(jj:jj+1) = 1
    4401          330 :    block_displ(jj  )     = displ
    4402          330 :    block_displ(jj+1)     = displ + bsize_frm + bsize_frecord(irec)
    4403          330 :    jj=jj+2
    4404          330 :    displ = displ + bsize_frecord(irec) + 2*bsize_frm ! Move to the beginning of the next column.
    4405          335 :    if (xmpio_max_address(displ)) then ! Check for wraparound.
    4406            0 :       ierr = -1; return
    4407              :    end if
    4408              :  end do
    4409              : 
    4410            5 :  block_length(nb+2) = 1
    4411            5 :  block_displ (nb+2) = displ
    4412            5 :  block_type  (nb+2) = MPI_UB
    4413              : 
    4414            5 :  call xmpio_type_struct(nb+2,block_length,block_displ,block_type,frmarkers_type,mpierr)
    4415              : 
    4416            5 :  ABI_FREE(block_length)
    4417            5 :  ABI_FREE(block_displ)
    4418            5 :  ABI_FREE(block_type)
    4419              : 
    4420            5 :  call MPI_TYPE_COMMIT(frmarkers_type,mpierr)
    4421            5 :  call MPI_FILE_SET_VIEW(myfh,offset,MPI_BYTE,frmarkers_type,"native",MPI_INFO_NULL,mpierr)
    4422              : 
    4423            5 :  jj=1
    4424           15 :  ABI_MALLOC(delim_record,(nb))
    4425          335 :  do irec=1,nfrec
    4426          990 :    delim_record(jj:jj+1)=bsize_frecord(irec)
    4427          335 :    jj=jj+2
    4428              :  end do
    4429              : 
    4430              :  ! Write all markers according to the MPI type of the Fortran marker.
    4431            5 :  SELECT CASE (bsize_frm)
    4432              : 
    4433              :  CASE (4)
    4434           15 :    ABI_MALLOC(bufdelim4,(nb))
    4435          670 :    bufdelim4=delim_record
    4436            5 :    if (sc_mode==xmpio_single) then
    4437            0 :      call MPI_FILE_WRITE    (myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4438            5 :    else if (sc_mode==xmpio_collective) then
    4439            5 :      call MPI_FILE_WRITE_ALL(myfh,bufdelim4,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4440              :    else
    4441            0 :      ierr=2
    4442              :    end if
    4443            5 :    ABI_FREE(bufdelim4)
    4444              : 
    4445              :  CASE (8)
    4446            0 :    ABI_MALLOC(bufdelim8,(nb))
    4447            0 :    bufdelim8=delim_record
    4448            0 :    if (sc_mode==xmpio_single) then
    4449            0 :      call MPI_FILE_WRITE    (myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4450            0 :    else if (sc_mode==xmpio_collective) then
    4451            0 :      call MPI_FILE_WRITE_ALL(myfh,bufdelim8,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4452              :    else
    4453            0 :      ierr=2
    4454              :    end if
    4455            0 :    ABI_FREE(bufdelim8)
    4456              : 
    4457              : #ifdef HAVE_FC_INT_QUAD
    4458              :  CASE (16)
    4459            0 :    ABI_MALLOC(bufdelim16,(nb))
    4460            0 :    bufdelim16=delim_record
    4461            0 :    if (sc_mode==xmpio_single) then
    4462            0 :      call MPI_FILE_WRITE    (myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4463            0 :    else if (sc_mode==xmpio_collective) then
    4464            0 :      call MPI_FILE_WRITE_ALL(myfh,bufdelim16,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4465              :    else
    4466            0 :      ierr=2
    4467              :    end if
    4468            0 :    ABI_FREE(bufdelim16)
    4469              : #endif
    4470              : 
    4471              :  CASE (2)
    4472            0 :    ABI_MALLOC(bufdelim2,(nb))
    4473            0 :    bufdelim2=delim_record
    4474            0 :    if (sc_mode==xmpio_single) then
    4475            0 :      call MPI_FILE_WRITE    (myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4476            0 :    else if (sc_mode==xmpio_collective) then
    4477            0 :      call MPI_FILE_WRITE_ALL(myfh,bufdelim2,2*nfrec,mpi_type_frm,MPI_STATUS_IGNORE,mpierr)
    4478              :    else
    4479            0 :      ierr=2
    4480              :    end if
    4481            0 :    ABI_FREE(bufdelim2)
    4482              : 
    4483              :  CASE DEFAULT
    4484            5 :    ierr=-2
    4485              :  END SELECT
    4486              : 
    4487              :  ! Free memory
    4488            5 :  call MPI_TYPE_FREE(frmarkers_type,mpierr)
    4489            5 :  ABI_FREE(delim_record)
    4490              : 
    4491            5 : end subroutine xmpio_write_frmarkers
    4492              : #endif
    4493              : !!***
    4494              : 
    4495              : !------------------------------------------------------------------------------------
    4496              : 
    4497              : !!****f* m_xmpi/xmpio_create_fherm_packed
    4498              : !! NAME
    4499              : !!  xmpio_create_fherm_packed
    4500              : !!
    4501              : !! FUNCTION
    4502              : !!  Returns an MPI datatype that can be used to (read|write) with MPI-IO the columns of an
    4503              : !!  Hermitian matrix whose upper triangle is written on a Fortran binary file.
    4504              : !!  Note that the view assumes that the file pointer used to create the MPI-IO view
    4505              : !!  points to the first element of the first column. In other words,the first Fortran record marker
    4506              : !!  (if any) is not taken into account in the calculation of the displacements.
    4507              : !!
    4508              : !! INPUTS
    4509              : !!  array_of_starts(2)=starting coordinates in the global Hermitian matrix
    4510              : !!     (array of positive integers with jj>=ii, Fortran convention)
    4511              : !!  array_of_ends(2)=final coordinates in the global Hermitian matrix
    4512              : !!     (array of positive integers, jj>=ii, Fortran convention)
    4513              : !!  is_fortran_file=.FALSE. is C stream is used. .TRUE. for writing Fortran binary files.
    4514              : !!  old_type=MPI datatype of the elements of the matrix.
    4515              : !!
    4516              : !! OUTPUT
    4517              : !!  my_offset=Offset relative to the beginning of the matrix in the file.
    4518              : !!  hmat_type=New MPI type.
    4519              : !!  offset_err= error code
    4520              : !!
    4521              : !! NOTES
    4522              : !!  The matrix on file is written in the following FORTRAN format (let us assume a 3x3 matrix for simplicity)
    4523              : !!
    4524              : !!    m (1,1)             m
    4525              : !!    m (1,2) (2,2)       m
    4526              : !!    m (1,3) (2,3) (3,3) m
    4527              : !!
    4528              : !!  each Fortran record stores a column of the packed Hermitian matrix, "m" denotes the Fortran
    4529              : !!  record marker that introduces holes in the MPI-IO file view.
    4530              : !!  To read the columns from (1,2) up to (2,2) one should use array_of_starts=(1,2) and array_of_ends=(2,2).
    4531              : !!  The MPI-IO file view should be created by moving the file pointer so that it points to the elements (1,2).
    4532              : !!
    4533              : !!  File views for C-streams is not optimal since one can use a single slice of contigous data.
    4534              : !!
    4535              : !! SOURCE
    4536              : 
    4537              : #ifdef HAVE_MPI_IO
    4538              : 
    4539            0 : subroutine xmpio_create_fherm_packed(array_of_starts,array_of_ends,is_fortran_file,my_offset,old_type,hmat_type,offset_err)
    4540              : 
    4541              : !Arguments ------------------------------------
    4542              : !scalars
    4543              :  integer,intent(in) :: old_type
    4544              :  integer,intent(out) :: offset_err,hmat_type
    4545              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offset
    4546              :  logical,intent(in) :: is_fortran_file
    4547              : !arrays
    4548              :  integer,intent(in) :: array_of_starts(2),array_of_ends(2)
    4549              : 
    4550              : !Local variables-------------------------------
    4551              : !scalars
    4552              :  integer :: nrow,my_ncol,ii,bsize_old,col,jj_glob,bsize_frm,prev_col,mpierr
    4553              :  integer(XMPI_OFFSET_KIND) :: col_displ
    4554              : !arrays
    4555            0 :  integer,allocatable :: col_type(:),block_length(:),block_type(:)
    4556            0 :  integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
    4557              : !************************************************************************
    4558              : 
    4559            0 :  offset_err=0
    4560              : 
    4561              :  ! Byte size of old_type.
    4562            0 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    4563              : 
    4564            0 :  bsize_frm=0; if (is_fortran_file) bsize_frm = xmpio_bsize_frm
    4565              : 
    4566            0 :  my_ncol = array_of_ends(2) - array_of_starts(2) + 1
    4567              :  !
    4568              :  ! Calculate my offset relative to the beginning of the matrix in the file.
    4569            0 :  prev_col = array_of_starts(2)-1
    4570            0 :  my_offset = (prev_col*(prev_col+1)/2)*bsize_old + (array_of_starts(1)-1)*bsize_old + 2*prev_col*bsize_frm + bsize_frm
    4571              :  !
    4572              :  ! col_type(col) describes the col-th column of the packed matrix.
    4573              :  ! block_displ(col+1) stores its displacement taking into account the Fortran marker.
    4574            0 :  ABI_MALLOC(col_type,(my_ncol))
    4575            0 :  ABI_MALLOC(block_displ,(my_ncol+2))
    4576              : 
    4577            0 :  if (my_ncol>1) then
    4578              :    col_displ=0
    4579            0 :    do col=1,my_ncol
    4580            0 :     jj_glob = (col-1) + array_of_starts(2)
    4581            0 :     nrow = jj_glob
    4582            0 :     if (jj_glob==array_of_starts(2)) nrow = jj_glob - array_of_starts(1) + 1 ! First column treated by me.
    4583            0 :     if (jj_glob==array_of_ends(2))   nrow = array_of_ends(1)                 ! Last column treated by me.
    4584            0 :     call MPI_Type_contiguous(nrow,old_type,col_type(col),mpierr)
    4585              :     !
    4586            0 :     if (xmpio_max_address(col_displ)) offset_err=1  ! Test for wraparounds
    4587            0 :     block_displ(col+1) = col_displ
    4588            0 :     col_displ = col_displ + nrow * bsize_old + 2 * bsize_frm  ! Move to the next column.
    4589              :    end do
    4590              : 
    4591            0 :  else if (my_ncol==1) then  ! The case of a single column is treated separately.
    4592            0 :     block_displ(2) = 0
    4593            0 :     nrow = array_of_ends(1) - array_of_starts(1) + 1
    4594            0 :     call MPI_Type_contiguous(nrow,old_type,col_type(2),mpierr)
    4595            0 :     col_displ= nrow*bsize_old
    4596            0 :     if (xmpio_max_address(col_displ)) offset_err=1  ! Test for wraparounds
    4597              :  else
    4598            0 :    call xmpi_abort(msg="my_ncol cannot be negative!")
    4599              :  end if
    4600              : 
    4601            0 :  ABI_MALLOC(block_length,(my_ncol+2))
    4602            0 :  ABI_MALLOC(block_type,(my_ncol+2))
    4603              : 
    4604            0 :  block_length(1)=1
    4605            0 :  block_displ (1)=0
    4606            0 :  block_type  (1)=MPI_LB
    4607              : 
    4608            0 :  do ii=2,my_ncol+1
    4609            0 :    block_length(ii)=1
    4610            0 :    block_type(ii)  =col_type(ii-1)
    4611              :    !write(std_out,*)" ii-1, depl, length, type: ",ii-1,block_displ(ii),block_length(ii),block_type(ii)
    4612              :  end do
    4613              : 
    4614            0 :  block_length(my_ncol+2)= 1
    4615            0 :  block_displ (my_ncol+2)= col_displ
    4616            0 :  block_type  (my_ncol+2)= MPI_UB
    4617              : 
    4618            0 :  call xmpio_type_struct(my_ncol+2,block_length,block_displ,block_type,hmat_type,mpierr)
    4619              : 
    4620            0 :  call MPI_TYPE_COMMIT(hmat_type,mpierr)
    4621              : 
    4622            0 :  ABI_FREE(block_length)
    4623            0 :  ABI_FREE(block_displ)
    4624            0 :  ABI_FREE(block_type)
    4625              : 
    4626            0 :  do col=1,my_ncol
    4627            0 :    call MPI_TYPE_FREE(col_type(col),mpierr)
    4628              :  end do
    4629              : 
    4630            0 :  ABI_FREE(col_type)
    4631              : 
    4632            0 : end subroutine xmpio_create_fherm_packed
    4633              : !!***
    4634              : #endif
    4635              : 
    4636              : !------------------------------------------------------------------------------------
    4637              : 
    4638              : !!****f* m_xmpi/xmpio_create_coldistr_from_fpacked
    4639              : !! NAME
    4640              : !!  xmpio_create_coldistr_from_fpacked
    4641              : !!
    4642              : !! FUNCTION
    4643              : !!  Returns an MPI datatype that can be used to MPI-IO (read|write) the columns of an
    4644              : !!  (Hermitian|Symmetric) matrix whose upper triangle is written on a Fortran binary file.
    4645              : !!  Note that the view assumes that the file pointer used to instanciate the MPI-IO view
    4646              : !!  points to the first element of the first column. In other words,the first Fortran record marker
    4647              : !!  (if any) is not taken into account in the calculation of the displacements.
    4648              : !!
    4649              : !! INPUTS
    4650              : !!  sizes(2)=Number of elements of type old_type in each dimension of the full array (array of positive integers)
    4651              : !!  my_cols(2)=initial and final column to (read|write). Array of positive integers, Fortran convention.
    4652              : !!  old_type=MPI datatype of the elements of the matrix.
    4653              : !!
    4654              : !! OUTPUT
    4655              : !!  new_type=New MPI type that can be used to instanciate the MPI-IO view for the Fortran file.
    4656              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    4657              : !!    marker (lets call it "base"). Each node should (read|write) using my_offset = base + my_offpad.
    4658              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    4659              : !!    to make it more efficient) without having to change the client code.
    4660              : !!  offset_err=Error code. A non-zero returned value signals that the global matrix is tool large
    4661              : !!    for a single MPI-IO access (see notes below).
    4662              : !!
    4663              : !! NOTES
    4664              : !!  1) The matrix on file is written in the following FORTRAN format (let us assume a 3x3 matrix for simplicity)
    4665              : !!
    4666              : !!      m (1,1)             m
    4667              : !!      m (1,2) (2,2)       m
    4668              : !!      m (1,3) (2,3) (3,3) m
    4669              : !!
    4670              : !!     each Fortran record stores a column of the packed matrix, "m" denotes the Fortran
    4671              : !!     record marker that introduces holes in the file view.
    4672              : !!
    4673              : !!  2) With (signed) Fortran integers, the maximum size of the file that
    4674              : !!     that can be read in one-shot is around 2Gb when etype is set to byte.
    4675              : !!     Using a larger etype might create portability problems (real data on machines using
    4676              : !!     integer*16 for the marker) since etype must be a multiple of the Fortran record marker
    4677              : !!     Due to the above reason, block_displ is given in bytes but it has to be defined as Fortran
    4678              : !!     integer. If the displacement cannot be stored in a Fortran integer, the routine returns
    4679              : !!     offset_err=1 so that the caller will know that several MPI-IO reads are nedded to
    4680              : !!     read the file.
    4681              : !!
    4682              : !! SOURCE
    4683              : 
    4684              : #ifdef HAVE_MPI_IO
    4685              : 
    4686            0 : subroutine xmpio_create_coldistr_from_fpacked(sizes,my_cols,old_type,new_type,my_offpad,offset_err)
    4687              : 
    4688              : !Arguments ------------------------------------
    4689              : !scalars
    4690              :  integer,intent(in) :: old_type
    4691              :  integer,intent(out) :: new_type,offset_err
    4692              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    4693              : !arrays
    4694              :  integer,intent(in) :: sizes(2),my_cols(2)
    4695              : 
    4696              : !Local variables-------------------------------
    4697              : !scalars
    4698              :  integer :: my_ncol,bsize_old,my_col
    4699              :  integer :: my_nels,my_el,row_glob,ii_hpk,jj_hpk,col_glob,bsize_frm,mpierr
    4700              :  integer(XMPI_OFFSET_KIND) :: my_offset,ijp_glob
    4701              :  !character(len=500) :: msg
    4702              : !arrays
    4703            0 :  integer,allocatable :: block_length(:),block_type(:)
    4704            0 :  integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
    4705              : !************************************************************************
    4706              : 
    4707              :  ! Byte size of the Fortran record marker.
    4708            0 :  bsize_frm = xmpio_bsize_frm
    4709              : 
    4710              :  ! Byte size of old_type.
    4711            0 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    4712              : 
    4713              :  ! my number of columns and total numer of elements to be read.
    4714            0 :  my_ncol = my_cols(2) - my_cols(1) + 1
    4715            0 :  my_nels = my_ncol*sizes(1)
    4716              :  !
    4717              :  ! block_displ(el+1) stores the displacement of the local element el taking into account the Fortran marker.
    4718            0 :  ABI_MALLOC(block_displ,(my_nels+2))
    4719            0 :  ABI_MALLOC(block_length,(my_nels+2))
    4720            0 :  ABI_MALLOC(block_type,(my_nels+2))
    4721              : 
    4722            0 :  block_length(1)=1
    4723            0 :  block_displ (1)=0
    4724            0 :  block_type  (1)=MPI_LB
    4725              :  !
    4726              :  ! * the view assumes that the file pointer used to instanciate the MPI-IO view
    4727              :  !   points to the first element of the first column. In other words,the first Fortran record marker
    4728              :  !   is not taken into account in the calculation of the displacements.
    4729            0 :  my_offpad=xmpio_bsize_frm
    4730              : 
    4731              :  ! * Some matrix elements are read twice. This part has to be tested.
    4732            0 :  offset_err=0; my_el=0
    4733            0 :  do my_col=1,my_ncol
    4734            0 :    col_glob = (my_col-1) + my_cols(1)
    4735            0 :    do row_glob=1,sizes(1)
    4736            0 :      if (col_glob>=row_glob) then
    4737            0 :        ii_hpk = row_glob
    4738            0 :        jj_hpk = col_glob
    4739            0 :        ijp_glob = row_glob + col_glob*(col_glob-1)/2  ! Index for packed form
    4740              :      else ! Exchange the indices as (jj,ii) will be read.
    4741            0 :        ii_hpk = col_glob
    4742            0 :        jj_hpk = row_glob
    4743            0 :        ijp_glob = col_glob + row_glob*(row_glob-1)/2  ! Index for packed form
    4744              :      end if
    4745            0 :      my_el = my_el+1
    4746            0 :      my_offset = (ijp_glob-1)* bsize_old + (jj_hpk-1)*2*bsize_frm
    4747            0 :      if (xmpio_max_address(my_offset)) offset_err=1   ! Check for wraparounds.
    4748            0 :      block_displ (my_el+1)=my_offset
    4749            0 :      block_length(my_el+1)=1
    4750            0 :      block_type  (my_el+1)=old_type
    4751              :      !write(std_out,*)" my_el, displ: ",my_el,block_displ(my_el+1)
    4752              :    end do
    4753              :  end do
    4754              : 
    4755            0 :  block_length(my_nels+2)=1
    4756            0 :  block_displ (my_nels+2)=my_offset
    4757            0 :  block_type  (my_nels+2)=MPI_UB
    4758              : 
    4759            0 :  call xmpio_type_struct(my_nels+2,block_length,block_displ,block_type,new_type,mpierr)
    4760              : 
    4761            0 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    4762              : 
    4763            0 :  ABI_FREE(block_length)
    4764            0 :  ABI_FREE(block_displ)
    4765            0 :  ABI_FREE(block_type)
    4766              : 
    4767            0 : end subroutine xmpio_create_coldistr_from_fpacked
    4768              : !!***
    4769              : #endif
    4770              : 
    4771              : !------------------------------------------------------------------------------------
    4772              : 
    4773              : !!****f* m_xmpi/xmpio_create_coldistr_from_fp3blocks
    4774              : !! NAME
    4775              : !!  xmpio_create_coldistr_from_fp3blocks
    4776              : !!
    4777              : !! FUNCTION
    4778              : !!  Returns an MPI datatype that can be used to MPI-IO (read|write) the columns of a
    4779              : !!  matrix of the form  M = (S1    F3)
    4780              : !!                          (F3^H  S2)
    4781              : !!  where S1 and S2 are square (symmetric|Hermitian) matrices whose upper triangle is stored on file
    4782              : !!  while F3 is a generic matrix (not necessarily square) stored in full mode.
    4783              : !!  The Fortran file contains the blocks in the following order.
    4784              : !!      upper(S1)
    4785              : !!      upper(S2)
    4786              : !!      F3
    4787              : !! INPUTS
    4788              : !!  sizes(2)=Number of elements of type old_type in each dimension of the full array M (array of positive integers)
    4789              : !!  my_cols(2)=initial and final column to (read|write). Array of positive integers, Fortran convention.
    4790              : !!  block_sizes(2,3)=The sizes of S1, S2, F.
    4791              : !!  old_type=MPI datatype of the elements of the matrix.
    4792              : !!
    4793              : !! OUTPUT
    4794              : !!  new_type=New MPI type that can be used to instanciate the MPI-IO view for the Fortran file.
    4795              : !!  my_offpad=Offset to be added to the file pointer giving the position of the first Fortran record
    4796              : !!    marker (lets call it "base"). Each node should (read|write) using my_offset = base + my_offpad.
    4797              : !!    my_offpad is used so that one can safely change the way the fileview is generated (for example
    4798              : !!    to make it more efficient) without having to change the client code.
    4799              : !!  offset_err=Error code. A non-zero returned value signals that the global matrix is tool large
    4800              : !!    for a single MPI-IO access (see notes below).
    4801              : !!
    4802              : !! NOTES
    4803              : !!  1) block_displ is given in bytes due to the presence of the marker.
    4804              : !!     If the displacement of an element is too large, the routine returns
    4805              : !!     offset_err=1 so that the caller knows that several MPI-IO reads are required to (read| write) the file.
    4806              : !!
    4807              : !! SOURCE
    4808              : 
    4809              : #ifdef HAVE_MPI_IO
    4810              : 
    4811            0 : subroutine xmpio_create_coldistr_from_fp3blocks(sizes,block_sizes,my_cols,old_type,new_type,my_offpad,offset_err)
    4812              : 
    4813              : !Arguments ------------------------------------
    4814              : !scalars
    4815              :  integer,intent(in) :: old_type
    4816              :  integer,intent(out) :: new_type,offset_err
    4817              :  integer(XMPI_OFFSET_KIND),intent(out) :: my_offpad
    4818              : !arrays
    4819              :  integer,intent(in) :: sizes(2),my_cols(2),block_sizes(2,3)
    4820              : 
    4821              : !Local variables-------------------------------
    4822              : !scalars
    4823              :  integer :: my_ncol,bsize_old,my_col,which_block,uplo,swap
    4824              :  integer :: my_nels,my_el,row_glob,ii_hpk,jj_hpk,ii,jj
    4825              :  integer :: col_glob,bsize_frm,mpierr,row_shift,col_shift,n1,n2
    4826              :  integer(XMPI_OFFSET_KIND) :: my_offset,ijp,bsize_tot,max_displ,min_displ
    4827              :  integer(XMPI_ADDRESS_KIND) :: address
    4828              : !arrays
    4829            0 :  integer,allocatable :: block_length(:),block_type(:)
    4830            0 :  integer(XMPI_ADDRESS_KIND),allocatable :: block_displ(:)
    4831              :  integer(XMPI_OFFSET_KIND) :: bsize_mat(2)
    4832              : !************************************************************************
    4833              : 
    4834            0 :  if (sizes(1) /= SUM(block_sizes(1,1:2)) .or. &
    4835              :      sizes(2) /= SUM(block_sizes(2,1:2)) ) then
    4836            0 :    write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: Inconsistency between block_sizes ans sizes "
    4837            0 :    call xmpi_abort()
    4838              :  end if
    4839              : 
    4840            0 :  if (block_sizes(1,1) /= block_sizes(2,1) .or.&
    4841              :      block_sizes(1,2) /= block_sizes(2,2) ) then
    4842            0 :    write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: first two blocks must be square"
    4843            0 :    call xmpi_abort()
    4844              :  end if
    4845              : 
    4846            0 :  if (block_sizes(2,3) /= block_sizes(2,2) .or.&
    4847              :      block_sizes(1,3) /= block_sizes(1,1) ) then
    4848            0 :    write(std_out,*)" xmpio_create_coldistr_from_fp3blocks: Full matrix must be square"
    4849            0 :    call xmpi_abort()
    4850              :  end if
    4851              : 
    4852            0 :  write(std_out,*)" xmpio_create_coldistr_from_fp3blocks is still under testing"
    4853              :  !call xmpi_abort()
    4854              : 
    4855              :  ! Byte size of the Fortran record marker.
    4856            0 :  bsize_frm = xmpio_bsize_frm
    4857              : 
    4858              :  ! Byte size of old_type.
    4859            0 :  call MPI_TYPE_SIZE(old_type,bsize_old,mpierr)
    4860              : 
    4861              :  ! my number of columns and total numer of elements to be read.
    4862            0 :  my_ncol = my_cols(2) - my_cols(1) + 1
    4863            0 :  my_nels = sizes(1)*my_ncol
    4864              :  !
    4865              :  ! block_displ(el+1) stores the displacement of the local element el taking into account the Fortran marker.
    4866            0 :  ABI_MALLOC(block_displ,(my_nels+2))
    4867            0 :  ABI_MALLOC(block_length,(my_nels+2))
    4868            0 :  ABI_MALLOC(block_type,(my_nels+2))
    4869              :  !
    4870              :  ! * the view assumes that the file pointer used to instanciate the MPI-IO view
    4871              :  !   points to the first element of the first column. In other words,the first Fortran record marker
    4872              :  !   is not taken into account in the calculation of the displacements.
    4873            0 :  my_offpad=xmpio_bsize_frm
    4874              :  !
    4875              :  ! Byte size of the first two blocks including the markers.
    4876            0 :  n1=block_sizes(1,1)
    4877            0 :  bsize_mat(1) = (n1*(n1+1)/2)*bsize_old + 2*n1*bsize_frm
    4878              : 
    4879            0 :  n2=block_sizes(1,2)
    4880            0 :  bsize_mat(2) = (n2*(n2+1)/2)*bsize_old + 2*n2*bsize_frm
    4881              : 
    4882            0 :  bsize_tot=SUM(bsize_mat) +  PRODUCT(block_sizes(:,3))*bsize_old + block_sizes(2,3)*2*bsize_frm - bsize_frm
    4883            0 :  write(std_out,*)"bsize_mat",bsize_mat,"bsize_tot",bsize_tot
    4884              :  !
    4885              :  ! * Some matrix elements are read twice. This part has to be tested.
    4886            0 :  offset_err=0; my_el=0; max_displ=0; min_displ=HUGE(address)
    4887            0 :  do my_col=1,my_ncol
    4888            0 :    col_glob = (my_col-1) + my_cols(1)
    4889            0 :    do row_glob=1,sizes(1)
    4890              :      !
    4891            0 :      which_block=3
    4892            0 :      if (row_glob<=block_sizes(1,1).and.col_glob<=block_sizes(2,1)) which_block=1
    4893            0 :      if (row_glob >block_sizes(1,1).and.col_glob >block_sizes(2,1)) which_block=2
    4894              : 
    4895            0 :      if ( ANY(which_block == (/1,2/)) ) then ! S1 or S2
    4896              :        !
    4897            0 :        row_shift=(which_block-1)*block_sizes(1,1)
    4898            0 :        col_shift=(which_block-1)*block_sizes(2,1)
    4899              : 
    4900            0 :        ii_hpk = row_glob - row_shift
    4901            0 :        jj_hpk = col_glob - col_shift
    4902            0 :        if (jj_hpk<ii_hpk) then ! Exchange the indices so that the symmetric is read.
    4903            0 :          swap   = jj_hpk
    4904            0 :          jj_hpk = ii_hpk
    4905            0 :          ii_hpk = swap
    4906              :        end if
    4907            0 :        ijp = ii_hpk + jj_hpk*(jj_hpk-1)/2  ! Index for packed form
    4908            0 :        my_offset = (ijp-1)*bsize_old + (jj_hpk-1)*2*bsize_frm
    4909            0 :        if (which_block==2) my_offset=my_offset+bsize_mat(1)    ! Shift the offset to account for S1.
    4910              :        !my_offset=4
    4911              :        !
    4912              :      else
    4913              :        ! The element belongs either to F3 of F3^H.
    4914              :        ! Now find whether it is the upper or the lower block since only F3 is stored on file.
    4915            0 :        uplo=1; if (row_glob>block_sizes(1,1)) uplo=2
    4916              : 
    4917              :        if (uplo==1) then
    4918            0 :          row_shift=0
    4919            0 :          col_shift=block_sizes(2,1)
    4920              :        else
    4921              :          row_shift=block_sizes(1,1)
    4922              :          col_shift=0
    4923              :        end if
    4924            0 :        ii = row_glob - row_shift
    4925            0 :        jj = col_glob - col_shift
    4926              : 
    4927            0 :        if (uplo==2) then ! Exchange the indices since the symmetric element will be read.
    4928            0 :          swap=jj
    4929            0 :          jj  =ii
    4930            0 :          ii  =swap
    4931              :        end if
    4932              : 
    4933            0 :        my_offset = (ii-1)*bsize_old + (jj-1)*block_sizes(1,3)*bsize_old + (jj-1)*2*bsize_frm
    4934            0 :        my_offset = my_offset + SUM(bsize_mat)
    4935              :        !if (uplo==1) my_offset=my_offset + bsize_mat(1)
    4936              :        !my_offset=0
    4937              :        !if (ii==1.and.jj==1) write(std_out,*)" (1,1) offset = ",my_offset
    4938              :        !if (ii==block_sizes(1,3).and.jj==block_sizes(2,3)) write(std_out,*)" (n,n) offset =", my_offset
    4939            0 :        if (my_offset>=bsize_tot-1*bsize_old) then
    4940            0 :          write(std_out,*)"WARNING (my_offset>bsize_tot-bsize_old),",ii,jj,my_offset,bsize_tot
    4941              :        end if
    4942              :      end if
    4943              : 
    4944            0 :      if (xmpio_max_address(my_offset)) offset_err=1   ! Check for wraparounds.
    4945            0 :      my_el = my_el+1
    4946            0 :      block_displ (my_el+1)=my_offset
    4947            0 :      block_length(my_el+1)=1
    4948            0 :      block_type  (my_el+1)=old_type
    4949            0 :      max_displ = MAX(max_displ,my_offset)
    4950            0 :      min_displ = MIN(min_displ,my_offset)
    4951              :      !if (which_block==3) write(std_out,*)" my_el, which, displ: ",my_el,which_block,block_displ(my_el+1)
    4952              :    end do
    4953              :  end do
    4954              : 
    4955              :  !write(std_out,*)" MAX displ = ",max_displ," my_nels = ",my_nels
    4956              :  !write(std_out,*)" MIN displ = ",MINVAL(block_displ(2:my_nels+1))
    4957              : 
    4958              :  !block_displ (1)=max_displ ! Do not change this value.
    4959              :  !if (min_displ>0) block_displ (1)=min_displ ! Do not change this value.
    4960              : 
    4961              :  block_displ (1)=min_displ
    4962            0 :  block_displ (1)=0
    4963            0 :  block_length(1)=0
    4964            0 :  block_type  (1)=MPI_LB
    4965              : 
    4966            0 :  block_length(my_nels+2)=0
    4967              :  !block_displ (my_nels+2)=bsize_tot
    4968            0 :  block_displ (my_nels+2)=max_displ
    4969            0 :  block_type  (my_nels+2)=MPI_UB
    4970              : 
    4971            0 :  call xmpio_type_struct(my_nels+2,block_length,block_displ,block_type,new_type,mpierr)
    4972              :  !call xmpio_type_struct(my_nels,block_length(2:),block_displ(2:),block_type(2:),new_type,mpierr)
    4973              : 
    4974              :  !call MPI_TYPE_CREATE_INDEXED_BLOCK(my_nels, block_length(2:), block_displ(2:), old_type, new_type, mpierr)
    4975              : 
    4976            0 :  call MPI_TYPE_COMMIT(new_type,mpierr)
    4977              : 
    4978            0 :  ABI_FREE(block_length)
    4979            0 :  ABI_FREE(block_displ)
    4980            0 :  ABI_FREE(block_type)
    4981              : 
    4982            0 : end subroutine xmpio_create_coldistr_from_fp3blocks
    4983              : !!***
    4984              : #endif
    4985              : 
    4986              : !!****f* m_xmpi/xmpi_distrib_2d
    4987              : !! NAME
    4988              : !! xmpi_distrib_2d
    4989              : !!
    4990              : !! FUNCTION
    4991              : !!  Try to optimally distribute nprocs in a 2d grid of shape (n1, n2) given a problem of dimension (size1, size2).
    4992              : !!  Use order string to define priorities:
    4993              : !!      "12" or "21" if both dimensions should be optimized (if not possibile the first one gets optimized).
    4994              : !!      "1" or "2" to optimize only one dimension.
    4995              : !!  Return: exit status in ierr.
    4996              : !!
    4997              : !! SOURCE
    4998              : 
    4999           26 : subroutine xmpi_distrib_2d(nprocs, order, size1, size2, n1, n2, ierr)
    5000              : 
    5001              : !Arguments ------------------------------------
    5002              :  integer,intent(in) :: nprocs, size1, size2
    5003              :  character(len=*),intent(in) :: order
    5004              :  integer,intent(out) :: n1, n2, ierr
    5005              : 
    5006              : !Local variables-------------------------------
    5007              :  integer :: ii
    5008              : !----------------------------------------------------------------------
    5009              : 
    5010           26 :  ierr = 1; n1 = -1; n2 = -1
    5011              : 
    5012           40 :  select case (order)
    5013              :  case ("12")
    5014           14 :    call balance_12()
    5015           14 :    if (ierr /= 0) call balance_1()
    5016              :  case ("21")
    5017            3 :    call balance_21()
    5018            3 :    if (ierr /= 0) call balance_2()
    5019              :  case ("1")
    5020            9 :    call balance_1()
    5021              :  case ("2")
    5022            0 :    call balance_2()
    5023              :  case default
    5024              :    ! Wrong order
    5025           26 :    ierr = -1
    5026              :  end select
    5027              : 
    5028              : contains
    5029              : 
    5030           14 : subroutine balance_12()
    5031              :  ! Try to find n1 x n2 = nprocs so that (size1, size2) are multiple of (n1, n2)
    5032           14 :  do ii=nprocs,1,-1
    5033           14 :    if (mod(size1, ii) == 0 .and. mod(nprocs, ii) == 0 .and. mod(size2, nprocs / ii) == 0) then
    5034           14 :      n1 = ii; n2 = nprocs / ii; ierr = 0; exit
    5035              :    end if
    5036              :  end do
    5037              : 
    5038           14 : end subroutine balance_12
    5039              : 
    5040            3 : subroutine balance_21()
    5041              :  ! Try to find n1 x n2 = nprocs so that (size1, size2) are multiple of (n1, n2)
    5042            3 :  do ii=nprocs,1,-1
    5043            3 :    if (mod(size2, ii) == 0 .and. mod(nprocs, ii) == 0 .and. mod(size1, nprocs / ii) == 0) then
    5044            3 :      n2 = ii; n1 = nprocs / ii; ierr = 0; exit
    5045              :    end if
    5046              :  end do
    5047            3 : end subroutine balance_21
    5048              : 
    5049            9 : subroutine balance_1()
    5050              :  integer :: imod1
    5051              :  ! Try to find n1 x n2 = nprocs so that only size1 is multiple of n1. Allow for some load imbalance.
    5052            9 :  do ii=nprocs,1,-1
    5053            9 :    imod1 = mod(size1, ii)
    5054            9 :    if ((imod1 == 0 .or. imod1 >= nprocs / 2) .and. mod(nprocs, ii) == 0 .and. size2 >= (nprocs/ii)) then
    5055            9 :      n1 = ii; n2 = nprocs / ii; ierr = 0; exit
    5056              :    end if
    5057              :  end do
    5058              : 
    5059            9 :  if (ierr /= 0 .and. nprocs <= size1) then
    5060            0 :    n1 = nprocs; n2 = 1; ierr = 0; return
    5061              :  end if
    5062              : end subroutine balance_1
    5063              : 
    5064            0 : subroutine balance_2()
    5065              :  integer :: imod2
    5066              :  ! Try to find n1 x n2 = nprocs so that only size2 is multiple of n2. Allow for some load imbalance.
    5067            0 :  do ii=nprocs,1,-1
    5068            0 :    imod2 = mod(size2, ii)
    5069            0 :    if ((imod2 == 0 .or. imod2 >= nprocs / 2) .and. mod(nprocs, ii) == 0 .and. size1 >= (nprocs/ii)) then
    5070            0 :      n2 = ii; n1 = nprocs / ii; ierr = 0; exit
    5071              :    end if
    5072              :  end do
    5073              : 
    5074            0 :  if (ierr /= 0 .and. nprocs <= size2) then
    5075            0 :    n2 = nprocs; n1 = 1; ierr = 0; return
    5076              :  end if
    5077              : end subroutine balance_2
    5078              : 
    5079              : end subroutine xmpi_distrib_2d
    5080              : !!***
    5081              : 
    5082              : !----------------------------------------------------------------------
    5083              : 
    5084              : !!****f* m_xmpi/xmpi_split_nsppol
    5085              : !! NAME
    5086              : !! xmpi_split_nsppol
    5087              : !!
    5088              : !! FUNCTION
    5089              : !!  Distribute collinear spins. Also create and return indirect mapping to spin index and init %brange_spin
    5090              : !!
    5091              : !! INPUTS
    5092              : !!  in_comm=Input communicator
    5093              : !!  nsppol=Number of spins
    5094              : !!
    5095              : !! OUTPUT
    5096              : !!  my_nspins=Number of spins treated by this MPI proc
    5097              : !!  my_spins(my_nspins)=Spin index
    5098              : !!  comm_my_is(my_nspins)=Spin communicator for each spin treated by this MPI proc.
    5099              : !!
    5100              : !! SOURCE
    5101              : 
    5102            2 : subroutine xmpi_split_nsppol(in_comm, nsppol, my_nspins, my_spins, comm_my_is)
    5103              : 
    5104              : !Arguments ------------------------------------
    5105              : !scalars
    5106              :  integer,intent(in) :: in_comm, nsppol
    5107              :  integer,intent(out) :: my_nspins
    5108              :  integer,allocatable,intent(out) :: my_spins(:)
    5109              :  type(xcomm_t),allocatable,intent(out) :: comm_my_is(:)
    5110              : 
    5111              : !Local variables-------------------------------
    5112              : !scalars
    5113              :  integer :: spin, my_rank, ierr, color, all_nprocs
    5114              : !arrays
    5115            4 :  integer :: buff_spin(nsppol), comm_spin(nsppol)
    5116              : !----------------------------------------------------------------------
    5117              : 
    5118            2 :  all_nprocs = xmpi_comm_size(in_comm); my_rank = xmpi_comm_rank(in_comm)
    5119              : 
    5120            2 :  my_nspins = 0
    5121            4 :  do spin=1,nsppol
    5122              :    ! NB: If MPI_UNDEFINED is passed as the colour value, the subgroup in which the calling MPI process will be placed is MPI_COMM_NULL
    5123            2 :    color = 1
    5124            2 :    if (nsppol == 2 .and. all_nprocs > 1) then
    5125            0 :      color = xmpi_undefined
    5126            0 :      if (spin == 1 .and. my_rank <= (all_nprocs - 1) / 2) color = 1
    5127            0 :      if (spin == 2 .and. my_rank > (all_nprocs - 1) / 2) color = 1
    5128              :    end if
    5129              : 
    5130            2 :    call xmpi_comm_split(in_comm, color, my_rank, comm_spin(spin), ierr)
    5131            4 :    if (comm_spin(spin) /= xmpi_comm_null) then
    5132            2 :      my_nspins = my_nspins + 1
    5133            2 :      buff_spin(my_nspins) = spin
    5134              :    end if
    5135              :  end do
    5136              : 
    5137            8 :  ABI_MALLOC(comm_my_is, (my_nspins))
    5138            2 :  my_nspins = 0
    5139            4 :  do spin=1,nsppol
    5140            4 :    if (comm_spin(spin) /= xmpi_comm_null) then
    5141            2 :      my_nspins = my_nspins + 1
    5142            2 :      comm_my_is(my_nspins) = xcomm_from_mpi_int(comm_spin(spin), free=.True.)
    5143              :    end if
    5144              :  end do
    5145              : 
    5146            6 :  ABI_MALLOC(my_spins, (my_nspins))
    5147            6 :  my_spins = buff_spin(1:my_nspins)
    5148              : 
    5149            2 : end subroutine xmpi_split_nsppol
    5150              : !!***
    5151              : 
    5152              : ! Init xcomm_t instance from MPI integer. Relase comm_int if optional argument free is set to .True.
    5153              : ! [root]: Rank of the proc treating iteration `iter`
    5154              : 
    5155           86 : type(xcomm_t) function xcomm_from_mpi_int(comm_int, free) result(new)
    5156              : 
    5157              : !Arguments ------------------------------------
    5158              :   integer,intent(inout) :: comm_int
    5159              :   integer :: new_comm, ierr
    5160              :   logical,optional,intent(in) :: free
    5161              : !----------------------------------------------------------------------
    5162              : 
    5163           86 :   new%value = comm_int; new%me = 0; new%nproc = 1
    5164              : #ifdef HAVE_MPI
    5165           86 :   call MPI_Comm_dup(comm_int, new_comm, ierr)
    5166           86 :   new%value = new_comm
    5167           86 :   new%nproc = xmpi_comm_size(new_comm)
    5168           86 :   new%me = xmpi_comm_rank(new_comm)
    5169           86 :   if (present(free)) then
    5170           32 :     if (free) call xmpi_comm_free(comm_int)
    5171              :   end if
    5172              : #endif
    5173           86 : end function xcomm_from_mpi_int
    5174              : 
    5175              : ! Skip iteration `iter` according to rank in xcomm.
    5176              : ! [root]: Rank of the proc treating iteration `iter`
    5177              : 
    5178       428171 : logical function xcomm_skip(xcomm, iter, root)
    5179              : 
    5180              : !Arguments ------------------------------------
    5181              :  class(xcomm_t),intent(in) :: xcomm
    5182              :  integer,intent(in) :: iter
    5183              :  integer,optional,intent(out) :: root
    5184              : 
    5185              : !Local variables-------------------------------
    5186              :  integer :: root__
    5187              : !----------------------------------------------------------------------
    5188              : 
    5189       428171 :  root__ = mod(iter, xcomm%nproc)
    5190       428171 :  xcomm_skip = root__ /= xcomm%me
    5191       428171 :  if (present(root)) root = root__
    5192       428171 : end function xcomm_skip
    5193              : 
    5194          177 : subroutine xcomm_set_to_self(xcomm)
    5195              :  class(xcomm_t),intent(inout) :: xcomm
    5196          177 :  call xcomm%free()
    5197          177 :  xcomm%value = xmpi_comm_self; xcomm%me = 0; xcomm%nproc = 1
    5198          177 : end subroutine xcomm_set_to_self
    5199              : 
    5200           58 : subroutine xcomm_set_to_null(xcomm)
    5201              : !Arguments ------------------------------------
    5202              :  class(xcomm_t),intent(inout) :: xcomm
    5203              : !----------------------------------------------------------------------
    5204              : 
    5205           58 :  call xcomm%free()
    5206           58 :  xcomm%value = xmpi_comm_null
    5207           58 : end subroutine xcomm_set_to_null
    5208              : 
    5209         1830 : subroutine xcomm_free(xcomm)
    5210              : !Arguments ------------------------------------
    5211              :  class(xcomm_t),intent(inout) :: xcomm
    5212              : !----------------------------------------------------------------------
    5213         1830 :  call xmpi_comm_free(xcomm%value)
    5214         1830 :  xcomm%me = -1; xcomm%nproc = 0
    5215         1830 : end subroutine xcomm_free
    5216              : 
    5217              : ! Build sub-communicators in a Cartesian grid.
    5218          652 : subroutine xcomm_from_cart_sub(xcomm, comm_cart, keepdim)
    5219              : 
    5220              : !Arguments ------------------------------------
    5221              :  class(xcomm_t),intent(out) :: xcomm
    5222              :  integer,intent(in) :: comm_cart
    5223              :  logical,intent(in) :: keepdim(:)
    5224              : 
    5225              : !Local variables-------------------------------
    5226              :  integer :: ierr
    5227              : !----------------------------------------------------------------------
    5228              : 
    5229              : #ifdef HAVE_MPI
    5230          652 :  call MPI_CART_SUB(comm_cart, keepdim, xcomm%value, ierr)
    5231              : #endif
    5232          652 :  xcomm%me = xmpi_comm_rank(xcomm%value)
    5233          652 :  xcomm%nproc = xmpi_comm_size(xcomm%value)
    5234              : 
    5235          652 : end subroutine xcomm_from_cart_sub
    5236              : 
    5237              : ! Creates new communicators based on split types and keys
    5238              : 
    5239           30 : type(xcomm_t) function xcomm_split_type(xcomm, split_type, key) result(out_xcomm)
    5240              : 
    5241              :  class(xcomm_t),intent(in) :: xcomm
    5242              :  integer,intent(in),optional :: split_type, key
    5243              : 
    5244              : !Local variables-------------------------------
    5245              :  integer :: split_type__, key__, shared_comm, ierr
    5246              : !----------------------------------------------------------------------
    5247              : 
    5248            0 :  key__ = 0; if (present(key)) key__ = key
    5249              : 
    5250              : #ifdef HAVE_MPI
    5251              :  ! Get node-level communicator
    5252           30 :  split_type__ = MPI_COMM_TYPE_SHARED; if (present(split_type)) split_type__ = split_type
    5253           30 :  call MPI_Comm_split_type(xcomm%value, split_type__, key__, MPI_INFO_NULL, shared_comm, ierr)
    5254           30 :  if (ierr /= MPI_SUCCESS) call xmpi_abort(msg="MPI_COMM_SPLIT_TYPE returned ierr /= 0")
    5255           30 :  out_xcomm = xcomm_from_mpi_int(shared_comm, free=.True.)
    5256              : #else
    5257              :  call out_xcomm%set_to_self()
    5258              : #endif
    5259              : 
    5260           30 : end function xcomm_split_type
    5261              : 
    5262              : ! Prepare a typical gatherv operation in which each MPI rank sends
    5263              : ! `nitems_per_rank(rank+1)` items and each item has length `nelem_per_item`.
    5264              : ! Final results are packed according to the rank of the processor.
    5265              : 
    5266            0 : subroutine xcomm_prep_gatherv(xcomm, nelem_per_item, nitems_per_rank, sendcount, recvcounts, displs)
    5267              : 
    5268              : !Arguments ------------------------------------
    5269              :  class(xcomm_t),intent(in) :: xcomm
    5270              :  integer,intent(in) :: nelem_per_item, nitems_per_rank(xcomm%nproc)
    5271              :  integer,intent(out) :: sendcount
    5272              :  integer, allocatable, intent(out) :: recvcounts(:), displs(:)
    5273              : 
    5274              : !Local variables-------------------
    5275              :  integer :: ii
    5276              : !----------------------------------------------------------------------
    5277              : 
    5278            0 :  ABI_MALLOC(recvcounts, (xcomm%nproc))
    5279            0 :  ABI_MALLOC(displs, (xcomm%nproc))
    5280            0 :  sendcount = nelem_per_item * nitems_per_rank(xcomm%me + 1)
    5281              : 
    5282            0 :  recvcounts(:) = nelem_per_item * nitems_per_rank
    5283            0 :  displs(1) = 0
    5284            0 :  do ii=2,xcomm%nproc
    5285            0 :    displs(ii) = nelem_per_item * sum(nitems_per_rank(1:ii-1))
    5286              :  end do
    5287            0 : end subroutine xcomm_prep_gatherv
    5288              : !!***
    5289              : 
    5290              : ! Debugging tool to print the hostname of the procs in the communicator
    5291            0 : subroutine xcomm_print_names(xcomm)
    5292              : 
    5293              : !Arguments ------------------------------------
    5294              :  class(xcomm_t),intent(in) :: xcomm
    5295              : 
    5296              : !Local variables-------------------
    5297              :  integer :: ip, ierr !, shared_comm
    5298            0 :  character(len=xmpi_max_processor_name) :: my_name, names(xcomm%nproc)
    5299              : !----------------------------------------------------------------------
    5300              : 
    5301            0 :  call xmpi_name(my_name, ierr)
    5302              :  ! FIXME
    5303              :  !call xmpi_allgather(my_name, names, xcomm%value, ierr)
    5304              : 
    5305              : ! ! Get node-level communicator.
    5306              : ! shared_comm = xmpi_comm_world
    5307              : !#ifdef HAVE_MPI
    5308              : ! call MPI_Comm_split_type(xcomm%value, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, shared_comm, ierr)
    5309              : !#endif
    5310              : ! shared_rank = xmpi_comm_rank(shared_comm)
    5311              : ! shared_size = xmpi_comm_size(shared_comm)
    5312              : 
    5313            0 :  if (xcomm%me == 0) then
    5314            0 :    write(std_out, "(a5,2x,a20)")"rank", "hostname"
    5315            0 :    do ip=0,xcomm%nproc-1
    5316            0 :      write(std_out, "(i5,2x,a20)")ip, trim(names(ip+1))
    5317              :      !write(*,*) 'Global rank', xcomm%me, trim(name(:name_len)), 'Shared rank', shared_rank, 'Shared size', shared_size
    5318              :    end do
    5319              :  end if
    5320              : 
    5321            0 : end subroutine xcomm_print_names
    5322              : !!***
    5323              : 
    5324              : ! True if all procs in xcomm can create a shared memory region. Cache the result.
    5325          174 : logical function xcomm_can_use_shmem(xcomm) result(ok)
    5326              : 
    5327              : !Arguments ------------------------------------
    5328              :  class(xcomm_t),intent(inout) :: xcomm
    5329              : !Local variables-------------------
    5330              :  integer :: ierr, new_comm
    5331              : !----------------------------------------------------------------------
    5332              : 
    5333          174 :  ok = .False.
    5334              : #ifdef HAVE_MPI
    5335          174 :  if (xcomm%can_use_shmem__ == - 1) then
    5336              :    ! First call --> cache result
    5337          126 :    call MPI_COMM_SPLIT_TYPE(xcomm%value, MPI_COMM_TYPE_SHARED, xcomm%me, MPI_INFO_NULL, new_comm, ierr)
    5338          126 :    xcomm%can_use_shmem__ = merge(1, 0, xmpi_comm_size(new_comm) == xcomm%nproc)
    5339          126 :    call xmpi_comm_free(new_comm)
    5340              :  end if
    5341          174 :  ok = xcomm%can_use_shmem__ == 1
    5342              : #endif
    5343              : 
    5344          174 : end function xcomm_can_use_shmem
    5345              : !!***
    5346              : 
    5347           78 : subroutine xcomm_allocate_shared_master(xcomm, count, kind, info, baseptr, win)
    5348              : 
    5349              : !Arguments ------------------------------------
    5350              :  class(xcomm_t),intent(inout) :: xcomm
    5351              :  integer(kind=XMPI_ADDRESS_KIND), intent(in) :: count
    5352              :  integer,intent(in) :: kind, info
    5353              :  type(c_ptr),intent(out) :: baseptr
    5354              :  integer,intent(out) :: win
    5355              : 
    5356              : !Local variables-------------------
    5357              :  integer :: disp_unit, ierr
    5358              :  integer(kind=XMPI_ADDRESS_KIND) :: my_size
    5359              : !----------------------------------------------------------------------
    5360              : 
    5361           78 :  if (.not. xcomm%can_use_shmem()) call xmpi_abort(msg="MPI communicator does not support shared memory allocation!")
    5362              : 
    5363           78 :  select case (kind)
    5364              :  case (sp)
    5365            0 :    disp_unit = xmpi_bsize_sp
    5366              :  case (dp)
    5367           78 :    disp_unit = xmpi_bsize_dp
    5368              :  case default
    5369           78 :    call xmpi_abort(msg="Invalid kind")
    5370              :  end select
    5371              : 
    5372              : #ifdef HAVE_MPI_ALLOCATE_SHARED_CPTR
    5373              :  ! This call is problematic as the API with type(c_ptr) requires mpi_f08 else gcc complains with
    5374              :  ! Error: Type mismatch in argument 'baseptr' at (1); passed TYPE(c_ptr) to INTEGER(8)
    5375              :  ! See https://github.com/pmodels/mpich/issues/2659
    5376              :  ! Converting C_PTR to INTEGER(KIND=MPI_ADDRESS_KIND) with the trick below is not portable:
    5377              :  !address = transfer(baseptr, address)
    5378              : 
    5379           78 :  my_size = 0; if (xcomm%me == 0) my_size = count * disp_unit
    5380           78 :  call MPI_WIN_ALLOCATE_SHARED(my_size, disp_unit, info, xcomm%value, baseptr, win, ierr)
    5381           78 :  if (ierr /= MPI_SUCCESS) call xmpi_abort(msg="mpi_win_allocated_shared returned ierr /= 0")
    5382           78 :  xmpi_count_wins = xmpi_count_wins + 1
    5383              : 
    5384              :  ! Synchronize to ensure memory is allocated.
    5385           78 :  call MPI_Barrier(xcomm%value, ierr)
    5386              : 
    5387           78 :  if (xcomm%me /= 0) then
    5388           52 :    call MPI_WIN_SHARED_QUERY(win, 0, my_size, disp_unit, baseptr, ierr)
    5389           52 :    if (ierr /= MPI_SUCCESS) call xmpi_abort(msg="mpi_win_shared_query returned ierr /= 0")
    5390              :  end if
    5391              : 
    5392              :  ! No local operations prior to this epoch, so give an assertion
    5393           78 :  call MPI_Win_fence(MPI_MODE_NOPRECEDE, win, ierr)
    5394           78 :  if (ierr /= MPI_SUCCESS) call xmpi_abort(msg="mpi_win_shared_query returned ierr /= 0")
    5395              : 
    5396           78 :  call MPI_Barrier(xcomm%value, ierr)
    5397              : 
    5398              : #else
    5399              :  call xmpi_abort(msg="MPI_WIN_ALLOCATE_SHARED with C_PTR is not supported by your MPI library!")
    5400              : #endif
    5401              : 
    5402           78 : end subroutine xcomm_allocate_shared_master
    5403              : !!***
    5404              : 
    5405              : !!****f* m_xmpi/pool2d_from_dims
    5406              : !! NAME
    5407              : !!  pool2d_from_dims
    5408              : !!
    5409              : !! FUNCTION
    5410              : !!  Build pool of MPI procs to distribute (n1 x n2) tasks.
    5411              : !!
    5412              : !! INPUTS
    5413              : !!  n1, n2: dimensions of the problem
    5414              : !!  input_comm: Initial MPI communicator
    5415              : !!  with_pools: Set it to False to use just one pool.
    5416              : !!  [rectangular]: If True, change the number of procs in each pool so that it's possible to
    5417              : !!      create a rectangular grid. Useful for Scalapack algorithms in which 1d grid are not efficient.
    5418              : !!      Default: False.
    5419              : !!
    5420              : !! SOURCE
    5421              : 
    5422            0 : subroutine pool2d_from_dims(pool, n1, n2, input_comm, with_pools, rectangular)
    5423              : 
    5424              : !Arguments-------------------------
    5425              :  class(xmpi_pool2d_t),intent(out) :: pool
    5426              :  integer,intent(in) :: n1, n2, input_comm
    5427              :  logical,intent(in) :: with_pools
    5428              :  logical,optional,intent(in) :: rectangular
    5429              : 
    5430              : !Local variables-------------------
    5431              :  integer :: itask, ntasks, my_rank, nprocs, color, mpierr, jj, i1, i2, my_ntasks, new_comm
    5432              :  integer :: grid_dims(2) !, check(n1, n2)
    5433            0 :  integer,allocatable :: my_inds(:)
    5434              : !----------------------------------------------------------------------
    5435              : 
    5436            0 :  my_rank = xmpi_comm_rank(input_comm); nprocs = xmpi_comm_size(input_comm)
    5437              : 
    5438            0 :  pool%n1 = n1; pool%n2 = n2
    5439            0 :  ABI_MALLOC(pool%treats, (n1, n2))
    5440            0 :  pool%treats = .False.
    5441              : 
    5442            0 :  ntasks = n1 * n2; color = ntasks + 1
    5443              : 
    5444            0 :  if (.not. with_pools) then
    5445            0 :    pool%treats = .True.; color = 1
    5446              : 
    5447            0 :  else if (nprocs <= ntasks) then
    5448            0 :     color = my_rank
    5449            0 :     call xmpi_split_block(ntasks, input_comm, my_ntasks, my_inds)
    5450            0 :     do jj=1,size(my_inds)
    5451            0 :       itask = my_inds(jj) ! = i1 + (i2 - 1) * n1
    5452            0 :       i1 = mod(itask - 1, n1) + 1
    5453            0 :       i2 = 1 + (itask - i1) / n1
    5454            0 :       pool%treats(i1, i2) = .True.
    5455              :     end do
    5456            0 :     ABI_FREE(my_inds)
    5457              :  else
    5458            0 :    i2_loop: do i2=1,n2
    5459            0 :      do i1=1,n1
    5460            0 :        itask = i1 + (i2 - 1) * n1
    5461            0 :        if (xmpi_distrib_with_replicas(itask, ntasks, my_rank, nprocs)) then
    5462            0 :          pool%treats(i1, i2) = .True.; color = itask; exit i2_loop
    5463              :        end if
    5464              :      end do
    5465              :    end do i2_loop
    5466              :  end if
    5467              : 
    5468              :  !DEBUG
    5469              :  ! where (pool%treats)
    5470              :  !   check = 1
    5471              :  ! else where
    5472              :  !   check = 0
    5473              :  ! end where
    5474              :  ! call xmpi_sum(check, input_comm, mpierr)
    5475              :  ! if (any(check == 0)) then
    5476              :  !   write(std_out, *) check
    5477              :  !   call xmpi_abort(msg="Wrong distribution in pool2d_from_dims")
    5478              :  ! end if
    5479              :  !END_DEBUG
    5480              : 
    5481            0 :  call xmpi_comm_split(input_comm, color, my_rank, new_comm, mpierr)
    5482            0 :  pool%comm = xcomm_from_mpi_int(new_comm)
    5483            0 :  call xmpi_comm_free(new_comm)
    5484              : 
    5485            0 :  if (present(rectangular)) then
    5486            0 :    if (rectangular) then
    5487            0 :      if (pool%comm%nproc == 1 .or. is_rectangular_grid(pool%comm%nproc, grid_dims)) return
    5488              : 
    5489            0 :      do jj=pool%comm%nproc-1,1,-1
    5490            0 :        if (is_rectangular_grid(jj, grid_dims)) then
    5491            0 :          color = merge(1, 0, pool%comm%me < jj)
    5492            0 :          call xmpi_comm_split(pool%comm%value, color, pool%comm%me, new_comm, mpierr)
    5493            0 :          call pool%comm%free()
    5494            0 :          pool%comm = xcomm_from_mpi_int(new_comm)
    5495            0 :          call xmpi_comm_free(new_comm)
    5496            0 :          if (color == 0) pool%treats = .False.
    5497              :          exit
    5498              :        end if
    5499              :      end do
    5500              :    end if
    5501              :  end if
    5502              : 
    5503              : contains
    5504              : 
    5505            0 : logical function is_rectangular_grid(nproc, grid_dims) result (ans)
    5506              :  integer,intent(in) :: nproc
    5507              :  integer,intent(out) :: grid_dims(2)
    5508              : 
    5509              : !----------------------------------------------------------------------
    5510              :  integer :: i
    5511              :  ! Search for a rectangular grid of processors
    5512            0 :  i = INT(SQRT(float(nproc)))
    5513            0 :  do while (MOD(nproc,i) /= 0)
    5514            0 :    i = i - 1
    5515              :  end do
    5516            0 :  i = max(i, 1)
    5517              : 
    5518            0 :  grid_dims(1) = i
    5519            0 :  grid_dims(2) = int(nproc / i)
    5520            0 :  ans = grid_dims(1) > 1 .and. grid_dims(2) > 1
    5521              : 
    5522            0 : end function is_rectangular_grid
    5523              : 
    5524              : end subroutine pool2d_from_dims
    5525              : !!***
    5526              : 
    5527              : !!****f* m_xmpi/pool2d_free
    5528              : !! NAME
    5529              : !!  pool2d_free
    5530              : !!
    5531              : !! FUNCTION
    5532              : !!  Free memory
    5533              : 
    5534            0 : subroutine pool2d_free(pool)
    5535              : 
    5536              : !Arguments-------------------------
    5537              :  class(xmpi_pool2d_t),intent(inout) :: pool
    5538              : !----------------------------------------------------------------------
    5539              : 
    5540            0 :  ABI_SFREE(pool%treats)
    5541            0 :  call pool%comm%free()
    5542              : 
    5543            0 : end subroutine pool2d_free
    5544              : !!***
    5545              : 
    5546         6564 : subroutine xmpi_win_fence(assert, win, ierr)
    5547              : 
    5548              : !Arguments ------------------------------------
    5549              :  integer,intent(in) :: win, assert
    5550              :  integer,intent(out) :: ierr
    5551              : !----------------------------------------------------------------------
    5552              : 
    5553         6564 :  ierr = 0
    5554              : #ifdef HAVE_MPI
    5555         6564 :  call MPI_WIN_FENCE(assert, win, ierr)
    5556              : #endif
    5557              : 
    5558         6564 : end subroutine xmpi_win_fence
    5559              : 
    5560           78 : subroutine xmpi_win_free(win, ierr)
    5561              : 
    5562              : !Arguments-------------------------
    5563              :  integer,intent(inout) :: win
    5564              :  integer,intent(out) :: ierr
    5565              : !----------------------------------------------------------------------
    5566              : 
    5567           78 :  ierr = 0
    5568              : #ifdef HAVE_MPI
    5569           78 :  call MPI_WIN_FREE(win, ierr)
    5570           78 :  win = xmpi_undefined
    5571           78 :  xmpi_count_wins = xmpi_count_wins - 1
    5572              : #endif
    5573              : 
    5574           78 : end subroutine xmpi_win_free
    5575              : !!***
    5576              : 
    5577              : ! Return the number of nodes `num_nodes` in the `in_comm` communicator.
    5578              : 
    5579              : subroutine xmpi_get_nodes_in_comm(in_comm, num_nodes, nprocs_per_node)
    5580              : 
    5581              : !Arguments-------------------------
    5582              :  integer,intent(in) :: in_comm
    5583              :  integer,intent(out) :: num_nodes
    5584              :  integer,optional,allocatable,intent(out) :: nprocs_per_node(:)
    5585              : 
    5586              : !Local variables-------------------
    5587              :  integer :: ierr, in_rank, node_comm, node_rank !, masters_comm, color, np
    5588              : !----------------------------------------------------------------------
    5589              : 
    5590              : #ifndef HAVE_MPI
    5591              :  num_nodes = 1
    5592              :  if (present(nprocs_per_node)) then
    5593              :    ABI_MALLOC(nprocs_per_node, (num_nodes))
    5594              :    nprocs_per_node = 1
    5595              :  end if
    5596              : 
    5597              : #else
    5598              :  in_rank = xmpi_comm_rank(in_comm)
    5599              :  call MPI_COMM_SPLIT_TYPE(in_comm, MPI_COMM_TYPE_SHARED, in_rank, MPI_INFO_NULL, node_comm, ierr)
    5600              :  node_rank = xmpi_comm_rank(node_comm)
    5601              :  num_nodes = merge(1, 0, node_rank == 0)
    5602              :  call xmpi_sum(num_nodes, in_comm, ierr)
    5603              : 
    5604              :  !if (present(nprocs_per_node)) then
    5605              :  !  ABI_MALLOC(nprocs_per_node, (num_nodes))
    5606              :  !  color = merge(0, 1, node_rank == 0)
    5607              :  !  call xmpi_comm_split(in_comm, color, in_rank, masters_comm, ierr)
    5608              :  !  if (color == 0) then
    5609              :  !    np = xmpi_comm_size(node_comm)
    5610              :  !    call MPI_GATHER(np, 1, MPI_INT, nprocs_per_node, 1, MPI_INT, 0, masters_comm, ierr)
    5611              :  !  end if
    5612              :  !  call xmpi_comm_free(masters_comm)
    5613              :  !end if
    5614              : 
    5615              :  call xmpi_comm_free(node_comm)
    5616              : #endif
    5617              : 
    5618              : end subroutine xmpi_get_nodes_in_comm
    5619              : !!***
    5620              : 
    5621            0 : end module m_xmpi
    5622              : !!***
        

Generated by: LCOV version 2.3-1