Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Interface to the message passing library MPI
10 : !> \par History
11 : !> JGH (02-Jan-2001): New error handling
12 : !> Performance tools
13 : !> JGH (14-Jan-2001): New routines mp_comm_compare, mp_cart_coords,
14 : !> mp_rank_compare, mp_alltoall
15 : !> JGH (06-Feb-2001): New routines mp_comm_free
16 : !> JGH (22-Mar-2001): New routines mp_comm_dup
17 : !> fawzi (04-NOV-2004): storable performance info (for f77 interface)
18 : !> Wrapper routine for mpi_gatherv added (22.12.2005,MK)
19 : !> JGH (13-Feb-2006): Flexible precision
20 : !> JGH (15-Feb-2006): single precision mp_alltoall
21 : !> \note Concurrent calls must use thread-private buffers and requests. Concurrent collectives,
22 : !> or point-to-point calls that do not use distinct tags, must use distinct communicators.
23 : !> Communicator creation, duplication, splitting, ownership changes, and destruction must
24 : !> happen outside OpenMP parallel regions.
25 : !> \author JGH
26 : ! **************************************************************************************************
27 : MODULE message_passing
28 : USE ISO_C_BINDING, ONLY: C_F_POINTER, C_PTR
29 : USE kinds, ONLY: &
30 : dp, int_4, int_4_size, int_8, int_8_size, real_4, real_4_size, real_8, &
31 : real_8_size, default_string_length
32 : USE machine, ONLY: m_abort
33 : USE mp_perf_env, ONLY: add_perf, add_mp_perf_env, rm_mp_perf_env
34 : USE OMP_LIB, ONLY: omp_get_level, omp_get_thread_num, omp_in_parallel
35 : #if defined(__MIMIC)
36 : USE mcl, ONLY: mcl_initialize, mcl_is_initialized, mcl_abort
37 : #endif
38 :
39 : #include "../base/base_uses.f90"
40 :
41 : ! To simplify the transition between the old MPI module and the F08-style module,
42 : ! we introduce these constants to switch between the required handle types
43 : ! Unfortunately, Fortran does not offer something like typedef in C++
44 : #if defined(__parallel) && defined(__MPI_F08)
45 : #define MPI_DATA_TYPE TYPE(MPI_Datatype)
46 : #define MPI_COMM_TYPE TYPE(MPI_Comm)
47 : #define MPI_REQUEST_TYPE TYPE(MPI_Request)
48 : #define MPI_WIN_TYPE TYPE(MPI_Win)
49 : #define MPI_FILE_TYPE TYPE(MPI_File)
50 : #define MPI_INFO_TYPE TYPE(MPI_Info)
51 : #define MPI_STATUS_TYPE TYPE(MPI_Status)
52 : #define MPI_GROUP_TYPE TYPE(MPI_Group)
53 : #define MPI_STATUS_EXTRACT(X) %X
54 : #define MPI_GET_COMP %mpi_val
55 : #else
56 : #define MPI_DATA_TYPE INTEGER
57 : #define MPI_COMM_TYPE INTEGER
58 : #define MPI_REQUEST_TYPE INTEGER
59 : #define MPI_WIN_TYPE INTEGER
60 : #define MPI_FILE_TYPE INTEGER
61 : #define MPI_INFO_TYPE INTEGER
62 : #define MPI_STATUS_TYPE INTEGER, DIMENSION(MPI_STATUS_SIZE)
63 : #define MPI_GROUP_TYPE INTEGER
64 : #define MPI_STATUS_EXTRACT(X) (X)
65 : #define MPI_GET_COMP
66 : #endif
67 :
68 : #if defined(__parallel)
69 : ! subroutines: unfortunately, mpi implementations do not provide interfaces for all subroutines
70 : ! (problems with types and ranks explosion),
71 : ! we do not quite know what is in the module, so we can not include any....
72 : ! to nevertheless get checking for what is included, we use the mpi module
73 : ! without use clause, getting all there is
74 : #if defined(__MPI_F08)
75 : USE mpi_f08
76 : #else
77 : USE mpi
78 : #endif
79 : #endif
80 :
81 : IMPLICIT NONE
82 : PRIVATE
83 :
84 : ! parameters that might be needed
85 : #if defined(__parallel)
86 : LOGICAL, PARAMETER :: cp2k_is_parallel = .TRUE.
87 : INTEGER, PARAMETER, PUBLIC :: mp_any_tag = MPI_ANY_TAG
88 : INTEGER, PARAMETER, PUBLIC :: mp_any_source = MPI_ANY_SOURCE
89 : MPI_COMM_TYPE, PARAMETER :: mp_comm_null_handle = MPI_COMM_NULL
90 : MPI_COMM_TYPE, PARAMETER :: mp_comm_self_handle = MPI_COMM_SELF
91 : MPI_COMM_TYPE, PARAMETER :: mp_comm_world_handle = MPI_COMM_WORLD
92 : MPI_REQUEST_TYPE, PARAMETER :: mp_request_null_handle = MPI_REQUEST_NULL
93 : MPI_WIN_TYPE, PARAMETER :: mp_win_null_handle = MPI_WIN_NULL
94 : MPI_FILE_TYPE, PARAMETER :: mp_file_null_handle = MPI_FILE_NULL
95 : MPI_INFO_TYPE, PARAMETER :: mp_info_null_handle = MPI_INFO_NULL
96 : MPI_DATA_TYPE, PARAMETER :: mp_datatype_null_handle = MPI_DATATYPE_NULL
97 : INTEGER, PARAMETER, PRIVATE :: mp_comm_split_type_shared_id = MPI_COMM_TYPE_SHARED
98 : INTEGER, PARAMETER, PUBLIC :: mp_status_size = MPI_STATUS_SIZE
99 : INTEGER, PARAMETER, PUBLIC :: mp_proc_null = MPI_PROC_NULL
100 : ! Set max allocatable memory by MPI to 2 GiByte
101 : INTEGER(KIND=MPI_ADDRESS_KIND), PARAMETER, PRIVATE :: mp_max_memory_size = HUGE(INT(1, KIND=int_4))
102 :
103 : INTEGER, PARAMETER, PUBLIC :: mp_max_library_version_string = MPI_MAX_LIBRARY_VERSION_STRING
104 :
105 : INTEGER, PARAMETER, PUBLIC :: file_offset = MPI_OFFSET_KIND
106 : INTEGER, PARAMETER, PUBLIC :: address_kind = MPI_ADDRESS_KIND
107 : INTEGER, PARAMETER, PUBLIC :: file_amode_create = MPI_MODE_CREATE
108 : INTEGER, PARAMETER, PUBLIC :: file_amode_rdonly = MPI_MODE_RDONLY
109 : INTEGER, PARAMETER, PUBLIC :: file_amode_wronly = MPI_MODE_WRONLY
110 : INTEGER, PARAMETER, PUBLIC :: file_amode_rdwr = MPI_MODE_RDWR
111 : INTEGER, PARAMETER, PUBLIC :: file_amode_excl = MPI_MODE_EXCL
112 : INTEGER, PARAMETER, PUBLIC :: file_amode_append = MPI_MODE_APPEND
113 : #else
114 : LOGICAL, PARAMETER :: cp2k_is_parallel = .FALSE.
115 : INTEGER, PARAMETER, PUBLIC :: mp_any_tag = -1
116 : INTEGER, PARAMETER, PUBLIC :: mp_any_source = -2
117 : MPI_COMM_TYPE, PARAMETER :: mp_comm_null_handle = -3
118 : MPI_COMM_TYPE, PARAMETER :: mp_comm_self_handle = -11
119 : MPI_COMM_TYPE, PARAMETER :: mp_comm_world_handle = -12
120 : MPI_REQUEST_TYPE, PARAMETER :: mp_request_null_handle = -4
121 : MPI_WIN_TYPE, PARAMETER :: mp_win_null_handle = -5
122 : MPI_FILE_TYPE, PARAMETER :: mp_file_null_handle = -6
123 : MPI_INFO_TYPE, PARAMETER :: mp_info_null_handle = -7
124 : MPI_DATA_TYPE, PARAMETER :: mp_datatype_null_handle = -8
125 : INTEGER, PARAMETER, PRIVATE :: mp_comm_split_type_shared_id = -13
126 : INTEGER, PARAMETER, PUBLIC :: mp_status_size = -9
127 : INTEGER, PARAMETER, PUBLIC :: mp_proc_null = -10
128 : INTEGER, PARAMETER, PUBLIC :: mp_max_library_version_string = 1
129 :
130 : INTEGER, PARAMETER, PUBLIC :: file_offset = int_8
131 : INTEGER, PARAMETER, PUBLIC :: address_kind = int_8
132 : INTEGER, PARAMETER, PUBLIC :: file_amode_create = 1
133 : INTEGER, PARAMETER, PUBLIC :: file_amode_rdonly = 2
134 : INTEGER, PARAMETER, PUBLIC :: file_amode_wronly = 4
135 : INTEGER, PARAMETER, PUBLIC :: file_amode_rdwr = 8
136 : INTEGER, PARAMETER, PUBLIC :: file_amode_excl = 64
137 : INTEGER, PARAMETER, PUBLIC :: file_amode_append = 128
138 : #endif
139 :
140 : ! we need to fix this to a given number (crossing fingers)
141 : ! so that the serial code using Fortran stream IO and the MPI have the same sizes.
142 : INTEGER, PARAMETER, PUBLIC :: mpi_character_size = 1
143 : INTEGER, PARAMETER, PUBLIC :: mpi_integer_size = 4
144 :
145 : CHARACTER(LEN=*), PARAMETER, PRIVATE :: moduleN = 'message_passing'
146 :
147 : ! internal reference counter used to debug communicator leaks
148 : INTEGER, PRIVATE, SAVE :: debug_comm_count
149 :
150 : ! Thread-support level provided by MPI. A negative value means that MPI has
151 : ! not been initialized by CP2K or queried from an embedding application yet.
152 : INTEGER, PRIVATE, SAVE :: mp_thread_level_provided = -1
153 :
154 : ! MPI can be initialized by CP2K or by an embedding application. Only the
155 : ! component that initialized MPI is allowed to finalize it.
156 : #if defined(__parallel)
157 : LOGICAL, PRIVATE, SAVE :: mp_mpi_initialized_by_cp2k = .FALSE.
158 : #endif
159 : LOGICAL, PRIVATE, SAVE :: mp_world_is_initialized = .FALSE.
160 :
161 : PUBLIC :: mp_comm_type
162 : PUBLIC :: mp_request_type
163 : PUBLIC :: mp_win_type
164 : PUBLIC :: mp_file_type
165 : PUBLIC :: mp_info_type
166 : PUBLIC :: mp_split_type
167 : PUBLIC :: mp_cart_type
168 :
169 : PUBLIC :: mp_para_env_type, mp_para_env_p_type, mp_para_cart_type
170 : PUBLIC :: mp_para_env_create, mp_para_env_release, &
171 : mp_para_cart_create, mp_para_cart_release
172 :
173 : #if defined(__MIMIC)
174 : ! Stores the split world communicator to finalize a MiMiC run
175 : MPI_COMM_TYPE, PRIVATE, SAVE :: mimic_comm_world
176 : #endif
177 :
178 : TYPE mp_comm_type
179 : PRIVATE
180 : MPI_COMM_TYPE :: handle = mp_comm_null_handle
181 : ! Number of dimensions within a Cartesian topology (useful with mp_cart_type)
182 : INTEGER :: ndims = 1
183 : ! Meta data to the communicator
184 : INTEGER, PUBLIC :: mepos = -1, source = -1, num_pe = -1
185 : CONTAINS
186 : ! Setters/Getters
187 : PROCEDURE, PASS, NON_OVERRIDABLE :: set_handle => mp_comm_type_set_handle
188 : PROCEDURE, PASS, NON_OVERRIDABLE :: get_handle => mp_comm_type_get_handle
189 : ! Comparisons
190 : PROCEDURE, PRIVATE, PASS, NON_OVERRIDABLE :: mp_comm_op_eq
191 : PROCEDURE, PRIVATE, PASS, NON_OVERRIDABLE :: mp_comm_op_neq
192 : GENERIC, PUBLIC :: operator(==) => mp_comm_op_eq
193 : GENERIC, PUBLIC :: operator(/=) => mp_comm_op_neq
194 : ! Communication routines
195 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: &
196 : mp_sendrecv_i, mp_sendrecv_l, mp_sendrecv_r, mp_sendrecv_d, &
197 : mp_sendrecv_c, mp_sendrecv_z, &
198 : mp_sendrecv_iv, mp_sendrecv_im2, mp_sendrecv_im3, mp_sendrecv_im4, &
199 : mp_sendrecv_lv, mp_sendrecv_lm2, mp_sendrecv_lm3, mp_sendrecv_lm4, &
200 : mp_sendrecv_rv, mp_sendrecv_rm2, mp_sendrecv_rm3, mp_sendrecv_rm4, &
201 : mp_sendrecv_dv, mp_sendrecv_dm2, mp_sendrecv_dm3, mp_sendrecv_dm4, &
202 : mp_sendrecv_cv, mp_sendrecv_cm2, mp_sendrecv_cm3, mp_sendrecv_cm4, &
203 : mp_sendrecv_zv, mp_sendrecv_zm2, mp_sendrecv_zm3, mp_sendrecv_zm4
204 : GENERIC, PUBLIC :: sendrecv => mp_sendrecv_i, mp_sendrecv_l, &
205 : mp_sendrecv_r, mp_sendrecv_d, mp_sendrecv_c, mp_sendrecv_z, &
206 : mp_sendrecv_iv, mp_sendrecv_im2, mp_sendrecv_im3, mp_sendrecv_im4, &
207 : mp_sendrecv_lv, mp_sendrecv_lm2, mp_sendrecv_lm3, mp_sendrecv_lm4, &
208 : mp_sendrecv_rv, mp_sendrecv_rm2, mp_sendrecv_rm3, mp_sendrecv_rm4, &
209 : mp_sendrecv_dv, mp_sendrecv_dm2, mp_sendrecv_dm3, mp_sendrecv_dm4, &
210 : mp_sendrecv_cv, mp_sendrecv_cm2, mp_sendrecv_cm3, mp_sendrecv_cm4, &
211 : mp_sendrecv_zv, mp_sendrecv_zm2, mp_sendrecv_zm3, mp_sendrecv_zm4
212 :
213 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_minloc_iv, &
214 : mp_minloc_lv, mp_minloc_rv, mp_minloc_dv
215 : GENERIC, PUBLIC :: minloc => mp_minloc_iv, &
216 : mp_minloc_lv, mp_minloc_rv, mp_minloc_dv
217 :
218 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_maxloc_iv, &
219 : mp_maxloc_lv, mp_maxloc_rv, mp_maxloc_dv
220 : GENERIC, PUBLIC :: maxloc => mp_maxloc_iv, &
221 : mp_maxloc_lv, mp_maxloc_rv, mp_maxloc_dv
222 :
223 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_shift_im, mp_shift_i, &
224 : mp_shift_lm, mp_shift_l, mp_shift_rm, mp_shift_r, &
225 : mp_shift_dm, mp_shift_d, mp_shift_cm, mp_shift_c, &
226 : mp_shift_zm, mp_shift_z
227 : GENERIC, PUBLIC :: shift => mp_shift_im, mp_shift_i, &
228 : mp_shift_lm, mp_shift_l, mp_shift_rm, mp_shift_r, &
229 : mp_shift_dm, mp_shift_d, mp_shift_cm, mp_shift_c, &
230 : mp_shift_zm, mp_shift_z
231 :
232 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_bcast_i, mp_bcast_iv, mp_bcast_im, mp_bcast_i3, &
233 : mp_bcast_l, mp_bcast_lv, mp_bcast_lm, mp_bcast_l3, &
234 : mp_bcast_r, mp_bcast_rv, mp_bcast_rm, mp_bcast_r3, &
235 : mp_bcast_d, mp_bcast_dv, mp_bcast_dm, mp_bcast_d3, &
236 : mp_bcast_c, mp_bcast_cv, mp_bcast_cm, mp_bcast_c3, &
237 : mp_bcast_z, mp_bcast_zv, mp_bcast_zm, mp_bcast_z3, &
238 : mp_bcast_b, mp_bcast_bv, mp_bcast_av, mp_bcast_am, &
239 : mp_bcast_i_src, mp_bcast_iv_src, mp_bcast_im_src, mp_bcast_i3_src, &
240 : mp_bcast_l_src, mp_bcast_lv_src, mp_bcast_lm_src, mp_bcast_l3_src, &
241 : mp_bcast_r_src, mp_bcast_rv_src, mp_bcast_rm_src, mp_bcast_r3_src, &
242 : mp_bcast_d_src, mp_bcast_dv_src, mp_bcast_dm_src, mp_bcast_d3_src, &
243 : mp_bcast_c_src, mp_bcast_cv_src, mp_bcast_cm_src, mp_bcast_c3_src, &
244 : mp_bcast_z_src, mp_bcast_zv_src, mp_bcast_zm_src, mp_bcast_z3_src, &
245 : mp_bcast_b_src, mp_bcast_bv_src, mp_bcast_av_src, mp_bcast_am_src
246 : GENERIC, PUBLIC :: bcast => mp_bcast_i, mp_bcast_iv, mp_bcast_im, mp_bcast_i3, &
247 : mp_bcast_l, mp_bcast_lv, mp_bcast_lm, mp_bcast_l3, &
248 : mp_bcast_r, mp_bcast_rv, mp_bcast_rm, mp_bcast_r3, &
249 : mp_bcast_d, mp_bcast_dv, mp_bcast_dm, mp_bcast_d3, &
250 : mp_bcast_c, mp_bcast_cv, mp_bcast_cm, mp_bcast_c3, &
251 : mp_bcast_z, mp_bcast_zv, mp_bcast_zm, mp_bcast_z3, &
252 : mp_bcast_b, mp_bcast_bv, mp_bcast_av, mp_bcast_am, &
253 : mp_bcast_i_src, mp_bcast_iv_src, mp_bcast_im_src, mp_bcast_i3_src, &
254 : mp_bcast_l_src, mp_bcast_lv_src, mp_bcast_lm_src, mp_bcast_l3_src, &
255 : mp_bcast_r_src, mp_bcast_rv_src, mp_bcast_rm_src, mp_bcast_r3_src, &
256 : mp_bcast_d_src, mp_bcast_dv_src, mp_bcast_dm_src, mp_bcast_d3_src, &
257 : mp_bcast_c_src, mp_bcast_cv_src, mp_bcast_cm_src, mp_bcast_c3_src, &
258 : mp_bcast_z_src, mp_bcast_zv_src, mp_bcast_zm_src, mp_bcast_z3_src, &
259 : mp_bcast_b_src, mp_bcast_bv_src, mp_bcast_av_src, mp_bcast_am_src
260 :
261 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_ibcast_i, mp_ibcast_iv, &
262 : mp_ibcast_l, mp_ibcast_lv, mp_ibcast_r, mp_ibcast_rv, &
263 : mp_ibcast_d, mp_ibcast_dv, mp_ibcast_c, mp_ibcast_cv, &
264 : mp_ibcast_z, mp_ibcast_zv
265 : GENERIC, PUBLIC :: ibcast => mp_ibcast_i, mp_ibcast_iv, &
266 : mp_ibcast_l, mp_ibcast_lv, mp_ibcast_r, mp_ibcast_rv, &
267 : mp_ibcast_d, mp_ibcast_dv, mp_ibcast_c, mp_ibcast_cv, &
268 : mp_ibcast_z, mp_ibcast_zv
269 :
270 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: &
271 : mp_sum_i, mp_sum_iv, mp_sum_im, mp_sum_im3, mp_sum_im4, &
272 : mp_sum_l, mp_sum_lv, mp_sum_lm, mp_sum_lm3, mp_sum_lm4, &
273 : mp_sum_r, mp_sum_rv, mp_sum_rm, mp_sum_rm3, mp_sum_rm4, &
274 : mp_sum_d, mp_sum_dv, mp_sum_dm, mp_sum_dm3, mp_sum_dm4, &
275 : mp_sum_c, mp_sum_cv, mp_sum_cm, mp_sum_cm3, mp_sum_cm4, &
276 : mp_sum_z, mp_sum_zv, mp_sum_zm, mp_sum_zm3, mp_sum_zm4, &
277 : mp_sum_root_iv, mp_sum_root_im, mp_sum_root_lv, mp_sum_root_lm, &
278 : mp_sum_root_rv, mp_sum_root_rm, mp_sum_root_dv, mp_sum_root_dm, &
279 : mp_sum_root_cv, mp_sum_root_cm, mp_sum_root_zv, mp_sum_root_zm, &
280 : mp_sum_b, mp_sum_bv
281 : GENERIC, PUBLIC :: sum => mp_sum_i, mp_sum_iv, mp_sum_im, mp_sum_im3, mp_sum_im4, &
282 : mp_sum_l, mp_sum_lv, mp_sum_lm, mp_sum_lm3, mp_sum_lm4, &
283 : mp_sum_r, mp_sum_rv, mp_sum_rm, mp_sum_rm3, mp_sum_rm4, &
284 : mp_sum_d, mp_sum_dv, mp_sum_dm, mp_sum_dm3, mp_sum_dm4, &
285 : mp_sum_c, mp_sum_cv, mp_sum_cm, mp_sum_cm3, mp_sum_cm4, &
286 : mp_sum_z, mp_sum_zv, mp_sum_zm, mp_sum_zm3, mp_sum_zm4, &
287 : mp_sum_root_iv, mp_sum_root_im, mp_sum_root_lv, mp_sum_root_lm, &
288 : mp_sum_root_rv, mp_sum_root_rm, mp_sum_root_dv, mp_sum_root_dm, &
289 : mp_sum_root_cv, mp_sum_root_cm, mp_sum_root_zv, mp_sum_root_zm, &
290 : mp_sum_b, mp_sum_bv
291 :
292 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_isum_iv, &
293 : mp_isum_lv, mp_isum_rv, mp_isum_dv, mp_isum_cv, &
294 : mp_isum_zv, mp_isum_bv
295 : GENERIC, PUBLIC :: isum => mp_isum_iv, &
296 : mp_isum_lv, mp_isum_rv, mp_isum_dv, mp_isum_cv, &
297 : mp_isum_zv, mp_isum_bv
298 :
299 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_sum_partial_im, &
300 : mp_sum_partial_lm, mp_sum_partial_rm, mp_sum_partial_dm, &
301 : mp_sum_partial_cm, mp_sum_partial_zm
302 : GENERIC, PUBLIC :: sum_partial => mp_sum_partial_im, &
303 : mp_sum_partial_lm, mp_sum_partial_rm, mp_sum_partial_dm, &
304 : mp_sum_partial_cm, mp_sum_partial_zm
305 :
306 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_max_i, mp_max_iv, &
307 : mp_max_im, &
308 : mp_max_l, mp_max_lv, mp_max_lm, &
309 : mp_max_r, mp_max_rv, mp_max_rm, &
310 : mp_max_d, mp_max_dv, mp_max_dm, &
311 : mp_max_c, mp_max_cv, mp_max_cm, &
312 : mp_max_z, mp_max_zv, mp_max_zm, &
313 : mp_max_root_i, mp_max_root_l, &
314 : mp_max_root_r, mp_max_root_d, mp_max_root_c, mp_max_root_z, &
315 : mp_max_root_im, mp_max_root_lm, mp_max_root_rm, mp_max_root_dm, &
316 : mp_max_root_cm, mp_max_root_zm
317 : GENERIC, PUBLIC :: max => mp_max_i, mp_max_iv, &
318 : mp_max_im, &
319 : mp_max_l, mp_max_lv, mp_max_lm, &
320 : mp_max_r, mp_max_rv, mp_max_rm, &
321 : mp_max_d, mp_max_dv, mp_max_dm, &
322 : mp_max_c, mp_max_cv, mp_max_cm, &
323 : mp_max_z, mp_max_zv, mp_max_zm, &
324 : mp_max_root_i, mp_max_root_l, &
325 : mp_max_root_r, mp_max_root_d, mp_max_root_c, mp_max_root_z, &
326 : mp_max_root_im, mp_max_root_lm, mp_max_root_rm, mp_max_root_dm, &
327 : mp_max_root_cm, mp_max_root_zm
328 :
329 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_min_i, mp_min_iv, &
330 : mp_min_im, &
331 : mp_min_l, mp_min_lv, mp_min_lm, &
332 : mp_min_r, mp_min_rv, mp_min_rm, &
333 : mp_min_d, mp_min_dv, mp_min_dm, &
334 : mp_min_c, mp_min_cv, mp_min_cm, &
335 : mp_min_z, mp_min_zv, mp_min_zm
336 : GENERIC, PUBLIC :: min => mp_min_i, mp_min_iv, &
337 : mp_min_im, &
338 : mp_min_l, mp_min_lv, mp_min_lm, &
339 : mp_min_r, mp_min_rv, mp_min_rm, &
340 : mp_min_d, mp_min_dv, mp_min_dm, &
341 : mp_min_c, mp_min_cv, mp_min_cm, &
342 : mp_min_z, mp_min_zv, mp_min_zm
343 :
344 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: &
345 : mp_sum_scatter_iv, mp_sum_scatter_lv, mp_sum_scatter_rv, &
346 : mp_sum_scatter_dv, mp_sum_scatter_cv, mp_sum_scatter_zv
347 : GENERIC, PUBLIC :: sum_scatter => &
348 : mp_sum_scatter_iv, mp_sum_scatter_lv, mp_sum_scatter_rv, &
349 : mp_sum_scatter_dv, mp_sum_scatter_cv, mp_sum_scatter_zv
350 :
351 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_prod_r, mp_prod_d, mp_prod_c, mp_prod_z
352 : GENERIC, PUBLIC :: prod => mp_prod_r, mp_prod_d, mp_prod_c, mp_prod_z
353 :
354 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_gather_i, mp_gather_iv, mp_gather_im, &
355 : mp_gather_l, mp_gather_lv, mp_gather_lm, &
356 : mp_gather_r, mp_gather_rv, mp_gather_rm, &
357 : mp_gather_d, mp_gather_dv, mp_gather_dm, &
358 : mp_gather_c, mp_gather_cv, mp_gather_cm, &
359 : mp_gather_z, mp_gather_zv, mp_gather_zm, &
360 : mp_gather_i_src, mp_gather_iv_src, mp_gather_im_src, &
361 : mp_gather_l_src, mp_gather_lv_src, mp_gather_lm_src, &
362 : mp_gather_r_src, mp_gather_rv_src, mp_gather_rm_src, &
363 : mp_gather_d_src, mp_gather_dv_src, mp_gather_dm_src, &
364 : mp_gather_c_src, mp_gather_cv_src, mp_gather_cm_src, &
365 : mp_gather_z_src, mp_gather_zv_src, mp_gather_zm_src
366 : GENERIC, PUBLIC :: gather => mp_gather_i, mp_gather_iv, mp_gather_im, &
367 : mp_gather_l, mp_gather_lv, mp_gather_lm, &
368 : mp_gather_r, mp_gather_rv, mp_gather_rm, &
369 : mp_gather_d, mp_gather_dv, mp_gather_dm, &
370 : mp_gather_c, mp_gather_cv, mp_gather_cm, &
371 : mp_gather_z, mp_gather_zv, mp_gather_zm, &
372 : mp_gather_i_src, mp_gather_iv_src, mp_gather_im_src, &
373 : mp_gather_l_src, mp_gather_lv_src, mp_gather_lm_src, &
374 : mp_gather_r_src, mp_gather_rv_src, mp_gather_rm_src, &
375 : mp_gather_d_src, mp_gather_dv_src, mp_gather_dm_src, &
376 : mp_gather_c_src, mp_gather_cv_src, mp_gather_cm_src, &
377 : mp_gather_z_src, mp_gather_zv_src, mp_gather_zm_src
378 :
379 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_gatherv_iv, &
380 : mp_gatherv_lv, mp_gatherv_rv, mp_gatherv_dv, &
381 : mp_gatherv_cv, mp_gatherv_zv, mp_gatherv_lm2, mp_gatherv_rm2, &
382 : mp_gatherv_dm2, mp_gatherv_cm2, mp_gatherv_zm2, mp_gatherv_iv_src, &
383 : mp_gatherv_lv_src, mp_gatherv_rv_src, mp_gatherv_dv_src, &
384 : mp_gatherv_cv_src, mp_gatherv_zv_src, mp_gatherv_lm2_src, mp_gatherv_rm2_src, &
385 : mp_gatherv_dm2_src, mp_gatherv_cm2_src, mp_gatherv_zm2_src
386 : GENERIC, PUBLIC :: gatherv => mp_gatherv_iv, &
387 : mp_gatherv_lv, mp_gatherv_rv, mp_gatherv_dv, &
388 : mp_gatherv_cv, mp_gatherv_zv, mp_gatherv_lm2, mp_gatherv_rm2, &
389 : mp_gatherv_dm2, mp_gatherv_cm2, mp_gatherv_zm2, mp_gatherv_iv_src, &
390 : mp_gatherv_lv_src, mp_gatherv_rv_src, mp_gatherv_dv_src, &
391 : mp_gatherv_cv_src, mp_gatherv_zv_src, mp_gatherv_lm2_src, mp_gatherv_rm2_src, &
392 : mp_gatherv_dm2_src, mp_gatherv_cm2_src, mp_gatherv_zm2_src
393 :
394 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_igatherv_iv, &
395 : mp_igatherv_lv, mp_igatherv_rv, mp_igatherv_dv, &
396 : mp_igatherv_cv, mp_igatherv_zv
397 : GENERIC, PUBLIC :: igatherv => mp_igatherv_iv, &
398 : mp_igatherv_lv, mp_igatherv_rv, mp_igatherv_dv, &
399 : mp_igatherv_cv, mp_igatherv_zv
400 :
401 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_allgather_i, mp_allgather_i2, &
402 : mp_allgather_i12, mp_allgather_i23, mp_allgather_i34, &
403 : mp_allgather_i22, mp_allgather_l, mp_allgather_l2, &
404 : mp_allgather_l12, mp_allgather_l23, mp_allgather_l34, &
405 : mp_allgather_l22, mp_allgather_r, mp_allgather_r2, &
406 : mp_allgather_r12, mp_allgather_r23, mp_allgather_r34, &
407 : mp_allgather_r22, mp_allgather_d, mp_allgather_d2, &
408 : mp_allgather_d12, mp_allgather_d23, mp_allgather_d34, &
409 : mp_allgather_d22, mp_allgather_c, mp_allgather_c2, &
410 : mp_allgather_c12, mp_allgather_c23, mp_allgather_c34, &
411 : mp_allgather_c22, mp_allgather_z, mp_allgather_z2, &
412 : mp_allgather_z12, mp_allgather_z23, mp_allgather_z34, &
413 : mp_allgather_z22
414 : GENERIC, PUBLIC :: allgather => mp_allgather_i, mp_allgather_i2, &
415 : mp_allgather_i12, mp_allgather_i23, mp_allgather_i34, &
416 : mp_allgather_i22, mp_allgather_l, mp_allgather_l2, &
417 : mp_allgather_l12, mp_allgather_l23, mp_allgather_l34, &
418 : mp_allgather_l22, mp_allgather_r, mp_allgather_r2, &
419 : mp_allgather_r12, mp_allgather_r23, mp_allgather_r34, &
420 : mp_allgather_r22, mp_allgather_d, mp_allgather_d2, &
421 : mp_allgather_d12, mp_allgather_d23, mp_allgather_d34, &
422 : mp_allgather_d22, mp_allgather_c, mp_allgather_c2, &
423 : mp_allgather_c12, mp_allgather_c23, mp_allgather_c34, &
424 : mp_allgather_c22, mp_allgather_z, mp_allgather_z2, &
425 : mp_allgather_z12, mp_allgather_z23, mp_allgather_z34, &
426 : mp_allgather_z22
427 :
428 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_allgatherv_iv, mp_allgatherv_lv, &
429 : mp_allgatherv_rv, mp_allgatherv_dv, mp_allgatherv_cv, mp_allgatherv_zv, &
430 : mp_allgatherv_im2, mp_allgatherv_lm2, mp_allgatherv_rm2, &
431 : mp_allgatherv_dm2, mp_allgatherv_cm2, mp_allgatherv_zm2
432 : GENERIC, PUBLIC :: allgatherv => mp_allgatherv_iv, mp_allgatherv_lv, &
433 : mp_allgatherv_rv, mp_allgatherv_dv, mp_allgatherv_cv, mp_allgatherv_zv, &
434 : mp_allgatherv_im2, mp_allgatherv_lm2, mp_allgatherv_rm2, &
435 : mp_allgatherv_dm2, mp_allgatherv_cm2, mp_allgatherv_zm2
436 :
437 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_iallgather_i, mp_iallgather_l, &
438 : mp_iallgather_r, mp_iallgather_d, mp_iallgather_c, mp_iallgather_z, &
439 : mp_iallgather_i11, mp_iallgather_l11, mp_iallgather_r11, mp_iallgather_d11, &
440 : mp_iallgather_c11, mp_iallgather_z11, mp_iallgather_i13, mp_iallgather_l13, &
441 : mp_iallgather_r13, mp_iallgather_d13, mp_iallgather_c13, mp_iallgather_z13, &
442 : mp_iallgather_i22, mp_iallgather_l22, mp_iallgather_r22, mp_iallgather_d22, &
443 : mp_iallgather_c22, mp_iallgather_z22, mp_iallgather_i24, mp_iallgather_l24, &
444 : mp_iallgather_r24, mp_iallgather_d24, mp_iallgather_c24, mp_iallgather_z24, &
445 : mp_iallgather_i33, mp_iallgather_l33, mp_iallgather_r33, mp_iallgather_d33, &
446 : mp_iallgather_c33, mp_iallgather_z33
447 : GENERIC, PUBLIC :: iallgather => mp_iallgather_i, mp_iallgather_l, &
448 : mp_iallgather_r, mp_iallgather_d, mp_iallgather_c, mp_iallgather_z, &
449 : mp_iallgather_i11, mp_iallgather_l11, mp_iallgather_r11, mp_iallgather_d11, &
450 : mp_iallgather_c11, mp_iallgather_z11, mp_iallgather_i13, mp_iallgather_l13, &
451 : mp_iallgather_r13, mp_iallgather_d13, mp_iallgather_c13, mp_iallgather_z13, &
452 : mp_iallgather_i22, mp_iallgather_l22, mp_iallgather_r22, mp_iallgather_d22, &
453 : mp_iallgather_c22, mp_iallgather_z22, mp_iallgather_i24, mp_iallgather_l24, &
454 : mp_iallgather_r24, mp_iallgather_d24, mp_iallgather_c24, mp_iallgather_z24, &
455 : mp_iallgather_i33, mp_iallgather_l33, mp_iallgather_r33, mp_iallgather_d33, &
456 : mp_iallgather_c33, mp_iallgather_z33
457 :
458 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_iallgatherv_iv, mp_iallgatherv_iv2, &
459 : mp_iallgatherv_lv, mp_iallgatherv_lv2, mp_iallgatherv_rv, mp_iallgatherv_rv2, &
460 : mp_iallgatherv_dv, mp_iallgatherv_dv2, mp_iallgatherv_cv, mp_iallgatherv_cv2, &
461 : mp_iallgatherv_zv, mp_iallgatherv_zv2
462 : GENERIC, PUBLIC :: iallgatherv => mp_iallgatherv_iv, mp_iallgatherv_iv2, &
463 : mp_iallgatherv_lv, mp_iallgatherv_lv2, mp_iallgatherv_rv, mp_iallgatherv_rv2, &
464 : mp_iallgatherv_dv, mp_iallgatherv_dv2, mp_iallgatherv_cv, mp_iallgatherv_cv2, &
465 : mp_iallgatherv_zv, mp_iallgatherv_zv2
466 :
467 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_scatter_iv, mp_scatter_lv, &
468 : mp_scatter_rv, mp_scatter_dv, mp_scatter_cv, mp_scatter_zv
469 : GENERIC, PUBLIC :: scatter => mp_scatter_iv, mp_scatter_lv, &
470 : mp_scatter_rv, mp_scatter_dv, mp_scatter_cv, mp_scatter_zv
471 :
472 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_iscatter_i, mp_iscatter_l, &
473 : mp_iscatter_r, mp_iscatter_d, mp_iscatter_c, mp_iscatter_z, &
474 : mp_iscatter_iv2, mp_iscatter_lv2, mp_iscatter_rv2, mp_iscatter_dv2, &
475 : mp_iscatter_cv2, mp_iscatter_zv2
476 : GENERIC, PUBLIC :: iscatter => mp_iscatter_i, mp_iscatter_l, &
477 : mp_iscatter_r, mp_iscatter_d, mp_iscatter_c, mp_iscatter_z, &
478 : mp_iscatter_iv2, mp_iscatter_lv2, mp_iscatter_rv2, mp_iscatter_dv2, &
479 : mp_iscatter_cv2, mp_iscatter_zv2
480 :
481 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_iscatterv_iv, mp_iscatterv_lv, &
482 : mp_iscatterv_rv, mp_iscatterv_dv, mp_iscatterv_cv, mp_iscatterv_zv
483 : GENERIC, PUBLIC :: iscatterv => mp_iscatterv_iv, mp_iscatterv_lv, &
484 : mp_iscatterv_rv, mp_iscatterv_dv, mp_iscatterv_cv, mp_iscatterv_zv
485 :
486 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_alltoall_i, mp_alltoall_i22, mp_alltoall_i33, &
487 : mp_alltoall_i44, mp_alltoall_i55, mp_alltoall_i45, mp_alltoall_i34, &
488 : mp_alltoall_i11v, mp_alltoall_i22v, mp_alltoall_i54, &
489 : mp_alltoall_l, mp_alltoall_l22, mp_alltoall_l33, &
490 : mp_alltoall_l44, mp_alltoall_l55, mp_alltoall_l45, mp_alltoall_l34, &
491 : mp_alltoall_l11v, mp_alltoall_l22v, mp_alltoall_l54, &
492 : mp_alltoall_r, mp_alltoall_r22, mp_alltoall_r33, &
493 : mp_alltoall_r44, mp_alltoall_r55, mp_alltoall_r45, mp_alltoall_r34, &
494 : mp_alltoall_r11v, mp_alltoall_r22v, mp_alltoall_r54, &
495 : mp_alltoall_d, mp_alltoall_d22, mp_alltoall_d33, &
496 : mp_alltoall_d44, mp_alltoall_d55, mp_alltoall_d45, mp_alltoall_d34, &
497 : mp_alltoall_d11v, mp_alltoall_d22v, mp_alltoall_d54, &
498 : mp_alltoall_c, mp_alltoall_c22, mp_alltoall_c33, &
499 : mp_alltoall_c44, mp_alltoall_c55, mp_alltoall_c45, mp_alltoall_c34, &
500 : mp_alltoall_c11v, mp_alltoall_c22v, mp_alltoall_c54, &
501 : mp_alltoall_z, mp_alltoall_z22, mp_alltoall_z33, &
502 : mp_alltoall_z44, mp_alltoall_z55, mp_alltoall_z45, mp_alltoall_z34, &
503 : mp_alltoall_z11v, mp_alltoall_z22v, mp_alltoall_z54
504 : GENERIC, PUBLIC :: alltoall => mp_alltoall_i, mp_alltoall_i22, mp_alltoall_i33, &
505 : mp_alltoall_i44, mp_alltoall_i55, mp_alltoall_i45, mp_alltoall_i34, &
506 : mp_alltoall_i11v, mp_alltoall_i22v, mp_alltoall_i54, &
507 : mp_alltoall_l, mp_alltoall_l22, mp_alltoall_l33, &
508 : mp_alltoall_l44, mp_alltoall_l55, mp_alltoall_l45, mp_alltoall_l34, &
509 : mp_alltoall_l11v, mp_alltoall_l22v, mp_alltoall_l54, &
510 : mp_alltoall_r, mp_alltoall_r22, mp_alltoall_r33, &
511 : mp_alltoall_r44, mp_alltoall_r55, mp_alltoall_r45, mp_alltoall_r34, &
512 : mp_alltoall_r11v, mp_alltoall_r22v, mp_alltoall_r54, &
513 : mp_alltoall_d, mp_alltoall_d22, mp_alltoall_d33, &
514 : mp_alltoall_d44, mp_alltoall_d55, mp_alltoall_d45, mp_alltoall_d34, &
515 : mp_alltoall_d11v, mp_alltoall_d22v, mp_alltoall_d54, &
516 : mp_alltoall_c, mp_alltoall_c22, mp_alltoall_c33, &
517 : mp_alltoall_c44, mp_alltoall_c55, mp_alltoall_c45, mp_alltoall_c34, &
518 : mp_alltoall_c11v, mp_alltoall_c22v, mp_alltoall_c54, &
519 : mp_alltoall_z, mp_alltoall_z22, mp_alltoall_z33, &
520 : mp_alltoall_z44, mp_alltoall_z55, mp_alltoall_z45, mp_alltoall_z34, &
521 : mp_alltoall_z11v, mp_alltoall_z22v, mp_alltoall_z54
522 :
523 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_send_i, mp_send_iv, mp_send_im2, mp_send_im3, &
524 : mp_send_l, mp_send_lv, mp_send_lm2, mp_send_lm3, &
525 : mp_send_r, mp_send_rv, mp_send_rm2, mp_send_rm3, &
526 : mp_send_d, mp_send_dv, mp_send_dm2, mp_send_dm3, &
527 : mp_send_c, mp_send_cv, mp_send_cm2, mp_send_cm3, &
528 : mp_send_z, mp_send_zv, mp_send_zm2, mp_send_zm3
529 : GENERIC, PUBLIC :: send => mp_send_i, mp_send_iv, mp_send_im2, mp_send_im3, &
530 : mp_send_l, mp_send_lv, mp_send_lm2, mp_send_lm3, &
531 : mp_send_r, mp_send_rv, mp_send_rm2, mp_send_rm3, &
532 : mp_send_d, mp_send_dv, mp_send_dm2, mp_send_dm3, &
533 : mp_send_c, mp_send_cv, mp_send_cm2, mp_send_cm3, &
534 : mp_send_z, mp_send_zv, mp_send_zm2, mp_send_zm3
535 :
536 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_recv_i, mp_recv_iv, mp_recv_im2, mp_recv_im3, &
537 : mp_recv_l, mp_recv_lv, mp_recv_lm2, mp_recv_lm3, &
538 : mp_recv_r, mp_recv_rv, mp_recv_rm2, mp_recv_rm3, &
539 : mp_recv_d, mp_recv_dv, mp_recv_dm2, mp_recv_dm3, &
540 : mp_recv_c, mp_recv_cv, mp_recv_cm2, mp_recv_cm3, &
541 : mp_recv_z, mp_recv_zv, mp_recv_zm2, mp_recv_zm3
542 : GENERIC, PUBLIC :: recv => mp_recv_i, mp_recv_iv, mp_recv_im2, mp_recv_im3, &
543 : mp_recv_l, mp_recv_lv, mp_recv_lm2, mp_recv_lm3, &
544 : mp_recv_r, mp_recv_rv, mp_recv_rm2, mp_recv_rm3, &
545 : mp_recv_d, mp_recv_dv, mp_recv_dm2, mp_recv_dm3, &
546 : mp_recv_c, mp_recv_cv, mp_recv_cm2, mp_recv_cm3, &
547 : mp_recv_z, mp_recv_zv, mp_recv_zm2, mp_recv_zm3
548 :
549 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_isendrecv_i, mp_isendrecv_iv, &
550 : mp_isendrecv_l, mp_isendrecv_lv, mp_isendrecv_r, mp_isendrecv_rv, &
551 : mp_isendrecv_d, mp_isendrecv_dv, mp_isendrecv_c, mp_isendrecv_cv, &
552 : mp_isendrecv_z, mp_isendrecv_zv
553 : GENERIC, PUBLIC :: isendrecv => mp_isendrecv_i, mp_isendrecv_iv, &
554 : mp_isendrecv_l, mp_isendrecv_lv, mp_isendrecv_r, mp_isendrecv_rv, &
555 : mp_isendrecv_d, mp_isendrecv_dv, mp_isendrecv_c, mp_isendrecv_cv, &
556 : mp_isendrecv_z, mp_isendrecv_zv
557 :
558 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_isend_iv, mp_isend_im2, mp_isend_im3, mp_isend_im4, &
559 : mp_isend_lv, mp_isend_lm2, mp_isend_lm3, mp_isend_lm4, &
560 : mp_isend_rv, mp_isend_rm2, mp_isend_rm3, mp_isend_rm4, &
561 : mp_isend_dv, mp_isend_dm2, mp_isend_dm3, mp_isend_dm4, &
562 : mp_isend_cv, mp_isend_cm2, mp_isend_cm3, mp_isend_cm4, &
563 : mp_isend_zv, mp_isend_zm2, mp_isend_zm3, mp_isend_zm4, &
564 : mp_isend_bv, mp_isend_bm3, mp_isend_custom
565 : GENERIC, PUBLIC :: isend => mp_isend_iv, mp_isend_im2, mp_isend_im3, mp_isend_im4, &
566 : mp_isend_lv, mp_isend_lm2, mp_isend_lm3, mp_isend_lm4, &
567 : mp_isend_rv, mp_isend_rm2, mp_isend_rm3, mp_isend_rm4, &
568 : mp_isend_dv, mp_isend_dm2, mp_isend_dm3, mp_isend_dm4, &
569 : mp_isend_cv, mp_isend_cm2, mp_isend_cm3, mp_isend_cm4, &
570 : mp_isend_zv, mp_isend_zm2, mp_isend_zm3, mp_isend_zm4, &
571 : mp_isend_bv, mp_isend_bm3, mp_isend_custom
572 :
573 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_irecv_iv, mp_irecv_im2, mp_irecv_im3, mp_irecv_im4, &
574 : mp_irecv_lv, mp_irecv_lm2, mp_irecv_lm3, mp_irecv_lm4, &
575 : mp_irecv_rv, mp_irecv_rm2, mp_irecv_rm3, mp_irecv_rm4, &
576 : mp_irecv_dv, mp_irecv_dm2, mp_irecv_dm3, mp_irecv_dm4, &
577 : mp_irecv_cv, mp_irecv_cm2, mp_irecv_cm3, mp_irecv_cm4, &
578 : mp_irecv_zv, mp_irecv_zm2, mp_irecv_zm3, mp_irecv_zm4, &
579 : mp_irecv_bv, mp_irecv_bm3, mp_irecv_custom
580 : GENERIC, PUBLIC :: irecv => mp_irecv_iv, mp_irecv_im2, mp_irecv_im3, mp_irecv_im4, &
581 : mp_irecv_lv, mp_irecv_lm2, mp_irecv_lm3, mp_irecv_lm4, &
582 : mp_irecv_rv, mp_irecv_rm2, mp_irecv_rm3, mp_irecv_rm4, &
583 : mp_irecv_dv, mp_irecv_dm2, mp_irecv_dm3, mp_irecv_dm4, &
584 : mp_irecv_cv, mp_irecv_cm2, mp_irecv_cm3, mp_irecv_cm4, &
585 : mp_irecv_zv, mp_irecv_zm2, mp_irecv_zm3, mp_irecv_zm4, &
586 : mp_irecv_bv, mp_irecv_bm3, mp_irecv_custom
587 :
588 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: probe => mp_probe
589 :
590 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: sync => mp_sync
591 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: isync => mp_isync
592 :
593 : PROCEDURE, PUBLIC, PASS(comm1), NON_OVERRIDABLE :: compare => mp_comm_compare
594 : PROCEDURE, PUBLIC, PASS(comm1), NON_OVERRIDABLE :: rank_compare => mp_rank_compare
595 :
596 : PROCEDURE, PUBLIC, PASS(comm2), NON_OVERRIDABLE :: from_dup => mp_comm_dup
597 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: mp_comm_free
598 : GENERIC, PUBLIC :: free => mp_comm_free
599 :
600 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: mp_comm_init
601 : GENERIC, PUBLIC :: init => mp_comm_init
602 :
603 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: get_size => mp_comm_size
604 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: get_rank => mp_comm_rank
605 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: get_ndims => mp_comm_get_ndims
606 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: is_source => mp_comm_is_source
607 :
608 : ! Creation routines
609 : PROCEDURE, PRIVATE, PASS(sub_comm), NON_OVERRIDABLE :: mp_comm_split, mp_comm_split_direct
610 : GENERIC, PUBLIC :: from_split => mp_comm_split, mp_comm_split_direct
611 : PROCEDURE, PUBLIC, PASS(sub_comm), NON_OVERRIDABLE :: from_split_type => mp_comm_split_type
612 : PROCEDURE, PUBLIC, PASS(mp_new_comm), NON_OVERRIDABLE :: from_reordering => mp_reordering
613 : PROCEDURE, PUBLIC, PASS(comm_new), NON_OVERRIDABLE :: mp_comm_assign
614 : GENERIC, PUBLIC :: ASSIGNMENT(=) => mp_comm_assign
615 :
616 : ! Other Getters
617 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_comm_get_tag_ub
618 : GENERIC, PUBLIC :: get_tag_ub => mp_comm_get_tag_ub
619 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_comm_get_host_rank
620 : GENERIC, PUBLIC :: get_host_rank => mp_comm_get_host_rank
621 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_comm_get_io_rank
622 : GENERIC, PUBLIC :: get_io_rank => mp_comm_get_io_rank
623 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: mp_comm_get_wtime_is_global
624 : GENERIC, PUBLIC :: get_wtime_is_global => mp_comm_get_wtime_is_global
625 : END TYPE
626 :
627 : TYPE mp_request_type
628 : PRIVATE
629 : MPI_REQUEST_TYPE :: handle = mp_request_null_handle
630 : CONTAINS
631 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: set_handle => mp_request_type_set_handle
632 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: get_handle => mp_request_type_get_handle
633 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_request_op_eq
634 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_request_op_neq
635 : GENERIC, PUBLIC :: OPERATOR(==) => mp_request_op_eq
636 : GENERIC, PUBLIC :: OPERATOR(/=) => mp_request_op_neq
637 :
638 : PROCEDURE, PUBLIC, PASS(request), NON_OVERRIDABLE :: test => mp_test_1
639 :
640 : PROCEDURE, PUBLIC, PASS(request), NON_OVERRIDABLE :: wait => mp_wait
641 : END TYPE
642 :
643 : TYPE mp_win_type
644 : PRIVATE
645 : MPI_WIN_TYPE :: handle = mp_win_null_handle
646 : CONTAINS
647 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: set_handle => mp_win_type_set_handle
648 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: get_handle => mp_win_type_get_handle
649 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_win_op_eq
650 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_win_op_neq
651 : GENERIC, PUBLIC :: OPERATOR(==) => mp_win_op_eq
652 : GENERIC, PUBLIC :: OPERATOR(/=) => mp_win_op_neq
653 :
654 : PROCEDURE, PRIVATE, PASS(win), NON_OVERRIDABLE :: mp_win_create_iv, mp_win_create_lv, &
655 : mp_win_create_rv, mp_win_create_dv, mp_win_create_cv, mp_win_create_zv
656 : GENERIC, PUBLIC :: create => mp_win_create_iv, mp_win_create_lv, &
657 : mp_win_create_rv, mp_win_create_dv, mp_win_create_cv, mp_win_create_zv
658 :
659 : PROCEDURE, PRIVATE, PASS(win), NON_OVERRIDABLE :: mp_rget_iv, mp_rget_lv, &
660 : mp_rget_rv, mp_rget_dv, mp_rget_cv, mp_rget_zv
661 : GENERIC, PUBLIC :: rget => mp_rget_iv, mp_rget_lv, &
662 : mp_rget_rv, mp_rget_dv, mp_rget_cv, mp_rget_zv
663 :
664 : PROCEDURE, PUBLIC, PASS(win), NON_OVERRIDABLE :: free => mp_win_free
665 : PROCEDURE, PUBLIC, PASS(win_new), NON_OVERRIDABLE :: mp_win_assign
666 : GENERIC, PUBLIC :: ASSIGNMENT(=) => mp_win_assign
667 :
668 : PROCEDURE, PUBLIC, PASS(win), NON_OVERRIDABLE :: lock_all => mp_win_lock_all
669 : PROCEDURE, PUBLIC, PASS(win), NON_OVERRIDABLE :: unlock_all => mp_win_unlock_all
670 : PROCEDURE, PUBLIC, PASS(win), NON_OVERRIDABLE :: flush_all => mp_win_flush_all
671 : END TYPE
672 :
673 : TYPE mp_file_type
674 : PRIVATE
675 : MPI_FILE_TYPE :: handle = mp_file_null_handle
676 : CONTAINS
677 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: set_handle => mp_file_type_set_handle
678 : PROCEDURE, PUBLIC, NON_OVERRIDABLE :: get_handle => mp_file_type_get_handle
679 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_file_op_eq
680 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_file_op_neq
681 : GENERIC, PUBLIC :: OPERATOR(==) => mp_file_op_eq
682 : GENERIC, PUBLIC :: OPERATOR(/=) => mp_file_op_neq
683 :
684 : PROCEDURE, PRIVATE, PASS(fh), NON_OVERRIDABLE :: mp_file_write_at_ch, mp_file_write_at_chv, &
685 : mp_file_write_at_i, mp_file_write_at_iv, mp_file_write_at_r, mp_file_write_at_rv, &
686 : mp_file_write_at_d, mp_file_write_at_dv, mp_file_write_at_c, mp_file_write_at_cv, &
687 : mp_file_write_at_z, mp_file_write_at_zv, mp_file_write_at_l, mp_file_write_at_lv
688 : GENERIC, PUBLIC :: write_at => mp_file_write_at_ch, mp_file_write_at_chv, &
689 : mp_file_write_at_i, mp_file_write_at_iv, mp_file_write_at_r, mp_file_write_at_rv, &
690 : mp_file_write_at_d, mp_file_write_at_dv, mp_file_write_at_c, mp_file_write_at_cv, &
691 : mp_file_write_at_z, mp_file_write_at_zv, mp_file_write_at_l, mp_file_write_at_lv
692 :
693 : PROCEDURE, PRIVATE, PASS(fh), NON_OVERRIDABLE :: mp_file_write_at_all_ch, mp_file_write_at_all_chv, &
694 : mp_file_write_at_all_i, mp_file_write_at_all_iv, mp_file_write_at_all_l, mp_file_write_at_all_lv, &
695 : mp_file_write_at_all_r, mp_file_write_at_all_rv, mp_file_write_at_all_d, mp_file_write_at_all_dv, &
696 : mp_file_write_at_all_c, mp_file_write_at_all_cv, mp_file_write_at_all_z, mp_file_write_at_all_zv
697 : GENERIC, PUBLIC :: write_at_all => mp_file_write_at_all_ch, mp_file_write_at_all_chv, &
698 : mp_file_write_at_all_i, mp_file_write_at_all_iv, mp_file_write_at_all_l, mp_file_write_at_all_lv, &
699 : mp_file_write_at_all_r, mp_file_write_at_all_rv, mp_file_write_at_all_d, mp_file_write_at_all_dv, &
700 : mp_file_write_at_all_c, mp_file_write_at_all_cv, mp_file_write_at_all_z, mp_file_write_at_all_zv
701 :
702 : PROCEDURE, PRIVATE, PASS(fh), NON_OVERRIDABLE :: mp_file_read_at_ch, mp_file_read_at_chv, &
703 : mp_file_read_at_i, mp_file_read_at_iv, mp_file_read_at_r, mp_file_read_at_rv, &
704 : mp_file_read_at_d, mp_file_read_at_dv, mp_file_read_at_c, mp_file_read_at_cv, &
705 : mp_file_read_at_z, mp_file_read_at_zv, mp_file_read_at_l, mp_file_read_at_lv
706 : GENERIC, PUBLIC :: read_at => mp_file_read_at_ch, mp_file_read_at_chv, &
707 : mp_file_read_at_i, mp_file_read_at_iv, mp_file_read_at_r, mp_file_read_at_rv, &
708 : mp_file_read_at_d, mp_file_read_at_dv, mp_file_read_at_c, mp_file_read_at_cv, &
709 : mp_file_read_at_z, mp_file_read_at_zv, mp_file_read_at_l, mp_file_read_at_lv
710 :
711 : PROCEDURE, PRIVATE, PASS(fh), NON_OVERRIDABLE :: mp_file_read_at_all_ch, mp_file_read_at_all_chv, &
712 : mp_file_read_at_all_i, mp_file_read_at_all_iv, mp_file_read_at_all_l, mp_file_read_at_all_lv, &
713 : mp_file_read_at_all_r, mp_file_read_at_all_rv, mp_file_read_at_all_d, mp_file_read_at_all_dv, &
714 : mp_file_read_at_all_c, mp_file_read_at_all_cv, mp_file_read_at_all_z, mp_file_read_at_all_zv
715 : GENERIC, PUBLIC :: read_at_all => mp_file_read_at_all_ch, mp_file_read_at_all_chv, &
716 : mp_file_read_at_all_i, mp_file_read_at_all_iv, mp_file_read_at_all_l, mp_file_read_at_all_lv, &
717 : mp_file_read_at_all_r, mp_file_read_at_all_rv, mp_file_read_at_all_d, mp_file_read_at_all_dv, &
718 : mp_file_read_at_all_c, mp_file_read_at_all_cv, mp_file_read_at_all_z, mp_file_read_at_all_zv
719 :
720 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: open => mp_file_open
721 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: close => mp_file_close
722 : PROCEDURE, PRIVATE, PASS(fh_new), NON_OVERRIDABLE :: mp_file_assign
723 : GENERIC, PUBLIC :: ASSIGNMENT(=) => mp_file_assign
724 :
725 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: get_size => mp_file_get_size
726 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: get_position => mp_file_get_position
727 :
728 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: read_all => mp_file_read_all_chv
729 : PROCEDURE, PUBLIC, PASS(fh), NON_OVERRIDABLE :: write_all => mp_file_write_all_chv
730 : END TYPE
731 :
732 : TYPE mp_info_type
733 : PRIVATE
734 : MPI_INFO_TYPE :: handle = mp_info_null_handle
735 : CONTAINS
736 : PROCEDURE, NON_OVERRIDABLE :: set_handle => mp_info_type_set_handle
737 : PROCEDURE, NON_OVERRIDABLE :: get_handle => mp_info_type_get_handle
738 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_info_op_eq
739 : PROCEDURE, PRIVATE, NON_OVERRIDABLE :: mp_info_op_neq
740 : GENERIC, PUBLIC :: OPERATOR(==) => mp_info_op_eq
741 : GENERIC, PUBLIC :: OPERATOR(/=) => mp_info_op_neq
742 : END TYPE
743 :
744 : TYPE, EXTENDS(mp_comm_type) :: mp_cart_type
745 : INTEGER, DIMENSION(:), ALLOCATABLE, PUBLIC :: mepos_cart, num_pe_cart
746 : LOGICAL, DIMENSION(:), ALLOCATABLE, PUBLIC :: periodic
747 : CONTAINS
748 : PROCEDURE, PUBLIC, PASS(comm_cart), NON_OVERRIDABLE :: create => mp_cart_create
749 : PROCEDURE, PUBLIC, PASS(sub_comm), NON_OVERRIDABLE :: from_sub => mp_cart_sub
750 :
751 : PROCEDURE, PRIVATE, PASS(comm), NON_OVERRIDABLE :: get_info_cart => mp_cart_get
752 :
753 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: coords => mp_cart_coords
754 : PROCEDURE, PUBLIC, PASS(comm), NON_OVERRIDABLE :: rank_cart => mp_cart_rank
755 : END TYPE
756 :
757 : ! **************************************************************************************************
758 : !> \brief stores all the informations relevant to an mpi environment
759 : !> \param owns_group if it owns the group (and thus should free it when
760 : !> this object is deallocated)
761 : !> \param ref_count the reference count, when it is zero this object gets
762 : !> deallocated
763 : !> \par History
764 : !> 08.2002 created [fawzi]
765 : !> \author Fawzi Mohamed
766 : ! **************************************************************************************************
767 : TYPE, EXTENDS(mp_comm_type) :: mp_para_env_type
768 : PRIVATE
769 : ! We set it to true to have less initialization steps in case we create a new communicator
770 : LOGICAL :: owns_group = .TRUE.
771 : INTEGER :: ref_count = -1
772 : CONTAINS
773 : PROCEDURE, PUBLIC, PASS(para_env), NON_OVERRIDABLE :: retain => mp_para_env_retain
774 : PROCEDURE, PUBLIC, PASS(para_env), NON_OVERRIDABLE :: is_valid => mp_para_env_is_valid
775 : END TYPE mp_para_env_type
776 :
777 : ! **************************************************************************************************
778 : !> \brief represent a pointer to a para env (to build arrays)
779 : !> \param para_env the pointer to the para_env
780 : !> \par History
781 : !> 07.2003 created [fawzi]
782 : !> \author Fawzi Mohamed
783 : ! **************************************************************************************************
784 : TYPE mp_para_env_p_type
785 : TYPE(mp_para_env_type), POINTER :: para_env => NULL()
786 : END TYPE mp_para_env_p_type
787 :
788 : ! **************************************************************************************************
789 : !> \brief represent a multidimensional parallel environment
790 : !> \param mepos_cart the position of the actual processor
791 : !> \param num_pe_cart number of processors in the group in each dimension
792 : !> \param source_cart id of a special processor (for example the one for i-o,
793 : !> or the master
794 : !> \param owns_group if it owns the group (and thus should free it when
795 : !> this object is deallocated)
796 : !> \param ref_count the reference count, when it is zero this object gets
797 : !> deallocated
798 : !> \note
799 : !> not yet implemented for mpi
800 : !> \par History
801 : !> 08.2002 created [fawzi]
802 : !> \author Fawzi Mohamed
803 : ! **************************************************************************************************
804 : TYPE, EXTENDS(mp_cart_type) :: mp_para_cart_type
805 : PRIVATE
806 : ! We set it to true to have less initialization steps in case we create a new communicator
807 : LOGICAL :: owns_group = .TRUE.
808 : INTEGER :: ref_count = -1
809 : CONTAINS
810 : PROCEDURE, PUBLIC, PASS(cart), NON_OVERRIDABLE :: retain => mp_para_cart_retain
811 : PROCEDURE, PUBLIC, PASS(cart), NON_OVERRIDABLE :: is_valid => mp_para_cart_is_valid
812 : END TYPE mp_para_cart_type
813 :
814 : ! Create the constants from the corresponding handles
815 : TYPE(mp_comm_type), PARAMETER, PUBLIC :: mp_comm_null = mp_comm_type(mp_comm_null_handle)
816 : TYPE(mp_comm_type), PARAMETER, PUBLIC :: mp_comm_self = mp_comm_type(mp_comm_self_handle)
817 : TYPE(mp_comm_type), PARAMETER, PUBLIC :: mp_comm_world = mp_comm_type(mp_comm_world_handle)
818 : TYPE(mp_request_type), PARAMETER, PUBLIC :: mp_request_null = mp_request_type(mp_request_null_handle)
819 : TYPE(mp_win_type), PARAMETER, PUBLIC :: mp_win_null = mp_win_type(mp_win_null_handle)
820 : TYPE(mp_file_type), PARAMETER, PUBLIC :: mp_file_null = mp_file_type(mp_file_null_handle)
821 : TYPE(mp_info_type), PARAMETER, PUBLIC :: mp_info_null = mp_info_type(mp_info_null_handle)
822 :
823 : ! Bundles an MPI communicator split type with the info hint it requires
824 : TYPE mp_split_type
825 : PRIVATE
826 : INTEGER :: split_type = mp_comm_split_type_shared_id
827 : TYPE(mp_info_type) :: info = mp_info_null
828 : END TYPE
829 :
830 : ! Node-local (shared-memory) split; needs no info hint.
831 : TYPE(mp_split_type), PARAMETER, PUBLIC :: mp_comm_split_type_shared = &
832 : mp_split_type(mp_comm_split_type_shared_id, mp_info_null)
833 :
834 : #if !defined(__parallel)
835 : ! This communicator is to be used in serial mode to emulate a valid communicator which is not a compiler constant
836 : INTEGER, PARAMETER, PRIVATE :: mp_comm_default_handle = 1
837 : TYPE(mp_comm_type), PARAMETER, PRIVATE :: mp_comm_default = mp_comm_type(mp_comm_default_handle)
838 : #endif
839 :
840 : ! Constants to compare communicators
841 : INTEGER, PARAMETER, PUBLIC :: mp_comm_ident = 0
842 : INTEGER, PARAMETER, PUBLIC :: mp_comm_congruent = 1
843 : INTEGER, PARAMETER, PUBLIC :: mp_comm_similar = 2
844 : INTEGER, PARAMETER, PUBLIC :: mp_comm_unequal = 3
845 : INTEGER, PARAMETER, PUBLIC :: mp_comm_compare_default = -1
846 :
847 : ! init and error
848 : PUBLIC :: mp_world_init, mp_world_finalize, mp_query_thread_level
849 : PUBLIC :: mp_abort
850 :
851 : ! informational / generation of sub comms
852 : PUBLIC :: mp_dims_create
853 : PUBLIC :: cp2k_is_parallel
854 :
855 : ! message passing
856 : PUBLIC :: mp_waitall, mp_waitany
857 : PUBLIC :: mp_testall, mp_testany
858 :
859 : ! Memory management
860 : PUBLIC :: mp_allocate, mp_deallocate
861 :
862 : ! I/O
863 : PUBLIC :: mp_file_delete
864 : PUBLIC :: mp_file_get_amode
865 :
866 : ! some 'advanced types' currently only used for dbcsr
867 : PUBLIC :: mp_type_descriptor_type
868 : PUBLIC :: mp_type_make
869 : PUBLIC :: mp_type_size
870 :
871 : ! vector types
872 : PUBLIC :: mp_type_indexed_make_r, mp_type_indexed_make_d, &
873 : mp_type_indexed_make_c, mp_type_indexed_make_z
874 :
875 : ! More I/O types and routines: variable spaced data using bytes for spacings
876 : PUBLIC :: mp_file_descriptor_type
877 : PUBLIC :: mp_file_type_free
878 : PUBLIC :: mp_file_type_hindexed_make_chv
879 : PUBLIC :: mp_file_type_set_view_chv
880 :
881 : PUBLIC :: mp_get_library_version
882 :
883 : ! assumed to be private
884 :
885 : INTERFACE mp_waitall
886 : MODULE PROCEDURE mp_waitall_1, mp_waitall_2
887 : END INTERFACE
888 :
889 : INTERFACE mp_testall
890 : MODULE PROCEDURE mp_testall_tv
891 : END INTERFACE
892 :
893 : INTERFACE mp_testany
894 : MODULE PROCEDURE mp_testany_1, mp_testany_2
895 : END INTERFACE
896 :
897 : INTERFACE mp_type_free
898 : MODULE PROCEDURE mp_type_free_m, mp_type_free_v
899 : END INTERFACE
900 :
901 : !
902 : ! interfaces to deal easily with scalars / vectors / matrices / ...
903 : ! of the different types (integers, doubles, logicals, characters)
904 : !
905 : INTERFACE mp_allocate
906 : MODULE PROCEDURE mp_allocate_i, &
907 : mp_allocate_l, &
908 : mp_allocate_r, &
909 : mp_allocate_d, &
910 : mp_allocate_c, &
911 : mp_allocate_z
912 : END INTERFACE
913 :
914 : INTERFACE mp_deallocate
915 : MODULE PROCEDURE mp_deallocate_i, &
916 : mp_deallocate_l, &
917 : mp_deallocate_r, &
918 : mp_deallocate_d, &
919 : mp_deallocate_c, &
920 : mp_deallocate_z
921 : END INTERFACE
922 :
923 : INTERFACE mp_type_make
924 : MODULE PROCEDURE mp_type_make_struct
925 : MODULE PROCEDURE mp_type_make_i, mp_type_make_l, &
926 : mp_type_make_r, mp_type_make_d, &
927 : mp_type_make_c, mp_type_make_z
928 : END INTERFACE
929 :
930 : INTERFACE mp_alloc_mem
931 : MODULE PROCEDURE mp_alloc_mem_i, mp_alloc_mem_l, &
932 : mp_alloc_mem_d, mp_alloc_mem_z, &
933 : mp_alloc_mem_r, mp_alloc_mem_c
934 : END INTERFACE
935 :
936 : INTERFACE mp_free_mem
937 : MODULE PROCEDURE mp_free_mem_i, mp_free_mem_l, &
938 : mp_free_mem_d, mp_free_mem_z, &
939 : mp_free_mem_r, mp_free_mem_c
940 : END INTERFACE
941 :
942 : ! Type declarations
943 : TYPE mp_indexing_meta_type
944 : INTEGER, DIMENSION(:), POINTER :: index => NULL(), chunks => NULL()
945 : END TYPE mp_indexing_meta_type
946 :
947 : TYPE mp_type_descriptor_type
948 : MPI_DATA_TYPE :: type_handle = mp_datatype_null_handle
949 : INTEGER :: length = -1
950 : #if defined(__parallel)
951 : INTEGER(kind=mpi_address_kind) :: base = -1
952 : #endif
953 : INTEGER(kind=int_4), DIMENSION(:), POINTER :: data_i => NULL()
954 : INTEGER(kind=int_8), DIMENSION(:), POINTER :: data_l => NULL()
955 : REAL(kind=real_4), DIMENSION(:), POINTER :: data_r => NULL()
956 : REAL(kind=real_8), DIMENSION(:), POINTER :: data_d => NULL()
957 : COMPLEX(kind=real_4), DIMENSION(:), POINTER :: data_c => NULL()
958 : COMPLEX(kind=real_8), DIMENSION(:), POINTER :: data_z => NULL()
959 : TYPE(mp_type_descriptor_type), DIMENSION(:), POINTER :: subtype => NULL()
960 : INTEGER :: vector_descriptor(2) = -1
961 : LOGICAL :: has_indexing = .FALSE.
962 : TYPE(mp_indexing_meta_type) :: index_descriptor = mp_indexing_meta_type()
963 : END TYPE mp_type_descriptor_type
964 :
965 : TYPE mp_file_indexing_meta_type
966 : INTEGER, DIMENSION(:), POINTER :: index => NULL()
967 : INTEGER(kind=file_offset), &
968 : DIMENSION(:), POINTER :: chunks => NULL()
969 : END TYPE mp_file_indexing_meta_type
970 :
971 : TYPE mp_file_descriptor_type
972 : MPI_DATA_TYPE :: type_handle = mp_datatype_null_handle
973 : INTEGER :: length = -1
974 : LOGICAL :: has_indexing = .FALSE.
975 : TYPE(mp_file_indexing_meta_type) :: index_descriptor = mp_file_indexing_meta_type()
976 : END TYPE
977 :
978 : ! we make some assumptions on the length of INTEGERS, REALS and LOGICALS
979 : INTEGER, PARAMETER :: intlen = BIT_SIZE(0)/8
980 : INTEGER, PARAMETER :: reallen = 8
981 : INTEGER, PARAMETER :: loglen = BIT_SIZE(0)/8
982 : INTEGER, PARAMETER :: charlen = 1
983 :
984 : LOGICAL, PUBLIC, SAVE :: mp_collect_timings = .FALSE.
985 :
986 : CONTAINS
987 :
988 : #:mute
989 : #:set types = ["comm", "request", "win", "file", "info"]
990 : #:endmute
991 : #:for type in types
992 3367821 : LOGICAL FUNCTION mp_${type}$_op_eq(${type}$1, ${type}$2)
993 : CLASS(mp_${type}$_type), INTENT(IN) :: ${type}$1, ${type}$2
994 : #if defined(__parallel) && defined(__MPI_F08)
995 3367821 : mp_${type}$_op_eq = (${type}$1%handle%mpi_val == ${type}$2%handle%mpi_val)
996 : #else
997 : mp_${type}$_op_eq = (${type}$1%handle == ${type}$2%handle)
998 : #endif
999 3367821 : END FUNCTION mp_${type}$_op_eq
1000 :
1001 3608176 : LOGICAL FUNCTION mp_${type}$_op_neq(${type}$1, ${type}$2)
1002 : CLASS(mp_${type}$_type), INTENT(IN) :: ${type}$1, ${type}$2
1003 : #if defined(__parallel) && defined(__MPI_F08)
1004 3608176 : mp_${type}$_op_neq = (${type}$1%handle%mpi_val /= ${type}$2%handle%mpi_val)
1005 : #else
1006 : mp_${type}$_op_neq = (${type}$1%handle /= ${type}$2%handle)
1007 : #endif
1008 3608176 : END FUNCTION mp_${type}$_op_neq
1009 :
1010 9488666 : ELEMENTAL #{if type=="comm"}#IMPURE #{endif}#SUBROUTINE mp_${type}$_type_set_handle(this, handle #{if type=="comm"}#, ndims#{endif}#)
1011 : CLASS(mp_${type}$_type), INTENT(INOUT) :: this
1012 : INTEGER, INTENT(IN) :: handle
1013 : #:if type=="comm"
1014 : INTEGER, INTENT(IN), OPTIONAL :: ndims
1015 : #:endif
1016 :
1017 : #if defined(__parallel) && defined(__MPI_F08)
1018 9488666 : this%handle%mpi_val = handle
1019 : #else
1020 : this%handle = handle
1021 : #endif
1022 :
1023 : #:if type=="comm"
1024 : SELECT TYPE (this)
1025 : CLASS IS (mp_cart_type)
1026 0 : IF (.NOT. PRESENT(ndims)) &
1027 : CALL cp_abort(__LOCATION__, &
1028 0 : "Setup of a cartesian communicator requires information on the number of dimensions!")
1029 : END SELECT
1030 9484602 : IF (PRESENT(ndims)) this%ndims = ndims
1031 9484602 : CALL this%init()
1032 : #:endif
1033 :
1034 9488666 : END SUBROUTINE mp_${type}$_type_set_handle
1035 :
1036 3172249 : ELEMENTAL FUNCTION mp_${type}$_type_get_handle(this) RESULT(handle)
1037 : CLASS(mp_${type}$_type), INTENT(IN) :: this
1038 : INTEGER :: handle
1039 :
1040 : #if defined(__parallel) && defined(__MPI_F08)
1041 3172249 : handle = this%handle%mpi_val
1042 : #else
1043 : handle = this%handle
1044 : #endif
1045 3172249 : END FUNCTION mp_${type}$_type_get_handle
1046 : #:endfor
1047 :
1048 27908 : FUNCTION mp_comm_get_tag_ub(comm) RESULT(tag_ub)
1049 : CLASS(mp_comm_type), INTENT(IN) :: comm
1050 : INTEGER :: tag_ub
1051 :
1052 : #if defined(__parallel)
1053 : INTEGER :: ierr
1054 : LOGICAL :: flag
1055 : INTEGER(KIND=MPI_ADDRESS_KIND) :: attrval
1056 :
1057 27908 : CALL MPI_COMM_GET_ATTR(comm%handle, MPI_TAG_UB, attrval, flag, ierr)
1058 27908 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_get_attr @ mp_comm_get_tag_ub")
1059 27908 : IF (.NOT. flag) THEN
1060 : CALL cp_warn(__LOCATION__, "Upper bound of tags not available! "// &
1061 0 : "Only the guaranteed minimum of 32767 is used.")
1062 0 : tag_ub = 32767
1063 : ELSE
1064 27908 : tag_ub = INT(attrval, KIND=KIND(tag_ub))
1065 : END IF
1066 : #else
1067 : MARK_USED(comm)
1068 : tag_ub = HUGE(1)
1069 : #endif
1070 27908 : END FUNCTION mp_comm_get_tag_ub
1071 :
1072 0 : FUNCTION mp_comm_get_host_rank(comm) RESULT(host_rank)
1073 : CLASS(mp_comm_type), INTENT(IN) :: comm
1074 : INTEGER :: host_rank
1075 :
1076 : #if defined(__parallel)
1077 : INTEGER :: ierr
1078 : LOGICAL :: flag
1079 : INTEGER(KIND=MPI_ADDRESS_KIND) :: attrval
1080 :
1081 0 : CALL MPI_COMM_GET_ATTR(comm%handle, MPI_HOST, attrval, flag, ierr)
1082 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_get_attr @ mp_comm_get_host_rank")
1083 0 : IF (.NOT. flag) CPABORT("Host process rank not available!")
1084 0 : host_rank = INT(attrval, KIND=KIND(host_rank))
1085 : #else
1086 : MARK_USED(comm)
1087 : host_rank = 0
1088 : #endif
1089 0 : END FUNCTION mp_comm_get_host_rank
1090 :
1091 0 : FUNCTION mp_comm_get_io_rank(comm) RESULT(io_rank)
1092 : CLASS(mp_comm_type), INTENT(IN) :: comm
1093 : INTEGER :: io_rank
1094 :
1095 : #if defined(__parallel)
1096 : INTEGER :: ierr
1097 : LOGICAL :: flag
1098 : INTEGER(KIND=MPI_ADDRESS_KIND) :: attrval
1099 :
1100 0 : CALL MPI_COMM_GET_ATTR(comm%handle, MPI_IO, attrval, flag, ierr)
1101 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_get_attr @ mp_comm_get_io_rank")
1102 0 : IF (.NOT. flag) CPABORT("IO rank not available!")
1103 0 : io_rank = INT(attrval, KIND=KIND(io_rank))
1104 : #else
1105 : MARK_USED(comm)
1106 : io_rank = 0
1107 : #endif
1108 0 : END FUNCTION mp_comm_get_io_rank
1109 :
1110 0 : FUNCTION mp_comm_get_wtime_is_global(comm) RESULT(wtime_is_global)
1111 : CLASS(mp_comm_type), INTENT(IN) :: comm
1112 : LOGICAL :: wtime_is_global
1113 :
1114 : #if defined(__parallel)
1115 : INTEGER :: ierr
1116 : LOGICAL :: flag
1117 : INTEGER(KIND=MPI_ADDRESS_KIND) :: attrval
1118 :
1119 0 : CALL MPI_COMM_GET_ATTR(comm%handle, MPI_TAG_UB, attrval, flag, ierr)
1120 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_get_attr @ mp_comm_get_wtime_is_global")
1121 0 : IF (.NOT. flag) CPABORT("Synchronization state of WTIME not available!")
1122 0 : wtime_is_global = (attrval == 1_MPI_ADDRESS_KIND)
1123 : #else
1124 : MARK_USED(comm)
1125 : wtime_is_global = .TRUE.
1126 : #endif
1127 0 : END FUNCTION mp_comm_get_wtime_is_global
1128 :
1129 : ! **************************************************************************************************
1130 : !> \brief Abort if an MPI lifecycle operation is attempted from an OpenMP parallel region.
1131 : !> \param routine_name name of the calling routine
1132 : ! **************************************************************************************************
1133 13690040 : SUBROUTINE mp_assert_outside_parallel(routine_name)
1134 : CHARACTER(LEN=*), INTENT(IN) :: routine_name
1135 :
1136 13690040 : IF (omp_in_parallel()) THEN
1137 : CALL cp_abort(__LOCATION__, &
1138 0 : TRIM(routine_name)//" must be called outside an OpenMP parallel region.")
1139 : END IF
1140 13690040 : END SUBROUTINE mp_assert_outside_parallel
1141 :
1142 : ! **************************************************************************************************
1143 : !> \brief Abort unless MPI provides MPI_THREAD_MULTIPLE support.
1144 : ! **************************************************************************************************
1145 10864 : SUBROUTINE mp_assert_thread_multiple()
1146 : #if defined(__parallel)
1147 10864 : IF (mp_thread_level_provided < MPI_THREAD_MULTIPLE) THEN
1148 : CALL cp_abort(__LOCATION__, &
1149 : "CP2K requires MPI_THREAD_MULTIPLE, but MPI provides "// &
1150 0 : TRIM(mp_get_thread_level_name())//".")
1151 : END IF
1152 : #endif
1153 10864 : END SUBROUTINE mp_assert_thread_multiple
1154 :
1155 : ! **************************************************************************************************
1156 : !> \brief Initialize MPI or attach to an MPI environment provided by an embedding application.
1157 : !> \param initialize_mpi whether CP2K should initialize MPI when it is not active yet
1158 : ! **************************************************************************************************
1159 21728 : SUBROUTINE mp_initialize_thread_support(initialize_mpi)
1160 : LOGICAL, INTENT(IN) :: initialize_mpi
1161 : #if defined(__parallel)
1162 : INTEGER :: ierr
1163 : LOGICAL :: finalized, initialized
1164 :
1165 10864 : CALL mpi_finalized(finalized, ierr)
1166 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_finalized @ mp_initialize_thread_support")
1167 10864 : IF (finalized) THEN
1168 0 : CALL cp_abort(__LOCATION__, "MPI has already been finalized.")
1169 : END IF
1170 :
1171 10864 : CALL mpi_initialized(initialized, ierr)
1172 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_initialized @ mp_initialize_thread_support")
1173 10864 : IF (.NOT. initialized) THEN
1174 10864 : IF (.NOT. initialize_mpi) THEN
1175 : CALL cp_abort(__LOCATION__, &
1176 0 : "MPI must be initialized by the embedding application before CP2K.")
1177 : END IF
1178 10864 : CALL mpi_init_thread(MPI_THREAD_MULTIPLE, mp_thread_level_provided, ierr)
1179 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_init_thread @ mp_initialize_thread_support")
1180 10864 : mp_mpi_initialized_by_cp2k = .TRUE.
1181 : ELSE
1182 0 : CALL mpi_query_thread(mp_thread_level_provided, ierr)
1183 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_query_thread @ mp_initialize_thread_support")
1184 : END IF
1185 10864 : CALL mp_assert_thread_multiple()
1186 : #else
1187 : MARK_USED(initialize_mpi)
1188 : mp_thread_level_provided = -1
1189 : #endif
1190 10864 : END SUBROUTINE mp_initialize_thread_support
1191 :
1192 : ! **************************************************************************************************
1193 : !> \brief Query the MPI thread-support level when MPI is managed by an embedding application.
1194 : ! **************************************************************************************************
1195 0 : SUBROUTINE mp_query_thread_level()
1196 0 : CALL mp_assert_outside_parallel("mp_query_thread_level")
1197 0 : CALL mp_initialize_thread_support(.FALSE.)
1198 0 : END SUBROUTINE mp_query_thread_level
1199 :
1200 : ! **************************************************************************************************
1201 : !> \brief Return a human-readable name for the observed MPI thread-support level.
1202 : !> \return MPI thread-support level name
1203 : ! **************************************************************************************************
1204 0 : CHARACTER(LEN=32) FUNCTION mp_get_thread_level_name()
1205 : #if defined(__parallel)
1206 0 : SELECT CASE (mp_thread_level_provided)
1207 : CASE (MPI_THREAD_SINGLE)
1208 0 : mp_get_thread_level_name = "MPI_THREAD_SINGLE"
1209 : CASE (MPI_THREAD_FUNNELED)
1210 0 : mp_get_thread_level_name = "MPI_THREAD_FUNNELED"
1211 : CASE (MPI_THREAD_SERIALIZED)
1212 0 : mp_get_thread_level_name = "MPI_THREAD_SERIALIZED"
1213 : CASE (MPI_THREAD_MULTIPLE)
1214 0 : mp_get_thread_level_name = "MPI_THREAD_MULTIPLE"
1215 : CASE DEFAULT
1216 0 : mp_get_thread_level_name = "not initialized"
1217 : END SELECT
1218 : #else
1219 : mp_get_thread_level_name = "not applicable"
1220 : #endif
1221 0 : END FUNCTION mp_get_thread_level_name
1222 :
1223 : ! **************************************************************************************************
1224 : !> \brief initializes the system default communicator
1225 : !> \param mp_comm [output] : handle of the default communicator
1226 : !> \par History
1227 : !> 2.2004 created [Joost VandeVondele ]
1228 : !> \note
1229 : !> While active, this routine may only be called once. If MPI is already initialized,
1230 : !> CP2K validates MPI_THREAD_MULTIPLE and attaches without taking ownership.
1231 : ! **************************************************************************************************
1232 10864 : SUBROUTINE mp_world_init(mp_comm)
1233 : CLASS(mp_comm_type), INTENT(OUT) :: mp_comm
1234 : #if defined(__parallel)
1235 : INTEGER :: ierr
1236 : #if defined(__MIMIC)
1237 : INTEGER :: mimic_handle
1238 : #endif
1239 : #endif
1240 :
1241 10864 : CALL mp_assert_outside_parallel("mp_world_init")
1242 10864 : IF (mp_world_is_initialized) THEN
1243 0 : CALL cp_abort(__LOCATION__, "mp_world_init called while already initialized.")
1244 : END IF
1245 10864 : CALL mp_initialize_thread_support(.TRUE.)
1246 : #if defined(__parallel)
1247 10864 : CALL mpi_comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN, ierr)
1248 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_set_errhandler @ mp_world_init")
1249 : #endif
1250 10864 : debug_comm_count = 1
1251 10864 : mp_comm = mp_comm_world
1252 : #if defined(__MIMIC)
1253 10864 : mimic_handle = mp_comm%get_handle()
1254 10864 : CALL mcl_initialize(mimic_handle)
1255 10864 : CALL mp_comm%set_handle(mimic_handle)
1256 : #if defined(__MPI_F08)
1257 10864 : mimic_comm_world%mpi_val = mimic_handle
1258 : #else
1259 : mimic_comm_world = mimic_handle
1260 : #endif
1261 : #endif
1262 10864 : CALL mp_comm%init()
1263 10864 : CALL add_mp_perf_env()
1264 10864 : mp_world_is_initialized = .TRUE.
1265 10864 : END SUBROUTINE mp_world_init
1266 :
1267 : ! **************************************************************************************************
1268 : !> \brief re-create the system default communicator with a different MPI
1269 : !> rank order
1270 : !> \param mp_comm [output] : handle of the default communicator
1271 : !> \param mp_new_comm ...
1272 : !> \param ranks_order ...
1273 : !> \par History
1274 : !> 1.2012 created [ Christiane Pousa ]
1275 : !> \note
1276 : !> should only be called once, at very beginning of CP2K run
1277 : ! **************************************************************************************************
1278 764 : SUBROUTINE mp_reordering(mp_comm, mp_new_comm, ranks_order)
1279 : CLASS(mp_comm_type), INTENT(IN) :: mp_comm
1280 : CLASS(mp_comm_type), INTENT(out) :: mp_new_comm
1281 : INTEGER, DIMENSION(:), CONTIGUOUS, INTENT(IN) :: ranks_order
1282 :
1283 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_reordering'
1284 :
1285 : INTEGER :: handle, ierr
1286 : #if defined(__parallel)
1287 : MPI_GROUP_TYPE :: newgroup, oldgroup
1288 : #endif
1289 :
1290 764 : CALL mp_assert_outside_parallel(routineN)
1291 764 : CALL mp_timeset(routineN, handle)
1292 : ierr = 0
1293 : #if defined(__parallel)
1294 :
1295 764 : CALL mpi_comm_group(mp_comm%handle, oldgroup, ierr)
1296 764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_group @ mp_reordering")
1297 764 : CALL mpi_group_incl(oldgroup, SIZE(ranks_order), ranks_order, newgroup, ierr)
1298 764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_group_incl @ mp_reordering")
1299 :
1300 764 : CALL mpi_comm_create(mp_comm%handle, newgroup, mp_new_comm%handle, ierr)
1301 764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_create @ mp_reordering")
1302 :
1303 764 : CALL mpi_group_free(oldgroup, ierr)
1304 764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_group_free @ mp_reordering")
1305 764 : CALL mpi_group_free(newgroup, ierr)
1306 764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_group_free @ mp_reordering")
1307 :
1308 764 : CALL add_perf(perf_id=1, count=1)
1309 : #else
1310 : MARK_USED(mp_comm)
1311 : MARK_USED(ranks_order)
1312 : mp_new_comm%handle = mp_comm_default_handle
1313 : #endif
1314 764 : debug_comm_count = debug_comm_count + 1
1315 764 : CALL mp_new_comm%init()
1316 764 : CALL mp_timestop(handle)
1317 764 : END SUBROUTINE mp_reordering
1318 :
1319 : ! **************************************************************************************************
1320 : !> \brief Finalize the system default communicator and MPI when CP2K owns MPI.
1321 : !> \par History
1322 : !> 2.2004 created [Joost VandeVondele]
1323 : ! **************************************************************************************************
1324 21728 : SUBROUTINE mp_world_finalize()
1325 :
1326 : CHARACTER(LEN=default_string_length) :: debug_comm_count_char
1327 : #if defined(__parallel)
1328 : INTEGER :: ierr
1329 : #endif
1330 :
1331 10864 : CALL mp_assert_outside_parallel("mp_world_finalize")
1332 10864 : IF (.NOT. mp_world_is_initialized) THEN
1333 : CALL cp_abort(__LOCATION__, &
1334 0 : "mp_world_finalize called without a matching mp_world_init.")
1335 : END IF
1336 : #if defined(__parallel)
1337 : #if defined(__MIMIC)
1338 10864 : CALL mpi_barrier(mimic_comm_world, ierr)
1339 : #else
1340 : CALL mpi_barrier(MPI_COMM_WORLD, ierr) ! call mpi directly to avoid 0 stack pointer
1341 : #endif
1342 : #endif
1343 10864 : CALL rm_mp_perf_env()
1344 :
1345 10864 : debug_comm_count = debug_comm_count - 1
1346 : #if defined(__parallel)
1347 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_barrier @ mp_world_finalize")
1348 : #endif
1349 10864 : IF (debug_comm_count /= 0) THEN
1350 : ! A bug, we're leaking or double-freeing communicators. Needs to be fixed where the leak happens.
1351 : ! Memory leak checking might be helpful to locate the culprit
1352 0 : WRITE (unit=debug_comm_count_char, FMT='(I2)') debug_comm_count
1353 : CALL cp_abort(__LOCATION__, "mp_world_finalize: assert failed:"// &
1354 0 : " leaking communicators "//ADJUSTL(TRIM(debug_comm_count_char)))
1355 : END IF
1356 : #if defined(__parallel)
1357 10864 : IF (mp_mpi_initialized_by_cp2k) THEN
1358 10864 : CALL mpi_finalize(ierr)
1359 10864 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_finalize @ mp_world_finalize")
1360 : END IF
1361 : #endif
1362 10864 : mp_thread_level_provided = -1
1363 : #if defined(__parallel)
1364 10864 : mp_mpi_initialized_by_cp2k = .FALSE.
1365 : #endif
1366 10864 : mp_world_is_initialized = .FALSE.
1367 :
1368 10864 : END SUBROUTINE mp_world_finalize
1369 :
1370 : ! all the following routines should work for a given communicator, not MPI_WORLD
1371 :
1372 : ! **************************************************************************************************
1373 : !> \brief globally stops all tasks
1374 : !> this is intended to be low level, most of CP2K should call cp_abort()
1375 : ! **************************************************************************************************
1376 0 : SUBROUTINE mp_abort()
1377 : INTEGER :: ierr
1378 : #if defined(__MIMIC)
1379 : LOGICAL :: mcl_initialized
1380 : #endif
1381 :
1382 0 : ierr = 0
1383 :
1384 : #if !defined(__NO_ABORT)
1385 : #if defined(__parallel)
1386 : #if defined(__MIMIC)
1387 : CALL mcl_is_initialized(mcl_initialized)
1388 : IF (mcl_initialized) CALL mcl_abort(1, ierr)
1389 : #endif
1390 : CALL mpi_abort(MPI_COMM_WORLD, 1, ierr)
1391 : #else
1392 : CALL m_abort()
1393 : #endif
1394 : #endif
1395 : ! this routine never returns and levels with non-zero exit code
1396 0 : STOP 1
1397 : END SUBROUTINE mp_abort
1398 :
1399 : ! **************************************************************************************************
1400 : !> \brief stops *after an mpi error* translating the error code
1401 : !> \param ierr an error code * returned by an mpi call *
1402 : !> \param prg_code ...
1403 : !> \note
1404 : !> this function is private to message_passing.F
1405 : ! **************************************************************************************************
1406 0 : SUBROUTINE mp_stop(ierr, prg_code)
1407 : INTEGER, INTENT(IN) :: ierr
1408 : CHARACTER(LEN=*), INTENT(IN) :: prg_code
1409 :
1410 : #if defined(__parallel)
1411 : INTEGER :: istat, len
1412 : CHARACTER(LEN=MPI_MAX_ERROR_STRING) :: error_string
1413 : CHARACTER(LEN=MPI_MAX_ERROR_STRING + 512) :: full_error
1414 : #else
1415 : CHARACTER(LEN=512) :: full_error
1416 : #endif
1417 :
1418 : #if defined(__parallel)
1419 0 : CALL mpi_error_string(ierr, error_string, len, istat)
1420 0 : WRITE (full_error, '(A,I0,A)') ' MPI error ', ierr, ' in '//TRIM(prg_code)//' : '//error_string(1:len)
1421 : #else
1422 : WRITE (full_error, '(A,I0,A)') ' MPI error (!?) ', ierr, ' in '//TRIM(prg_code)
1423 : #endif
1424 :
1425 0 : CPABORT(full_error)
1426 :
1427 0 : END SUBROUTINE mp_stop
1428 :
1429 : ! **************************************************************************************************
1430 : !> \brief synchronizes with a barrier a given group of mpi tasks
1431 : !> \param group mpi communicator
1432 : ! **************************************************************************************************
1433 9152088 : SUBROUTINE mp_sync(comm)
1434 : CLASS(mp_comm_type), INTENT(IN) :: comm
1435 :
1436 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_sync'
1437 :
1438 : INTEGER :: handle, ierr
1439 :
1440 : ierr = 0
1441 4576044 : CALL mp_timeset(routineN, handle)
1442 :
1443 : #if defined(__parallel)
1444 4576044 : CALL mpi_barrier(comm%handle, ierr)
1445 4576044 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_barrier @ mp_sync")
1446 4576044 : CALL add_perf(perf_id=5, count=1)
1447 : #else
1448 : MARK_USED(comm)
1449 : #endif
1450 4576044 : CALL mp_timestop(handle)
1451 :
1452 4576044 : END SUBROUTINE mp_sync
1453 :
1454 : ! **************************************************************************************************
1455 : !> \brief synchronizes with a barrier a given group of mpi tasks
1456 : !> \param comm mpi communicator
1457 : !> \param request ...
1458 : ! **************************************************************************************************
1459 0 : SUBROUTINE mp_isync(comm, request)
1460 : CLASS(mp_comm_type), INTENT(IN) :: comm
1461 : TYPE(mp_request_type), INTENT(OUT) :: request
1462 :
1463 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_isync'
1464 :
1465 : INTEGER :: handle, ierr
1466 :
1467 : ierr = 0
1468 0 : CALL mp_timeset(routineN, handle)
1469 :
1470 : #if defined(__parallel)
1471 0 : CALL mpi_ibarrier(comm%handle, request%handle, ierr)
1472 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_ibarrier @ mp_isync")
1473 0 : CALL add_perf(perf_id=26, count=1)
1474 : #else
1475 : MARK_USED(comm)
1476 : request = mp_request_null
1477 : #endif
1478 0 : CALL mp_timestop(handle)
1479 :
1480 0 : END SUBROUTINE mp_isync
1481 :
1482 : ! **************************************************************************************************
1483 : !> \brief returns task id for a given mpi communicator
1484 : !> \param taskid The ID of the communicator
1485 : !> \param comm mpi communicator
1486 : ! **************************************************************************************************
1487 52512960 : SUBROUTINE mp_comm_rank(taskid, comm)
1488 :
1489 : INTEGER, INTENT(OUT) :: taskid
1490 : CLASS(mp_comm_type), INTENT(IN) :: comm
1491 :
1492 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_rank'
1493 :
1494 : INTEGER :: handle
1495 : #if defined(__parallel)
1496 : INTEGER :: ierr
1497 : #endif
1498 :
1499 26256480 : CALL mp_timeset(routineN, handle)
1500 :
1501 : #if defined(__parallel)
1502 26256480 : CALL mpi_comm_rank(comm%handle, taskid, ierr)
1503 26256480 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_rank @ mp_comm_rank")
1504 : #else
1505 : MARK_USED(comm)
1506 : taskid = 0
1507 : #endif
1508 26256480 : CALL mp_timestop(handle)
1509 :
1510 26256480 : END SUBROUTINE mp_comm_rank
1511 :
1512 : ! **************************************************************************************************
1513 : !> \brief returns number of tasks for a given mpi communicator
1514 : !> \param numtask ...
1515 : !> \param comm mpi communicator
1516 : ! **************************************************************************************************
1517 52512960 : SUBROUTINE mp_comm_size(numtask, comm)
1518 :
1519 : INTEGER, INTENT(OUT) :: numtask
1520 : CLASS(mp_comm_type), INTENT(IN) :: comm
1521 :
1522 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_size'
1523 :
1524 : INTEGER :: handle
1525 : #if defined(__parallel)
1526 : INTEGER :: ierr
1527 : #endif
1528 :
1529 26256480 : CALL mp_timeset(routineN, handle)
1530 :
1531 : #if defined(__parallel)
1532 26256480 : CALL mpi_comm_size(comm%handle, numtask, ierr)
1533 26256480 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_rank @ mp_comm_size")
1534 : #else
1535 : MARK_USED(comm)
1536 : numtask = 1
1537 : #endif
1538 26256480 : CALL mp_timestop(handle)
1539 :
1540 26256480 : END SUBROUTINE mp_comm_size
1541 :
1542 : ! **************************************************************************************************
1543 : !> \brief returns info for a given Cartesian MPI communicator
1544 : !> \param comm ...
1545 : !> \param ndims ...
1546 : !> \param dims ...
1547 : !> \param task_coor ...
1548 : !> \param periods ...
1549 : ! **************************************************************************************************
1550 12282090 : SUBROUTINE mp_cart_get(comm, dims, task_coor, periods)
1551 :
1552 : CLASS(mp_cart_type), INTENT(IN) :: comm
1553 : INTEGER, INTENT(OUT), OPTIONAL :: dims(comm%ndims), task_coor(comm%ndims)
1554 : LOGICAL, INTENT(out), OPTIONAL :: periods(comm%ndims)
1555 :
1556 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_cart_get'
1557 :
1558 : INTEGER :: handle
1559 : #if defined(__parallel)
1560 : INTEGER :: ierr
1561 24564180 : INTEGER :: my_dims(comm%ndims), my_task_coor(comm%ndims)
1562 24564180 : LOGICAL :: my_periods(comm%ndims)
1563 : #endif
1564 :
1565 12282090 : CALL mp_timeset(routineN, handle)
1566 :
1567 : #if defined(__parallel)
1568 12282090 : CALL mpi_cart_get(comm%handle, comm%ndims, my_dims, my_periods, my_task_coor, ierr)
1569 12282090 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_cart_get @ mp_cart_get")
1570 49129270 : IF (PRESENT(dims)) dims = my_dims
1571 49129270 : IF (PRESENT(task_coor)) task_coor = my_task_coor
1572 49129270 : IF (PRESENT(periods)) periods = my_periods
1573 : #else
1574 : MARK_USED(comm)
1575 : IF (PRESENT(task_coor)) task_coor = 0
1576 : IF (PRESENT(dims)) dims = 1
1577 : IF (PRESENT(periods)) periods = .FALSE.
1578 : #endif
1579 12282090 : CALL mp_timestop(handle)
1580 :
1581 12282090 : END SUBROUTINE mp_cart_get
1582 :
1583 0 : INTEGER ELEMENTAL FUNCTION mp_comm_get_ndims(comm)
1584 : CLASS(mp_comm_type), INTENT(IN) :: comm
1585 :
1586 0 : mp_comm_get_ndims = comm%ndims
1587 :
1588 0 : END FUNCTION
1589 :
1590 : ! **************************************************************************************************
1591 : !> \brief creates a cartesian communicator from any communicator
1592 : !> \param comm_old ...
1593 : !> \param ndims ...
1594 : !> \param dims ...
1595 : !> \param pos ...
1596 : !> \param comm_cart ...
1597 : ! **************************************************************************************************
1598 2439734 : SUBROUTINE mp_cart_create(comm_old, ndims, dims, comm_cart)
1599 :
1600 : CLASS(mp_comm_type), INTENT(IN) :: comm_old
1601 : INTEGER, INTENT(IN) :: ndims
1602 : INTEGER, INTENT(INOUT) :: dims(ndims)
1603 : CLASS(mp_cart_type), INTENT(OUT) :: comm_cart
1604 :
1605 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_cart_create'
1606 :
1607 : INTEGER :: handle, ierr
1608 : #if defined(__parallel)
1609 2439734 : LOGICAL, DIMENSION(1:ndims) :: period
1610 : LOGICAL :: reorder
1611 : #endif
1612 :
1613 2439734 : ierr = 0
1614 2439734 : CALL mp_assert_outside_parallel(routineN)
1615 2439734 : CALL mp_timeset(routineN, handle)
1616 :
1617 2439734 : comm_cart%handle = comm_old%handle
1618 : #if defined(__parallel)
1619 :
1620 6620956 : IF (ANY(dims == 0)) CALL mpi_dims_create(comm_old%num_pe, ndims, dims, ierr)
1621 2439734 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_dims_create @ mp_cart_create")
1622 :
1623 : ! FIX ME. Quick hack to avoid problems with realspace grids for compilers
1624 : ! like IBM that actually reorder the processors when creating the new
1625 : ! communicator
1626 2439734 : reorder = .FALSE.
1627 7320112 : period = .TRUE.
1628 : CALL mpi_cart_create(comm_old%handle, ndims, dims, period, reorder, comm_cart%handle, &
1629 2439734 : ierr)
1630 2439734 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_cart_create @ mp_cart_create")
1631 2439734 : CALL add_perf(perf_id=1, count=1)
1632 : #else
1633 : dims = 1
1634 : comm_cart%handle = mp_comm_default_handle
1635 : #endif
1636 2439734 : comm_cart%ndims = ndims
1637 2439734 : debug_comm_count = debug_comm_count + 1
1638 2439734 : CALL comm_cart%init()
1639 2439734 : CALL mp_timestop(handle)
1640 :
1641 2439734 : END SUBROUTINE mp_cart_create
1642 :
1643 : ! **************************************************************************************************
1644 : !> \brief wrapper to MPI_Cart_coords
1645 : !> \param comm ...
1646 : !> \param rank ...
1647 : !> \param coords ...
1648 : ! **************************************************************************************************
1649 76452 : SUBROUTINE mp_cart_coords(comm, rank, coords)
1650 :
1651 : CLASS(mp_cart_type), INTENT(IN) :: comm
1652 : INTEGER, INTENT(IN) :: rank
1653 : INTEGER, DIMENSION(:), INTENT(OUT) :: coords
1654 :
1655 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_cart_coords'
1656 :
1657 : INTEGER :: handle, ierr, m
1658 :
1659 : ierr = 0
1660 76452 : CALL mp_timeset(routineN, handle)
1661 :
1662 76452 : m = SIZE(coords)
1663 : #if defined(__parallel)
1664 76452 : CALL mpi_cart_coords(comm%handle, rank, m, coords, ierr)
1665 76452 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_cart_coords @ mp_cart_coords")
1666 : #else
1667 : coords = 0
1668 : MARK_USED(rank)
1669 : MARK_USED(comm)
1670 : #endif
1671 76452 : CALL mp_timestop(handle)
1672 :
1673 76452 : END SUBROUTINE mp_cart_coords
1674 :
1675 : ! **************************************************************************************************
1676 : !> \brief wrapper to MPI_Comm_compare
1677 : !> \param comm1 ...
1678 : !> \param comm2 ...
1679 : !> \param res ...
1680 : ! **************************************************************************************************
1681 4616 : FUNCTION mp_comm_compare(comm1, comm2) RESULT(res)
1682 :
1683 : CLASS(mp_comm_type), INTENT(IN) :: comm1, comm2
1684 : INTEGER :: res
1685 :
1686 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_compare'
1687 :
1688 : INTEGER :: handle
1689 : #if defined(__parallel)
1690 : INTEGER :: ierr, iout
1691 : #endif
1692 :
1693 2308 : CALL mp_timeset(routineN, handle)
1694 :
1695 2308 : res = 0
1696 : #if defined(__parallel)
1697 2308 : CALL mpi_comm_compare(comm1%handle, comm2%handle, iout, ierr)
1698 2308 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_compare @ mp_comm_compare")
1699 : SELECT CASE (iout)
1700 : CASE (MPI_IDENT)
1701 2308 : res = mp_comm_ident
1702 : CASE (MPI_CONGRUENT)
1703 2308 : res = mp_comm_congruent
1704 : CASE (MPI_SIMILAR)
1705 0 : res = mp_comm_similar
1706 : CASE (MPI_UNEQUAL)
1707 0 : res = mp_comm_unequal
1708 : CASE default
1709 2308 : CPABORT("Unknown comparison state of the communicators!")
1710 : END SELECT
1711 : #else
1712 : MARK_USED(comm1)
1713 : MARK_USED(comm2)
1714 : #endif
1715 2308 : CALL mp_timestop(handle)
1716 :
1717 2308 : END FUNCTION mp_comm_compare
1718 :
1719 : ! **************************************************************************************************
1720 : !> \brief wrapper to MPI_Cart_sub
1721 : !> \param comm ...
1722 : !> \param rdim ...
1723 : !> \param sub_comm ...
1724 : ! **************************************************************************************************
1725 1820 : SUBROUTINE mp_cart_sub(comm, rdim, sub_comm)
1726 :
1727 : CLASS(mp_cart_type), INTENT(IN) :: comm
1728 : LOGICAL, DIMENSION(:), CONTIGUOUS, INTENT(IN) :: rdim
1729 : CLASS(mp_cart_type), INTENT(OUT) :: sub_comm
1730 :
1731 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_cart_sub'
1732 :
1733 : INTEGER :: handle
1734 : #if defined(__parallel)
1735 : INTEGER :: ierr
1736 : #endif
1737 :
1738 1820 : CALL mp_assert_outside_parallel(routineN)
1739 1820 : CALL mp_timeset(routineN, handle)
1740 :
1741 : #if defined(__parallel)
1742 1820 : CALL mpi_cart_sub(comm%handle, rdim, sub_comm%handle, ierr)
1743 1820 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_cart_sub @ mp_cart_sub")
1744 : #else
1745 : MARK_USED(comm)
1746 : MARK_USED(rdim)
1747 : sub_comm%handle = mp_comm_default_handle
1748 : #endif
1749 7280 : sub_comm%ndims = COUNT(rdim)
1750 1820 : debug_comm_count = debug_comm_count + 1
1751 1820 : CALL sub_comm%init()
1752 1820 : CALL mp_timestop(handle)
1753 :
1754 1820 : END SUBROUTINE mp_cart_sub
1755 :
1756 : ! **************************************************************************************************
1757 : !> \brief wrapper to MPI_Comm_free
1758 : !> \param comm ...
1759 : ! **************************************************************************************************
1760 6044716 : SUBROUTINE mp_comm_free(comm)
1761 :
1762 : CLASS(mp_comm_type), INTENT(INOUT) :: comm
1763 :
1764 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_free'
1765 :
1766 : INTEGER :: handle
1767 : LOGICAL :: free_comm
1768 : #if defined(__parallel)
1769 : INTEGER :: ierr
1770 : #endif
1771 :
1772 6044716 : CALL mp_assert_outside_parallel(routineN)
1773 6044716 : free_comm = .TRUE.
1774 : SELECT TYPE (comm)
1775 : CLASS IS (mp_para_env_type)
1776 1511184 : free_comm = .FALSE.
1777 1511184 : IF (comm%ref_count <= 0) &
1778 0 : CPABORT("para_env%ref_count <= 0")
1779 1511184 : comm%ref_count = comm%ref_count - 1
1780 1511184 : IF (comm%ref_count <= 0) THEN
1781 320127 : free_comm = comm%owns_group
1782 : END IF
1783 : CLASS IS (mp_para_cart_type)
1784 148 : free_comm = .FALSE.
1785 148 : IF (comm%ref_count <= 0) &
1786 0 : CPABORT("para_cart%ref_count <= 0")
1787 148 : comm%ref_count = comm%ref_count - 1
1788 148 : IF (comm%ref_count <= 0) THEN
1789 148 : free_comm = comm%owns_group
1790 : END IF
1791 : END SELECT
1792 :
1793 6044716 : CALL mp_timeset(routineN, handle)
1794 :
1795 6044716 : IF (free_comm) THEN
1796 : #if defined(__parallel)
1797 4818628 : CALL mpi_comm_free(comm%handle, ierr)
1798 4818628 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_free @ mp_comm_free")
1799 : #else
1800 : comm%handle = mp_comm_null_handle
1801 : #endif
1802 4818628 : debug_comm_count = debug_comm_count - 1
1803 : END IF
1804 :
1805 : SELECT TYPE (comm)
1806 : CLASS IS (mp_cart_type)
1807 3352915 : DEALLOCATE (comm%periodic, comm%mepos_cart, comm%num_pe_cart)
1808 : END SELECT
1809 :
1810 6044716 : CALL mp_timestop(handle)
1811 :
1812 6044716 : END SUBROUTINE mp_comm_free
1813 :
1814 : ! **************************************************************************************************
1815 : !> \brief check whether the environment exists
1816 : !> \param para_env ...
1817 : !> \return ...
1818 : ! **************************************************************************************************
1819 1258745 : ELEMENTAL LOGICAL FUNCTION mp_para_env_is_valid(para_env)
1820 : CLASS(mp_para_env_type), INTENT(IN) :: para_env
1821 :
1822 1258745 : mp_para_env_is_valid = para_env%ref_count > 0
1823 :
1824 1258745 : END FUNCTION mp_para_env_is_valid
1825 :
1826 : ! **************************************************************************************************
1827 : !> \brief increase the reference counter but ensure that you free it later
1828 : !> \param para_env ...
1829 : ! **************************************************************************************************
1830 1191065 : ELEMENTAL IMPURE SUBROUTINE mp_para_env_retain(para_env)
1831 : CLASS(mp_para_env_type), INTENT(INOUT) :: para_env
1832 :
1833 1191065 : CALL mp_assert_outside_parallel("mp_para_env_retain")
1834 1191065 : para_env%ref_count = para_env%ref_count + 1
1835 :
1836 1191065 : END SUBROUTINE mp_para_env_retain
1837 :
1838 : ! **************************************************************************************************
1839 : !> \brief check whether the given environment is valid, i.e. existent
1840 : !> \param cart ...
1841 : !> \return ...
1842 : ! **************************************************************************************************
1843 148 : ELEMENTAL LOGICAL FUNCTION mp_para_cart_is_valid(cart)
1844 : CLASS(mp_para_cart_type), INTENT(IN) :: cart
1845 :
1846 148 : mp_para_cart_is_valid = cart%ref_count > 0
1847 :
1848 148 : END FUNCTION mp_para_cart_is_valid
1849 :
1850 : ! **************************************************************************************************
1851 : !> \brief increase the reference counter, don't forget to free it later
1852 : !> \param cart ...
1853 : ! **************************************************************************************************
1854 0 : ELEMENTAL IMPURE SUBROUTINE mp_para_cart_retain(cart)
1855 : CLASS(mp_para_cart_type), INTENT(INOUT) :: cart
1856 :
1857 0 : CALL mp_assert_outside_parallel("mp_para_cart_retain")
1858 0 : cart%ref_count = cart%ref_count + 1
1859 :
1860 0 : END SUBROUTINE mp_para_cart_retain
1861 :
1862 : ! **************************************************************************************************
1863 : !> \brief wrapper to MPI_Comm_dup
1864 : !> \param comm1 ...
1865 : !> \param comm2 ...
1866 : ! **************************************************************************************************
1867 950703 : SUBROUTINE mp_comm_dup(comm1, comm2)
1868 :
1869 : CLASS(mp_comm_type), INTENT(IN) :: comm1
1870 : CLASS(mp_comm_type), INTENT(OUT) :: comm2
1871 :
1872 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_dup'
1873 :
1874 : INTEGER :: handle
1875 : #if defined(__parallel)
1876 : INTEGER :: ierr
1877 : #endif
1878 :
1879 950703 : CALL mp_assert_outside_parallel(routineN)
1880 950703 : CALL mp_timeset(routineN, handle)
1881 :
1882 : #if defined(__parallel)
1883 950703 : CALL mpi_comm_dup(comm1%handle, comm2%handle, ierr)
1884 950703 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_dup @ mp_comm_dup")
1885 : #else
1886 : MARK_USED(comm1)
1887 : comm2%handle = mp_comm_default_handle
1888 : #endif
1889 950703 : comm2%ndims = comm1%ndims
1890 950703 : debug_comm_count = debug_comm_count + 1
1891 950703 : CALL comm2%init()
1892 950703 : CALL mp_timestop(handle)
1893 :
1894 950703 : END SUBROUTINE mp_comm_dup
1895 :
1896 : ! **************************************************************************************************
1897 : !> \brief Implements a simple assignment function to overload the assignment operator
1898 : !> \param comm_new communicator on the r.h.s. of the assignment operator
1899 : !> \param comm_old communicator on the l.h.s. of the assignment operator
1900 : ! **************************************************************************************************
1901 11845881 : ELEMENTAL IMPURE SUBROUTINE mp_comm_assign(comm_new, comm_old)
1902 : CLASS(mp_comm_type), INTENT(IN) :: comm_old
1903 : CLASS(mp_comm_type), INTENT(OUT) :: comm_new
1904 :
1905 11845881 : comm_new%handle = comm_old%handle
1906 11845881 : comm_new%ndims = comm_old%ndims
1907 11845881 : CALL comm_new%init(.FALSE.)
1908 11845881 : END SUBROUTINE
1909 :
1910 : ! **************************************************************************************************
1911 : !> \brief check whether the local process is the source process
1912 : !> \param para_env ...
1913 : !> \return ...
1914 : ! **************************************************************************************************
1915 17286226 : ELEMENTAL LOGICAL FUNCTION mp_comm_is_source(comm)
1916 : CLASS(mp_comm_type), INTENT(IN) :: comm
1917 :
1918 17286226 : mp_comm_is_source = comm%source == comm%mepos
1919 :
1920 17286226 : END FUNCTION mp_comm_is_source
1921 :
1922 : ! **************************************************************************************************
1923 : !> \brief Initializes the communicator (mostly relevant for its derived classes)
1924 : !> \param comm ...
1925 : ! **************************************************************************************************
1926 26159975 : ELEMENTAL IMPURE SUBROUTINE mp_comm_init(comm, owns_group)
1927 : CLASS(mp_comm_type), INTENT(INOUT) :: comm
1928 : LOGICAL, INTENT(IN), OPTIONAL :: owns_group
1929 :
1930 : ! Only reference-counted communicators update ownership state during initialization.
1931 : SELECT TYPE (comm)
1932 : CLASS IS (mp_para_env_type)
1933 341865 : CALL mp_assert_outside_parallel("mp_comm_init")
1934 : CLASS IS (mp_para_cart_type)
1935 148 : CALL mp_assert_outside_parallel("mp_comm_init")
1936 : END SELECT
1937 :
1938 26159975 : IF (comm%handle MPI_GET_COMP /= mp_comm_null_handle MPI_GET_COMP) THEN
1939 25980749 : comm%source = 0
1940 25980749 : CALL comm%get_size(comm%num_pe)
1941 25980749 : CALL comm%get_rank(comm%mepos)
1942 : END IF
1943 :
1944 : SELECT TYPE (comm)
1945 : CLASS IS (mp_cart_type)
1946 12282090 : IF (ALLOCATED(comm%periodic)) DEALLOCATE (comm%periodic)
1947 12282090 : IF (ALLOCATED(comm%mepos_cart)) DEALLOCATE (comm%mepos_cart)
1948 12282090 : IF (ALLOCATED(comm%num_pe_cart)) DEALLOCATE (comm%num_pe_cart)
1949 :
1950 : ASSOCIATE (ndims => comm%ndims)
1951 :
1952 0 : ALLOCATE (comm%periodic(ndims), comm%mepos_cart(ndims), &
1953 61410450 : comm%num_pe_cart(ndims))
1954 : END ASSOCIATE
1955 :
1956 36847180 : comm%mepos_cart = 0
1957 36847180 : comm%periodic = .FALSE.
1958 12282090 : IF (comm%handle MPI_GET_COMP /= mp_comm_null_handle MPI_GET_COMP) THEN
1959 : CALL comm%get_info_cart(comm%num_pe_cart, comm%mepos_cart, &
1960 12282090 : comm%periodic)
1961 : END IF
1962 : END SELECT
1963 :
1964 : SELECT TYPE (comm)
1965 : CLASS IS (mp_para_env_type)
1966 341865 : IF (PRESENT(owns_group)) comm%owns_group = owns_group
1967 341865 : comm%ref_count = 1
1968 : CLASS IS (mp_para_cart_type)
1969 148 : IF (PRESENT(owns_group)) comm%owns_group = owns_group
1970 148 : comm%ref_count = 1
1971 : END SELECT
1972 :
1973 26159975 : END SUBROUTINE
1974 :
1975 : ! **************************************************************************************************
1976 : !> \brief creates a new para environment
1977 : !> \param para_env the new parallel environment
1978 : !> \param group the id of the actual mpi_group
1979 : !> \par History
1980 : !> 08.2002 created [fawzi]
1981 : !> \author Fawzi Mohamed
1982 : ! **************************************************************************************************
1983 0 : SUBROUTINE mp_para_env_create(para_env, group)
1984 : TYPE(mp_para_env_type), POINTER :: para_env
1985 : CLASS(mp_comm_type), INTENT(in) :: group
1986 :
1987 0 : CALL mp_assert_outside_parallel("mp_para_env_create")
1988 0 : IF (ASSOCIATED(para_env)) &
1989 0 : CPABORT("The passed para_env must not be associated!")
1990 0 : ALLOCATE (para_env)
1991 0 : para_env%mp_comm_type = group
1992 0 : CALL para_env%init()
1993 0 : END SUBROUTINE mp_para_env_create
1994 :
1995 : ! **************************************************************************************************
1996 : !> \brief releases the para object (to be called when you don't want anymore
1997 : !> the shared copy of this object)
1998 : !> \param para_env the new group
1999 : !> \par History
2000 : !> 08.2002 created [fawzi]
2001 : !> \author Fawzi Mohamed
2002 : !> \note
2003 : !> to avoid circular dependencies cp_log_handling has a private copy
2004 : !> of this method (see cp_log_handling:my_mp_para_env_release)!
2005 : ! **************************************************************************************************
2006 1271742 : SUBROUTINE mp_para_env_release(para_env)
2007 : TYPE(mp_para_env_type), POINTER :: para_env
2008 :
2009 1271742 : CALL mp_assert_outside_parallel("mp_para_env_release")
2010 1271742 : IF (ASSOCIATED(para_env)) THEN
2011 1235218 : CALL para_env%free()
2012 1235218 : IF (.NOT. para_env%is_valid()) DEALLOCATE (para_env)
2013 : END IF
2014 1271742 : NULLIFY (para_env)
2015 1271742 : END SUBROUTINE mp_para_env_release
2016 :
2017 : ! **************************************************************************************************
2018 : !> \brief creates a cart (multidimensional parallel environment)
2019 : !> \param cart the cart environment to create
2020 : !> \param group the mpi communicator
2021 : !> \author fawzi
2022 : ! **************************************************************************************************
2023 0 : SUBROUTINE mp_para_cart_create(cart, group)
2024 : TYPE(mp_para_cart_type), POINTER, INTENT(OUT) :: cart
2025 : CLASS(mp_comm_type), INTENT(in) :: group
2026 :
2027 0 : CALL mp_assert_outside_parallel("mp_para_cart_create")
2028 0 : IF (ASSOCIATED(cart)) &
2029 0 : CPABORT("The passed para_cart must not be associated!")
2030 0 : ALLOCATE (cart)
2031 0 : cart%mp_cart_type = group
2032 0 : CALL cart%init()
2033 :
2034 0 : END SUBROUTINE mp_para_cart_create
2035 :
2036 : ! **************************************************************************************************
2037 : !> \brief releases the given cart
2038 : !> \param cart the cart to release
2039 : !> \author fawzi
2040 : ! **************************************************************************************************
2041 148 : SUBROUTINE mp_para_cart_release(cart)
2042 : TYPE(mp_para_cart_type), POINTER :: cart
2043 :
2044 148 : CALL mp_assert_outside_parallel("mp_para_cart_release")
2045 148 : IF (ASSOCIATED(cart)) THEN
2046 148 : CALL cart%free()
2047 148 : IF (.NOT. cart%is_valid()) DEALLOCATE (cart)
2048 : END IF
2049 148 : NULLIFY (cart)
2050 148 : END SUBROUTINE mp_para_cart_release
2051 :
2052 : ! **************************************************************************************************
2053 : !> \brief wrapper to MPI_Group_translate_ranks
2054 : !> \param comm1 ...
2055 : !> \param comm2 ...
2056 : !> \param rank ...
2057 : ! **************************************************************************************************
2058 3401824 : SUBROUTINE mp_rank_compare(comm1, comm2, rank)
2059 :
2060 : CLASS(mp_comm_type), INTENT(IN) :: comm1, comm2
2061 : INTEGER, DIMENSION(:), CONTIGUOUS, INTENT(OUT) :: rank
2062 :
2063 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_rank_compare'
2064 :
2065 : INTEGER :: handle
2066 : #if defined(__parallel)
2067 : INTEGER :: i, ierr, n, n1, n2
2068 3401824 : INTEGER, ALLOCATABLE, DIMENSION(:) :: rin
2069 : MPI_GROUP_TYPE :: g1, g2
2070 : #endif
2071 :
2072 3401824 : CALL mp_timeset(routineN, handle)
2073 :
2074 10205472 : rank = 0
2075 : #if defined(__parallel)
2076 3401824 : CALL mpi_comm_size(comm1%handle, n1, ierr)
2077 3401824 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_size @ mp_rank_compare")
2078 3401824 : CALL mpi_comm_size(comm2%handle, n2, ierr)
2079 3401824 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_size @ mp_rank_compare")
2080 3401824 : n = MAX(n1, n2)
2081 3401824 : CALL mpi_comm_group(comm1%handle, g1, ierr)
2082 3401824 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_group @ mp_rank_compare")
2083 3401824 : CALL mpi_comm_group(comm2%handle, g2, ierr)
2084 3401824 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_comm_group @ mp_rank_compare")
2085 10205472 : ALLOCATE (rin(0:n - 1), STAT=ierr)
2086 3401824 : IF (ierr /= 0) &
2087 0 : CPABORT("allocate @ mp_rank_compare")
2088 10205472 : DO i = 0, n - 1
2089 10205472 : rin(i) = i
2090 : END DO
2091 3401824 : CALL mpi_group_translate_ranks(g1, n, rin, g2, rank, ierr)
2092 3401824 : IF (ierr /= 0) CALL mp_stop(ierr, &
2093 0 : "mpi_group_translate_rank @ mp_rank_compare")
2094 3401824 : CALL mpi_group_free(g1, ierr)
2095 3401824 : IF (ierr /= 0) &
2096 0 : CPABORT("group_free @ mp_rank_compare")
2097 3401824 : CALL mpi_group_free(g2, ierr)
2098 3401824 : IF (ierr /= 0) &
2099 0 : CPABORT("group_free @ mp_rank_compare")
2100 3401824 : DEALLOCATE (rin)
2101 : #else
2102 : MARK_USED(comm1)
2103 : MARK_USED(comm2)
2104 : #endif
2105 3401824 : CALL mp_timestop(handle)
2106 :
2107 23812768 : END SUBROUTINE mp_rank_compare
2108 :
2109 : ! **************************************************************************************************
2110 : !> \brief wrapper to MPI_Dims_create
2111 : !> \param nodes ...
2112 : !> \param dims ...
2113 : ! **************************************************************************************************
2114 1198764 : SUBROUTINE mp_dims_create(nodes, dims)
2115 :
2116 : INTEGER, INTENT(IN) :: nodes
2117 : INTEGER, DIMENSION(:), INTENT(INOUT) :: dims
2118 :
2119 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_dims_create'
2120 :
2121 : INTEGER :: handle, ndim
2122 : #if defined(__parallel)
2123 : INTEGER :: ierr
2124 : #endif
2125 :
2126 1198764 : CALL mp_timeset(routineN, handle)
2127 :
2128 1198764 : ndim = SIZE(dims)
2129 : #if defined(__parallel)
2130 1198764 : IF (ANY(dims == 0)) CALL mpi_dims_create(nodes, ndim, dims, ierr)
2131 1198764 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_dims_create @ mp_dims_create")
2132 : #else
2133 : dims = 1
2134 : MARK_USED(nodes)
2135 : #endif
2136 1198764 : CALL mp_timestop(handle)
2137 :
2138 1198764 : END SUBROUTINE mp_dims_create
2139 :
2140 : ! **************************************************************************************************
2141 : !> \brief wrapper to MPI_Cart_rank
2142 : !> \param comm ...
2143 : !> \param pos ...
2144 : !> \param rank ...
2145 : ! **************************************************************************************************
2146 11319490 : SUBROUTINE mp_cart_rank(comm, pos, rank)
2147 : CLASS(mp_cart_type), INTENT(IN) :: comm
2148 : INTEGER, DIMENSION(:), INTENT(IN) :: pos
2149 : INTEGER, INTENT(OUT) :: rank
2150 :
2151 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_cart_rank'
2152 :
2153 : INTEGER :: handle
2154 : #if defined(__parallel)
2155 : INTEGER :: ierr
2156 : #endif
2157 :
2158 11319490 : CALL mp_timeset(routineN, handle)
2159 :
2160 : #if defined(__parallel)
2161 11319490 : CALL mpi_cart_rank(comm%handle, pos, rank, ierr)
2162 11319490 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_cart_rank @ mp_cart_rank")
2163 : #else
2164 : rank = 0
2165 : MARK_USED(comm)
2166 : MARK_USED(pos)
2167 : #endif
2168 11319490 : CALL mp_timestop(handle)
2169 :
2170 11319490 : END SUBROUTINE mp_cart_rank
2171 :
2172 : ! **************************************************************************************************
2173 : !> \brief waits for completion of the given request
2174 : !> \param request ...
2175 : !> \par History
2176 : !> 08.2003 created [f&j]
2177 : !> \author joost & fawzi
2178 : !> \note
2179 : !> see isendrecv
2180 : ! **************************************************************************************************
2181 19436 : SUBROUTINE mp_wait(request)
2182 : CLASS(mp_request_type), INTENT(inout) :: request
2183 :
2184 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_wait'
2185 :
2186 : INTEGER :: handle
2187 : #if defined(__parallel)
2188 : INTEGER :: ierr
2189 : #endif
2190 :
2191 9718 : CALL mp_timeset(routineN, handle)
2192 :
2193 : #if defined(__parallel)
2194 :
2195 9718 : CALL mpi_wait(request%handle, MPI_STATUS_IGNORE, ierr)
2196 9718 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_wait @ mp_wait")
2197 :
2198 9718 : CALL add_perf(perf_id=9, count=1)
2199 : #else
2200 : request%handle = mp_request_null_handle
2201 : #endif
2202 9718 : CALL mp_timestop(handle)
2203 9718 : END SUBROUTINE mp_wait
2204 :
2205 : ! **************************************************************************************************
2206 : !> \brief waits for completion of the given requests
2207 : !> \param requests ...
2208 : !> \par History
2209 : !> 08.2003 created [f&j]
2210 : !> \author joost & fawzi
2211 : !> \note
2212 : !> see isendrecv
2213 : ! **************************************************************************************************
2214 4106277 : SUBROUTINE mp_waitall_1(requests)
2215 : TYPE(mp_request_type), DIMENSION(:), INTENT(inout) :: requests
2216 :
2217 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_waitall_1'
2218 :
2219 : INTEGER :: handle
2220 : #if defined(__parallel)
2221 : INTEGER :: count, ierr
2222 : #endif
2223 :
2224 4106277 : CALL mp_timeset(routineN, handle)
2225 : #if defined(__parallel)
2226 4106277 : count = SIZE(requests)
2227 4106277 : CALL mpi_waitall_internal(count, requests, ierr)
2228 4106277 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_waitall @ mp_waitall_1")
2229 4106277 : CALL add_perf(perf_id=9, count=1)
2230 : #else
2231 : requests = mp_request_null
2232 : #endif
2233 4106277 : CALL mp_timestop(handle)
2234 4106277 : END SUBROUTINE mp_waitall_1
2235 :
2236 : ! **************************************************************************************************
2237 : !> \brief waits for completion of the given requests
2238 : !> \param requests ...
2239 : !> \par History
2240 : !> 08.2003 created [f&j]
2241 : !> \author joost & fawzi
2242 : ! **************************************************************************************************
2243 1026228 : SUBROUTINE mp_waitall_2(requests)
2244 : TYPE(mp_request_type), DIMENSION(:, :), INTENT(inout) :: requests
2245 :
2246 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_waitall_2'
2247 :
2248 : INTEGER :: handle
2249 : #if defined(__parallel)
2250 : INTEGER :: count, ierr
2251 : #endif
2252 :
2253 1026228 : CALL mp_timeset(routineN, handle)
2254 : #if defined(__parallel)
2255 3078684 : count = SIZE(requests)
2256 5891271 : CALL mpi_waitall_internal(count, requests, ierr)
2257 1026228 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_waitall @ mp_waitall_2")
2258 1026228 : CALL add_perf(perf_id=9, count=1)
2259 : #else
2260 : requests = mp_request_null
2261 : #endif
2262 1026228 : CALL mp_timestop(handle)
2263 1026228 : END SUBROUTINE mp_waitall_2
2264 :
2265 : ! **************************************************************************************************
2266 : !> \brief wrapper needed to deal with interfaces as present in openmpi 1.8.1
2267 : !> the issue is with the rank or requests
2268 : !> \param count ...
2269 : !> \param array_of_requests ...
2270 : !> \param ierr ...
2271 : !> \author Joost VandeVondele
2272 : ! **************************************************************************************************
2273 : #if defined(__parallel)
2274 5132505 : SUBROUTINE mpi_waitall_internal(count, array_of_requests, ierr)
2275 : INTEGER, INTENT(in) :: count
2276 : TYPE(mp_request_type), DIMENSION(count), INTENT(inout) :: array_of_requests
2277 : INTEGER, INTENT(out) :: ierr
2278 :
2279 5132505 : MPI_REQUEST_TYPE, ALLOCATABLE, DIMENSION(:), TARGET :: request_handles
2280 :
2281 49325949 : ALLOCATE (request_handles(count), SOURCE=array_of_requests(1:count)%handle)
2282 5132505 : CALL mpi_waitall(count, request_handles, MPI_STATUSES_IGNORE, ierr)
2283 19551633 : array_of_requests(1:count)%handle = request_handles(:)
2284 5132505 : DEALLOCATE (request_handles)
2285 :
2286 5132505 : END SUBROUTINE mpi_waitall_internal
2287 : #endif
2288 :
2289 : ! **************************************************************************************************
2290 : !> \brief waits for completion of any of the given requests
2291 : !> \param requests ...
2292 : !> \param completed ...
2293 : !> \par History
2294 : !> 09.2008 created
2295 : !> \author Iain Bethune (c) The Numerical Algorithms Group (NAG) Ltd, 2008 on behalf of the HECToR project
2296 : ! **************************************************************************************************
2297 12536 : SUBROUTINE mp_waitany(requests, completed)
2298 : TYPE(mp_request_type), DIMENSION(:), INTENT(inout) :: requests
2299 : INTEGER, INTENT(out) :: completed
2300 :
2301 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_waitany'
2302 :
2303 : INTEGER :: handle
2304 : #if defined(__parallel)
2305 : INTEGER :: count, ierr
2306 12536 : MPI_REQUEST_TYPE, ALLOCATABLE, DIMENSION(:) :: request_handles
2307 : #endif
2308 :
2309 12536 : CALL mp_timeset(routineN, handle)
2310 :
2311 : #if defined(__parallel)
2312 12536 : count = SIZE(requests)
2313 : ! Convert CP2K's request_handles to the plain handle for the library
2314 100288 : ALLOCATE (request_handles(count), SOURCE=requests(1:count)%handle)
2315 :
2316 12536 : CALL mpi_waitany(count, request_handles, completed, MPI_STATUS_IGNORE, ierr)
2317 12536 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_waitany @ mp_waitany")
2318 :
2319 : ! Convert the plain handles to CP2K handles
2320 37608 : requests(1:count)%handle = request_handles(:)
2321 12536 : DEALLOCATE (request_handles)
2322 12536 : CALL add_perf(perf_id=9, count=1)
2323 : #else
2324 : requests = mp_request_null
2325 : completed = 1
2326 : #endif
2327 12536 : CALL mp_timestop(handle)
2328 25072 : END SUBROUTINE mp_waitany
2329 :
2330 : ! **************************************************************************************************
2331 : !> \brief Tests for completion of the given requests.
2332 : !> \brief We use mpi_test so that we can use a single status.
2333 : !> \param requests the list of requests to test
2334 : !> \return logical which determines if requests are complete
2335 : !> \par History
2336 : !> 3.2016 adapted to any shape [Nico Holmberg]
2337 : !> \author Alfio Lazzaro
2338 : ! **************************************************************************************************
2339 6400 : FUNCTION mp_testall_tv(requests) RESULT(flag)
2340 : TYPE(mp_request_type), DIMENSION(:), INTENT(INOUT) :: requests
2341 : LOGICAL :: flag
2342 :
2343 : #if defined(__parallel)
2344 : INTEGER :: i, ierr
2345 : LOGICAL, DIMENSION(:), POINTER :: flags
2346 : #endif
2347 :
2348 6400 : flag = .TRUE.
2349 :
2350 : #if defined(__parallel)
2351 19200 : ALLOCATE (flags(SIZE(requests)))
2352 25600 : DO i = 1, SIZE(requests)
2353 19200 : CALL mpi_test(requests(i)%handle, flags(i), MPI_STATUS_IGNORE, ierr)
2354 19200 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_testall @ mp_testall_tv")
2355 45279 : flag = flag .AND. flags(i)
2356 : END DO
2357 6400 : DEALLOCATE (flags)
2358 : #else
2359 : requests = mp_request_null
2360 : #endif
2361 6400 : END FUNCTION mp_testall_tv
2362 :
2363 : ! **************************************************************************************************
2364 : !> \brief Tests for completion of the given request.
2365 : !> \param request the request
2366 : !> \param flag logical which determines if the request is completed
2367 : !> \par History
2368 : !> 3.2016 created
2369 : !> \author Nico Holmberg
2370 : ! **************************************************************************************************
2371 467 : FUNCTION mp_test_1(request) RESULT(flag)
2372 : CLASS(mp_request_type), INTENT(inout) :: request
2373 : LOGICAL :: flag
2374 :
2375 : #if defined(__parallel)
2376 : INTEGER :: ierr
2377 :
2378 467 : CALL mpi_test(request%handle, flag, MPI_STATUS_IGNORE, ierr)
2379 467 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_test @ mp_test_1")
2380 : #else
2381 : MARK_USED(request)
2382 : flag = .TRUE.
2383 : #endif
2384 467 : END FUNCTION mp_test_1
2385 :
2386 : ! **************************************************************************************************
2387 : !> \brief tests for completion of the given requests
2388 : !> \param requests ...
2389 : !> \param completed ...
2390 : !> \param flag ...
2391 : !> \par History
2392 : !> 08.2011 created
2393 : !> \author Iain Bethune
2394 : ! **************************************************************************************************
2395 0 : SUBROUTINE mp_testany_1(requests, completed, flag)
2396 : TYPE(mp_request_type), DIMENSION(:), INTENT(inout) :: requests
2397 : INTEGER, INTENT(out), OPTIONAL :: completed
2398 : LOGICAL, INTENT(out), OPTIONAL :: flag
2399 :
2400 : #if defined(__parallel)
2401 : INTEGER :: completed_l, count, ierr
2402 : LOGICAL :: flag_l
2403 :
2404 0 : count = SIZE(requests)
2405 :
2406 0 : CALL mpi_testany_internal(count, requests, completed_l, flag_l, MPI_STATUS_IGNORE, ierr)
2407 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_testany_1 @ mp_testany")
2408 :
2409 0 : IF (PRESENT(completed)) completed = completed_l
2410 0 : IF (PRESENT(flag)) flag = flag_l
2411 : #else
2412 : MARK_USED(requests)
2413 : IF (PRESENT(completed)) completed = 1
2414 : IF (PRESENT(flag)) flag = .TRUE.
2415 : #endif
2416 0 : END SUBROUTINE mp_testany_1
2417 :
2418 : ! **************************************************************************************************
2419 : !> \brief tests for completion of the given requests
2420 : !> \param requests ...
2421 : !> \param completed ...
2422 : !> \param flag ...
2423 : !> \par History
2424 : !> 08.2011 created
2425 : !> \author Iain Bethune
2426 : ! **************************************************************************************************
2427 0 : SUBROUTINE mp_testany_2(requests, completed, flag)
2428 : TYPE(mp_request_type), DIMENSION(:, :), INTENT(inout) :: requests
2429 : INTEGER, INTENT(out), OPTIONAL :: completed
2430 : LOGICAL, INTENT(out), OPTIONAL :: flag
2431 :
2432 : #if defined(__parallel)
2433 : INTEGER :: completed_l, count, ierr
2434 : LOGICAL :: flag_l
2435 :
2436 0 : count = SIZE(requests)
2437 :
2438 0 : CALL mpi_testany_internal(count, requests, completed_l, flag_l, MPI_STATUS_IGNORE, ierr)
2439 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_testany_2 @ mp_testany")
2440 :
2441 0 : IF (PRESENT(completed)) completed = completed_l
2442 0 : IF (PRESENT(flag)) flag = flag_l
2443 : #else
2444 : MARK_USED(requests)
2445 : IF (PRESENT(completed)) completed = 1
2446 : IF (PRESENT(flag)) flag = .TRUE.
2447 : #endif
2448 0 : END SUBROUTINE mp_testany_2
2449 :
2450 : ! **************************************************************************************************
2451 : !> \brief wrapper needed to deal with interfaces as present in openmpi 1.8.1
2452 : !> the issue is with the rank or requests
2453 : !> \param count ...
2454 : !> \param array_of_requests ...
2455 : !> \param index ...
2456 : !> \param flag ...
2457 : !> \param status ...
2458 : !> \param ierr ...
2459 : !> \author Joost VandeVondele
2460 : ! **************************************************************************************************
2461 : #if defined(__parallel)
2462 0 : SUBROUTINE mpi_testany_internal(count, array_of_requests, index, flag, status, ierr)
2463 : INTEGER, INTENT(in) :: count
2464 : TYPE(mp_request_type), DIMENSION(count), INTENT(inout) :: array_of_requests
2465 : INTEGER, INTENT(out) :: index
2466 : LOGICAL, INTENT(out) :: flag
2467 : MPI_STATUS_TYPE, INTENT(out) :: status
2468 : INTEGER, INTENT(out) :: ierr
2469 :
2470 0 : MPI_REQUEST_TYPE, ALLOCATABLE, DIMENSION(:) :: request_handles
2471 :
2472 0 : ALLOCATE (request_handles(count), SOURCE=array_of_requests(1:count)%handle)
2473 0 : CALL mpi_testany(count, request_handles, index, flag, status, ierr)
2474 0 : array_of_requests(1:count)%handle = request_handles(:)
2475 0 : DEALLOCATE (request_handles)
2476 :
2477 0 : END SUBROUTINE mpi_testany_internal
2478 : #endif
2479 :
2480 : ! **************************************************************************************************
2481 : !> \brief the direct way to split a communicator each color is a sub_comm,
2482 : !> the rank order is according to the order in the orig comm
2483 : !> \param comm ...
2484 : !> \param sub_comm ...
2485 : !> \param color ...
2486 : !> \param key ...
2487 : !> \author Joost VandeVondele
2488 : ! **************************************************************************************************
2489 1149874 : SUBROUTINE mp_comm_split_direct(comm, sub_comm, color, key)
2490 : CLASS(mp_comm_type), INTENT(in) :: comm
2491 : CLASS(mp_comm_type), INTENT(OUT) :: sub_comm
2492 : INTEGER, INTENT(in) :: color
2493 : INTEGER, INTENT(in), OPTIONAL :: key
2494 :
2495 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_split_direct'
2496 :
2497 : INTEGER :: handle
2498 : #if defined(__parallel)
2499 : INTEGER :: ierr, my_key
2500 : #endif
2501 :
2502 1149874 : CALL mp_assert_outside_parallel(routineN)
2503 1149874 : CALL mp_timeset(routineN, handle)
2504 :
2505 : #if defined(__parallel)
2506 1149874 : my_key = 0
2507 1149874 : IF (PRESENT(key)) my_key = key
2508 1149874 : CALL mpi_comm_split(comm%handle, color, my_key, sub_comm%handle, ierr)
2509 1149874 : IF (ierr /= mpi_success) CALL mp_stop(ierr, routineN)
2510 1149874 : CALL add_perf(perf_id=10, count=1)
2511 : #else
2512 : sub_comm%handle = mp_comm_default_handle
2513 : MARK_USED(comm)
2514 : MARK_USED(color)
2515 : MARK_USED(key)
2516 : #endif
2517 1149874 : debug_comm_count = debug_comm_count + 1
2518 1149874 : CALL sub_comm%init()
2519 1149874 : CALL mp_timestop(handle)
2520 :
2521 1149874 : END SUBROUTINE mp_comm_split_direct
2522 : ! **************************************************************************************************
2523 : !> \brief splits a communicator by a predefined MPI split type, e.g. mp_comm_split_type_shared
2524 : !> to obtain the node-local (shared-memory) sub-communicator each rank belongs to
2525 : !> \param comm ...
2526 : !> \param sub_comm ...
2527 : !> \param split the split-type/info bundle (e.g. mp_comm_split_type_shared)
2528 : !> \param key controls the rank ordering within each sub_comm (default 0)
2529 : ! **************************************************************************************************
2530 2 : SUBROUTINE mp_comm_split_type(comm, sub_comm, split, key)
2531 : CLASS(mp_comm_type), INTENT(in) :: comm
2532 : CLASS(mp_comm_type), INTENT(OUT) :: sub_comm
2533 : TYPE(mp_split_type), INTENT(in) :: split
2534 : INTEGER, INTENT(in), OPTIONAL :: key
2535 :
2536 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_comm_split_type'
2537 :
2538 : INTEGER :: handle
2539 : #if defined(__parallel)
2540 : INTEGER :: ierr, my_key
2541 : #endif
2542 :
2543 2 : CALL mp_assert_outside_parallel(routineN)
2544 2 : CALL mp_timeset(routineN, handle)
2545 :
2546 : #if defined(__parallel)
2547 2 : my_key = 0
2548 2 : IF (PRESENT(key)) my_key = key
2549 : CALL mpi_comm_split_type(comm%handle, split%split_type, my_key, split%info%handle, &
2550 2 : sub_comm%handle, ierr)
2551 2 : IF (ierr /= mpi_success) CALL mp_stop(ierr, routineN)
2552 2 : CALL add_perf(perf_id=10, count=1)
2553 : #else
2554 : sub_comm%handle = mp_comm_default_handle
2555 : MARK_USED(comm)
2556 : MARK_USED(split)
2557 : MARK_USED(key)
2558 : #endif
2559 2 : debug_comm_count = debug_comm_count + 1
2560 2 : CALL sub_comm%init()
2561 2 : CALL mp_timestop(handle)
2562 :
2563 2 : END SUBROUTINE mp_comm_split_type
2564 : ! **************************************************************************************************
2565 : !> \brief splits the given communicator in group in subgroups trying to organize
2566 : !> them in a way that the communication within each subgroup is
2567 : !> efficient (but not necessarily the communication between subgroups)
2568 : !> \param comm the mpi communicator that you want to split
2569 : !> \param sub_comm the communicator for the subgroup (created, needs to be freed later)
2570 : !> \param ngroups actual number of groups
2571 : !> \param group_distribution input : allocated with array with the nprocs entries (0 .. nprocs-1)
2572 : !> \param subgroup_min_size the minimum size of the subgroup
2573 : !> \param n_subgroups the number of subgroups wanted
2574 : !> \param group_partition n_subgroups sized array containing the number of cpus wanted per group.
2575 : !> should match the total number of cpus (only used if present and associated) (0..ngroups-1)
2576 : !> \param stride create groups using a stride (default=1) through the ranks of the comm to be split.
2577 : !> \par History
2578 : !> 10.2003 created [fawzi]
2579 : !> 02.2004 modified [Joost VandeVondele]
2580 : !> \author Fawzi Mohamed
2581 : !> \note
2582 : !> at least one of subgroup_min_size and n_subgroups is needed,
2583 : !> the other default to the value needed to use most processors.
2584 : !> if less cpus are present than needed for subgroup min size, n_subgroups,
2585 : !> just one comm is created that contains all cpus
2586 : ! **************************************************************************************************
2587 275731 : SUBROUTINE mp_comm_split(comm, sub_comm, ngroups, group_distribution, &
2588 275731 : subgroup_min_size, n_subgroups, group_partition, stride)
2589 : CLASS(mp_comm_type), INTENT(in) :: comm
2590 : CLASS(mp_comm_type), INTENT(out) :: sub_comm
2591 : INTEGER, INTENT(out) :: ngroups
2592 : INTEGER, DIMENSION(0:), INTENT(INOUT) :: group_distribution
2593 : INTEGER, INTENT(in), OPTIONAL :: subgroup_min_size, &
2594 : n_subgroups
2595 : INTEGER, DIMENSION(0:), INTENT(IN), OPTIONAL :: group_partition
2596 : INTEGER, OPTIONAL, INTENT(IN) :: stride
2597 :
2598 : CHARACTER(LEN=*), PARAMETER :: routineN = 'mp_comm_split', &
2599 : routineP = moduleN//':'//routineN
2600 :
2601 : INTEGER :: handle, mepos, nnodes
2602 : #if defined(__parallel)
2603 : INTEGER :: color, i, ierr, j, k, &
2604 : my_subgroup_min_size, &
2605 : istride, local_stride, irank
2606 275731 : INTEGER, DIMENSION(:), ALLOCATABLE :: rank_permutation
2607 : #endif
2608 :
2609 275731 : CALL mp_assert_outside_parallel(routineN)
2610 275731 : CALL mp_timeset(routineN, handle)
2611 :
2612 : ! actual number of groups
2613 :
2614 275731 : IF (.NOT. PRESENT(subgroup_min_size) .AND. .NOT. PRESENT(n_subgroups)) THEN
2615 0 : CPABORT(routineP//" missing arguments")
2616 : END IF
2617 275731 : IF (PRESENT(subgroup_min_size) .AND. PRESENT(n_subgroups)) THEN
2618 0 : CPABORT(routineP//" too many arguments")
2619 : END IF
2620 :
2621 275731 : CALL comm%get_size(nnodes)
2622 275731 : CALL comm%get_rank(mepos)
2623 :
2624 275731 : IF (UBOUND(group_distribution, 1) /= nnodes - 1) THEN
2625 0 : CPABORT(routineP//" group_distribution wrong bounds")
2626 : END IF
2627 :
2628 : #if defined(__parallel)
2629 275731 : IF (PRESENT(subgroup_min_size)) THEN
2630 154 : IF (subgroup_min_size < 0 .OR. subgroup_min_size > nnodes) THEN
2631 0 : CPABORT(routineP//" subgroup_min_size too small or too large")
2632 : END IF
2633 154 : ngroups = nnodes/subgroup_min_size
2634 154 : my_subgroup_min_size = subgroup_min_size
2635 : ELSE ! n_subgroups
2636 275577 : IF (n_subgroups <= 0) THEN
2637 0 : CPABORT(routineP//" n_subgroups too small")
2638 : END IF
2639 275577 : IF (nnodes/n_subgroups > 0) THEN ! we have a least one cpu per group
2640 271801 : ngroups = n_subgroups
2641 : ELSE ! well, only one group then
2642 3776 : ngroups = 1
2643 : END IF
2644 275577 : my_subgroup_min_size = nnodes/ngroups
2645 : END IF
2646 :
2647 : ! rank_permutation: is a permutation of ranks, so that groups are not necessarily continuous in rank of the master group
2648 : ! while the order is not critical (we only color ranks), it can e.g. be used to make groups that have just 1 rank per node
2649 : ! (by setting stride equal to the number of mpi ranks per node), or by sharing a node between two groups (stride 2).
2650 827193 : ALLOCATE (rank_permutation(0:nnodes - 1))
2651 275731 : local_stride = 1
2652 275731 : IF (PRESENT(stride)) local_stride = stride
2653 275731 : k = 0
2654 551462 : DO istride = 1, local_stride
2655 551462 : DO irank = istride - 1, nnodes - 1, local_stride
2656 547685 : rank_permutation(k) = irank
2657 547685 : k = k + 1
2658 : END DO
2659 : END DO
2660 :
2661 823416 : DO i = 0, nnodes - 1
2662 823416 : group_distribution(rank_permutation(i)) = MIN(i/my_subgroup_min_size, ngroups - 1)
2663 : END DO
2664 : ! even the user gave a partition, see if we can use it to overwrite this choice
2665 275731 : IF (PRESENT(group_partition)) THEN
2666 1112636 : IF (ALL(group_partition > 0) .AND. (SUM(group_partition) == nnodes) .AND. (ngroups == SIZE(group_partition))) THEN
2667 98 : k = 0
2668 98 : DO i = 0, SIZE(group_partition) - 1
2669 166 : DO j = 1, group_partition(i)
2670 68 : group_distribution(rank_permutation(k)) = i
2671 132 : k = k + 1
2672 : END DO
2673 : END DO
2674 : ELSE
2675 : ! just ignore silently as we have reasonable defaults. Probably a warning would not be to bad
2676 : END IF
2677 : END IF
2678 275731 : DEALLOCATE (rank_permutation)
2679 275731 : color = group_distribution(mepos)
2680 275731 : CALL mpi_comm_split(comm%handle, color, 0, sub_comm%handle, ierr)
2681 275731 : IF (ierr /= mpi_success) CALL mp_stop(ierr, "in "//routineP//" split")
2682 :
2683 275731 : CALL add_perf(perf_id=10, count=1)
2684 : #else
2685 : sub_comm%handle = mp_comm_default_handle
2686 : group_distribution(0) = 0
2687 : ngroups = 1
2688 : MARK_USED(comm)
2689 : MARK_USED(stride)
2690 : MARK_USED(group_partition)
2691 : #endif
2692 275731 : debug_comm_count = debug_comm_count + 1
2693 275731 : CALL sub_comm%init()
2694 275731 : CALL mp_timestop(handle)
2695 :
2696 551462 : END SUBROUTINE mp_comm_split
2697 :
2698 : ! **************************************************************************************************
2699 : !> \brief probes for an incoming message with any tag
2700 : !> \param[inout] source the source of the possible incoming message,
2701 : !> if MP_ANY_SOURCE it is a blocking one and return value is the source
2702 : !> of the next incoming message
2703 : !> if source is a different value it is a non-blocking probe returning
2704 : !> MP_ANY_SOURCE if there is no incoming message
2705 : !> \param[in] comm the communicator
2706 : !> \param[out] tag the tag of the incoming message
2707 : !> \author Mandes
2708 : ! **************************************************************************************************
2709 1394608 : SUBROUTINE mp_probe(source, comm, tag)
2710 : INTEGER, INTENT(INOUT) :: source
2711 : CLASS(mp_comm_type), INTENT(IN) :: comm
2712 : INTEGER, INTENT(OUT) :: tag
2713 :
2714 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_probe'
2715 :
2716 : INTEGER :: handle
2717 : #if defined(__parallel)
2718 : INTEGER :: ierr
2719 : MPI_STATUS_TYPE :: status_single
2720 : LOGICAL :: flag
2721 : #endif
2722 :
2723 : ! ---------------------------------------------------------------------------
2724 :
2725 1394608 : CALL mp_timeset(routineN, handle)
2726 :
2727 : #if defined(__parallel)
2728 1394608 : IF (source == mp_any_source) THEN
2729 14 : CALL mpi_probe(mp_any_source, mp_any_tag, comm%handle, status_single, ierr)
2730 14 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_probe @ mp_probe")
2731 14 : source = status_single MPI_STATUS_EXTRACT(MPI_SOURCE)
2732 14 : tag = status_single MPI_STATUS_EXTRACT(MPI_TAG)
2733 : ELSE
2734 : flag = .FALSE.
2735 1394594 : CALL mpi_iprobe(source, mp_any_tag, comm%handle, flag, status_single, ierr)
2736 1394594 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_iprobe @ mp_probe")
2737 1394594 : IF (flag .EQV. .FALSE.) THEN
2738 1386774 : source = mp_any_source
2739 1386774 : tag = -1 !status_single(MPI_TAG) ! in case of flag==false status is undefined
2740 : ELSE
2741 7820 : tag = status_single MPI_STATUS_EXTRACT(MPI_TAG)
2742 : END IF
2743 : END IF
2744 : #else
2745 : tag = -1
2746 : MARK_USED(comm)
2747 : MARK_USED(source)
2748 : #endif
2749 1394608 : CALL mp_timestop(handle)
2750 1394608 : END SUBROUTINE mp_probe
2751 :
2752 : ! **************************************************************************************************
2753 : ! Here come the data routines with none of the standard data types.
2754 : ! **************************************************************************************************
2755 :
2756 : ! **************************************************************************************************
2757 : !> \brief ...
2758 : !> \param msg ...
2759 : !> \param source ...
2760 : !> \param comm ...
2761 : ! **************************************************************************************************
2762 748568 : SUBROUTINE mp_bcast_b(msg, source, comm)
2763 : LOGICAL, INTENT(INOUT) :: msg
2764 : INTEGER, INTENT(IN) :: source
2765 : CLASS(mp_comm_type), INTENT(IN) :: comm
2766 :
2767 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_b'
2768 :
2769 : INTEGER :: handle
2770 : #if defined(__parallel)
2771 : INTEGER :: ierr, msglen
2772 : #endif
2773 :
2774 748568 : CALL mp_timeset(routineN, handle)
2775 :
2776 : #if defined(__parallel)
2777 748568 : msglen = 1
2778 748568 : CALL mpi_bcast(msg, msglen, MPI_LOGICAL, source, comm%handle, ierr)
2779 748568 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
2780 748568 : CALL add_perf(perf_id=2, count=1, msg_size=msglen*loglen)
2781 : #else
2782 : MARK_USED(msg)
2783 : MARK_USED(source)
2784 : MARK_USED(comm)
2785 : #endif
2786 748568 : CALL mp_timestop(handle)
2787 748568 : END SUBROUTINE mp_bcast_b
2788 :
2789 : ! **************************************************************************************************
2790 : !> \brief ...
2791 : !> \param msg ...
2792 : !> \param source ...
2793 : !> \param comm ...
2794 : ! **************************************************************************************************
2795 684387 : SUBROUTINE mp_bcast_b_src(msg, comm)
2796 : LOGICAL, INTENT(INOUT) :: msg
2797 : CLASS(mp_comm_type), INTENT(IN) :: comm
2798 :
2799 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_b_src'
2800 :
2801 : INTEGER :: handle
2802 : #if defined(__parallel)
2803 : INTEGER :: ierr, msglen
2804 : #endif
2805 :
2806 684387 : CALL mp_timeset(routineN, handle)
2807 :
2808 : #if defined(__parallel)
2809 684387 : msglen = 1
2810 684387 : CALL mpi_bcast(msg, msglen, MPI_LOGICAL, comm%source, comm%handle, ierr)
2811 684387 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
2812 684387 : CALL add_perf(perf_id=2, count=1, msg_size=msglen*loglen)
2813 : #else
2814 : MARK_USED(msg)
2815 : MARK_USED(comm)
2816 : #endif
2817 684387 : CALL mp_timestop(handle)
2818 684387 : END SUBROUTINE mp_bcast_b_src
2819 :
2820 : ! **************************************************************************************************
2821 : !> \brief ...
2822 : !> \param msg ...
2823 : !> \param source ...
2824 : !> \param comm ...
2825 : ! **************************************************************************************************
2826 0 : SUBROUTINE mp_bcast_bv(msg, source, comm)
2827 : LOGICAL, CONTIGUOUS, INTENT(INOUT) :: msg(:)
2828 : INTEGER, INTENT(IN) :: source
2829 : CLASS(mp_comm_type), INTENT(IN) :: comm
2830 :
2831 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_bv'
2832 :
2833 : INTEGER :: handle
2834 : #if defined(__parallel)
2835 : INTEGER :: ierr, msglen
2836 : #endif
2837 :
2838 0 : CALL mp_timeset(routineN, handle)
2839 :
2840 : #if defined(__parallel)
2841 0 : msglen = SIZE(msg)
2842 0 : CALL mpi_bcast(msg, msglen, MPI_LOGICAL, source, comm%handle, ierr)
2843 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
2844 0 : CALL add_perf(perf_id=2, count=1, msg_size=msglen*loglen)
2845 : #else
2846 : MARK_USED(msg)
2847 : MARK_USED(source)
2848 : MARK_USED(comm)
2849 : #endif
2850 0 : CALL mp_timestop(handle)
2851 0 : END SUBROUTINE mp_bcast_bv
2852 :
2853 : ! **************************************************************************************************
2854 : !> \brief ...
2855 : !> \param msg ...
2856 : !> \param comm ...
2857 : ! **************************************************************************************************
2858 0 : SUBROUTINE mp_bcast_bv_src(msg, comm)
2859 : LOGICAL, CONTIGUOUS, INTENT(INOUT) :: msg(:)
2860 : CLASS(mp_comm_type), INTENT(IN) :: comm
2861 :
2862 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_bv_src'
2863 :
2864 : INTEGER :: handle
2865 : #if defined(__parallel)
2866 : INTEGER :: ierr, msglen
2867 : #endif
2868 :
2869 0 : CALL mp_timeset(routineN, handle)
2870 :
2871 : #if defined(__parallel)
2872 0 : msglen = SIZE(msg)
2873 0 : CALL mpi_bcast(msg, msglen, MPI_LOGICAL, comm%source, comm%handle, ierr)
2874 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
2875 0 : CALL add_perf(perf_id=2, count=1, msg_size=msglen*loglen)
2876 : #else
2877 : MARK_USED(msg)
2878 : MARK_USED(comm)
2879 : #endif
2880 0 : CALL mp_timestop(handle)
2881 0 : END SUBROUTINE mp_bcast_bv_src
2882 :
2883 : ! **************************************************************************************************
2884 : !> \brief Non-blocking send of logical vector data
2885 : !> \param msgin the input message
2886 : !> \param dest the destination processor
2887 : !> \param comm the communicator object
2888 : !> \param request communication request index
2889 : !> \param tag message tag
2890 : !> \par History
2891 : !> 3.2016 added _bv subroutine [Nico Holmberg]
2892 : !> \author fawzi
2893 : !> \note see mp_irecv_iv
2894 : !> \note
2895 : !> arrays can be pointers or assumed shape, but they must be contiguous!
2896 : ! **************************************************************************************************
2897 16 : SUBROUTINE mp_isend_bv(msgin, dest, comm, request, tag)
2898 : LOGICAL, DIMENSION(:), INTENT(IN) :: msgin
2899 : INTEGER, INTENT(IN) :: dest
2900 : CLASS(mp_comm_type), INTENT(IN) :: comm
2901 : TYPE(mp_request_type), INTENT(out) :: request
2902 : INTEGER, INTENT(in), OPTIONAL :: tag
2903 :
2904 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_isend_bv'
2905 :
2906 : INTEGER :: handle
2907 : #if defined(__parallel)
2908 : INTEGER :: ierr, msglen, my_tag
2909 : LOGICAL :: foo(1)
2910 : #endif
2911 :
2912 16 : CALL mp_timeset(routineN, handle)
2913 :
2914 : #if defined(__parallel)
2915 : #if !defined(__GNUC__) || __GNUC__ >= 9
2916 32 : CPASSERT(IS_CONTIGUOUS(msgin) .OR. PRODUCT(SHAPE(msgin)) == 0)
2917 : #endif
2918 :
2919 16 : my_tag = 0
2920 16 : IF (PRESENT(tag)) my_tag = tag
2921 :
2922 16 : msglen = SIZE(msgin, 1)
2923 16 : IF (msglen > 0) THEN
2924 : CALL mpi_isend(msgin(1), msglen, MPI_LOGICAL, dest, my_tag, &
2925 16 : comm%handle, request%handle, ierr)
2926 : ELSE
2927 : CALL mpi_isend(foo, msglen, MPI_LOGICAL, dest, my_tag, &
2928 0 : comm%handle, request%handle, ierr)
2929 : END IF
2930 16 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_isend @ "//routineN)
2931 :
2932 16 : CALL add_perf(perf_id=11, count=1, msg_size=msglen*loglen)
2933 : #else
2934 : CPABORT("mp_isend called in non parallel case")
2935 : MARK_USED(msgin)
2936 : MARK_USED(dest)
2937 : MARK_USED(comm)
2938 : MARK_USED(tag)
2939 : request = mp_request_null
2940 : #endif
2941 16 : CALL mp_timestop(handle)
2942 16 : END SUBROUTINE mp_isend_bv
2943 :
2944 : ! **************************************************************************************************
2945 : !> \brief Non-blocking receive of logical vector data
2946 : !> \param msgout the received message
2947 : !> \param source the source processor
2948 : !> \param comm the communicator object
2949 : !> \param request communication request index
2950 : !> \param tag message tag
2951 : !> \par History
2952 : !> 3.2016 added _bv subroutine [Nico Holmberg]
2953 : !> \author fawzi
2954 : !> \note see mp_irecv_iv
2955 : !> \note
2956 : !> arrays can be pointers or assumed shape, but they must be contiguous!
2957 : ! **************************************************************************************************
2958 16 : SUBROUTINE mp_irecv_bv(msgout, source, comm, request, tag)
2959 : LOGICAL, DIMENSION(:), INTENT(INOUT) :: msgout
2960 : INTEGER, INTENT(IN) :: source
2961 : CLASS(mp_comm_type), INTENT(IN) :: comm
2962 : TYPE(mp_request_type), INTENT(out) :: request
2963 : INTEGER, INTENT(in), OPTIONAL :: tag
2964 :
2965 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_irecv_bv'
2966 :
2967 : INTEGER :: handle
2968 : #if defined(__parallel)
2969 : INTEGER :: ierr, msglen, my_tag
2970 : LOGICAL :: foo(1)
2971 : #endif
2972 :
2973 16 : CALL mp_timeset(routineN, handle)
2974 :
2975 : #if defined(__parallel)
2976 : #if !defined(__GNUC__) || __GNUC__ >= 9
2977 32 : CPASSERT(IS_CONTIGUOUS(msgout) .OR. PRODUCT(SHAPE(msgout)) == 0)
2978 : #endif
2979 :
2980 16 : my_tag = 0
2981 16 : IF (PRESENT(tag)) my_tag = tag
2982 :
2983 16 : msglen = SIZE(msgout, 1)
2984 16 : IF (msglen > 0) THEN
2985 : CALL mpi_irecv(msgout(1), msglen, MPI_LOGICAL, source, my_tag, &
2986 16 : comm%handle, request%handle, ierr)
2987 : ELSE
2988 : CALL mpi_irecv(foo, msglen, MPI_LOGICAL, source, my_tag, &
2989 0 : comm%handle, request%handle, ierr)
2990 : END IF
2991 16 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_ircv @ "//routineN)
2992 :
2993 16 : CALL add_perf(perf_id=12, count=1, msg_size=msglen*loglen)
2994 : #else
2995 : CPABORT("mp_irecv called in non parallel case")
2996 : MARK_USED(msgout)
2997 : MARK_USED(source)
2998 : MARK_USED(comm)
2999 : MARK_USED(tag)
3000 : request = mp_request_null
3001 : #endif
3002 16 : CALL mp_timestop(handle)
3003 16 : END SUBROUTINE mp_irecv_bv
3004 :
3005 : ! **************************************************************************************************
3006 : !> \brief Non-blocking send of rank-3 logical data
3007 : !> \param msgin the input message
3008 : !> \param dest the destination processor
3009 : !> \param comm the communicator object
3010 : !> \param request communication request index
3011 : !> \param tag message tag
3012 : !> \par History
3013 : !> 2.2016 added _bm3 subroutine [Nico Holmberg]
3014 : !> \author fawzi
3015 : !> \note see mp_irecv_iv
3016 : !> \note
3017 : !> arrays can be pointers or assumed shape, but they must be contiguous!
3018 : ! **************************************************************************************************
3019 0 : SUBROUTINE mp_isend_bm3(msgin, dest, comm, request, tag)
3020 : LOGICAL, DIMENSION(:, :, :), INTENT(INOUT) :: msgin
3021 : INTEGER, INTENT(IN) :: dest
3022 : CLASS(mp_comm_type), INTENT(IN) :: comm
3023 : TYPE(mp_request_type), INTENT(out) :: request
3024 : INTEGER, INTENT(in), OPTIONAL :: tag
3025 :
3026 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_isend_bm3'
3027 :
3028 : INTEGER :: handle
3029 : #if defined(__parallel)
3030 : INTEGER :: ierr, msglen, my_tag
3031 : LOGICAL :: foo(1)
3032 : #endif
3033 :
3034 0 : CALL mp_timeset(routineN, handle)
3035 :
3036 : #if defined(__parallel)
3037 : #if !defined(__GNUC__) || __GNUC__ >= 9
3038 0 : CPASSERT(IS_CONTIGUOUS(msgin) .OR. PRODUCT(SHAPE(msgin)) == 0)
3039 : #endif
3040 :
3041 0 : my_tag = 0
3042 0 : IF (PRESENT(tag)) my_tag = tag
3043 :
3044 0 : msglen = SIZE(msgin, 1)*SIZE(msgin, 2)*SIZE(msgin, 3)
3045 0 : IF (msglen > 0) THEN
3046 : CALL mpi_isend(msgin(1, 1, 1), msglen, MPI_LOGICAL, dest, my_tag, &
3047 0 : comm%handle, request%handle, ierr)
3048 : ELSE
3049 : CALL mpi_isend(foo, msglen, MPI_LOGICAL, dest, my_tag, &
3050 0 : comm%handle, request%handle, ierr)
3051 : END IF
3052 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_isend @ "//routineN)
3053 :
3054 0 : CALL add_perf(perf_id=11, count=1, msg_size=msglen*loglen)
3055 : #else
3056 : CPABORT("mp_isend called in non parallel case")
3057 : MARK_USED(msgin)
3058 : MARK_USED(dest)
3059 : MARK_USED(comm)
3060 : MARK_USED(tag)
3061 : request = mp_request_null
3062 : #endif
3063 0 : CALL mp_timestop(handle)
3064 0 : END SUBROUTINE mp_isend_bm3
3065 :
3066 : ! **************************************************************************************************
3067 : !> \brief Non-blocking receive of rank-3 logical data
3068 : !> \param msgout the received message
3069 : !> \param source the source processor
3070 : !> \param comm the communicator object
3071 : !> \param request communication request index
3072 : !> \param tag message tag
3073 : !> \par History
3074 : !> 2.2016 added _bm3 subroutine [Nico Holmberg]
3075 : !> \author fawzi
3076 : !> \note see mp_irecv_iv
3077 : !> \note
3078 : !> arrays can be pointers or assumed shape, but they must be contiguous!
3079 : ! **************************************************************************************************
3080 0 : SUBROUTINE mp_irecv_bm3(msgout, source, comm, request, tag)
3081 : LOGICAL, DIMENSION(:, :, :), INTENT(INOUT) :: msgout
3082 : INTEGER, INTENT(IN) :: source
3083 : CLASS(mp_comm_type), INTENT(IN) :: comm
3084 : TYPE(mp_request_type), INTENT(out) :: request
3085 : INTEGER, INTENT(in), OPTIONAL :: tag
3086 :
3087 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_irecv_bm3'
3088 :
3089 : INTEGER :: handle
3090 : #if defined(__parallel)
3091 : INTEGER :: ierr, msglen, my_tag
3092 : LOGICAL :: foo(1)
3093 : #endif
3094 :
3095 0 : CALL mp_timeset(routineN, handle)
3096 :
3097 : #if defined(__parallel)
3098 : #if !defined(__GNUC__) || __GNUC__ >= 9
3099 0 : CPASSERT(IS_CONTIGUOUS(msgout) .OR. PRODUCT(SHAPE(msgout)) == 0)
3100 : #endif
3101 :
3102 0 : my_tag = 0
3103 0 : IF (PRESENT(tag)) my_tag = tag
3104 :
3105 0 : msglen = SIZE(msgout, 1)*SIZE(msgout, 2)*SIZE(msgout, 3)
3106 0 : IF (msglen > 0) THEN
3107 : CALL mpi_irecv(msgout(1, 1, 1), msglen, MPI_LOGICAL, source, my_tag, &
3108 0 : comm%handle, request%handle, ierr)
3109 : ELSE
3110 : CALL mpi_irecv(foo, msglen, MPI_LOGICAL, source, my_tag, &
3111 0 : comm%handle, request%handle, ierr)
3112 : END IF
3113 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_ircv @ "//routineN)
3114 :
3115 0 : CALL add_perf(perf_id=12, count=1, msg_size=msglen*loglen)
3116 : #else
3117 : CPABORT("mp_irecv called in non parallel case")
3118 : MARK_USED(msgout)
3119 : MARK_USED(source)
3120 : MARK_USED(comm)
3121 : MARK_USED(request)
3122 : MARK_USED(tag)
3123 : request = mp_request_null
3124 : #endif
3125 0 : CALL mp_timestop(handle)
3126 0 : END SUBROUTINE mp_irecv_bm3
3127 :
3128 : ! **************************************************************************************************
3129 : !> \brief Broadcasts a string.
3130 : !> \param msg ...
3131 : !> \param source ...
3132 : !> \param comm ...
3133 : ! **************************************************************************************************
3134 4782735 : SUBROUTINE mp_bcast_av(msg, source, comm)
3135 : CHARACTER(LEN=*), INTENT(INOUT) :: msg
3136 : INTEGER, INTENT(IN) :: source
3137 : CLASS(mp_comm_type), INTENT(IN) :: comm
3138 :
3139 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_av'
3140 :
3141 : INTEGER :: handle
3142 : #if defined(__parallel)
3143 : INTEGER :: ierr, msglen
3144 : #endif
3145 :
3146 4782735 : CALL mp_timeset(routineN, handle)
3147 :
3148 : #if defined(__parallel)
3149 4782735 : msglen = LEN(msg)*charlen
3150 4782735 : IF (comm%mepos /= source) msg = "" ! need to clear msg
3151 4782735 : CALL mpi_bcast(msg, msglen, MPI_CHARACTER, source, comm%handle, ierr)
3152 4782735 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
3153 4782735 : CALL add_perf(perf_id=2, count=1, msg_size=msglen)
3154 : #else
3155 : MARK_USED(msg)
3156 : MARK_USED(source)
3157 : MARK_USED(comm)
3158 : #endif
3159 4782735 : CALL mp_timestop(handle)
3160 4782735 : END SUBROUTINE mp_bcast_av
3161 :
3162 : ! **************************************************************************************************
3163 : !> \brief Broadcasts a string.
3164 : !> \param msg ...
3165 : !> \param comm ...
3166 : ! **************************************************************************************************
3167 920 : SUBROUTINE mp_bcast_av_src(msg, comm)
3168 : CHARACTER(LEN=*), INTENT(INOUT) :: msg
3169 : CLASS(mp_comm_type), INTENT(IN) :: comm
3170 :
3171 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_av_src'
3172 :
3173 : INTEGER :: handle
3174 : #if defined(__parallel)
3175 : INTEGER :: ierr, msglen
3176 : #endif
3177 :
3178 920 : CALL mp_timeset(routineN, handle)
3179 :
3180 : #if defined(__parallel)
3181 920 : msglen = LEN(msg)*charlen
3182 920 : IF (.NOT. comm%is_source()) msg = "" ! need to clear msg
3183 920 : CALL mpi_bcast(msg, msglen, MPI_CHARACTER, comm%source, comm%handle, ierr)
3184 920 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
3185 920 : CALL add_perf(perf_id=2, count=1, msg_size=msglen)
3186 : #else
3187 : MARK_USED(msg)
3188 : MARK_USED(comm)
3189 : #endif
3190 920 : CALL mp_timestop(handle)
3191 920 : END SUBROUTINE mp_bcast_av_src
3192 :
3193 : ! **************************************************************************************************
3194 : !> \brief ...
3195 : !> \param msg ...
3196 : !> \param source ...
3197 : !> \param comm ...
3198 : ! **************************************************************************************************
3199 28 : SUBROUTINE mp_bcast_am(msg, source, comm)
3200 : CHARACTER(LEN=*), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3201 : INTEGER, INTENT(IN) :: source
3202 : CLASS(mp_comm_type), INTENT(IN) :: comm
3203 :
3204 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_am'
3205 :
3206 : INTEGER :: handle
3207 : #if defined(__parallel)
3208 : INTEGER :: ierr, msglen
3209 : #endif
3210 :
3211 28 : CALL mp_timeset(routineN, handle)
3212 :
3213 : #if defined(__parallel)
3214 28 : msglen = SIZE(msg)*LEN(msg(1))*charlen
3215 1922 : IF (comm%mepos /= source) msg = "" ! need to clear msg
3216 28 : CALL mpi_bcast(msg, msglen, MPI_CHARACTER, source, comm%handle, ierr)
3217 28 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
3218 28 : CALL add_perf(perf_id=2, count=1, msg_size=msglen)
3219 : #else
3220 : MARK_USED(msg)
3221 : MARK_USED(source)
3222 : MARK_USED(comm)
3223 : #endif
3224 28 : CALL mp_timestop(handle)
3225 28 : END SUBROUTINE mp_bcast_am
3226 :
3227 92202 : SUBROUTINE mp_bcast_am_src(msg, comm)
3228 : CHARACTER(LEN=*), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3229 : CLASS(mp_comm_type), INTENT(IN) :: comm
3230 :
3231 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_bcast_am_src'
3232 :
3233 : INTEGER :: handle
3234 : #if defined(__parallel)
3235 : INTEGER :: ierr, msglen
3236 : #endif
3237 :
3238 92202 : CALL mp_timeset(routineN, handle)
3239 :
3240 : #if defined(__parallel)
3241 92202 : msglen = SIZE(msg)*LEN(msg(1))*charlen
3242 46193202 : IF (.NOT. comm%is_source()) msg = "" ! need to clear msg
3243 92202 : CALL mpi_bcast(msg, msglen, MPI_CHARACTER, comm%source, comm%handle, ierr)
3244 92202 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_bcast @ "//routineN)
3245 92202 : CALL add_perf(perf_id=2, count=1, msg_size=msglen)
3246 : #else
3247 : MARK_USED(msg)
3248 : MARK_USED(comm)
3249 : #endif
3250 92202 : CALL mp_timestop(handle)
3251 92202 : END SUBROUTINE mp_bcast_am_src
3252 :
3253 : ! **************************************************************************************************
3254 : !> \brief Finds the location of the minimal element in a vector.
3255 : !> \param[in,out] msg Find location of minimum element among these
3256 : !> data (input).
3257 : !> \param[in] comm Message passing environment identifier
3258 : !> \par MPI mapping
3259 : !> mpi_allreduce with the MPI_MINLOC reduction function identifier
3260 : !> \par Invalid data types
3261 : !> This routine is invalid for (int_8) data!
3262 : ! **************************************************************************************************
3263 862 : SUBROUTINE mp_minloc_dv(msg, comm)
3264 : REAL(kind=real_8), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3265 : CLASS(mp_comm_type), INTENT(IN) :: comm
3266 :
3267 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_minloc_dv'
3268 :
3269 : INTEGER :: handle
3270 : #if defined(__parallel)
3271 : INTEGER :: ierr, msglen
3272 862 : REAL(kind=real_8), ALLOCATABLE :: res(:)
3273 : #endif
3274 :
3275 : IF ("d" == "l" .AND. real_8 == int_8) THEN
3276 : CPABORT("Minimal location not available with long integers @ "//routineN)
3277 : END IF
3278 862 : CALL mp_timeset(routineN, handle)
3279 :
3280 : #if defined(__parallel)
3281 862 : msglen = SIZE(msg)
3282 2586 : ALLOCATE (res(1:msglen), STAT=ierr)
3283 862 : IF (ierr /= 0) &
3284 0 : CPABORT("allocate @ "//routineN)
3285 862 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2DOUBLE_PRECISION, MPI_MINLOC, comm%handle, ierr)
3286 862 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3287 2586 : msg = res
3288 862 : DEALLOCATE (res)
3289 862 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*real_8_size)
3290 : #else
3291 : MARK_USED(msg)
3292 : MARK_USED(comm)
3293 : #endif
3294 862 : CALL mp_timestop(handle)
3295 862 : END SUBROUTINE mp_minloc_dv
3296 :
3297 : ! **************************************************************************************************
3298 : !> \brief Finds the location of the minimal element in a vector.
3299 : !> \param[in,out] msg Find location of minimum element among these
3300 : !> data (input).
3301 : !> \param[in] comm Message passing environment identifier
3302 : !> \par MPI mapping
3303 : !> mpi_allreduce with the MPI_MINLOC reduction function identifier
3304 : !> \par Invalid data types
3305 : !> This routine is invalid for (int_8) data!
3306 : ! **************************************************************************************************
3307 0 : SUBROUTINE mp_minloc_iv(msg, comm)
3308 : INTEGER(KIND=int_4), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3309 : CLASS(mp_comm_type), INTENT(IN) :: comm
3310 :
3311 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_minloc_iv'
3312 :
3313 : INTEGER :: handle
3314 : #if defined(__parallel)
3315 : INTEGER :: ierr, msglen
3316 0 : INTEGER(KIND=int_4), ALLOCATABLE :: res(:)
3317 : #endif
3318 :
3319 : IF ("i" == "l" .AND. int_4 == int_8) THEN
3320 : CPABORT("Minimal location not available with long integers @ "//routineN)
3321 : END IF
3322 0 : CALL mp_timeset(routineN, handle)
3323 :
3324 : #if defined(__parallel)
3325 0 : msglen = SIZE(msg)
3326 0 : ALLOCATE (res(1:msglen))
3327 0 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2INTEGER, MPI_MINLOC, comm%handle, ierr)
3328 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3329 0 : msg = res
3330 0 : DEALLOCATE (res)
3331 0 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*int_4_size)
3332 : #else
3333 : MARK_USED(msg)
3334 : MARK_USED(comm)
3335 : #endif
3336 0 : CALL mp_timestop(handle)
3337 0 : END SUBROUTINE mp_minloc_iv
3338 :
3339 : ! **************************************************************************************************
3340 : !> \brief Finds the location of the minimal element in a vector.
3341 : !> \param[in,out] msg Find location of minimum element among these
3342 : !> data (input).
3343 : !> \param[in] comm Message passing environment identifier
3344 : !> \par MPI mapping
3345 : !> mpi_allreduce with the MPI_MINLOC reduction function identifier
3346 : !> \par Invalid data types
3347 : !> This routine is invalid for (int_8) data!
3348 : ! **************************************************************************************************
3349 0 : SUBROUTINE mp_minloc_lv(msg, comm)
3350 : INTEGER(KIND=int_8), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3351 : CLASS(mp_comm_type), INTENT(IN) :: comm
3352 :
3353 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_minloc_lv'
3354 :
3355 : INTEGER :: handle
3356 : #if defined(__parallel)
3357 : INTEGER :: ierr, msglen
3358 0 : INTEGER(KIND=int_8), ALLOCATABLE :: res(:)
3359 : #endif
3360 :
3361 : IF ("l" == "l" .AND. int_8 == int_8) THEN
3362 0 : CPABORT("Minimal location not available with long integers @ "//routineN)
3363 : END IF
3364 0 : CALL mp_timeset(routineN, handle)
3365 :
3366 : #if defined(__parallel)
3367 0 : msglen = SIZE(msg)
3368 0 : ALLOCATE (res(1:msglen))
3369 0 : CALL mpi_allreduce(msg, res, msglen/2, MPI_INTEGER8, MPI_MINLOC, comm%handle, ierr)
3370 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3371 0 : msg = res
3372 0 : DEALLOCATE (res)
3373 0 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*int_8_size)
3374 : #else
3375 : MARK_USED(msg)
3376 : MARK_USED(comm)
3377 : #endif
3378 0 : CALL mp_timestop(handle)
3379 0 : END SUBROUTINE mp_minloc_lv
3380 :
3381 : ! **************************************************************************************************
3382 : !> \brief Finds the location of the minimal element in a vector.
3383 : !> \param[in,out] msg Find location of minimum element among these
3384 : !> data (input).
3385 : !> \param[in] comm Message passing environment identifier
3386 : !> \par MPI mapping
3387 : !> mpi_allreduce with the MPI_MINLOC reduction function identifier
3388 : !> \par Invalid data types
3389 : !> This routine is invalid for (int_8) data!
3390 : ! **************************************************************************************************
3391 0 : SUBROUTINE mp_minloc_rv(msg, comm)
3392 : REAL(kind=real_4), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3393 : CLASS(mp_comm_type), INTENT(IN) :: comm
3394 :
3395 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_minloc_rv'
3396 :
3397 : INTEGER :: handle
3398 : #if defined(__parallel)
3399 : INTEGER :: ierr, msglen
3400 0 : REAL(kind=real_4), ALLOCATABLE :: res(:)
3401 : #endif
3402 :
3403 : IF ("r" == "l" .AND. real_4 == int_8) THEN
3404 : CPABORT("Minimal location not available with long integers @ "//routineN)
3405 : END IF
3406 0 : CALL mp_timeset(routineN, handle)
3407 :
3408 : #if defined(__parallel)
3409 0 : msglen = SIZE(msg)
3410 0 : ALLOCATE (res(1:msglen))
3411 0 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2REAL, MPI_MINLOC, comm%handle, ierr)
3412 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3413 0 : msg = res
3414 0 : DEALLOCATE (res)
3415 0 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*real_4_size)
3416 : #else
3417 : MARK_USED(msg)
3418 : MARK_USED(comm)
3419 : #endif
3420 0 : CALL mp_timestop(handle)
3421 0 : END SUBROUTINE mp_minloc_rv
3422 :
3423 : ! **************************************************************************************************
3424 : !> \brief Finds the location of the maximal element in a vector.
3425 : !> \param[in,out] msg Find location of maximum element among these
3426 : !> data (input).
3427 : !> \param[in] comm Message passing environment identifier
3428 : !> \par MPI mapping
3429 : !> mpi_allreduce with the MPI_MAXLOC reduction function identifier
3430 : !> \par Invalid data types
3431 : !> This routine is invalid for (int_8) data!
3432 : ! **************************************************************************************************
3433 9550907 : SUBROUTINE mp_maxloc_dv(msg, comm)
3434 : REAL(kind=real_8), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3435 : CLASS(mp_comm_type), INTENT(IN) :: comm
3436 :
3437 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_maxloc_dv'
3438 :
3439 : INTEGER :: handle
3440 : #if defined(__parallel)
3441 : INTEGER :: ierr, msglen
3442 9550907 : REAL(kind=real_8), ALLOCATABLE :: res(:)
3443 : #endif
3444 :
3445 : IF ("d" == "l" .AND. real_8 == int_8) THEN
3446 : CPABORT("Maximal location not available with long integers @ "//routineN)
3447 : END IF
3448 9550907 : CALL mp_timeset(routineN, handle)
3449 :
3450 : #if defined(__parallel)
3451 9550907 : msglen = SIZE(msg)
3452 28652721 : ALLOCATE (res(1:msglen))
3453 9550907 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2DOUBLE_PRECISION, MPI_MAXLOC, comm%handle, ierr)
3454 9550907 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3455 28652721 : msg = res
3456 9550907 : DEALLOCATE (res)
3457 9550907 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*real_8_size)
3458 : #else
3459 : MARK_USED(msg)
3460 : MARK_USED(comm)
3461 : #endif
3462 9550907 : CALL mp_timestop(handle)
3463 9550907 : END SUBROUTINE mp_maxloc_dv
3464 :
3465 : ! **************************************************************************************************
3466 : !> \brief Finds the location of the maximal element in a vector.
3467 : !> \param[in,out] msg Find location of maximum element among these
3468 : !> data (input).
3469 : !> \param[in] comm Message passing environment identifier
3470 : !> \par MPI mapping
3471 : !> mpi_allreduce with the MPI_MAXLOC reduction function identifier
3472 : !> \par Invalid data types
3473 : !> This routine is invalid for (int_8) data!
3474 : ! **************************************************************************************************
3475 216 : SUBROUTINE mp_maxloc_iv(msg, comm)
3476 : INTEGER(KIND=int_4), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3477 : CLASS(mp_comm_type), INTENT(IN) :: comm
3478 :
3479 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_maxloc_iv'
3480 :
3481 : INTEGER :: handle
3482 : #if defined(__parallel)
3483 : INTEGER :: ierr, msglen
3484 216 : INTEGER(KIND=int_4), ALLOCATABLE :: res(:)
3485 : #endif
3486 :
3487 : IF ("i" == "l" .AND. int_4 == int_8) THEN
3488 : CPABORT("Maximal location not available with long integers @ "//routineN)
3489 : END IF
3490 216 : CALL mp_timeset(routineN, handle)
3491 :
3492 : #if defined(__parallel)
3493 216 : msglen = SIZE(msg)
3494 648 : ALLOCATE (res(1:msglen))
3495 216 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2INTEGER, MPI_MAXLOC, comm%handle, ierr)
3496 216 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3497 648 : msg = res
3498 216 : DEALLOCATE (res)
3499 216 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*int_4_size)
3500 : #else
3501 : MARK_USED(msg)
3502 : MARK_USED(comm)
3503 : #endif
3504 216 : CALL mp_timestop(handle)
3505 216 : END SUBROUTINE mp_maxloc_iv
3506 :
3507 : ! **************************************************************************************************
3508 : !> \brief Finds the location of the maximal element in a vector.
3509 : !> \param[in,out] msg Find location of maximum element among these
3510 : !> data (input).
3511 : !> \param[in] comm Message passing environment identifier
3512 : !> \par MPI mapping
3513 : !> mpi_allreduce with the MPI_MAXLOC reduction function identifier
3514 : !> \par Invalid data types
3515 : !> This routine is invalid for (int_8) data!
3516 : ! **************************************************************************************************
3517 0 : SUBROUTINE mp_maxloc_lv(msg, comm)
3518 : INTEGER(KIND=int_8), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3519 : CLASS(mp_comm_type), INTENT(IN) :: comm
3520 :
3521 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_maxloc_lv'
3522 :
3523 : INTEGER :: handle
3524 : #if defined(__parallel)
3525 : INTEGER :: ierr, msglen
3526 0 : INTEGER(KIND=int_8), ALLOCATABLE :: res(:)
3527 : #endif
3528 :
3529 : IF ("l" == "l" .AND. int_8 == int_8) THEN
3530 0 : CPABORT("Maximal location not available with long integers @ "//routineN)
3531 : END IF
3532 0 : CALL mp_timeset(routineN, handle)
3533 :
3534 : #if defined(__parallel)
3535 0 : msglen = SIZE(msg)
3536 0 : ALLOCATE (res(1:msglen))
3537 0 : CALL mpi_allreduce(msg, res, msglen/2, MPI_INTEGER8, MPI_MAXLOC, comm%handle, ierr)
3538 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3539 0 : msg = res
3540 0 : DEALLOCATE (res)
3541 0 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*int_8_size)
3542 : #else
3543 : MARK_USED(msg)
3544 : MARK_USED(comm)
3545 : #endif
3546 0 : CALL mp_timestop(handle)
3547 0 : END SUBROUTINE mp_maxloc_lv
3548 :
3549 : ! **************************************************************************************************
3550 : !> \brief Finds the location of the maximal element in a vector.
3551 : !> \param[in,out] msg Find location of maximum element among these
3552 : !> data (input).
3553 : !> \param[in] comm Message passing environment identifier
3554 : !> \par MPI mapping
3555 : !> mpi_allreduce with the MPI_MAXLOC reduction function identifier
3556 : !> \par Invalid data types
3557 : !> This routine is invalid for (int_8) data!
3558 : ! **************************************************************************************************
3559 0 : SUBROUTINE mp_maxloc_rv(msg, comm)
3560 : REAL(kind=real_4), CONTIGUOUS, INTENT(INOUT) :: msg(:)
3561 : CLASS(mp_comm_type), INTENT(IN) :: comm
3562 :
3563 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_maxloc_rv'
3564 :
3565 : INTEGER :: handle
3566 : #if defined(__parallel)
3567 : INTEGER :: ierr, msglen
3568 0 : REAL(kind=real_4), ALLOCATABLE :: res(:)
3569 : #endif
3570 :
3571 : IF ("r" == "l" .AND. real_4 == int_8) THEN
3572 : CPABORT("Maximal location not available with long integers @ "//routineN)
3573 : END IF
3574 0 : CALL mp_timeset(routineN, handle)
3575 :
3576 : #if defined(__parallel)
3577 0 : msglen = SIZE(msg)
3578 0 : ALLOCATE (res(1:msglen))
3579 0 : CALL mpi_allreduce(msg, res, msglen/2, MPI_2REAL, MPI_MAXLOC, comm%handle, ierr)
3580 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3581 0 : msg = res
3582 0 : DEALLOCATE (res)
3583 0 : CALL add_perf(perf_id=3, count=1, msg_size=msglen*real_4_size)
3584 : #else
3585 : MARK_USED(msg)
3586 : MARK_USED(comm)
3587 : #endif
3588 0 : CALL mp_timestop(handle)
3589 0 : END SUBROUTINE mp_maxloc_rv
3590 :
3591 : ! **************************************************************************************************
3592 : !> \brief Logical OR reduction
3593 : !> \param[in,out] msg Datum to perform inclusive disjunction (input)
3594 : !> and resultant inclusive disjunction (output)
3595 : !> \param[in] comm Message passing environment identifier
3596 : !> \par MPI mapping
3597 : !> mpi_allreduce
3598 : ! **************************************************************************************************
3599 58902 : SUBROUTINE mp_sum_b(msg, comm)
3600 : LOGICAL, INTENT(INOUT) :: msg
3601 : CLASS(mp_comm_type), INTENT(IN) :: comm
3602 :
3603 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_sum_b'
3604 :
3605 : INTEGER :: handle
3606 : #if defined(__parallel)
3607 : INTEGER :: ierr, msglen
3608 : #endif
3609 :
3610 58902 : CALL mp_timeset(routineN, handle)
3611 : #if defined(__parallel)
3612 58902 : msglen = 1
3613 58902 : IF (comm%num_pe > 1) THEN
3614 3730 : CALL mpi_allreduce(MPI_IN_PLACE, msg, msglen, MPI_LOGICAL, MPI_LOR, comm%handle, ierr)
3615 3730 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3616 : END IF
3617 : #else
3618 : MARK_USED(msg)
3619 : MARK_USED(comm)
3620 : #endif
3621 58902 : CALL mp_timestop(handle)
3622 58902 : END SUBROUTINE mp_sum_b
3623 :
3624 : ! **************************************************************************************************
3625 : !> \brief Logical OR reduction
3626 : !> \param[in,out] msg Datum to perform inclusive disjunction (input)
3627 : !> and resultant inclusive disjunction (output)
3628 : !> \param[in] comm Message passing environment identifier
3629 : !> \par MPI mapping
3630 : !> mpi_allreduce
3631 : ! **************************************************************************************************
3632 0 : SUBROUTINE mp_sum_bv(msg, comm)
3633 : LOGICAL, DIMENSION(:), CONTIGUOUS, INTENT(INOUT) :: msg
3634 : CLASS(mp_comm_type), INTENT(IN) :: comm
3635 :
3636 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_sum_bv'
3637 :
3638 : INTEGER :: handle
3639 : #if defined(__parallel)
3640 : INTEGER :: ierr, msglen
3641 : #endif
3642 :
3643 0 : CALL mp_timeset(routineN, handle)
3644 : #if defined(__parallel)
3645 0 : msglen = SIZE(msg)
3646 0 : IF (msglen > 0 .AND. comm%num_pe > 1) THEN
3647 0 : CALL mpi_allreduce(MPI_IN_PLACE, msg, msglen, MPI_LOGICAL, MPI_LOR, comm%handle, ierr)
3648 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3649 : END IF
3650 : #else
3651 : MARK_USED(msg)
3652 : MARK_USED(comm)
3653 : #endif
3654 0 : CALL mp_timestop(handle)
3655 0 : END SUBROUTINE mp_sum_bv
3656 :
3657 : ! **************************************************************************************************
3658 : !> \brief Logical OR reduction
3659 : !> \param[in,out] msg Datum to perform inclusive disjunction (input)
3660 : !> and resultant inclusive disjunction (output)
3661 : !> \param[in] comm Message passing environment identifier
3662 : !> \param request ...
3663 : !> \par MPI mapping
3664 : !> mpi_allreduce
3665 : ! **************************************************************************************************
3666 0 : SUBROUTINE mp_isum_bv(msg, comm, request)
3667 : LOGICAL, DIMENSION(:), INTENT(INOUT) :: msg
3668 : CLASS(mp_comm_type), INTENT(IN) :: comm
3669 : TYPE(mp_request_type), INTENT(INOUT) :: request
3670 :
3671 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_isum_bv'
3672 :
3673 : INTEGER :: handle
3674 : #if defined(__parallel)
3675 : INTEGER :: ierr, msglen
3676 : #endif
3677 :
3678 0 : CALL mp_timeset(routineN, handle)
3679 : #if defined(__parallel)
3680 0 : msglen = SIZE(msg)
3681 : #if !defined(__GNUC__) || __GNUC__ >= 9
3682 0 : CPASSERT(IS_CONTIGUOUS(msg) .OR. PRODUCT(SHAPE(msg)) == 0)
3683 : #endif
3684 :
3685 0 : IF (msglen > 0 .AND. comm%num_pe > 1) THEN
3686 0 : CALL mpi_iallreduce(MPI_IN_PLACE, msg, msglen, MPI_LOGICAL, MPI_LOR, comm%handle, request%handle, ierr)
3687 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_allreduce @ "//routineN)
3688 : ELSE
3689 0 : request = mp_request_null
3690 : END IF
3691 : #else
3692 : MARK_USED(msg)
3693 : MARK_USED(comm)
3694 : request = mp_request_null
3695 : #endif
3696 0 : CALL mp_timestop(handle)
3697 0 : END SUBROUTINE mp_isum_bv
3698 :
3699 : ! **************************************************************************************************
3700 : !> \brief Get Version of the MPI Library (MPI 3)
3701 : !> \param[out] version Version of the library,
3702 : !> declared as CHARACTER(LEN=mp_max_library_version_string)
3703 : !> \param[out] resultlen Length (in printable characters) of
3704 : !> the result returned in version (integer)
3705 : ! **************************************************************************************************
3706 0 : SUBROUTINE mp_get_library_version(version, resultlen)
3707 : CHARACTER(len=*), INTENT(OUT) :: version
3708 : INTEGER, INTENT(OUT) :: resultlen
3709 :
3710 : #if defined(__parallel)
3711 : INTEGER :: ierr
3712 : #endif
3713 :
3714 0 : version = ''
3715 :
3716 : #if defined(__parallel)
3717 : ierr = 0
3718 0 : CALL mpi_get_library_version(version, resultlen, ierr)
3719 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_get_library_version @ mp_get_library_version")
3720 : #else
3721 : resultlen = 0
3722 : #endif
3723 0 : END SUBROUTINE mp_get_library_version
3724 :
3725 : ! **************************************************************************************************
3726 : !> \brief Opens a file
3727 : !> \param[in] groupid message passing environment identifier
3728 : !> \param[out] fh file handle (file storage unit)
3729 : !> \param[in] filepath path to the file
3730 : !> \param amode_status access mode
3731 : !> \param info ...
3732 : !> \par MPI-I/O mapping mpi_file_open
3733 : !> \par STREAM-I/O mapping OPEN
3734 : !>
3735 : !> \param[in](optional) info info object
3736 : !> \par History
3737 : !> 11.2012 created [Hossein Bani-Hashemian]
3738 : ! **************************************************************************************************
3739 2074 : SUBROUTINE mp_file_open(groupid, fh, filepath, amode_status, info)
3740 : CLASS(mp_comm_type), INTENT(IN) :: groupid
3741 : CLASS(mp_file_type), INTENT(OUT) :: fh
3742 : CHARACTER(len=*), INTENT(IN) :: filepath
3743 : INTEGER, INTENT(IN) :: amode_status
3744 : TYPE(mp_info_type), INTENT(IN), OPTIONAL :: info
3745 :
3746 : #if defined(__parallel)
3747 : INTEGER :: ierr
3748 : MPI_INFO_TYPE :: my_info
3749 : #else
3750 : CHARACTER(LEN=10) :: fstatus, fposition
3751 : INTEGER :: amode, handle, istat
3752 : LOGICAL :: exists, is_open
3753 : #endif
3754 :
3755 : #if defined(__parallel)
3756 : ierr = 0
3757 2074 : my_info = mpi_info_null
3758 2074 : IF (PRESENT(info)) my_info = info%handle
3759 2074 : CALL mpi_file_open(groupid%handle, filepath, amode_status, my_info, fh%handle, ierr)
3760 2074 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
3761 2074 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ mp_file_open")
3762 : #else
3763 : MARK_USED(groupid)
3764 : MARK_USED(info)
3765 : amode = amode_status
3766 : IF (amode > file_amode_append) THEN
3767 : fposition = "APPEND"
3768 : amode = amode - file_amode_append
3769 : ELSE
3770 : fposition = "REWIND"
3771 : END IF
3772 : IF ((amode == file_amode_create) .OR. &
3773 : (amode == file_amode_create + file_amode_wronly) .OR. &
3774 : (amode == file_amode_create + file_amode_wronly + file_amode_excl)) THEN
3775 : fstatus = "UNKNOWN"
3776 : ELSE
3777 : fstatus = "OLD"
3778 : END IF
3779 : ! Get a new unit number
3780 : DO handle = 1, 999
3781 : INQUIRE (UNIT=handle, EXIST=exists, OPENED=is_open, IOSTAT=istat)
3782 : IF (exists .AND. (.NOT. is_open) .AND. (istat == 0)) EXIT
3783 : END DO
3784 : OPEN (UNIT=handle, FILE=filepath, STATUS=fstatus, ACCESS="STREAM", POSITION=fposition)
3785 : fh%handle = handle
3786 : #endif
3787 2074 : END SUBROUTINE mp_file_open
3788 :
3789 : ! **************************************************************************************************
3790 : !> \brief Deletes a file. Auxiliary routine to emulate 'replace' action for mp_file_open.
3791 : !> Only the master processor should call this routine.
3792 : !> \param[in] filepath path to the file
3793 : !> \param[in](optional) info info object
3794 : !> \par History
3795 : !> 11.2017 created [Nico Holmberg]
3796 : ! **************************************************************************************************
3797 162 : SUBROUTINE mp_file_delete(filepath, info)
3798 : CHARACTER(len=*), INTENT(IN) :: filepath
3799 : TYPE(mp_info_type), INTENT(IN), OPTIONAL :: info
3800 :
3801 : #if defined(__parallel)
3802 : INTEGER :: ierr
3803 : MPI_INFO_TYPE :: my_info
3804 : LOGICAL :: exists
3805 :
3806 162 : ierr = 0
3807 162 : my_info = mpi_info_null
3808 162 : IF (PRESENT(info)) my_info = info%handle
3809 162 : INQUIRE (FILE=filepath, EXIST=exists)
3810 162 : IF (exists) CALL mpi_file_delete(filepath, my_info, ierr)
3811 162 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ mp_file_delete")
3812 : #else
3813 : MARK_USED(filepath)
3814 : MARK_USED(info)
3815 : ! Explicit file delete not necessary, handled by subsequent call to open_file with action 'replace'
3816 : #endif
3817 :
3818 162 : END SUBROUTINE mp_file_delete
3819 :
3820 : ! **************************************************************************************************
3821 : !> \brief Closes a file
3822 : !> \param[in] fh file handle (file storage unit)
3823 : !> \par MPI-I/O mapping mpi_file_close
3824 : !> \par STREAM-I/O mapping CLOSE
3825 : !>
3826 : !> \par History
3827 : !> 11.2012 created [Hossein Bani-Hashemian]
3828 : ! **************************************************************************************************
3829 4148 : SUBROUTINE mp_file_close(fh)
3830 : CLASS(mp_file_type), INTENT(INOUT) :: fh
3831 :
3832 : #if defined(__parallel)
3833 : INTEGER :: ierr
3834 :
3835 : ierr = 0
3836 2074 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
3837 2074 : CALL mpi_file_close(fh%handle, ierr)
3838 2074 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ mp_file_close")
3839 : #else
3840 : CLOSE (fh%handle)
3841 : fh%handle = mp_file_null_handle
3842 : #endif
3843 2074 : END SUBROUTINE mp_file_close
3844 :
3845 0 : SUBROUTINE mp_file_assign(fh_new, fh_old)
3846 : CLASS(mp_file_type), INTENT(OUT) :: fh_new
3847 : CLASS(mp_file_type), INTENT(IN) :: fh_old
3848 :
3849 0 : fh_new%handle = fh_old%handle
3850 :
3851 0 : END SUBROUTINE
3852 :
3853 : ! **************************************************************************************************
3854 : !> \brief Returns the file size
3855 : !> \param[in] fh file handle (file storage unit)
3856 : !> \param[out] file_size the file size
3857 : !> \par MPI-I/O mapping mpi_file_get_size
3858 : !> \par STREAM-I/O mapping INQUIRE
3859 : !>
3860 : !> \par History
3861 : !> 12.2012 created [Hossein Bani-Hashemian]
3862 : ! **************************************************************************************************
3863 0 : SUBROUTINE mp_file_get_size(fh, file_size)
3864 : CLASS(mp_file_type), INTENT(IN) :: fh
3865 : INTEGER(kind=file_offset), INTENT(OUT) :: file_size
3866 :
3867 : #if defined(__parallel)
3868 : INTEGER :: ierr
3869 : #endif
3870 :
3871 : #if defined(__parallel)
3872 : ierr = 0
3873 0 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
3874 0 : CALL mpi_file_get_size(fh%handle, file_size, ierr)
3875 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ mp_file_get_size")
3876 : #else
3877 : INQUIRE (UNIT=fh%handle, SIZE=file_size)
3878 : #endif
3879 0 : END SUBROUTINE mp_file_get_size
3880 :
3881 : ! **************************************************************************************************
3882 : !> \brief Returns the file position
3883 : !> \param[in] fh file handle (file storage unit)
3884 : !> \param[out] file_size the file position
3885 : !> \par MPI-I/O mapping mpi_file_get_position
3886 : !> \par STREAM-I/O mapping INQUIRE
3887 : !>
3888 : !> \par History
3889 : !> 11.2017 created [Nico Holmberg]
3890 : ! **************************************************************************************************
3891 4064 : SUBROUTINE mp_file_get_position(fh, pos)
3892 : CLASS(mp_file_type), INTENT(IN) :: fh
3893 : INTEGER(kind=file_offset), INTENT(OUT) :: pos
3894 :
3895 : #if defined(__parallel)
3896 : INTEGER :: ierr
3897 : #endif
3898 :
3899 : #if defined(__parallel)
3900 : ierr = 0
3901 2032 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
3902 2032 : CALL mpi_file_get_position(fh%handle, pos, ierr)
3903 2032 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ mp_file_get_position")
3904 : #else
3905 : INQUIRE (UNIT=fh%handle, POS=pos)
3906 : #endif
3907 2032 : END SUBROUTINE mp_file_get_position
3908 :
3909 : ! **************************************************************************************************
3910 : !> \brief (parallel) Blocking individual file write using explicit offsets
3911 : !> (serial) Unformatted stream write
3912 : !> \param[in] fh file handle (file storage unit)
3913 : !> \param[in] offset file offset (position)
3914 : !> \param[in] msg data to be written to the file
3915 : !> \param msglen ...
3916 : !> \par MPI-I/O mapping mpi_file_write_at
3917 : !> \par STREAM-I/O mapping WRITE
3918 : !> \param[in](optional) msglen number of the elements of data
3919 : ! **************************************************************************************************
3920 0 : SUBROUTINE mp_file_write_at_chv(fh, offset, msg, msglen)
3921 : CHARACTER, CONTIGUOUS, INTENT(IN) :: msg(:)
3922 : CLASS(mp_file_type), INTENT(IN) :: fh
3923 : INTEGER, INTENT(IN), OPTIONAL :: msglen
3924 : INTEGER(kind=file_offset), INTENT(IN) :: offset
3925 :
3926 : #if defined(__parallel)
3927 : INTEGER :: ierr, msg_len
3928 : #endif
3929 :
3930 : #if defined(__parallel)
3931 0 : msg_len = SIZE(msg)
3932 0 : IF (PRESENT(msglen)) msg_len = msglen
3933 0 : CALL MPI_FILE_WRITE_AT(fh%handle, offset, msg, msg_len, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
3934 0 : IF (ierr /= 0) &
3935 0 : CPABORT("mpi_file_write_at_chv @ mp_file_write_at_chv")
3936 : #else
3937 : MARK_USED(msglen)
3938 : WRITE (UNIT=fh%handle, POS=offset + 1) msg
3939 : #endif
3940 0 : END SUBROUTINE mp_file_write_at_chv
3941 :
3942 : ! **************************************************************************************************
3943 : !> \brief ...
3944 : !> \param fh ...
3945 : !> \param offset ...
3946 : !> \param msg ...
3947 : ! **************************************************************************************************
3948 9650 : SUBROUTINE mp_file_write_at_ch(fh, offset, msg)
3949 : CHARACTER(LEN=*), INTENT(IN) :: msg
3950 : CLASS(mp_file_type), INTENT(IN) :: fh
3951 : INTEGER(kind=file_offset), INTENT(IN) :: offset
3952 :
3953 : #if defined(__parallel)
3954 : INTEGER :: ierr
3955 : #endif
3956 :
3957 : #if defined(__parallel)
3958 9650 : CALL MPI_FILE_WRITE_AT(fh%handle, offset, msg, LEN(msg), MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
3959 9650 : IF (ierr /= 0) &
3960 0 : CPABORT("mpi_file_write_at_ch @ mp_file_write_at_ch")
3961 : #else
3962 : WRITE (UNIT=fh%handle, POS=offset + 1) msg
3963 : #endif
3964 9650 : END SUBROUTINE mp_file_write_at_ch
3965 :
3966 : ! **************************************************************************************************
3967 : !> \brief (parallel) Blocking collective file write using explicit offsets
3968 : !> (serial) Unformatted stream write
3969 : !> \param fh ...
3970 : !> \param offset ...
3971 : !> \param msg ...
3972 : !> \param msglen ...
3973 : !> \par MPI-I/O mapping mpi_file_write_at_all
3974 : !> \par STREAM-I/O mapping WRITE
3975 : ! **************************************************************************************************
3976 0 : SUBROUTINE mp_file_write_at_all_chv(fh, offset, msg, msglen)
3977 : CHARACTER, CONTIGUOUS, INTENT(IN) :: msg(:)
3978 : CLASS(mp_file_type), INTENT(IN) :: fh
3979 : INTEGER, INTENT(IN), OPTIONAL :: msglen
3980 : INTEGER(kind=file_offset), INTENT(IN) :: offset
3981 :
3982 : #if defined(__parallel)
3983 : INTEGER :: ierr, msg_len
3984 : #endif
3985 :
3986 : #if defined(__parallel)
3987 0 : msg_len = SIZE(msg)
3988 0 : IF (PRESENT(msglen)) msg_len = msglen
3989 0 : CALL MPI_FILE_WRITE_AT_ALL(fh%handle, offset, msg, msg_len, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
3990 0 : IF (ierr /= 0) &
3991 0 : CPABORT("mpi_file_write_at_all_chv @ mp_file_write_at_all_chv")
3992 : #else
3993 : MARK_USED(msglen)
3994 : WRITE (UNIT=fh%handle, POS=offset + 1) msg
3995 : #endif
3996 0 : END SUBROUTINE mp_file_write_at_all_chv
3997 :
3998 : ! **************************************************************************************************
3999 : !> \brief wrapper to MPI_File_write_at_all
4000 : !> \param fh ...
4001 : !> \param offset ...
4002 : !> \param msg ...
4003 : ! **************************************************************************************************
4004 0 : SUBROUTINE mp_file_write_at_all_ch(fh, offset, msg)
4005 : CHARACTER(LEN=*), INTENT(IN) :: msg
4006 : CLASS(mp_file_type), INTENT(IN) :: fh
4007 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4008 :
4009 : #if defined(__parallel)
4010 : INTEGER :: ierr
4011 : #endif
4012 :
4013 : #if defined(__parallel)
4014 0 : CALL MPI_FILE_WRITE_AT_ALL(fh%handle, offset, msg, LEN(msg), MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4015 0 : IF (ierr /= 0) &
4016 0 : CPABORT("mpi_file_write_at_all_ch @ mp_file_write_at_all_ch")
4017 : #else
4018 : WRITE (UNIT=fh%handle, POS=offset + 1) msg
4019 : #endif
4020 0 : END SUBROUTINE mp_file_write_at_all_ch
4021 :
4022 : ! **************************************************************************************************
4023 : !> \brief (parallel) Blocking individual file read using explicit offsets
4024 : !> (serial) Unformatted stream read
4025 : !> \param[in] fh file handle (file storage unit)
4026 : !> \param[in] offset file offset (position)
4027 : !> \param[out] msg data to be read from the file
4028 : !> \param msglen ...
4029 : !> \par MPI-I/O mapping mpi_file_read_at
4030 : !> \par STREAM-I/O mapping READ
4031 : !> \param[in](optional) msglen number of elements of data
4032 : ! **************************************************************************************************
4033 0 : SUBROUTINE mp_file_read_at_chv(fh, offset, msg, msglen)
4034 : CHARACTER, CONTIGUOUS, INTENT(OUT) :: msg(:)
4035 : CLASS(mp_file_type), INTENT(IN) :: fh
4036 : INTEGER, INTENT(IN), OPTIONAL :: msglen
4037 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4038 :
4039 : #if defined(__parallel)
4040 : INTEGER :: ierr, msg_len
4041 : #endif
4042 :
4043 : #if defined(__parallel)
4044 0 : msg_len = SIZE(msg)
4045 0 : IF (PRESENT(msglen)) msg_len = msglen
4046 0 : CALL MPI_FILE_READ_AT(fh%handle, offset, msg, msg_len, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4047 0 : IF (ierr /= 0) &
4048 0 : CPABORT("mpi_file_read_at_chv @ mp_file_read_at_chv")
4049 : #else
4050 : MARK_USED(msglen)
4051 : READ (UNIT=fh%handle, POS=offset + 1) msg
4052 : #endif
4053 0 : END SUBROUTINE mp_file_read_at_chv
4054 :
4055 : ! **************************************************************************************************
4056 : !> \brief wrapper to MPI_File_read_at
4057 : !> \param fh ...
4058 : !> \param offset ...
4059 : !> \param msg ...
4060 : ! **************************************************************************************************
4061 0 : SUBROUTINE mp_file_read_at_ch(fh, offset, msg)
4062 : CHARACTER(LEN=*), INTENT(OUT) :: msg
4063 : CLASS(mp_file_type), INTENT(IN) :: fh
4064 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4065 :
4066 : #if defined(__parallel)
4067 : INTEGER :: ierr
4068 : #endif
4069 :
4070 : #if defined(__parallel)
4071 0 : CALL MPI_FILE_READ_AT(fh%handle, offset, msg, LEN(msg), MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4072 0 : IF (ierr /= 0) &
4073 0 : CPABORT("mpi_file_read_at_ch @ mp_file_read_at_ch")
4074 : #else
4075 : READ (UNIT=fh%handle, POS=offset + 1) msg
4076 : #endif
4077 0 : END SUBROUTINE mp_file_read_at_ch
4078 :
4079 : ! **************************************************************************************************
4080 : !> \brief (parallel) Blocking collective file read using explicit offsets
4081 : !> (serial) Unformatted stream read
4082 : !> \param fh ...
4083 : !> \param offset ...
4084 : !> \param msg ...
4085 : !> \param msglen ...
4086 : !> \par MPI-I/O mapping mpi_file_read_at_all
4087 : !> \par STREAM-I/O mapping READ
4088 : ! **************************************************************************************************
4089 0 : SUBROUTINE mp_file_read_at_all_chv(fh, offset, msg, msglen)
4090 : CHARACTER, INTENT(OUT) :: msg(:)
4091 : CLASS(mp_file_type), INTENT(IN) :: fh
4092 : INTEGER, INTENT(IN), OPTIONAL :: msglen
4093 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4094 :
4095 : #if defined(__parallel)
4096 : INTEGER :: ierr, msg_len
4097 : #endif
4098 :
4099 : #if defined(__parallel)
4100 0 : msg_len = SIZE(msg)
4101 0 : IF (PRESENT(msglen)) msg_len = msglen
4102 0 : CALL MPI_FILE_READ_AT_ALL(fh%handle, offset, msg, msg_len, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4103 0 : IF (ierr /= 0) &
4104 0 : CPABORT("mpi_file_read_at_all_chv @ mp_file_read_at_all_chv")
4105 : #else
4106 : MARK_USED(msglen)
4107 : READ (UNIT=fh%handle, POS=offset + 1) msg
4108 : #endif
4109 0 : END SUBROUTINE mp_file_read_at_all_chv
4110 :
4111 : ! **************************************************************************************************
4112 : !> \brief wrapper to MPI_File_read_at_all
4113 : !> \param fh ...
4114 : !> \param offset ...
4115 : !> \param msg ...
4116 : ! **************************************************************************************************
4117 0 : SUBROUTINE mp_file_read_at_all_ch(fh, offset, msg)
4118 : CHARACTER(LEN=*), INTENT(OUT) :: msg
4119 : CLASS(mp_file_type), INTENT(IN) :: fh
4120 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4121 :
4122 : #if defined(__parallel)
4123 : INTEGER :: ierr
4124 : #endif
4125 :
4126 : #if defined(__parallel)
4127 0 : CALL MPI_FILE_READ_AT_ALL(fh%handle, offset, msg, LEN(msg), MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4128 0 : IF (ierr /= 0) &
4129 0 : CPABORT("mpi_file_read_at_all_ch @ mp_file_read_at_all_ch")
4130 : #else
4131 : READ (UNIT=fh%handle, POS=offset + 1) msg
4132 : #endif
4133 0 : END SUBROUTINE mp_file_read_at_all_ch
4134 :
4135 : ! **************************************************************************************************
4136 : !> \brief Returns the size of a data type in bytes
4137 : !> \param[in] type_descriptor data type
4138 : !> \param[out] type_size size of the data type
4139 : !> \par MPI mapping
4140 : !> mpi_type_size
4141 : !>
4142 : ! **************************************************************************************************
4143 0 : SUBROUTINE mp_type_size(type_descriptor, type_size)
4144 : TYPE(mp_type_descriptor_type), INTENT(IN) :: type_descriptor
4145 : INTEGER, INTENT(OUT) :: type_size
4146 :
4147 : #if defined(__parallel)
4148 : INTEGER :: ierr
4149 :
4150 : ierr = 0
4151 0 : CALL MPI_TYPE_SIZE(type_descriptor%type_handle, type_size, ierr)
4152 0 : IF (ierr /= 0) &
4153 0 : CPABORT("mpi_type_size failed @ mp_type_size")
4154 : #else
4155 : SELECT CASE (type_descriptor%type_handle)
4156 : CASE (1)
4157 : type_size = real_4_size
4158 : CASE (3)
4159 : type_size = real_8_size
4160 : CASE (5)
4161 : type_size = 2*real_4_size
4162 : CASE (7)
4163 : type_size = 2*real_8_size
4164 : END SELECT
4165 : #endif
4166 0 : END SUBROUTINE mp_type_size
4167 :
4168 : ! **************************************************************************************************
4169 : !> \brief wrapper to MPI_Type_create_struct
4170 : !> \param subtypes ...
4171 : !> \param vector_descriptor ...
4172 : !> \param index_descriptor ...
4173 : !> \return ...
4174 : ! **************************************************************************************************
4175 0 : FUNCTION mp_type_make_struct(subtypes, &
4176 : vector_descriptor, index_descriptor) &
4177 0 : RESULT(type_descriptor)
4178 : TYPE(mp_type_descriptor_type), &
4179 : DIMENSION(:), INTENT(IN) :: subtypes
4180 : INTEGER, DIMENSION(2), INTENT(IN), &
4181 : OPTIONAL :: vector_descriptor
4182 : TYPE(mp_indexing_meta_type), &
4183 : INTENT(IN), OPTIONAL :: index_descriptor
4184 : TYPE(mp_type_descriptor_type) :: type_descriptor
4185 :
4186 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_type_make_struct'
4187 :
4188 : INTEGER :: i, n
4189 0 : INTEGER, ALLOCATABLE, DIMENSION(:) :: lengths
4190 : #if defined(__parallel)
4191 : INTEGER :: ierr
4192 : INTEGER(kind=mpi_address_kind), &
4193 0 : ALLOCATABLE, DIMENSION(:) :: displacements
4194 : #if defined(__MPI_F08)
4195 : ! Even OpenMPI 5.x misses mpi_get_address in the F08 interface
4196 : EXTERNAL :: mpi_get_address
4197 : #endif
4198 : #endif
4199 0 : MPI_DATA_TYPE, ALLOCATABLE, DIMENSION(:) :: old_types
4200 :
4201 0 : n = SIZE(subtypes)
4202 0 : type_descriptor%length = 1
4203 : #if defined(__parallel)
4204 0 : ierr = 0
4205 0 : CALL mpi_get_address(MPI_BOTTOM, type_descriptor%base, ierr)
4206 0 : IF (ierr /= 0) &
4207 0 : CPABORT("MPI_get_address @ "//routineN)
4208 0 : ALLOCATE (displacements(n))
4209 : #endif
4210 0 : type_descriptor%vector_descriptor(1:2) = 1
4211 0 : type_descriptor%has_indexing = .FALSE.
4212 0 : ALLOCATE (type_descriptor%subtype(n))
4213 0 : type_descriptor%subtype(:) = subtypes(:)
4214 0 : ALLOCATE (lengths(n), old_types(n))
4215 0 : DO i = 1, SIZE(subtypes)
4216 : #if defined(__parallel)
4217 0 : displacements(i) = subtypes(i)%base
4218 : #endif
4219 0 : old_types(i) = subtypes(i)%type_handle
4220 0 : lengths(i) = subtypes(i)%length
4221 : END DO
4222 : #if defined(__parallel)
4223 : CALL MPI_Type_create_struct(n, &
4224 : lengths, displacements, old_types, &
4225 0 : type_descriptor%type_handle, ierr)
4226 0 : IF (ierr /= 0) &
4227 0 : CPABORT("MPI_Type_create_struct @ "//routineN)
4228 0 : CALL MPI_Type_commit(type_descriptor%type_handle, ierr)
4229 0 : IF (ierr /= 0) &
4230 0 : CPABORT("MPI_Type_commit @ "//routineN)
4231 : #endif
4232 0 : IF (PRESENT(vector_descriptor) .OR. PRESENT(index_descriptor)) THEN
4233 0 : CPABORT(routineN//" Vectors and indices NYI")
4234 : END IF
4235 0 : END FUNCTION mp_type_make_struct
4236 :
4237 : ! **************************************************************************************************
4238 : !> \brief wrapper to MPI_Type_free
4239 : !> \param type_descriptor ...
4240 : ! **************************************************************************************************
4241 0 : RECURSIVE SUBROUTINE mp_type_free_m(type_descriptor)
4242 : TYPE(mp_type_descriptor_type), INTENT(inout) :: type_descriptor
4243 :
4244 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_type_free_m'
4245 :
4246 : INTEGER :: handle, i
4247 : #if defined(__parallel)
4248 : INTEGER :: ierr
4249 : #endif
4250 :
4251 0 : CALL mp_timeset(routineN, handle)
4252 :
4253 : ! If the subtype is associated, then it's a user-defined data type.
4254 :
4255 0 : IF (ASSOCIATED(type_descriptor%subtype)) THEN
4256 0 : DO i = 1, SIZE(type_descriptor%subtype)
4257 0 : CALL mp_type_free_m(type_descriptor%subtype(i))
4258 : END DO
4259 0 : DEALLOCATE (type_descriptor%subtype)
4260 : END IF
4261 : #if defined(__parallel)
4262 : ierr = 0
4263 0 : CALL MPI_Type_free(type_descriptor%type_handle, ierr)
4264 0 : IF (ierr /= 0) &
4265 0 : CPABORT("MPI_Type_free @ "//routineN)
4266 : #endif
4267 :
4268 0 : CALL mp_timestop(handle)
4269 :
4270 0 : END SUBROUTINE mp_type_free_m
4271 :
4272 : ! **************************************************************************************************
4273 : !> \brief ...
4274 : !> \param type_descriptors ...
4275 : ! **************************************************************************************************
4276 0 : SUBROUTINE mp_type_free_v(type_descriptors)
4277 : TYPE(mp_type_descriptor_type), DIMENSION(:), &
4278 : INTENT(inout) :: type_descriptors
4279 :
4280 : INTEGER :: i
4281 :
4282 0 : DO i = 1, SIZE(type_descriptors)
4283 0 : CALL mp_type_free(type_descriptors(i))
4284 : END DO
4285 :
4286 0 : END SUBROUTINE mp_type_free_v
4287 :
4288 : ! **************************************************************************************************
4289 : !> \brief Creates an indexed MPI type for arrays of strings using bytes for spacing (hindexed type)
4290 : !> \param count number of array blocks to read
4291 : !> \param lengths lengths of each array block
4292 : !> \param displs byte offsets for array blocks
4293 : !> \return container holding the created type
4294 : !> \author Nico Holmberg [05.2017]
4295 : ! **************************************************************************************************
4296 4148 : FUNCTION mp_file_type_hindexed_make_chv(count, lengths, displs) &
4297 : RESULT(type_descriptor)
4298 : INTEGER, INTENT(IN) :: count
4299 : INTEGER, DIMENSION(1:count), &
4300 : INTENT(IN), TARGET :: lengths
4301 : INTEGER(kind=file_offset), &
4302 : DIMENSION(1:count), INTENT(in), TARGET :: displs
4303 : TYPE(mp_file_descriptor_type) :: type_descriptor
4304 :
4305 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_file_hindexed_make_chv'
4306 :
4307 : INTEGER :: ierr, handle
4308 :
4309 : ierr = 0
4310 2074 : CALL mp_timeset(routineN, handle)
4311 :
4312 : #if defined(__parallel)
4313 : CALL MPI_Type_create_hindexed(count, lengths, INT(displs, KIND=address_kind), MPI_CHARACTER, &
4314 419310 : type_descriptor%type_handle, ierr)
4315 2074 : IF (ierr /= 0) &
4316 0 : CPABORT("MPI_Type_create_hindexed @ "//routineN)
4317 2074 : CALL MPI_Type_commit(type_descriptor%type_handle, ierr)
4318 2074 : IF (ierr /= 0) &
4319 0 : CPABORT("MPI_Type_commit @ "//routineN)
4320 : #else
4321 : type_descriptor%type_handle = 68
4322 : #endif
4323 2074 : type_descriptor%length = count
4324 2074 : type_descriptor%has_indexing = .TRUE.
4325 2074 : type_descriptor%index_descriptor%index => lengths
4326 2074 : type_descriptor%index_descriptor%chunks => displs
4327 :
4328 2074 : CALL mp_timestop(handle)
4329 :
4330 2074 : END FUNCTION mp_file_type_hindexed_make_chv
4331 :
4332 : ! **************************************************************************************************
4333 : !> \brief Uses a previously created indexed MPI character type to tell the MPI processes
4334 : !> how to partition (set_view) an opened file
4335 : !> \param fh the file handle associated with the input file
4336 : !> \param offset global offset determining where the relevant data begins
4337 : !> \param type_descriptor container for the MPI type
4338 : !> \author Nico Holmberg [05.2017]
4339 : ! **************************************************************************************************
4340 2074 : SUBROUTINE mp_file_type_set_view_chv(fh, offset, type_descriptor)
4341 : TYPE(mp_file_type), INTENT(IN) :: fh
4342 : INTEGER(kind=file_offset), INTENT(IN) :: offset
4343 : TYPE(mp_file_descriptor_type) :: type_descriptor
4344 :
4345 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_file_set_view_chv'
4346 :
4347 : INTEGER :: handle
4348 : #if defined(__parallel)
4349 : INTEGER :: ierr
4350 : #endif
4351 :
4352 2074 : CALL mp_timeset(routineN, handle)
4353 :
4354 : #if defined(__parallel)
4355 : ierr = 0
4356 2074 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
4357 : CALL MPI_File_set_view(fh%handle, offset, MPI_CHARACTER, &
4358 2074 : type_descriptor%type_handle, "native", MPI_INFO_NULL, ierr)
4359 2074 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ MPI_File_set_view")
4360 : #else
4361 : ! Uses absolute offsets stored in mp_file_descriptor_type
4362 : MARK_USED(fh)
4363 : MARK_USED(offset)
4364 : MARK_USED(type_descriptor)
4365 : #endif
4366 :
4367 2074 : CALL mp_timestop(handle)
4368 :
4369 2074 : END SUBROUTINE mp_file_type_set_view_chv
4370 :
4371 : ! **************************************************************************************************
4372 : !> \brief (parallel) Collective, blocking read of a character array from a file. File access pattern
4373 : ! determined by a previously set file view.
4374 : !> (serial) Unformatted stream read using explicit offsets
4375 : !> \param fh the file handle associated with the input file
4376 : !> \param msglen the message length of an individual vector component
4377 : !> \param ndims the number of vector components
4378 : !> \param buffer the buffer where the data is placed
4379 : !> \param type_descriptor container for the MPI type
4380 : !> \author Nico Holmberg [05.2017]
4381 : ! **************************************************************************************************
4382 42 : SUBROUTINE mp_file_read_all_chv(fh, msglen, ndims, buffer, type_descriptor)
4383 : CLASS(mp_file_type), INTENT(IN) :: fh
4384 : INTEGER, INTENT(IN) :: msglen
4385 : INTEGER, INTENT(IN) :: ndims
4386 : CHARACTER(LEN=msglen), DIMENSION(ndims), INTENT(INOUT) :: buffer
4387 : TYPE(mp_file_descriptor_type), &
4388 : INTENT(IN), OPTIONAL :: type_descriptor
4389 :
4390 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_file_read_all_chv'
4391 :
4392 : INTEGER :: handle
4393 : #if defined(__parallel)
4394 : INTEGER:: ierr
4395 : #else
4396 : INTEGER :: i
4397 : #endif
4398 :
4399 42 : CALL mp_timeset(routineN, handle)
4400 :
4401 : #if defined(__parallel)
4402 : ierr = 0
4403 : MARK_USED(type_descriptor)
4404 42 : CALL MPI_File_read_all(fh%handle, buffer, ndims*msglen, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4405 42 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ MPI_File_read_all")
4406 42 : CALL add_perf(perf_id=28, count=1, msg_size=ndims*msglen)
4407 : #else
4408 : MARK_USED(msglen)
4409 : MARK_USED(ndims)
4410 : IF (.NOT. PRESENT(type_descriptor)) &
4411 : CALL cp_abort(__LOCATION__, &
4412 : "Container for mp_file_descriptor_type must be present in serial call.")
4413 : IF (.NOT. type_descriptor%has_indexing) &
4414 : CALL cp_abort(__LOCATION__, &
4415 : "File view has not been set in mp_file_descriptor_type.")
4416 : ! Use explicit offsets
4417 : DO i = 1, ndims
4418 : READ (fh%handle, POS=type_descriptor%index_descriptor%chunks(i)) buffer(i)
4419 : END DO
4420 : #endif
4421 :
4422 42 : CALL mp_timestop(handle)
4423 :
4424 42 : END SUBROUTINE mp_file_read_all_chv
4425 :
4426 : ! **************************************************************************************************
4427 : !> \brief (parallel) Collective, blocking write of a character array to a file. File access pattern
4428 : ! determined by a previously set file view.
4429 : !> (serial) Unformatted stream write using explicit offsets
4430 : !> \param fh the file handle associated with the output file
4431 : !> \param msglen the message length of an individual vector component
4432 : !> \param ndims the number of vector components
4433 : !> \param buffer the buffer where the data is placed
4434 : !> \param type_descriptor container for the MPI type
4435 : !> \author Nico Holmberg [05.2017]
4436 : ! **************************************************************************************************
4437 2032 : SUBROUTINE mp_file_write_all_chv(fh, msglen, ndims, buffer, type_descriptor)
4438 : CLASS(mp_file_type), INTENT(IN) :: fh
4439 : INTEGER, INTENT(IN) :: msglen
4440 : INTEGER, INTENT(IN) :: ndims
4441 : CHARACTER(LEN=msglen), DIMENSION(ndims), INTENT(IN) :: buffer
4442 : TYPE(mp_file_descriptor_type), &
4443 : INTENT(IN), OPTIONAL :: type_descriptor
4444 :
4445 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_file_write_all_chv'
4446 :
4447 : INTEGER :: handle
4448 : #if defined(__parallel)
4449 : INTEGER :: ierr
4450 : #else
4451 : INTEGER :: i
4452 : #endif
4453 :
4454 2032 : CALL mp_timeset(routineN, handle)
4455 :
4456 : #if defined(__parallel)
4457 : MARK_USED(type_descriptor)
4458 2032 : CALL mpi_file_set_errhandler(fh%handle, MPI_ERRORS_RETURN, ierr)
4459 2032 : CALL MPI_File_write_all(fh%handle, buffer, ndims*msglen, MPI_CHARACTER, MPI_STATUS_IGNORE, ierr)
4460 2032 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_file_set_errhandler @ MPI_File_write_all")
4461 2032 : CALL add_perf(perf_id=28, count=1, msg_size=ndims*msglen)
4462 : #else
4463 : MARK_USED(msglen)
4464 : MARK_USED(ndims)
4465 : IF (.NOT. PRESENT(type_descriptor)) &
4466 : CALL cp_abort(__LOCATION__, &
4467 : "Container for mp_file_descriptor_type must be present in serial call.")
4468 : IF (.NOT. type_descriptor%has_indexing) &
4469 : CALL cp_abort(__LOCATION__, &
4470 : "File view has not been set in mp_file_descriptor_type.")
4471 : ! Use explicit offsets
4472 : DO i = 1, ndims
4473 : WRITE (fh%handle, POS=type_descriptor%index_descriptor%chunks(i)) buffer(i)
4474 : END DO
4475 : #endif
4476 :
4477 2032 : CALL mp_timestop(handle)
4478 :
4479 2032 : END SUBROUTINE mp_file_write_all_chv
4480 :
4481 : ! **************************************************************************************************
4482 : !> \brief Releases the type used for MPI I/O
4483 : !> \param type_descriptor the container for the MPI type
4484 : !> \author Nico Holmberg [05.2017]
4485 : ! **************************************************************************************************
4486 4148 : SUBROUTINE mp_file_type_free(type_descriptor)
4487 : TYPE(mp_file_descriptor_type) :: type_descriptor
4488 :
4489 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_file_type_free'
4490 :
4491 : INTEGER :: handle
4492 : #if defined(__parallel)
4493 : INTEGER :: ierr
4494 : #endif
4495 :
4496 2074 : CALL mp_timeset(routineN, handle)
4497 :
4498 : #if defined(__parallel)
4499 2074 : CALL MPI_Type_free(type_descriptor%type_handle, ierr)
4500 2074 : IF (ierr /= 0) &
4501 0 : CPABORT("MPI_Type_free @ "//routineN)
4502 : #endif
4503 : #if defined(__parallel) && defined(__MPI_F08)
4504 2074 : type_descriptor%type_handle%mpi_val = -1
4505 : #else
4506 : type_descriptor%type_handle = -1
4507 : #endif
4508 2074 : type_descriptor%length = -1
4509 2074 : IF (type_descriptor%has_indexing) THEN
4510 2074 : NULLIFY (type_descriptor%index_descriptor%index)
4511 2074 : NULLIFY (type_descriptor%index_descriptor%chunks)
4512 2074 : type_descriptor%has_indexing = .FALSE.
4513 : END IF
4514 :
4515 2074 : CALL mp_timestop(handle)
4516 :
4517 2074 : END SUBROUTINE mp_file_type_free
4518 :
4519 : ! **************************************************************************************************
4520 : !> \brief (parallel) Utility routine to determine MPI file access mode based on variables
4521 : ! that in the serial case would get passed to the intrinsic OPEN
4522 : !> (serial) No action
4523 : !> \param mpi_io flag that determines if MPI I/O will actually be used
4524 : !> \param replace flag that indicates whether file needs to be deleted prior to opening it
4525 : !> \param amode the MPI I/O access mode
4526 : !> \param form formatted or unformatted data?
4527 : !> \param action the variable that determines what to do with file
4528 : !> \param status the status flag:
4529 : !> \param position should the file be appended or rewound
4530 : !> \author Nico Holmberg [11.2017]
4531 : ! **************************************************************************************************
4532 2032 : SUBROUTINE mp_file_get_amode(mpi_io, replace, amode, form, action, status, position)
4533 : LOGICAL, INTENT(INOUT) :: mpi_io, replace
4534 : INTEGER, INTENT(OUT) :: amode
4535 : CHARACTER(len=*), INTENT(IN) :: form, action, status, position
4536 :
4537 2032 : amode = -1
4538 : #if defined(__parallel)
4539 : ! Disable mpi io for unformatted access
4540 0 : SELECT CASE (form)
4541 : CASE ("FORMATTED")
4542 : ! Do nothing
4543 : CASE ("UNFORMATTED")
4544 0 : mpi_io = .FALSE.
4545 : CASE DEFAULT
4546 2032 : CPABORT("Unknown MPI file form requested.")
4547 : END SELECT
4548 : ! Determine file access mode (limited set of allowed choices)
4549 2032 : SELECT CASE (action)
4550 : CASE ("WRITE")
4551 2032 : amode = file_amode_wronly
4552 0 : SELECT CASE (status)
4553 : CASE ("NEW")
4554 : ! Try to open new file for writing, crash if file already exists
4555 0 : amode = amode + file_amode_create + file_amode_excl
4556 : CASE ("UNKNOWN")
4557 : ! Open file for writing and create it if file does not exist
4558 1708 : amode = amode + file_amode_create
4559 76 : SELECT CASE (position)
4560 : CASE ("APPEND")
4561 : ! Append existing file
4562 76 : amode = amode + file_amode_append
4563 : CASE ("REWIND", "ASIS")
4564 : ! Do nothing
4565 : CASE DEFAULT
4566 1708 : CPABORT("Unknown MPI file position requested.")
4567 : END SELECT
4568 : CASE ("OLD")
4569 324 : SELECT CASE (position)
4570 : CASE ("APPEND")
4571 : ! Append existing file
4572 0 : amode = amode + file_amode_append
4573 : CASE ("REWIND", "ASIS")
4574 : ! Do nothing
4575 : CASE DEFAULT
4576 0 : CPABORT("Unknown MPI file position requested.")
4577 : END SELECT
4578 : CASE ("REPLACE")
4579 : ! Overwrite existing file. Must delete existing file first
4580 324 : amode = amode + file_amode_create
4581 324 : replace = .TRUE.
4582 : CASE ("SCRATCH")
4583 : ! Disable
4584 0 : mpi_io = .FALSE.
4585 : CASE DEFAULT
4586 2032 : CPABORT("Unknown MPI file status requested.")
4587 : END SELECT
4588 : CASE ("READ")
4589 0 : amode = file_amode_rdonly
4590 0 : SELECT CASE (status)
4591 : CASE ("NEW")
4592 0 : CPABORT("Cannot read from 'NEW' file.")
4593 : CASE ("REPLACE")
4594 0 : CPABORT("Illegal status 'REPLACE' for read.")
4595 : CASE ("UNKNOWN", "OLD")
4596 : ! Do nothing
4597 : CASE ("SCRATCH")
4598 : ! Disable
4599 0 : mpi_io = .FALSE.
4600 : CASE DEFAULT
4601 0 : CPABORT("Unknown MPI file status requested.")
4602 : END SELECT
4603 : CASE ("READWRITE")
4604 0 : amode = file_amode_rdwr
4605 0 : SELECT CASE (status)
4606 : CASE ("NEW")
4607 : ! Try to open new file, crash if file already exists
4608 0 : amode = amode + file_amode_create + file_amode_excl
4609 : CASE ("UNKNOWN")
4610 : ! Open file and create it if file does not exist
4611 0 : amode = amode + file_amode_create
4612 0 : SELECT CASE (position)
4613 : CASE ("APPEND")
4614 : ! Append existing file
4615 0 : amode = amode + file_amode_append
4616 : CASE ("REWIND", "ASIS")
4617 : ! Do nothing
4618 : CASE DEFAULT
4619 0 : CPABORT("Unknown MPI file position requested.")
4620 : END SELECT
4621 : CASE ("OLD")
4622 0 : SELECT CASE (position)
4623 : CASE ("APPEND")
4624 : ! Append existing file
4625 0 : amode = amode + file_amode_append
4626 : CASE ("REWIND", "ASIS")
4627 : ! Do nothing
4628 : CASE DEFAULT
4629 0 : CPABORT("Unknown MPI file position requested.")
4630 : END SELECT
4631 : CASE ("REPLACE")
4632 : ! Overwrite existing file. Must delete existing file first
4633 0 : amode = amode + file_amode_create
4634 0 : replace = .TRUE.
4635 : CASE ("SCRATCH")
4636 : ! Disable
4637 0 : mpi_io = .FALSE.
4638 : CASE DEFAULT
4639 0 : CPABORT("Unknown MPI file status requested.")
4640 : END SELECT
4641 : CASE DEFAULT
4642 2032 : CPABORT("Unknown MPI file action requested.")
4643 : END SELECT
4644 : #else
4645 : MARK_USED(replace)
4646 : MARK_USED(form)
4647 : MARK_USED(position)
4648 : MARK_USED(status)
4649 : MARK_USED(action)
4650 : mpi_io = .FALSE.
4651 : #endif
4652 :
4653 2032 : END SUBROUTINE mp_file_get_amode
4654 :
4655 : ! **************************************************************************************************
4656 : !> \brief Non-blocking send of custom type
4657 : !> \param msgin ...
4658 : !> \param dest ...
4659 : !> \param comm ...
4660 : !> \param request ...
4661 : !> \param tag ...
4662 : ! **************************************************************************************************
4663 0 : SUBROUTINE mp_isend_custom(msgin, dest, comm, request, tag)
4664 : TYPE(mp_type_descriptor_type), INTENT(IN) :: msgin
4665 : INTEGER, INTENT(IN) :: dest
4666 : CLASS(mp_comm_type), INTENT(IN) :: comm
4667 : TYPE(mp_request_type), INTENT(out) :: request
4668 : INTEGER, INTENT(in), OPTIONAL :: tag
4669 :
4670 : INTEGER :: ierr, my_tag
4671 :
4672 : ierr = 0
4673 0 : my_tag = 0
4674 :
4675 : #if defined(__parallel)
4676 0 : IF (PRESENT(tag)) my_tag = tag
4677 :
4678 : CALL mpi_isend(MPI_BOTTOM, 1, msgin%type_handle, dest, my_tag, &
4679 0 : comm%handle, request%handle, ierr)
4680 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_isend @ mp_isend_custom")
4681 : #else
4682 : MARK_USED(msgin)
4683 : MARK_USED(dest)
4684 : MARK_USED(comm)
4685 : MARK_USED(tag)
4686 : ierr = 1
4687 : request = mp_request_null
4688 : CALL mp_stop(ierr, "mp_isend called in non parallel case")
4689 : #endif
4690 0 : END SUBROUTINE mp_isend_custom
4691 :
4692 : ! **************************************************************************************************
4693 : !> \brief Non-blocking receive of vector data
4694 : !> \param msgout ...
4695 : !> \param source ...
4696 : !> \param comm ...
4697 : !> \param request ...
4698 : !> \param tag ...
4699 : ! **************************************************************************************************
4700 0 : SUBROUTINE mp_irecv_custom(msgout, source, comm, request, tag)
4701 : TYPE(mp_type_descriptor_type), INTENT(INOUT) :: msgout
4702 : INTEGER, INTENT(IN) :: source
4703 : CLASS(mp_comm_type), INTENT(IN) :: comm
4704 : TYPE(mp_request_type), INTENT(out) :: request
4705 : INTEGER, INTENT(in), OPTIONAL :: tag
4706 :
4707 : INTEGER :: ierr, my_tag
4708 :
4709 : ierr = 0
4710 0 : my_tag = 0
4711 :
4712 : #if defined(__parallel)
4713 0 : IF (PRESENT(tag)) my_tag = tag
4714 :
4715 : CALL mpi_irecv(MPI_BOTTOM, 1, msgout%type_handle, source, my_tag, &
4716 0 : comm%handle, request%handle, ierr)
4717 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_irecv @ mp_irecv_custom")
4718 : #else
4719 : MARK_USED(msgout)
4720 : MARK_USED(source)
4721 : MARK_USED(comm)
4722 : MARK_USED(tag)
4723 : ierr = 1
4724 : request = mp_request_null
4725 : CPABORT("mp_irecv called in non parallel case")
4726 : #endif
4727 0 : END SUBROUTINE mp_irecv_custom
4728 :
4729 : ! **************************************************************************************************
4730 : !> \brief Window free
4731 : !> \param win ...
4732 : ! **************************************************************************************************
4733 0 : SUBROUTINE mp_win_free(win)
4734 : CLASS(mp_win_type), INTENT(INOUT) :: win
4735 :
4736 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_win_free'
4737 :
4738 : INTEGER :: handle
4739 : #if defined(__parallel)
4740 : INTEGER :: ierr
4741 : #endif
4742 :
4743 0 : CALL mp_timeset(routineN, handle)
4744 :
4745 : #if defined(__parallel)
4746 : ierr = 0
4747 0 : CALL mpi_win_free(win%handle, ierr)
4748 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_win_free @ "//routineN)
4749 :
4750 0 : CALL add_perf(perf_id=21, count=1)
4751 : #else
4752 : win%handle = mp_win_null_handle
4753 : #endif
4754 0 : CALL mp_timestop(handle)
4755 0 : END SUBROUTINE mp_win_free
4756 :
4757 0 : SUBROUTINE mp_win_assign(win_new, win_old)
4758 : CLASS(mp_win_type), INTENT(OUT) :: win_new
4759 : CLASS(mp_win_type), INTENT(IN) :: win_old
4760 :
4761 0 : win_new%handle = win_old%handle
4762 :
4763 0 : END SUBROUTINE mp_win_assign
4764 :
4765 : ! **************************************************************************************************
4766 : !> \brief Window flush
4767 : !> \param win ...
4768 : ! **************************************************************************************************
4769 0 : SUBROUTINE mp_win_flush_all(win)
4770 : CLASS(mp_win_type), INTENT(IN) :: win
4771 :
4772 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_win_flush_all'
4773 :
4774 : INTEGER :: handle, ierr
4775 :
4776 : ierr = 0
4777 0 : CALL mp_timeset(routineN, handle)
4778 :
4779 : #if defined(__parallel)
4780 0 : CALL mpi_win_flush_all(win%handle, ierr)
4781 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_win_flush_all @ "//routineN)
4782 : #else
4783 : MARK_USED(win)
4784 : #endif
4785 0 : CALL mp_timestop(handle)
4786 0 : END SUBROUTINE mp_win_flush_all
4787 :
4788 : ! **************************************************************************************************
4789 : !> \brief Window lock
4790 : !> \param win ...
4791 : ! **************************************************************************************************
4792 0 : SUBROUTINE mp_win_lock_all(win)
4793 : CLASS(mp_win_type), INTENT(IN) :: win
4794 :
4795 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_win_lock_all'
4796 :
4797 : INTEGER :: handle, ierr
4798 :
4799 : ierr = 0
4800 0 : CALL mp_timeset(routineN, handle)
4801 :
4802 : #if defined(__parallel)
4803 :
4804 0 : CALL mpi_win_lock_all(MPI_MODE_NOCHECK, win%handle, ierr)
4805 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_win_lock_all @ "//routineN)
4806 :
4807 0 : CALL add_perf(perf_id=19, count=1)
4808 : #else
4809 : MARK_USED(win)
4810 : #endif
4811 0 : CALL mp_timestop(handle)
4812 0 : END SUBROUTINE mp_win_lock_all
4813 :
4814 : ! **************************************************************************************************
4815 : !> \brief Window lock
4816 : !> \param win ...
4817 : ! **************************************************************************************************
4818 0 : SUBROUTINE mp_win_unlock_all(win)
4819 : CLASS(mp_win_type), INTENT(IN) :: win
4820 :
4821 : CHARACTER(len=*), PARAMETER :: routineN = 'mp_win_unlock_all'
4822 :
4823 : INTEGER :: handle, ierr
4824 :
4825 : ierr = 0
4826 0 : CALL mp_timeset(routineN, handle)
4827 :
4828 : #if defined(__parallel)
4829 :
4830 0 : CALL mpi_win_unlock_all(win%handle, ierr)
4831 0 : IF (ierr /= 0) CALL mp_stop(ierr, "mpi_win_unlock_all @ "//routineN)
4832 :
4833 0 : CALL add_perf(perf_id=19, count=1)
4834 : #else
4835 : MARK_USED(win)
4836 : #endif
4837 0 : CALL mp_timestop(handle)
4838 0 : END SUBROUTINE mp_win_unlock_all
4839 :
4840 : ! **************************************************************************************************
4841 : !> \brief Starts a timer region
4842 : !> \param routineN ...
4843 : !> \param handle ...
4844 : ! **************************************************************************************************
4845 426140790 : SUBROUTINE mp_timeset(routineN, handle)
4846 : CHARACTER(len=*), INTENT(IN) :: routineN
4847 : INTEGER, INTENT(OUT) :: handle
4848 :
4849 213189727 : handle = -1
4850 213189727 : IF (.NOT. mp_collect_timings) RETURN
4851 212951319 : IF (omp_get_thread_num() /= 0) RETURN
4852 212951063 : IF (omp_get_level() > 1) RETURN
4853 212951063 : CALL timeset(routineN, handle)
4854 : END SUBROUTINE mp_timeset
4855 :
4856 : ! **************************************************************************************************
4857 : !> \brief Ends a timer region
4858 : !> \param handle ...
4859 : ! **************************************************************************************************
4860 213189727 : SUBROUTINE mp_timestop(handle)
4861 : INTEGER, INTENT(IN) :: handle
4862 :
4863 213189727 : IF (handle >= 0) &
4864 212951063 : CALL timestop(handle)
4865 213189727 : END SUBROUTINE mp_timestop
4866 :
4867 : #:include 'message_passing.fypp'
4868 :
4869 123022344 : END MODULE message_passing
|