Yet Another eXchange Tool  DO_NOT_EDIT_HERE
ftest_common.f90
1 
12 
13 !
14 ! Maintainer: Jörg Behrens <behrens@dkrz.de>
15 ! Moritz Hanke <hanke@dkrz.de>
16 ! Thomas Jahns <jahns@dkrz.de>
17 ! URL: https://doc.redmine.dkrz.de/yaxt/html/
18 !
19 ! Redistribution and use in source and binary forms, with or without
20 ! modification, are permitted provided that the following conditions are
21 ! met:
22 !
23 ! Redistributions of source code must retain the above copyright notice,
24 ! this list of conditions and the following disclaimer.
25 !
26 ! Redistributions in binary form must reproduce the above copyright
27 ! notice, this list of conditions and the following disclaimer in the
28 ! documentation and/or other materials provided with the distribution.
29 !
30 ! Neither the name of the DKRZ GmbH nor the names of its contributors
31 ! may be used to endorse or promote products derived from this software
32 ! without specific prior written permission.
33 !
34 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35 ! IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 ! TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37 ! PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38 ! OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 ! EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 ! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41 ! PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 ! LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 ! NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 ! SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 !
46 MODULE ftest_common
47  USE mpi
48  USE xt_core, ONLY: i2, i4, i8
49  IMPLICIT NONE
50  PRIVATE
51  INTEGER, PUBLIC, PARAMETER :: dp = selected_real_kind(12, 307)
52 
53  TYPE timer
54  CHARACTER(len=20) :: label = 'undef'
55  INTEGER :: istate = -1
56  REAL(dp) :: t0 = 0.0_dp
57  REAL(dp) :: dt_work = 0.0_dp
58  END TYPE timer
59 
60  INTERFACE test_abort
61  MODULE PROCEDURE test_abort_cmsl_f
62  MODULE PROCEDURE test_abort_msl_f
63  END INTERFACE test_abort
64 
65  INTERFACE icmp
66  MODULE PROCEDURE icmp_2d
67  MODULE PROCEDURE icmp_3d
68  END INTERFACE icmp
69 
70  INTERFACE id_map
71  MODULE PROCEDURE id_map_i2, id_map_i4, id_map_i8
72  END INTERFACE id_map
73 
74  REAL(dp) :: sync_dt_sum = 0.0_dp
75  LOGICAL, PARAMETER :: debug = .false.
76  LOGICAL :: verbose = .false.
77 
78  PUBLIC :: init_mpi, finish_mpi
79  PUBLIC :: timer, treset, tstart, tstop, treport, mysync
80  PUBLIC :: id_map, icmp, factorize, regular_deco
81  PUBLIC :: test_abort, set_verbose, get_verbose
82 CONTAINS
83 
84  SUBROUTINE init_mpi
85  CHARACTER(len=*), PARAMETER :: context = 'init_mpi: '
86  INTEGER :: ierror
87  CALL mpi_init(ierror)
88  IF (ierror /= mpi_success) CALL test_abort(context//'MPI_INIT failed', &
89  __file__, __line__)
90  END SUBROUTINE init_mpi
91 
92  SUBROUTINE finish_mpi
93  CHARACTER(len=*), PARAMETER :: context = 'finish_mpi: '
94  INTEGER :: ierror
95  CALL mpi_finalize(ierror)
96  IF (ierror /= mpi_success) CALL test_abort(context//'MPI_FINALIZE failed', &
97  __file__, &
98  __line__)
99  END SUBROUTINE finish_mpi
100 
101  SUBROUTINE set_verbose(verb)
102  LOGICAL, INTENT(in) :: verb
103  verbose = verb
104  END SUBROUTINE set_verbose
105 
106  SUBROUTINE get_verbose(verb)
107  LOGICAL, INTENT(out) :: verb
108  verb = verbose
109  END SUBROUTINE get_verbose
110 
111  PURE SUBROUTINE treset(t, label)
112  TYPE(timer), INTENT(inout) :: t
113  CHARACTER(len=*), INTENT(in) :: label
114  t%label = label
115  t%istate = 0
116  t%t0 = 0.0_dp
117  t%dt_work = 0.0_dp
118  END SUBROUTINE treset
119 
120  SUBROUTINE tstart(t)
121  TYPE(timer), INTENT(inout) :: t
122  IF (debug) WRITE(0,*) 'tstart: ',t%label
123  CALL mysync
124  t%istate = 1
125  t%t0 = work_time()
126  END SUBROUTINE tstart
127 
128  SUBROUTINE tstop(t)
129  TYPE(timer), INTENT(inout) :: t
130  REAL(dp) :: t1
131  IF (debug) WRITE(0,*) 'tstop: ',t%label
132  t1 = work_time()
133  t%dt_work = t%dt_work + (t1 - t%t0)
134  t%istate = 0
135  CALL mysync
136 
137  END SUBROUTINE tstop
138 
139  SUBROUTINE treport(t,extra_label,comm)
140  TYPE(timer), INTENT(in) :: t
141  CHARACTER(len=*), INTENT(in) :: extra_label
142  INTEGER, INTENT(in) :: comm
143 
144  CHARACTER(len=*), PARAMETER :: context = 'treport: '
145  REAL(dp) :: work_sum, work_max, work_avg, e
146  REAL(dp) :: sbuf
147  REAL(dp), ALLOCATABLE :: rbuf(:)
148  INTEGER :: nprocs, rank, ierror
149 
150  sbuf = t%dt_work
151  CALL mpi_comm_rank(comm, rank, ierror)
152  IF (ierror /= mpi_success) &
153  CALL test_abort(context//'MPI_COMM_RANK failed', &
154  __file__, &
155  __line__)
156  CALL mpi_comm_size(comm, nprocs, ierror)
157  IF (ierror /= mpi_success) &
158  CALL test_abort(context//'MPI_COMM_RANK failed', &
159  __file__, &
160  __line__)
161  ALLOCATE(rbuf(0:nprocs-1))
162  rbuf = -1.0_dp
163  CALL mpi_gather(sbuf, 1, mpi_double_precision, &
164  & rbuf, 1, mpi_double_precision, &
165  & 0, comm, ierror)
166  IF (ierror /= mpi_success) CALL test_abort(context//'MPI_GATHER failed', &
167  __file__, &
168  __line__)
169 
170  IF (rank == 0) THEN
171  IF (rbuf(0) /= sbuf) CALL test_abort(context//'internal error (1)', &
172  __file__, &
173  __line__)
174  IF (any(rbuf < 0.0_dp)) CALL test_abort(context//'internal error (2)', &
175  __file__, &
176  __line__)
177  work_sum = sum(rbuf)
178  work_max = maxval(rbuf)
179  work_avg = work_sum / REAL(nprocs, dp)
180  e = work_avg / (work_max + 1.e-20_dp)
181 
182  IF (verbose) WRITE(0,'(A,I4,2X,A16,3F18.8)') &
183  'nprocs, label, wmax, wavg, e =', &
184  nprocs, extra_label//':'//t%label, &
185  work_max, work_avg, e
186  ENDIF
187 
188  END SUBROUTINE treport
189 
190  SUBROUTINE mysync
191  CHARACTER(len=*), PARAMETER :: context = 'mysync: '
192  INTEGER :: ierror
193  REAL(dp) :: t0, dt
194 
195  t0 = mpi_wtime()
196 
197  CALL mpi_barrier(mpi_comm_world, ierror)
198  IF (ierror /= mpi_success) CALL test_abort(context//'MPI_BARRIER failed', &
199  __file__, &
200  __line__)
201 
202  dt = (mpi_wtime() - t0)
203  sync_dt_sum = sync_dt_sum + dt
204 
205  END SUBROUTINE mysync
206 
207  REAL(dp) FUNCTION work_time()
208  work_time = mpi_wtime() - sync_dt_sum
209  RETURN
210  END FUNCTION work_time
211 
212  PURE SUBROUTINE id_map_i2(map)
213  INTEGER(i2), INTENT(out) :: map(:,:)
214 
215  INTEGER :: i, j, m, n
216 
217  m = SIZE(map, 1)
218  n = SIZE(map, 2)
219  DO j = 1, n
220  DO i = 1, m
221  map(i,j) = int((j - 1) * m + i, i2)
222  ENDDO
223  ENDDO
224 
225  END SUBROUTINE id_map_i2
226 
227  PURE SUBROUTINE id_map_i4(map)
228  INTEGER(i4), INTENT(out) :: map(:,:)
229 
230  INTEGER :: i, j, m, n
231 
232  m = SIZE(map, 1)
233  n = SIZE(map, 2)
234  DO j = 1, n
235  DO i = 1, m
236  map(i,j) = int((j - 1) * m + i, i4)
237  ENDDO
238  ENDDO
239 
240  END SUBROUTINE id_map_i4
241 
242  PURE SUBROUTINE id_map_i8(map)
243  INTEGER(i8), INTENT(out) :: map(:,:)
244 
245  INTEGER :: i, j, m, n
246 
247  m = SIZE(map, 1)
248  n = SIZE(map, 2)
249  DO j = 1, n
250  DO i = 1, m
251  map(i,j) = int((j - 1) * m + i, i8)
252  ENDDO
253  ENDDO
254 
255  END SUBROUTINE id_map_i8
256 
257  SUBROUTINE test_abort_msl_f(msg, source, line)
258  CHARACTER(*), INTENT(in) :: msg
259  CHARACTER(*), INTENT(in) :: source
260  INTEGER, VALUE, INTENT(in) :: line
261  CALL test_abort_cmsl_f(mpi_comm_world, msg, source, line)
262  END SUBROUTINE test_abort_msl_f
263 
264  SUBROUTINE test_abort_cmsl_f(comm, msg, source, line)
265  INTEGER, INTENT(in):: comm
266  CHARACTER(*), INTENT(in) :: msg
267  CHARACTER(*), INTENT(in) :: source
268  INTEGER, VALUE, INTENT(in) :: line
269 
270  INTERFACE
271  SUBROUTINE c_abort() bind(c, name='abort')
272  END SUBROUTINE c_abort
273  END INTERFACE
274 
275  INTEGER :: ierror
276  LOGICAL :: flag
277 
278  WRITE (0, '(3a,i0,2a)') 'Fatal error in ', source, ', line ', line, &
279  ': ', msg
280  FLUSH(0)
281  CALL mpi_initialized(flag, ierror)
282  IF (ierror == mpi_success .AND. flag) &
283  CALL mpi_abort(comm, 1, ierror)
284  CALL c_abort
285  END SUBROUTINE test_abort_cmsl_f
286 
287  SUBROUTINE icmp_2d(label, f,g, rank)
288  CHARACTER(len=*), PARAMETER :: context = 'ftest_common::icmp_2d: '
289  CHARACTER(len=*), INTENT(in) :: label
290  INTEGER, INTENT(in) :: f(:,:)
291  INTEGER, INTENT(in) :: g(:,:)
292  INTEGER, INTENT(in) :: rank
293 
294  INTEGER :: i, j, n1, n2
295 
296  n1 = SIZE(f,1)
297  n2 = SIZE(f,2)
298  IF (SIZE(g,1) /= n1 .OR. SIZE(g,2) /= n2) &
299  CALL test_abort(context//'shape mismatch error', &
300  __file__, &
301  __line__)
302 
303  DO j = 1, n2
304  DO i = 1, n1
305  IF (f(i,j) /= g(i,j)) THEN
306  WRITE(0,'(2a,4(a,i0))') context, label, ' test failed: i=', &
307  i, ', j=', j, ', f(i,j)=', f(i,j), ', g(i,j)=', g(i,j)
308  CALL test_abort(context//label//' test failed', &
309  __file__, &
310  __line__)
311  ENDIF
312  ENDDO
313  ENDDO
314  IF (verbose) WRITE(0,*) rank,':',context//label//' passed'
315  END SUBROUTINE icmp_2d
316 
317  SUBROUTINE icmp_3d(label, f,g, rank)
318  CHARACTER(len=*), PARAMETER :: context = 'ftest_common::icmp_3d: '
319  CHARACTER(len=*), INTENT(in) :: label
320  INTEGER, INTENT(in) :: f(:,:,:)
321  INTEGER, INTENT(in) :: g(:,:,:)
322  INTEGER, INTENT(in) :: rank
323 
324  INTEGER :: i1, i2, i3, n1, n2, n3
325 
326  n1 = SIZE(f,1)
327  n2 = SIZE(f,2)
328  n3 = SIZE(f,3)
329  IF (SIZE(g,1) /= n1 .OR. SIZE(g,2) /= n2 .OR. SIZE(g,3) /= n3) &
330  CALL test_abort(context//label//'shape mismatch', __file__, __line__)
331 
332  DO i3 = 1, n3
333  DO i2 = 1, n2
334  DO i1 = 1, n1
335  IF (f(i1,i2,i3) /= g(i1,i2,i3)) THEN
336  WRITE(0,*) context,label,&
337  ' test failed: i1, i2, i3, f(i1,i2,i3), g(i1,i2,i3) =', &
338  i1, i2, i3, f(i1,i2,i3), g(i1,i2,i3)
339  CALL test_abort(context//label//' test failed', &
340  __file__, &
341  __line__)
342  ENDIF
343  ENDDO
344  ENDDO
345  ENDDO
346  IF (verbose) WRITE(0,*) rank,':',context//label//' passed'
347  END SUBROUTINE icmp_3d
348 
349  SUBROUTINE factorize(c, a, b)
350  INTEGER, INTENT(in) :: c
351  INTEGER, INTENT(out) :: a, b ! c = a*b
352 
353  INTEGER :: x0, i
354 
355  IF (c<1) CALL test_abort('factorize: invalid process space', &
356  __file__, &
357  __line__)
358  IF (c <= 3 .OR. c == 5 .OR. c == 7) THEN
359  a = c
360  b = 1
361  RETURN
362  ENDIF
363 
364  ! simple approach, we try to be near c = (2*x) * x
365  x0 = int(sqrt(0.5 * REAL(c)) + 0.5)
366  a = 2*x0
367  f_loop: DO i = a, 1, -1
368  IF (mod(c,i) == 0) THEN
369  a = i
370  b = c/i
371  EXIT f_loop
372  ENDIF
373  ENDDO f_loop
374 
375  END SUBROUTINE factorize
376 
377  SUBROUTINE regular_deco(g_cn, c0, cn)
378  INTEGER, INTENT(in) :: g_cn
379  INTEGER, INTENT(out) :: c0(0:), cn(0:)
380 
381  ! convention: process space coords start at 0, grid point coords start at 1
382 
383  integer :: tn
384  INTEGER :: d, m
385  INTEGER :: it
386 
387  tn = SIZE(c0)
388  IF (tn<0) CALL test_abort('(tn<0)', __file__, __line__)
389  IF (tn>g_cn) CALL test_abort('regular_deco: too many task for such a core&
390  & region', &
391  __file__, &
392  __line__)
393 
394  d = g_cn/tn
395  m = mod(g_cn, tn)
396 
397  DO it = 0, m-1
398  cn(it) = d + 1
399  ENDDO
400  DO it = m, tn-1
401  cn(it) = d
402  ENDDO
403 
404  c0(0)=0
405  DO it = 1, tn-1
406  c0(it) = c0(it-1) + cn(it-1)
407  ENDDO
408  IF (c0(tn-1)+cn(tn-1) /= g_cn) &
409  CALL test_abort('regular_deco: internal error 1', &
410  __file__, &
411  __line__)
412  END SUBROUTINE regular_deco
413 
414 END MODULE ftest_common
415 !
416 ! Local Variables:
417 ! f90-continuation-indent: 5
418 ! coding: utf-8
419 ! indent-tabs-mode: nil
420 ! show-trailing-whitespace: t
421 ! require-trailing-newline: t
422 ! End:
423 !