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