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-11-08 00:10:28 Functions: 53.8 % 91 49
Branches: 21.3 % 1343 286

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

Generated by: LCOV version 2.3-1