FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
mpp_util.inc
1! -*-f90-*-
2
3
4!***********************************************************************
5!* GNU Lesser General Public License
6!*
7!* This file is part of the GFDL Flexible Modeling System (FMS).
8!*
9!* FMS is free software: you can redistribute it and/or modify it under
10!* the terms of the GNU Lesser General Public License as published by
11!* the Free Software Foundation, either version 3 of the License, or (at
12!* your option) any later version.
13!*
14!* FMS is distributed in the hope that it will be useful, but WITHOUT
15!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17!* for more details.
18!*
19!* You should have received a copy of the GNU Lesser General Public
20!* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
21!***********************************************************************
22!> @file
23!> @brief General utility functions for use in @ref mpp_mod
24
25!> @addtogroup mpp_mod
26!> @{
27
28#if defined(use_libMPI)
29#include <mpp_util_mpi.inc>
30#else
31#include <mpp_util_nocomm.inc>
32#endif
33
34 !> @brief This function returns the current standard fortran unit numbers for input.
35 function stdin()
36 integer :: stdin
37 stdin = in_unit
38 return
39 end function stdin
40
41 !> @brief This function returns the current standard fortran unit numbers for output.
42 function stdout()
43 integer :: stdout
44 stdout = out_unit
45 if( pe.NE.root_pe )stdout = stdlog()
46 return
47 end function stdout
48
49 !> @brief This function returns the current standard fortran unit numbers for error messages.
50 function stderr()
51 integer :: stderr
52 stderr = err_unit
53 return
54 end function stderr
55
56 !> @brief This function returns the current standard fortran unit numbers for log messages.
57 !! Log messages, by convention, are written to the file <TT>logfile.out</TT>.
58 function stdlog()
59 integer :: stdlog
60 logical :: opened
61 character(len=11) :: this_pe
62!$ logical :: omp_in_parallel
63!$ integer :: omp_get_num_threads
64!$ integer :: errunit
65
66
67!NOTES: We can not use mpp_error to handle the error because mpp_error
68! will call stdout and stdout will call stdlog for non-root-pe.
69! This will be a cicular call.
70
71!$ if( omp_in_parallel() .and. (omp_get_num_threads() > 1) ) then
72!$OMP single
73!$ errunit = stderr()
74!$ write( errunit,'(/a/)' ) 'FATAL: STDLOG: is called inside a OMP parallel region'
75#ifdef use_libMPI
76!$ call MPI_ABORT( MPI_COMM_WORLD, 1, error )
77#else
78!$ call ABORT()
79#endif
80!$OMP end single
81!$ endif
82
83 if( pe.EQ.root_pe )then
84 write(this_pe,'(a,i6.6,a)') '.',pe,'.out'
85 inquire( file=trim(configfile)//this_pe, opened=opened )
86 if( opened )then
87 FLUSH(log_unit)
88 else
89 open(newunit=log_unit, status='UNKNOWN', file=trim(configfile)//this_pe, position='APPEND', err=10 )
90 end if
91 stdlog = log_unit
92 else
93 inquire(unit=etc_unit, opened=opened )
94 if( opened )then
95 FLUSH(etc_unit)
96 else
97 open(newunit=etc_unit, status='UNKNOWN', file=trim(etcfile), position='APPEND', err=11 )
98 end if
99 stdlog = etc_unit
100 end if
101 return
10210 call mpp_error( fatal, 'STDLOG: unable to open '//trim(configfile)//this_pe//'.' )
10311 call mpp_error( fatal, 'STDLOG: unable to open '//trim(etcfile)//'.' )
104 end function stdlog
105
106 !#####################################################################
107 subroutine mpp_init_logfile()
108 integer :: p
109 logical :: exist
110 character(len=11) :: this_pe
111 if( pe.EQ.root_pe )then
112 do p=0,npes-1
113 write(this_pe,'(a,i6.6,a)') '.',p,'.out'
114 inquire( file=trim(configfile)//this_pe, exist=exist )
115 if(exist)then
116 open(newunit=log_unit, file=trim(configfile)//this_pe, status='REPLACE' )
117 close(log_unit)
118 endif
119 end do
120 end if
121 end subroutine mpp_init_logfile
122
123 !> Opens the warning log file, called during mpp_init
124 subroutine mpp_init_warninglog()
125 logical :: exist
126 character(len=11) :: this_pe
127 if( pe.EQ.root_pe )then
128 write(this_pe,'(a,i6.6,a)') '.',pe,'.out'
129 inquire( file=trim(warnfile)//this_pe, exist=exist )
130 if(exist)then
131 open(newunit=warn_unit, file=trim(warnfile)//this_pe, status='REPLACE' )
132 else
133 open(newunit=warn_unit, file=trim(warnfile)//this_pe, status='NEW' )
134 endif
135 end if
136 end subroutine mpp_init_warninglog
137
138 !> @brief This function returns unit number for the warning log
139 !! if on the root pe, otherwise returns the etc_unit value (usually /dev/null)
140 function warnlog()
141 integer :: warnlog
142 if(.not. module_is_initialized) call mpp_error(fatal, "mpp_mod: warnlog cannot be called before mpp_init")
143 if(root_pe .eq. pe) then
144 warnlog = warn_unit
145 else
146 warnlog = etc_unit
147 endif
148 return
149 end function warnlog
150
151 !#####################################################################
152 subroutine mpp_set_warn_level(flag)
153 integer, intent(in) :: flag
154
155 if( flag.EQ.warning )then
156 warnings_are_fatal = .false.
157 else if( flag.EQ.fatal )then
158 warnings_are_fatal = .true.
159 else
160 call mpp_error( fatal, 'MPP_SET_WARN_LEVEL: warning flag must be set to WARNING or FATAL.' )
161 end if
162 return
163 end subroutine mpp_set_warn_level
164
165 !#####################################################################
166 function mpp_error_state()
167 integer :: mpp_error_state
168 mpp_error_state = error_state
169 return
170 end function mpp_error_state
171
172!#####################################################################
173!> @brief overloads to mpp_error_basic, support for error_mesg routine in FMS
174subroutine mpp_error_mesg( routine, errormsg, errortype )
175 character(len=*), intent(in) :: routine, errormsg
176 integer, intent(in) :: errortype
177
178 call mpp_error( errortype, trim(routine)//': '//trim(errormsg) )
179 return
180end subroutine mpp_error_mesg
181
182!#####################################################################
183subroutine mpp_error_noargs()
184 call mpp_error(fatal)
185end subroutine mpp_error_noargs
186
187!#####################################################################
188subroutine mpp_error_is(errortype, errormsg1, mpp_ival, errormsg2)
189 integer, intent(in) :: errortype
190 INTEGER, intent(in) :: mpp_ival
191 character(len=*), intent(in) :: errormsg1
192 character(len=*), intent(in), optional :: errormsg2
193 call mpp_error( errortype, errormsg1, (/mpp_ival/), errormsg2)
194end subroutine mpp_error_is
195!#####################################################################
196subroutine mpp_error_rs(errortype, errormsg1, mpp_rval, errormsg2)
197 integer, intent(in) :: errortype
198 REAL, intent(in) :: mpp_rval
199 character(len=*), intent(in) :: errormsg1
200 character(len=*), intent(in), optional :: errormsg2
201 call mpp_error( errortype, errormsg1, (/mpp_rval/), errormsg2)
202end subroutine mpp_error_rs
203!#####################################################################
204subroutine mpp_error_ia(errortype, errormsg1, array, errormsg2)
205 integer, intent(in) :: errortype
206 INTEGER, dimension(:), intent(in) :: array
207 character(len=*), intent(in) :: errormsg1
208 character(len=*), intent(in), optional :: errormsg2
209 character(len=512) :: string
210
211 string = errormsg1//trim(array_to_char(array))
212 if(present(errormsg2)) string = trim(string)//errormsg2
213 call mpp_error_basic( errortype, trim(string))
214
215end subroutine mpp_error_ia
216
217!#####################################################################
218subroutine mpp_error_ra(errortype, errormsg1, array, errormsg2)
219 integer, intent(in) :: errortype
220 REAL, dimension(:), intent(in) :: array
221 character(len=*), intent(in) :: errormsg1
222 character(len=*), intent(in), optional :: errormsg2
223 character(len=512) :: string
224
225 string = errormsg1//trim(array_to_char(array))
226 if(present(errormsg2)) string = trim(string)//errormsg2
227 call mpp_error_basic( errortype, trim(string))
228
229end subroutine mpp_error_ra
230
231!#####################################################################
232#define _SUBNAME_ mpp_error_ia_ia
233#define _ARRAY1TYPE_ integer
234#define _ARRAY2TYPE_ integer
235#include <mpp_error_a_a.fh>
236#undef _SUBNAME_
237#undef _ARRAY1TYPE_
238#undef _ARRAY2TYPE_
239!#####################################################################
240#define _SUBNAME_ mpp_error_ia_ra
241#define _ARRAY1TYPE_ integer
242#define _ARRAY2TYPE_ real
243#include <mpp_error_a_a.fh>
244#undef _SUBNAME_
245#undef _ARRAY1TYPE_
246#undef _ARRAY2TYPE_
247!#####################################################################
248#define _SUBNAME_ mpp_error_ra_ia
249#define _ARRAY1TYPE_ real
250#define _ARRAY2TYPE_ integer
251#include <mpp_error_a_a.fh>
252#undef _SUBNAME_
253#undef _ARRAY1TYPE_
254#undef _ARRAY2TYPE_
255!#####################################################################
256#define _SUBNAME_ mpp_error_ra_ra
257#define _ARRAY1TYPE_ real
258#define _ARRAY2TYPE_ real
259#include <mpp_error_a_a.fh>
260#undef _SUBNAME_
261#undef _ARRAY1TYPE_
262#undef _ARRAY2TYPE_
263!#####################################################################
264#define _SUBNAME_ mpp_error_ia_is
265#define _ARRAY1TYPE_ integer
266#define _ARRAY2TYPE_ integer
267#include <mpp_error_a_s.fh>
268#undef _SUBNAME_
269#undef _ARRAY1TYPE_
270#undef _ARRAY2TYPE_
271!#####################################################################
272#define _SUBNAME_ mpp_error_ia_rs
273#define _ARRAY1TYPE_ integer
274#define _ARRAY2TYPE_ real
275#include <mpp_error_a_s.fh>
276#undef _SUBNAME_
277#undef _ARRAY1TYPE_
278#undef _ARRAY2TYPE_
279!#####################################################################
280#define _SUBNAME_ mpp_error_ra_is
281#define _ARRAY1TYPE_ real
282#define _ARRAY2TYPE_ integer
283#include <mpp_error_a_s.fh>
284#undef _SUBNAME_
285#undef _ARRAY1TYPE_
286#undef _ARRAY2TYPE_
287!#####################################################################
288#define _SUBNAME_ mpp_error_ra_rs
289#define _ARRAY1TYPE_ real
290#define _ARRAY2TYPE_ real
291#include <mpp_error_a_s.fh>
292#undef _SUBNAME_
293#undef _ARRAY1TYPE_
294#undef _ARRAY2TYPE_
295!#####################################################################
296#define _SUBNAME_ mpp_error_is_ia
297#define _ARRAY1TYPE_ integer
298#define _ARRAY2TYPE_ integer
299#include <mpp_error_s_a.fh>
300#undef _SUBNAME_
301#undef _ARRAY1TYPE_
302#undef _ARRAY2TYPE_
303!#####################################################################
304#define _SUBNAME_ mpp_error_is_ra
305#define _ARRAY1TYPE_ integer
306#define _ARRAY2TYPE_ real
307#include <mpp_error_s_a.fh>
308#undef _SUBNAME_
309#undef _ARRAY1TYPE_
310#undef _ARRAY2TYPE_
311!#####################################################################
312#define _SUBNAME_ mpp_error_rs_ia
313#define _ARRAY1TYPE_ real
314#define _ARRAY2TYPE_ integer
315#include <mpp_error_s_a.fh>
316#undef _SUBNAME_
317#undef _ARRAY1TYPE_
318#undef _ARRAY2TYPE_
319!#####################################################################
320#define _SUBNAME_ mpp_error_rs_ra
321#define _ARRAY1TYPE_ real
322#define _ARRAY2TYPE_ real
323#include <mpp_error_s_a.fh>
324#undef _SUBNAME_
325#undef _ARRAY1TYPE_
326#undef _ARRAY2TYPE_
327!#####################################################################
328#define _SUBNAME_ mpp_error_is_is
329#define _ARRAY1TYPE_ integer
330#define _ARRAY2TYPE_ integer
331#include <mpp_error_s_s.fh>
332#undef _SUBNAME_
333#undef _ARRAY1TYPE_
334#undef _ARRAY2TYPE_
335!#####################################################################
336#define _SUBNAME_ mpp_error_is_rs
337#define _ARRAY1TYPE_ integer
338#define _ARRAY2TYPE_ real
339#include <mpp_error_s_s.fh>
340#undef _SUBNAME_
341#undef _ARRAY1TYPE_
342#undef _ARRAY2TYPE_
343!#####################################################################
344#define _SUBNAME_ mpp_error_rs_is
345#define _ARRAY1TYPE_ real
346#define _ARRAY2TYPE_ integer
347#include <mpp_error_s_s.fh>
348#undef _SUBNAME_
349#undef _ARRAY1TYPE_
350#undef _ARRAY2TYPE_
351!#####################################################################
352#define _SUBNAME_ mpp_error_rs_rs
353#define _ARRAY1TYPE_ real
354#define _ARRAY2TYPE_ real
355#include <mpp_error_s_s.fh>
356#undef _SUBNAME_
357#undef _ARRAY1TYPE_
358#undef _ARRAY2TYPE_
359!#####################################################################
360function iarray_to_char(iarray) result(string)
361integer, intent(in) :: iarray(:)
362character(len=256) :: string
363character(len=32) :: chtmp
364integer :: i, len_tmp, len_string
365
366 string = ''
367 do i=1,size(iarray)
368 write(chtmp,'(i16)') iarray(i)
369 chtmp = adjustl(chtmp)
370 len_tmp = len_trim(chtmp)
371 len_string = len_trim(string)
372 string(len_string+1:len_string+len_tmp) = trim(chtmp)
373 string(len_string+len_tmp+1:len_string+len_tmp+1) = ','
374 enddo
375 len_string = len_trim(string)
376 string(len_string:len_string) = ' ' ! remove trailing comma
377
378end function iarray_to_char
379!#####################################################################
380function rarray_to_char(rarray) result(string)
381real, intent(in) :: rarray(:)
382character(len=256) :: string
383character(len=32) :: chtmp
384integer :: i, len_tmp, len_string
385
386 string = ''
387 do i=1,size(rarray)
388 write(chtmp,'(G16.9)') rarray(i)
389 chtmp = adjustl(chtmp)
390 len_tmp = len_trim(chtmp)
391 len_string = len_trim(string)
392 string(len_string+1:len_string+len_tmp) = trim(chtmp)
393 string(len_string+len_tmp+1:len_string+len_tmp+1) = ','
394 enddo
395 len_string = len_trim(string)
396 string(len_string:len_string) = ' ' ! remove trailing comma
397
398end function rarray_to_char
399
400 !> @brief Returns processor ID.
401 !!
402 !> This returns the unique ID associated with a PE. This number runs
403 !! between 0 and <TT>npes-1</TT>, where <TT>npes</TT> is the total
404 !! processor count, returned by <TT>mpp_npes</TT>. For a uniprocessor
405 !! application this will always return 0.
406 function mpp_pe()
407 integer :: mpp_pe
408
409 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_PE: You must first call mpp_init.' )
410 mpp_pe = pe
411 return
412 end function mpp_pe
413
414 !#####################################################################
415
416 !> @brief Returns processor count for current pelist
417 !!
418 !> This returns the number of PEs in the current pelist. For a uniprocessor application,
419 !! it will always return 1.
420 function mpp_npes()
421 integer :: mpp_npes
422
423 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_NPES: You must first call mpp_init.' )
424 mpp_npes = size(peset(current_peset_num)%list(:))
425 return
426 end function mpp_npes
427
428 !#####################################################################
429 function mpp_root_pe()
430 integer :: mpp_root_pe
431
432 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_ROOT_PE: You must first call mpp_init.' )
433 mpp_root_pe = root_pe
434 return
435 end function mpp_root_pe
436
437 !#####################################################################
438 subroutine mpp_set_root_pe(num)
439 integer, intent(in) :: num
440
441 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_SET_ROOT_PE: You must first call mpp_init.' )
442 if( .NOT.(any(num.EQ.peset(current_peset_num)%list(:))) ) &
443 call mpp_error( fatal, 'MPP_SET_ROOT_PE: you cannot set a root PE outside the current pelist.' )
444 root_pe = num
445 return
446 end subroutine mpp_set_root_pe
447
448 !> @brief Declare a pelist.
449 !!
450 !> This call is written specifically to accommodate a MPI restriction
451 !! that requires a parent communicator to create a child communicator, In
452 !! other words: a pelist cannot go off and declare a communicator, but
453 !! every PE in the parent, including those not in pelist(:), must get
454 !! together for the <TT>MPI_COMM_CREATE</TT> call. The parent is
455 !! typically <TT>MPI_COMM_WORLD</TT>, though it could also be a subset
456 !! that includes all PEs in <TT>pelist</TT>.
457 !!
458 !! This call implies synchronization across the PEs in the current
459 !! pelist, of which <TT>pelist</TT> is a subset.
460 subroutine mpp_declare_pelist( pelist, name, commID )
461 integer, intent(in) :: pelist(:) !> pelist you are declaring and storing within FMS
462 character(len=*), intent(in), optional :: name !> unique name for an input pelist
463 integer, intent(out), optional :: commID !> return of current MPI comm group communicator ID
464 integer :: i
465
466 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_DECLARE_PELIST: You must first call mpp_init.' )
467 i = get_peset(pelist)
468 write( peset(i)%name,'(a,i2.2)' ) 'PElist', i !default name
469 if( PRESENT(name) )peset(i)%name = name
470 if( PRESENT(commid) )commid = peset(i)%id
471
472 return
473 end subroutine mpp_declare_pelist
474
475 !#####################################################################
476
477 !> @brief Set context pelist
478 !!
479 !! This call sets the value of the current pelist, which is the
480 !! context for all subsequent "global" calls where the optional
481 !! <TT>pelist</TT> argument is omitted. All the PEs that are to be in the
482 !! current pelist must call it.
483 !!
484 !! In MPI, this call may hang unless <TT>pelist</TT> has been previous
485 !! declared using @ref mpp_declare_pelist
486 !!
487 !! If the argument <TT>pelist</TT> is absent, the current pelist is
488 !! set to the "world" pelist, of all PEs in the job.
489 subroutine mpp_set_current_pelist( pelist, no_sync )
490 !Once we branch off into a PE subset, we want subsequent "global" calls to
491 !sync only across this subset. This is declared as the current pelist (peset(current_peset_num)%list)
492 !when current_peset all pelist ops with no pelist should apply the current pelist.
493 !also, we set the start PE in this pelist to be the root_pe.
494 !unlike mpp_declare_pelist, this is called by the PEs in the pelist only
495 !so if the PEset has not been previously declared, this will hang in MPI.
496 !if pelist is omitted, we reset pelist to the world pelist.
497 integer, intent(in), optional :: pelist(:)
498 logical, intent(in), optional :: no_sync
499
500 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_SET_CURRENT_PELIST: You must first call mpp_init.' )
501 if( PRESENT(pelist) )then
502 if( .NOT.any(pe.EQ.pelist) )call mpp_error( fatal, 'MPP_SET_CURRENT_PELIST: pe must be in pelist.' )
503 current_peset_num = get_peset(pelist)
504 else
505 current_peset_num = world_peset_num
506 end if
507 call mpp_set_root_pe( minval(peset(current_peset_num)%list(:)) )
508 if(.not.PRESENT(no_sync))call mpp_sync() !this is called to make sure everyone in the current pelist is here.
509 ! npes = mpp_npes()
510 return
511 end subroutine mpp_set_current_pelist
512
513 !#####################################################################
514 function mpp_get_current_pelist_name()
515 ! Simply return the current pelist name
516 character(len=len(peset(current_peset_num)%name)) :: mpp_get_current_pelist_name
517
518 mpp_get_current_pelist_name = peset(current_peset_num)%name
519 end function mpp_get_current_pelist_name
520
521 !#####################################################################
522 !this is created for use by mpp_define_domains within a pelist
523 !will be published but not publicized
524 subroutine mpp_get_current_pelist( pelist, name, commID )
525 integer, intent(out) :: pelist(:)
526 character(len=*), intent(out), optional :: name
527 integer, intent(out), optional :: commID
528
529 if( size(pelist(:)).NE.size(peset(current_peset_num)%list(:)) ) &
530 call mpp_error( fatal, 'MPP_GET_CURRENT_PELIST: size(pelist) is wrong.' )
531 pelist(:) = peset(current_peset_num)%list(:)
532 if( PRESENT(name) )name = peset(current_peset_num)%name
533#ifdef use_libMPI
534 if( PRESENT(commid) )commid = peset(current_peset_num)%id
535#endif
536
537 return
538 end subroutine mpp_get_current_pelist
539
540!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
541 ! !
542 ! PERFORMANCE PROFILING CALLS !
543 ! !
544!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
545!predefined clock granularities, but you can use any integer!using CLOCK_LOOP and above may distort coarser-grain measurements
546 !> @brief Set the level of granularity of timing measurements.
547 !!
548 !> This routine and three other routines, mpp_clock_id, mpp_clock_begin(id),
549 !! and mpp_clock_end(id) may be used to time parallel code sections, and
550 !! extract parallel statistics. Clocks are identified by names, which
551 !! should be unique in the first 32 characters. The <TT>mpp_clock_id</TT>
552 !! call initializes a clock of a given name and returns an integer
553 !! <TT>id</TT>. This <TT>id</TT> can be used by subsequent
554 !! <TT>mpp_clock_begin</TT> and <TT>mpp_clock_end</TT> calls set around a
555 !! code section to be timed. Example:
556 !! <PRE>
557 !! integer :: id
558 !! id = mpp_clock_id( 'Atmosphere' )
559 !! call mpp_clock_begin(id)
560 !! call atmos_model()
561 !! call mpp_clock_end()
562 !! </PRE>
563 !! Two flags may be used to alter the behaviour of
564 !! <TT>mpp_clock</TT>. If the flag <TT>MPP_CLOCK_SYNC</TT> is turned on
565 !! by <TT>mpp_clock_id</TT>, the clock calls <TT>mpp_sync</TT> across all
566 !! the PEs in the current pelist at the top of the timed code section,
567 !! but allows each PE to complete the code section (and reach
568 !! <TT>mpp_clock_end</TT>) at different times. This allows us to measure
569 !! load imbalance for a given code section. Statistics are written to
570 !! <TT>stdout</TT> by <TT>mpp_exit</TT>.
571 !!
572 !! The flag <TT>MPP_CLOCK_DETAILED</TT> may be turned on by
573 !! <TT>mpp_clock_id</TT> to get detailed communication
574 !! profiles. Communication events of the types <TT>SEND, RECV, BROADCAST,
575 !! REDUCE</TT> and <TT>WAIT</TT> are separately measured for data volume
576 !! and time. Statistics are written to <TT>stdout</TT> by
577 !! <TT>mpp_exit</TT>, and individual PE info is also written to the file
578 !! <TT>mpp_clock.out.####</TT> where <TT>####</TT> is the PE id given by
579 !! <TT>mpp_pe</TT>.
580 !!
581 !! The flags <TT>MPP_CLOCK_SYNC</TT> and <TT>MPP_CLOCK_DETAILED</TT> are
582 !! integer parameters available by use association, and may be summed to
583 !! turn them both on.
584 !!
585 !! While the nesting of clocks is allowed, please note that turning on
586 !! the non-optional flags on inner clocks has certain subtle issues.
587 !! Turning on <TT>MPP_CLOCK_SYNC</TT> on an inner
588 !! clock may distort outer clock measurements of load imbalance. Turning
589 !! on <TT>MPP_CLOCK_DETAILED</TT> will stop detailed measurements on its
590 !! outer clock, since only one detailed clock may be active at one time.
591 !! Also, detailed clocks only time a certain number of events per clock
592 !! (currently 40000) to conserve memory. If this array overflows, a
593 !! warning message is printed, and subsequent events for this clock are
594 !! not timed.
595 !!
596 !! Timings are done using the <TT>f90</TT> standard
597 !! <TT>SYSTEM_CLOCK</TT> intrinsic.
598 !!
599 !! The resolution of SYSTEM_CLOCK is often too coarse for use except
600 !! across large swaths of code. On SGI systems this is transparently
601 !! overloaded with a higher resolution clock made available in a
602 !! non-portable fortran interface made available by
603 !! <TT>nsclock.c</TT>. This approach will eventually be extended to other
604 !! platforms.
605 !!
606 !! New behaviour added at the Havana release allows the user to embed
607 !! profiling calls at varying levels of granularity all over the code,
608 !! and for any particular run, set a threshold of granularity so that
609 !! finer-grained clocks become dormant.
610 !!
611 !! The threshold granularity is held in the private module variable
612 !! <TT>clock_grain</TT>. This value may be modified by the call
613 !! <TT>mpp_clock_set_grain</TT>, and affect clocks initiated by
614 !! subsequent calls to <TT>mpp_clock_id</TT>. The value of
615 !! <TT>clock_grain</TT> is set to an arbitrarily large number initially.
616 !!
617 !! Clocks initialized by <TT>mpp_clock_id</TT> can set a new optional
618 !! argument <TT>grain</TT> setting their granularity level. Clocks check
619 !! this level against the current value of <TT>clock_grain</TT>, and are
620 !! only triggered if they are <I>at or below ("coarser than")</I> the
621 !! threshold. Finer-grained clocks are dormant for that run.
622 !!
623 !!The following grain levels are pre-defined:
624 !!
625 !!<pre>
626 !!
627 !!
628 !! integer, parameter, public :: CLOCK_COMPONENT=1 !component level, e.g model, exchange
629 !! integer, parameter, public :: CLOCK_SUBCOMPONENT=11 !top level within a model component, e.g dynamics, physics
630 !! integer, parameter, public :: CLOCK_MODULE=21 !module level, e.g main subroutine of a physics module
631 !! integer, parameter, public :: CLOCK_ROUTINE=31 !level of individual subroutine or function
632 !! integer, parameter, public :: CLOCK_LOOP=41 !loops or blocks within a routine
633 !! integer, parameter, public :: CLOCK_INFRA=51 !infrastructure level, e.g halo update
634 !!</pre>
635 !!
636 !! Note that subsequent changes to <TT>clock_grain</TT> do not
637 !! change the status of already initiated clocks, and that if the
638 !! optional <TT>grain</TT> argument is absent, the clock is always
639 !! triggered. This guarantees backward compatibility.
640 subroutine mpp_clock_set_grain( grain )
641 integer, intent(in) :: grain
642 !set the granularity of times: only clocks whose grain is lower than
643 !clock_grain are triggered, finer-grained clocks are dormant.
644 !clock_grain is initialized to CLOCK_LOOP, so all clocks above the loop level
645 !are triggered if this is never called.
646 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_CLOCK_SET_GRAIN: You must first call mpp_init.' )
647
648 clock_grain = grain
649 return
650 end subroutine mpp_clock_set_grain
651
652 !#####################################################################
653 subroutine clock_init( id, name, flags, grain )
654 integer, intent(in) :: id
655 character(len=*), intent(in) :: name
656 integer, intent(in), optional :: flags, grain
657 integer :: i
658
659 clocks(id)%name = name
660 clocks(id)%hits = 0
661 clocks(id)%tick = 0
662 clocks(id)%total_ticks = 0
663 clocks(id)%sync_on_begin = .false.
664 clocks(id)%detailed = .false.
665 clocks(id)%peset_num = current_peset_num
666 if( PRESENT(flags) )then
667 if( btest(flags,0) )clocks(id)%sync_on_begin = .true.
668 if( btest(flags,1) )clocks(id)%detailed = .true.
669 end if
670 clocks(id)%grain = 0
671 if( PRESENT(grain) )clocks(id)%grain = grain
672 if( clocks(id)%detailed )then
673 allocate( clocks(id)%events(max_event_types) )
674 clocks(id)%events(event_allreduce)%name = 'ALLREDUCE'
675 clocks(id)%events(event_broadcast)%name = 'BROADCAST'
676 clocks(id)%events(event_recv)%name = 'RECV'
677 clocks(id)%events(event_send)%name = 'SEND'
678 clocks(id)%events(event_wait)%name = 'WAIT'
679 do i=1,max_event_types
680 clocks(id)%events(i)%ticks(:) = 0
681 clocks(id)%events(i)%bytes(:) = 0
682 clocks(id)%events(i)%calls = 0
683 end do
684 clock_summary(id)%name = name
685 clock_summary(id)%event(event_allreduce)%name = 'ALLREDUCE'
686 clock_summary(id)%event(event_broadcast)%name = 'BROADCAST'
687 clock_summary(id)%event(event_recv)%name = 'RECV'
688 clock_summary(id)%event(event_send)%name = 'SEND'
689 clock_summary(id)%event(event_wait)%name = 'WAIT'
690 do i=1,max_event_types
691 clock_summary(id)%event(i)%msg_size_sums(:) = 0.0
692 clock_summary(id)%event(i)%msg_time_sums(:) = 0.0
693 clock_summary(id)%event(i)%total_data = 0.0
694 clock_summary(id)%event(i)%total_time = 0.0
695 clock_summary(id)%event(i)%msg_size_cnts(:) = 0
696 clock_summary(id)%event(i)%total_cnts = 0
697 end do
698 end if
699 return
700 end subroutine clock_init
701
702 !#####################################################################
703 !> Return an ID for a new or existing clock
704 function mpp_clock_id( name, flags, grain )
705 integer :: mpp_clock_id
706 character(len=*), intent(in) :: name
707 integer, intent(in), optional :: flags, grain
708
709 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_CLOCK_ID: You must first call mpp_init.')
710
711 !if grain is present, the clock is only triggered if it
712 !is low ("coarse") enough: compared to clock_grain
713 !finer-grained clocks are dormant.
714 !if grain is absent, clock is triggered.
715 if( PRESENT(grain) )then
716 if( grain.GT.clock_grain )then
717 mpp_clock_id = 0
718 return
719 end if
720 end if
721 mpp_clock_id = 1
722
723 if( clock_num.EQ.0 )then !first
724 clock_num = mpp_clock_id
725 call clock_init(mpp_clock_id,name,flags)
726 else
727 find_clock: do while( trim(name).NE.trim(clocks(mpp_clock_id)%name) )
728 mpp_clock_id = mpp_clock_id + 1
729 if( mpp_clock_id.GT.clock_num )then
730 if( mpp_clock_id.GT.max_clocks )then
731 call mpp_error( fatal, 'MPP_CLOCK_ID: too many clock requests, ' // &
732 'check your clock id request or increase MAX_CLOCKS.')
733 else !new clock: initialize
734 clock_num = mpp_clock_id
735 call clock_init(mpp_clock_id,name,flags,grain)
736 exit find_clock
737 end if
738 end if
739 end do find_clock
740 endif
741 return
742 end function mpp_clock_id
743
744 !#####################################################################
745 subroutine mpp_clock_begin(id)
746 integer, intent(in) :: id
747
748 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_CLOCK_BEGIN: You must first call mpp_init.' )
749 if( .not. mpp_record_timing_data)return
750 if( id.EQ.0 )return
751 if( id.LT.0 .OR. id.GT.clock_num )call mpp_error( fatal, 'MPP_CLOCK_BEGIN: invalid id.' )
752
753!$OMP MASTER
754 if( clocks(id)%peset_num.NE.current_peset_num ) &
755 call mpp_error( fatal, 'MPP_CLOCK_BEGIN: cannot change pelist context of a clock.' )
756 if( clocks(id)%is_on) call mpp_error(fatal, 'MPP_CLOCK_BEGIN: mpp_clock_begin is called again '// &
757 'before calling mpp_clock_end for the clock '//trim(clocks(id)%name) )
758 if( clocks(id)%sync_on_begin .OR. sync_all_clocks )then
759 !do an untimed sync at the beginning of the clock
760 !this puts all PEs in the current pelist on par, so that measurements begin together
761 !ending time will be different, thus measuring load imbalance for this clock.
762 call mpp_sync()
763 end if
764
765 if (debug) then
766 num_clock_ids = num_clock_ids+1
767 if(num_clock_ids > max_clocks)call mpp_error(fatal,'MPP_CLOCK_BEGIN: max num previous_clock exceeded.' )
768 previous_clock(num_clock_ids) = current_clock
769 current_clock = id
770 endif
771 call system_clock( clocks(id)%tick )
772 clocks(id)%hits = clocks(id)%hits + 1
773 clocks(id)%is_on = .true.
774!$OMP END MASTER
775 return
776 end subroutine mpp_clock_begin
777
778 !#####################################################################
779 subroutine mpp_clock_end(id)
780 integer, intent(in) :: id
781 integer(i8_kind) :: delta
782 integer :: errunit
783
784 if( .NOT.module_is_initialized )call mpp_error( fatal, 'MPP_CLOCK_END: You must first call mpp_init.' )
785 if( .not. mpp_record_timing_data)return
786 if( id.EQ.0 )return
787 if( id.LT.0 .OR. id.GT.clock_num )call mpp_error( fatal, 'MPP_CLOCK_BEGIN: invalid id.' )
788!$OMP MASTER
789 if( .NOT. clocks(id)%is_on) call mpp_error(fatal, 'MPP_CLOCK_END: mpp_clock_end is called '// &
790 'before calling mpp_clock_begin for the clock '//trim(clocks(id)%name) )
791
792 call system_clock(end_tick)
793 if( clocks(id)%peset_num.NE.current_peset_num ) &
794 call mpp_error( fatal, 'MPP_CLOCK_END: cannot change pelist context of a clock.' )
795 delta = end_tick - clocks(id)%tick
796 if( delta.LT.0 )then
797 errunit = stderr()
798 write( errunit,* )'pe, id, start_tick, end_tick, delta, max_ticks=', pe, id, clocks(id)%tick, end_tick, &
799 & delta, max_ticks
800 delta = delta + max_ticks + 1
801 call mpp_error( warning, 'MPP_CLOCK_END: Clock rollover, assumed single roll.' )
802 end if
803 clocks(id)%total_ticks = clocks(id)%total_ticks + delta
804 if (debug) then
805 if(num_clock_ids < 1) call mpp_error(note,'MPP_CLOCK_END: min num previous_clock < 1.' )
806 current_clock = previous_clock(num_clock_ids)
807 num_clock_ids = num_clock_ids-1
808 endif
809 clocks(id)%is_on = .false.
810!$OMP END MASTER
811 return
812 end subroutine mpp_clock_end
813
814 !#####################################################################
815 subroutine mpp_record_time_start()
816
817 mpp_record_timing_data = .true.
818
819 end subroutine mpp_record_time_start
820
821 !#####################################################################
822 subroutine mpp_record_time_end()
823
824 mpp_record_timing_data = .false.
825
826 end subroutine mpp_record_time_end
827
828
829 !#####################################################################
830 subroutine increment_current_clock( event_id, bytes )
831 integer, intent(in) :: event_id
832 integer, intent(in), optional :: bytes
833 integer :: n
834 integer(i8_kind) :: delta
835 integer :: errunit
836
837 if( .not. mpp_record_timing_data )return
838 if( .not.debug .or. (current_clock.EQ.0) )return
839 if( current_clock.LT.0 .OR. current_clock.GT.clock_num )call mpp_error( fatal, &
840 & 'MPP_CLOCK_BEGIN: invalid current_clock.' )
841 if( .NOT.clocks(current_clock)%detailed )return
842 call system_clock(end_tick)
843 n = clocks(current_clock)%events(event_id)%calls + 1
844
845 if( n.EQ.max_events )call mpp_error( warning, &
846 'MPP_CLOCK: events exceed MAX_EVENTS, ignore detailed profiling data for clock '// &
847 & trim(clocks(current_clock)%name) )
848 if( n.GT.max_events )return
849
850 clocks(current_clock)%events(event_id)%calls = n
851 delta = end_tick - start_tick
852 if( delta.LT.0 )then
853 errunit = stderr()
854 write( errunit,* )'pe, event_id, start_tick, end_tick, delta, max_ticks=', &
855 pe, event_id, start_tick, end_tick, delta, max_ticks
856 delta = delta + max_ticks + 1
857 call mpp_error( warning, 'MPP_CLOCK_END: Clock rollover, assumed single roll.' )
858 end if
859 clocks(current_clock)%events(event_id)%ticks(n) = delta
860 if( PRESENT(bytes) )clocks(current_clock)%events(event_id)%bytes(n) = bytes
861 return
862 end subroutine increment_current_clock
863
864 !#####################################################################
865
866 subroutine dump_clock_summary()
867
868 real :: total_time,total_time_all,total_data
869 real :: msg_size,eff_BW,s
870 integer :: SD_UNIT, total_calls
871 integer :: j,k,ct, msg_cnt
872 character(len=2) :: u
873 character(len=FMS_FILE_LEN) :: filename
874 character(len=20),dimension(MAX_BINS),save :: bin
875
876 data bin( 1) /' 0 - 8 B: '/
877 data bin( 2) /' 8 - 16 B: '/
878 data bin( 3) /' 16 - 32 B: '/
879 data bin( 4) /' 32 - 64 B: '/
880 data bin( 5) /' 64 - 128 B: '/
881 data bin( 6) /'128 - 256 B: '/
882 data bin( 7) /'256 - 512 B: '/
883 data bin( 8) /'512 - 1024 B: '/
884 data bin( 9) /' 1.0 - 2.1 KB: '/
885 data bin(10) /' 2.1 - 4.1 KB: '/
886 data bin(11) /' 4.1 - 8.2 KB: '/
887 data bin(12) /' 8.2 - 16.4 KB: '/
888 data bin(13) /' 16.4 - 32.8 KB: '/
889 data bin(14) /' 32.8 - 65.5 KB: '/
890 data bin(15) /' 65.5 - 131.1 KB: '/
891 data bin(16) /'131.1 - 262.1 KB: '/
892 data bin(17) /'262.1 - 524.3 KB: '/
893 data bin(18) /'524.3 - 1048.6 KB: '/
894 data bin(19) /' 1.0 - 2.1 MB: '/
895 data bin(20) /' >2.1 MB: '/
896
897 if( .NOT.any(clocks(1:clock_num)%detailed) )return
898 write( filename,'(a,i6.6)' )'mpp_clock.out.', pe
899
900 open(newunit=sd_unit,file=trim(filename),form='formatted')
901
902 comm_type: do ct = 1,clock_num
903
904 if( .NOT.clocks(ct)%detailed )cycle
905 write(sd_unit,*) &
906 clock_summary(ct)%name(1:15),' Communication Data for PE ',pe
907
908 write(sd_unit,*) ' '
909 write(sd_unit,*) ' '
910
911 total_time_all = 0.0
912 event_type: do k = 1,max_event_types-1
913
914 if(clock_summary(ct)%event(k)%total_time == 0.0)cycle
915
916 total_time = clock_summary(ct)%event(k)%total_time
917 total_time_all = total_time_all + total_time
918 total_data = clock_summary(ct)%event(k)%total_data
919 total_calls = int(clock_summary(ct)%event(k)%total_cnts)
920
921 write(sd_unit,1000) clock_summary(ct)%event(k)%name(1:9) // ':'
922
923 write(sd_unit,1001) 'Total Data: ',total_data*1.0e-6, &
924 'MB; Total Time: ', total_time, &
925 'secs; Total Calls: ',total_calls
926
927 write(sd_unit,*) ' '
928 write(sd_unit,1002) ' Bin Counts Avg Size Eff B/W'
929 write(sd_unit,*) ' '
930
931 bin_loop: do j=1,max_bins
932
933 if(clock_summary(ct)%event(k)%msg_size_cnts(j)==0)cycle
934
935 if(j<=8)then
936 s = 1.0
937 u = ' B'
938 elseif(j<=18)then
939 s = 1.0e-3
940 u = 'KB'
941 else
942 s = 1.0e-6
943 u = 'MB'
944 endif
945
946 msg_cnt = int(clock_summary(ct)%event(k)%msg_size_cnts(j))
947 msg_size = &
948 s*(clock_summary(ct)%event(k)%msg_size_sums(j)/real(msg_cnt))
949 eff_bw = (1.0e-6)*( clock_summary(ct)%event(k)%msg_size_sums(j) / &
950 clock_summary(ct)%event(k)%msg_time_sums(j) )
951
952 write(sd_unit,1003) bin(j),msg_cnt,msg_size,u,eff_bw
953
954 end do bin_loop
955
956 write(sd_unit,*) ' '
957 write(sd_unit,*) ' '
958 end do event_type
959
960 ! "Data-less" WAIT
961
962 if(clock_summary(ct)%event(max_event_types)%total_time>0.0)then
963
964 total_time = clock_summary(ct)%event(max_event_types)%total_time
965 total_time_all = total_time_all + total_time
966 total_calls = int(clock_summary(ct)%event(max_event_types)%total_cnts)
967
968 write(sd_unit,1000) clock_summary(ct)%event(max_event_types)%name(1:9) // ':'
969
970 write(sd_unit,1004) 'Total Calls: ',total_calls,'; Total Time: ', &
971 total_time,'secs'
972
973 endif
974
975 write(sd_unit,*) ' '
976 write(sd_unit,1005) 'Total communication time spent for ' // &
977 clock_summary(ct)%name(1:9) // ': ',total_time_all,'secs'
978 write(sd_unit,*) ' '
979 write(sd_unit,*) ' '
980 write(sd_unit,*) ' '
981
982 end do comm_type
983
984 close(sd_unit)
985
9861000 format(a)
9871001 format(a,f8.2,a,f8.2,a,i6)
9881002 format(a)
9891003 format(a,i6,' ',' ',f9.1,a,' ',f9.2,'MB/sec')
9901004 format(a,i8,a,f9.2,a)
9911005 format(a,f9.2,a)
992 return
993 end subroutine dump_clock_summary
994
995 !#####################################################################
996
997 integer function get_unit()
998
999 integer,save :: i
1000 logical :: l_open
1001
1002 if (pe == root_pe) call mpp_error(warning, &
1003 'get_unit is deprecated and will be removed in a future release, please use the Fortran intrinsic newunit')
1004 do i=10,99
1005 inquire(unit=i,opened=l_open)
1006 if(.not.l_open)exit
1007 end do
1008
1009 if(i==100)then
1010 call mpp_error(fatal,'Unable to get I/O unit')
1011 else
1012 get_unit = i
1013 endif
1014
1015 return
1016 end function get_unit
1017
1018 !#####################################################################
1019
1020 subroutine sum_clock_data()
1021
1022 integer :: i,j,k,ct,event_size,event_cnt
1023 real :: msg_time
1024
1025 clock_type: do ct=1,clock_num
1026 if( .NOT.clocks(ct)%detailed )cycle
1027 event_type: do j=1,max_event_types-1
1028 event_cnt = clocks(ct)%events(j)%calls
1029 event_summary: do i=1,event_cnt
1030
1031 clock_summary(ct)%event(j)%total_cnts = &
1032 clock_summary(ct)%event(j)%total_cnts + 1
1033
1034 event_size = int(clocks(ct)%events(j)%bytes(i))
1035
1036 k = find_bin(event_size)
1037
1038 clock_summary(ct)%event(j)%msg_size_cnts(k) = &
1039 clock_summary(ct)%event(j)%msg_size_cnts(k) + 1
1040
1041 clock_summary(ct)%event(j)%msg_size_sums(k) = &
1042 clock_summary(ct)%event(j)%msg_size_sums(k) &
1043 + clocks(ct)%events(j)%bytes(i)
1044
1045 clock_summary(ct)%event(j)%total_data = &
1046 clock_summary(ct)%event(j)%total_data &
1047 + clocks(ct)%events(j)%bytes(i)
1048
1049 msg_time = clocks(ct)%events(j)%ticks(i)
1050 msg_time = tick_rate * real( clocks(ct)%events(j)%ticks(i) )
1051
1052 clock_summary(ct)%event(j)%msg_time_sums(k) = &
1053 clock_summary(ct)%event(j)%msg_time_sums(k) + msg_time
1054
1055 clock_summary(ct)%event(j)%total_time = &
1056 clock_summary(ct)%event(j)%total_time + msg_time
1057
1058 end do event_summary
1059 end do event_type
1060
1061 j = max_event_types ! WAITs
1062 ! "msg_size_cnts" doesn't really mean anything for WAIT
1063 ! but position will be used to store number of counts for now.
1064
1065 event_cnt = clocks(ct)%events(j)%calls
1066 clock_summary(ct)%event(j)%msg_size_cnts(1) = event_cnt
1067 clock_summary(ct)%event(j)%total_cnts = event_cnt
1068
1069 msg_time = tick_rate * real( sum( clocks(ct)%events(j)%ticks(1:event_cnt) ) )
1070 clock_summary(ct)%event(j)%msg_time_sums(1) = &
1071 clock_summary(ct)%event(j)%msg_time_sums(1) + msg_time
1072
1073 clock_summary(ct)%event(j)%total_time = clock_summary(ct)%event(j)%msg_time_sums(1)
1074
1075 end do clock_type
1076
1077 return
1078 contains
1079 integer function find_bin(event_size)
1080
1081 integer,intent(in) :: event_size
1082 integer :: k,msg_size
1083
1084 msg_size = 8
1085 k = 1
1086 do while(event_size>msg_size .and. k<max_bins)
1087 k = k+1
1088 msg_size = msg_size*2
1089 end do
1090 find_bin = k
1091 return
1092 end function find_bin
1093
1094 end subroutine sum_clock_data
1095
1096 !#####################################################################
1097 !> This routine will double the size of peset and copy the original peset data
1098 !! into the expanded one. The maximum allowed to expand is PESET_MAX.
1099 subroutine expand_peset()
1100 integer :: old_peset_max,n
1101 type(communicator), allocatable :: peset_old(:)
1102
1103 old_peset_max = current_peset_max
1104 if(old_peset_max .GE. peset_max) call mpp_error(fatal, &
1105 "mpp_mod(expand_peset): the number of peset reached PESET_MAX, increase PESET_MAX or contact developer")
1106
1107 ! copy data to a tempoary data
1108 allocate(peset_old(0:old_peset_max))
1109 do n = 0, old_peset_max
1110 peset_old(n)%count = peset(n)%count
1111 peset_old(n)%id = peset(n)%id
1112 peset_old(n)%group = peset(n)%group
1113 peset_old(n)%name = peset(n)%name
1114 peset_old(n)%start = peset(n)%start
1115 peset_old(n)%log2stride = peset(n)%log2stride
1116
1117 if( ASSOCIATED(peset(n)%list) ) then
1118 allocate(peset_old(n)%list(size(peset(n)%list(:))) )
1119 peset_old(n)%list(:) = peset(n)%list(:)
1120 deallocate(peset(n)%list)
1121 endif
1122 enddo
1123 deallocate(peset)
1124
1125 ! create the new peset
1126 current_peset_max = min(peset_max, 2*old_peset_max)
1127 allocate(peset(0:current_peset_max))
1128 peset(:)%count = -1
1129 peset(:)%id = -1
1130 peset(:)%group = -1
1131 peset(:)%start = -1
1132 peset(:)%log2stride = -1
1133 peset(:)%name = " "
1134 do n = 0, old_peset_max
1135 peset(n)%count = peset_old(n)%count
1136 peset(n)%id = peset_old(n)%id
1137 peset(n)%group = peset_old(n)%group
1138 peset(n)%name = peset_old(n)%name
1139 peset(n)%start = peset_old(n)%start
1140 peset(n)%log2stride = peset_old(n)%log2stride
1141
1142 if( ASSOCIATED(peset_old(n)%list) ) then
1143 allocate(peset(n)%list(size(peset_old(n)%list(:))) )
1144 peset(n)%list(:) = peset_old(n)%list(:)
1145 deallocate(peset_old(n)%list)
1146 endif
1147 enddo
1148 deallocate(peset_old)
1149
1150 call mpp_error(note, "mpp_mod(expand_peset): size of peset is expanded to ", current_peset_max)
1151
1152 end subroutine expand_peset
1153 !#####################################################################
1154
1155 function uppercase (cs)
1156 character(len=*), intent(in) :: cs
1157 character(len=len(cs)),target :: uppercase
1158 integer :: k,tlen
1159 character, pointer :: ca
1160 integer, parameter :: co=iachar('A')-iachar('a') ! case offset
1161 !The transfer function truncates the string with xlf90_r
1162 tlen = len_trim(cs)
1163 if(tlen <= 0) then ! catch IBM compiler bug
1164 uppercase = cs ! simply return input blank string
1165 else
1166 uppercase = cs(1:tlen)
1167 do k=1, tlen
1168 ca => uppercase(k:k)
1169 if(ca >= "a" .and. ca <= "z") ca = achar(ichar(ca)+co)
1170 enddo
1171 endif
1172 end function uppercase
1173
1174!#######################################################################
1175
1176 function lowercase (cs)
1177 character(len=*), intent(in) :: cs
1178 character(len=len(cs)),target :: lowercase
1179 integer, parameter :: co=iachar('a')-iachar('A') ! case offset
1180 integer :: k,tlen
1181 character, pointer :: ca
1182! The transfer function truncates the string with xlf90_r
1183 tlen = len_trim(cs)
1184 if(tlen <= 0) then ! catch IBM compiler bug
1185 lowercase = cs ! simply return input blank string
1186 else
1187 lowercase = cs(1:tlen)
1188 do k=1, tlen
1189 ca => lowercase(k:k)
1190 if(ca >= "A" .and. ca <= "Z") ca = achar(ichar(ca)+co)
1191 enddo
1192 endif
1193 end function lowercase
1194
1195
1196 !#######################################################################
1197
1198!-----------------------------------------------------------------------
1199!
1200! AUTHOR: Rusty Benson (rusty.benson@noaa.gov)
1201!
1202!
1203! THESE LINES MUST BE PRESENT IN MPP.F90
1204!
1205! ! public variable needed for reading an input nml file from an internal file
1206! character(len=:), dimension(:), allocatable, public :: input_nml_file
1207!
1208
1209!-----------------------------------------------------------------------
1210
1211!> Reads an existing input nml file into a character array and broadcasts
1212!! it to the non-root mpi-tasks. This allows the use of reads from an
1213!! internal file for namelist settings (requires 2003 compliant compiler)
1214!!
1215!! read(input_nml_file, nml=<name_nml>, iostat=status)
1216!!
1217!!
1218 subroutine read_input_nml(pelist_name_in, alt_input_nml_path)
1219
1220! Include variable "version" to be written to log file.
1221#include<file_version.h>
1222
1223 character(len=*), intent(in), optional :: pelist_name_in
1224 character(len=*), intent(in), optional :: alt_input_nml_path
1225! private variables
1226 integer :: log_unit
1227 integer :: i
1228 integer, dimension(2) :: lines_and_length
1229 logical :: file_exist
1230 character(len=len(peset(current_peset_num)%name)) :: pelist_name
1231 character(len=FMS_PATH_LEN) :: filename
1232
1233! check the status of input_nml_file
1234 if ( allocated(input_nml_file) ) then
1235 deallocate(input_nml_file)
1236 endif
1237
1238! the following code is necessary for using alternate namelist files (nests, stretched grids, etc)
1239 if (PRESENT(pelist_name_in)) then
1240 ! test to make sure length of pelist_name_in is <= pelist_name
1241 if (len(pelist_name_in) > len(pelist_name)) then
1242 call mpp_error(fatal, &
1243 "mpp_util.inc: read_input_nml optional argument pelist_name_in has size greater than local pelist_name")
1244 else
1245 pelist_name = pelist_name_in
1246 endif
1247 else
1248 pelist_name = mpp_get_current_pelist_name()
1249 endif
1250 filename='input_'//trim(pelist_name)//'.nml'
1251 inquire(file=filename, exist=file_exist)
1252 if (.not. file_exist ) then
1253 if (present(alt_input_nml_path)) then
1254 filename = alt_input_nml_path
1255 else
1256 filename = 'input.nml'
1257 end if
1258 endif
1259 lines_and_length = get_ascii_file_num_lines_and_length(filename)
1260 allocate(character(len=lines_and_length(2))::input_nml_file(lines_and_length(1)))
1261 call read_ascii_file(filename, lines_and_length(2), input_nml_file)
1262
1263! write info logfile
1264 if (pe == root_pe) then
1265 log_unit = stdlog()
1266 write(log_unit,'(a)') '========================================================================'
1267 write(log_unit,'(a)') 'READ_INPUT_NML: '//trim(version)
1268 write(log_unit,'(a)') 'READ_INPUT_NML: '//trim(filename)//' '
1269 do i = 1, lines_and_length(1)
1270 write(log_unit,*) trim(input_nml_file(i))
1271 enddo
1272 end if
1273 end subroutine read_input_nml
1274
1275
1276 !#######################################################################
1277 !z1l: This is extracted from read_ascii_file
1278 function get_ascii_file_num_lines(FILENAME, LENGTH, PELIST)
1279 character(len=*), intent(in) :: FILENAME
1280 integer, intent(in) :: LENGTH
1281 integer, intent(in), optional, dimension(:) :: PELIST
1282
1283 integer :: num_lines, get_ascii_file_num_lines
1284 character(len=LENGTH) :: str_tmp
1285 character(len=5) :: text
1286 integer :: status, f_unit, from_pe
1287 logical :: file_exist
1288
1289 if( read_ascii_file_on) then
1290 call mpp_error(fatal, &
1291 "mpp_util.inc: get_ascii_file_num_lines is called again before calling read_ascii_file")
1292 endif
1293 read_ascii_file_on = .true.
1294
1295 from_pe = root_pe
1296 get_ascii_file_num_lines = -1
1297 num_lines = -1
1298 if ( pe == root_pe ) then
1299 inquire(file=filename, exist=file_exist)
1300
1301 if ( file_exist ) then
1302 open(newunit=f_unit, file=filename, action='READ', status='OLD', iostat=status)
1303
1304 if ( status .ne. 0 ) then
1305 write (unit=text, fmt='(I5)') status
1306 call mpp_error(fatal, 'get_ascii_file_num_lines: Error opening file:' //trim(filename)// &
1307 '. (IOSTAT = '//trim(text)//')')
1308 else
1309 num_lines = 1
1310 do
1311 read (unit=f_unit, fmt='(A)', iostat=status) str_tmp
1312 if ( status .lt. 0 ) then
1313 ! deprecate num_lines by 1 and ensure num_lines is at least 1
1314 num_lines = max(num_lines - 1, 1)
1315 exit
1316 endif
1317 if ( status .gt. 0 ) then
1318 write (unit=text, fmt='(I5)') num_lines
1319 call mpp_error(fatal, 'get_ascii_file_num_lines: Error reading line '//trim(text)// &
1320 ' in file '//trim(filename)//'.')
1321 end if
1322 if ( len_trim(str_tmp) == length ) then
1323 write(unit=text, fmt='(I5)') length
1324 call mpp_error(fatal, 'get_ascii_file_num_lines: Length of output string ('//trim(text)//&
1325 & ' is too small. Increase the LENGTH value.')
1326 end if
1327 num_lines = num_lines + 1
1328 end do
1329 close(unit=f_unit)
1330 end if
1331 else
1332 call mpp_error(fatal, 'get_ascii_file_num_lines: File '//trim(filename)//' does not exist.')
1333 end if
1334 end if
1335
1336 ! Broadcast number of lines
1337 call mpp_broadcast(num_lines, from_pe, pelist=pelist)
1338 get_ascii_file_num_lines = num_lines
1339
1340 end function get_ascii_file_num_lines
1341
1342 !#######################################################################
1343 !> @brief Function to determine the maximum line length and number of lines from an ascii file
1344 function get_ascii_file_num_lines_and_length(FILENAME, PELIST)
1345 character(len=*), intent(in) :: FILENAME !< name of the file to be read
1346 integer, intent(in), optional, dimension(:) :: PELIST !< optional pelist
1347
1348 integer, dimension(2) :: get_ascii_file_num_lines_and_length !< number of lines (1) and
1349 !! max line length (2)
1350 integer :: num_lines, max_length
1351 integer, parameter :: LENGTH=1024
1352 character(len=LENGTH) :: str_tmp
1353 character(len=5) :: text
1354 integer :: status, f_unit, from_pe
1355 logical :: file_exist
1356
1357 if( read_ascii_file_on) then
1358 call mpp_error(fatal, &
1359 "mpp_util.inc: get_ascii_file_num_lines is called again before calling read_ascii_file")
1360 endif
1361 read_ascii_file_on = .true.
1362
1363 from_pe = root_pe
1364 get_ascii_file_num_lines_and_length = -1
1365 num_lines = -1
1366 max_length = -1
1367 if ( pe == root_pe ) then
1368 inquire(file=filename, exist=file_exist)
1369
1370 if ( file_exist ) then
1371 open(newunit=f_unit, file=filename, action='READ', status='OLD', iostat=status)
1372
1373 if ( status .ne. 0 ) then
1374 write (unit=text, fmt='(I5)') status
1375 call mpp_error(fatal, 'get_ascii_file_num_lines: Error opening file:' //trim(filename)// &
1376 '. (IOSTAT = '//trim(text)//')')
1377 else
1378 num_lines = 1
1379 max_length = 1
1380 do
1381 read (unit=f_unit, fmt='(A)', iostat=status) str_tmp
1382 if ( status .lt. 0 ) then
1383 ! deprecate num_lines by 1 and ensure num_lines is at least 1
1384 num_lines = max(num_lines - 1, 1)
1385 exit
1386 endif
1387 if ( status .gt. 0 ) then
1388 write (unit=text, fmt='(I5)') num_lines
1389 call mpp_error(fatal, 'get_ascii_file_num_lines: Error reading line '//trim(text)// &
1390 ' in file '//trim(filename)//'.')
1391 end if
1392 if ( len_trim(str_tmp) == length) then
1393 write(unit=text, fmt='(I5)') length
1394 call mpp_error(fatal, 'get_ascii_file_num_lines: Length of output string ('//trim(text)//&
1395 & ' is too small. Increase the LENGTH value.')
1396 end if
1397 if (len_trim(str_tmp) > max_length) max_length = len_trim(str_tmp)
1398 num_lines = num_lines + 1
1399 end do
1400 close(unit=f_unit)
1401 end if
1402 else
1403 call mpp_error(fatal, 'get_ascii_file_num_lines: File '//trim(filename)//' does not exist.')
1404 end if
1405 max_length = max_length+1
1406 end if
1407
1408 ! Broadcast number of lines
1409 call mpp_broadcast(num_lines, from_pe, pelist=pelist)
1410 call mpp_broadcast(max_length, from_pe, pelist=pelist)
1411 get_ascii_file_num_lines_and_length(1) = num_lines
1412 get_ascii_file_num_lines_and_length(2) = max_length
1413
1414 end function get_ascii_file_num_lines_and_length
1415
1416 !-----------------------------------------------------------------------
1417 !
1418 ! AUTHOR: Rusty Benson <rusty.benson@noaa.gov>,
1419 ! Seth Underwood <Seth.Underwood@noaa.gov>
1420 !
1421 !-----------------------------------------------------------------------
1422 ! subroutine READ_ASCII_FILE
1423 !
1424 !
1425 !> Reads any ascii file into a character array and broadcasts
1426 !! it to the non-root mpi-tasks. Based off READ_INPUT_NML.
1427 !!
1428 !! Passed in 'Content' array, must be of the form:
1429 !! character(len=LENGTH), dimension(:), allocatable :: array_name
1430 !!
1431 !! Reads from this array must be done in a do loop over the number of
1432 !! lines, i.e.:
1433 !!
1434 !! do i=1, num_lines
1435 !! read (UNIT=array_name(i), FMT=*) var1, var2, ...
1436 !! end do
1437 subroutine read_ascii_file(FILENAME, LENGTH, Content, PELIST)
1438 character(len=*), intent(in) :: FILENAME
1439 integer, intent(in) :: LENGTH
1440 character(len=*), intent(inout), dimension(:) :: Content
1441 integer, intent(in), optional, dimension(:) :: PELIST
1442
1443 ! Include variable "version" to be written to log file.
1444#include<file_version.h>
1445
1446 character(len=5) :: text
1447 logical :: file_exist
1448 integer :: status, f_unit, log_unit
1449 integer :: from_pe
1450 integer :: pnum_lines, num_lines
1451 character(len=LENGTH) :: str_tmp !< Temporary variable to store line from file
1452
1453 if( .NOT. read_ascii_file_on) then
1454 call mpp_error(fatal, &
1455 "mpp_util.inc: get_ascii_file_num_lines needs to be called before calling read_ascii_file")
1456 endif
1457 read_ascii_file_on = .false.
1458
1459 from_pe = root_pe
1460 num_lines = size(content(:))
1461
1462 if ( pe == root_pe ) then
1463 ! write info logfile
1464 log_unit = stdlog()
1465 write(log_unit,'(a)') '========================================================================'
1466 write(log_unit,'(a)') 'READ_ASCII_FILE: '//trim(version)
1467 write(log_unit,'(a)') 'READ_ASCII_FILE: File: '//trim(filename)
1468
1469 inquire(file=filename, exist=file_exist)
1470
1471 if ( file_exist ) then
1472 open(newunit=f_unit, file=filename, action='READ', status='OLD', iostat=status)
1473
1474 if ( status .ne. 0 ) then
1475 write (unit=text, fmt='(I5)') status
1476 call mpp_error(fatal, 'READ_ASCII_FILE: Error opening file: '// &
1477 & trim(filename)//'. (IOSTAT = '//trim(text)//')')
1478 else
1479
1480 if ( num_lines .gt. 0 ) then
1481 content(:) = ' '
1482
1483 rewind(unit=f_unit, iostat=status)
1484 if ( status .ne. 0 ) then
1485 write (unit=text, fmt='(I5)') status
1486 call mpp_error(fatal, 'READ_ASCII_FILE: Unable to re-read file '//trim(filename)//'. (IOSTAT = '&
1487 //trim(text)//'.')
1488 else
1489 ! A second 'sanity' check on the file
1490 pnum_lines = 1
1491
1492 do
1493 read (unit=f_unit, fmt='(A)', iostat=status) str_tmp
1494
1495 if ( status .lt. 0 ) then
1496 ! deprecate pnum_lines by 1 and ensure pnum_lines is at least 1
1497 pnum_lines = max(pnum_lines - 1, 1)
1498 exit
1499 endif
1500 if ( status .gt. 0 ) then
1501 write (unit=text, fmt='(I5)') pnum_lines
1502 call mpp_error(fatal, 'READ_ASCII_FILE: Error reading line '// &
1503 & trim(text)//' in file '//trim(filename)//'.')
1504 end if
1505 if(pnum_lines > num_lines) then
1506 call mpp_error(fatal, 'READ_ASCII_FILE: number of lines in file '//trim(filename)// &
1507 ' is greater than size(Content(:)). ')
1508 end if
1509 if ( len_trim(str_tmp) == length ) then
1510 write(unit=text, fmt='(I5)') length
1511 call mpp_error(fatal, 'READ_ASCII_FILE: Length of output string ('//trim(text)// &
1512 & ' is too small. Increase the LENGTH value.')
1513 end if
1514 content(pnum_lines) = str_tmp
1515 pnum_lines = pnum_lines + 1
1516 end do
1517 if(num_lines .NE. pnum_lines) then
1518 call mpp_error(fatal, 'READ_ASCII_FILE: number of lines in file '//trim(filename)// &
1519 ' does not equal to size(Content(:)) ' )
1520 end if
1521 end if
1522 end if
1523 close(unit=f_unit)
1524 end if
1525 else
1526 call mpp_error(fatal, 'READ_ASCII_FILE: File '//trim(filename)//' does not exist.')
1527 end if
1528 end if
1529
1530 ! Broadcast character array
1531 call mpp_broadcast(content, length, from_pe, pelist=pelist)
1532
1533 end subroutine read_ascii_file
1534!> @}
subroutine mpp_error_basic(errortype, errormsg)
A very basic error handler uses ABORT and FLUSH calls, may need to use cpp to rename.
integer function get_peset(pelist)
Makes a PE set out of a PE list. A PE list is an ordered list of PEs a PE set is a triad (start,...
subroutine mpp_sync(pelist, do_self)
Synchronize PEs in list.