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