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