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