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