4 !***********************************************************************
5 !* GNU Lesser General Public License
7 !* This file
is part of the GFDL Flexible Modeling System (FMS).
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.
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
19 !* You should have
received a copy of the GNU Lesser General Public
20 !* License along with FMS. If
not, see <http:
21 !***********************************************************************
25 #elif defined(use_libMPI) 31 !#####################################################################
32 ! <FUNCTION NAME=
"stdin">
34 ! Standard fortran
unit numbers.
37 ! This
function returns the current standard fortran
unit numbers
for input.
49 !
##################################################################### 50 ! <FUNCTION NAME=
"stdout">
52 ! Standard fortran
unit numbers.
55 ! This
function returns the current standard fortran
unit numbers
for output.
68 !
##################################################################### 69 ! <FUNCTION NAME=
"stderr">
71 ! Standard fortran
unit numbers.
74 ! This
function returns the current standard fortran
unit numbers
for error messages.
86 !
##################################################################### 87 ! <FUNCTION NAME=
"stdlog">
89 ! Standard fortran
unit numbers.
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>.
102 character(
len=11) :: this_pe
103 !$ logical :: omp_in_parallel
109 ! This
will be
a cicular call.
111 !$
if( omp_in_parallel() ) then
113 !$ errunit = stderr()
114 !$ write( errunit,'(/
a/)' ) 'FATAL: STDLOG:
is called
inside a OMP parallel region'
116 !$ call TRACE_BACK_STACK_AND_PRINT()
119 !$ call MPI_ABORT( MPI_COMM_WORLD, 1,
error )
126 if(
pe.EQ.root_pe )then
127 write(this_pe,
'(a,i6.6,a)')
'.',
pe,
'.out' 146 10 call
mpp_error( FATAL,
'STDLOG: unable to open ' 147 11 call
mpp_error( FATAL,
'STDLOG: unable to open ' 150 !#####################################################################
151 subroutine mpp_init_logfile()
154 character(
len=11) :: this_pe
155 if(
pe.EQ.root_pe )then
158 write(this_pe,
'(a,i6.6,a)')
'.',
p,
'.out' 166 end subroutine mpp_init_logfile
167 !#####################################################################
168 subroutine mpp_set_warn_level(flag)
171 if( flag.EQ.WARNING )then
173 else if( flag.EQ.FATAL )then
176 call
mpp_error( FATAL,
'MPP_SET_WARN_LEVEL: warning flag must be set to WARNING or FATAL.' )
179 end subroutine mpp_set_warn_level
181 !#####################################################################
182 function mpp_error_state()
183 integer :: mpp_error_state
186 end function mpp_error_state
188 !#####################################################################
189 !overloads to mpp_error_basic
191 subroutine mpp_error_mesg( routine, errormsg, errortype )
192 character(
len=*), intent(in) :: routine, errormsg
193 integer, intent(in) :: errortype
197 end subroutine mpp_error_mesg
199 !#####################################################################
200 subroutine mpp_error_noargs()
202 end subroutine mpp_error_noargs
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 229 if(present(errormsg2))
string = trim(
string)
230 call mpp_error_basic( errortype, trim(
string))
232 end subroutine mpp_error_Ia
234 !#####################################################################
235 subroutine mpp_error_Ra(errortype, errormsg1, array, errormsg2)
236 integer, intent(in) :: errortype
238 character(
len=*), intent(in) :: errormsg1
239 character(
len=*), intent(in), optional :: errormsg2
240 character(
len=512) ::
string 243 if(present(errormsg2))
string = trim(
string)
244 call mpp_error_basic( errortype, trim(
string))
246 end subroutine mpp_error_Ra
248 !#####################################################################
249 #define _SUBNAME_ mpp_error_ia_ia
252 #include <mpp_error_a_a.h>
256 !#####################################################################
257 #define _SUBNAME_ mpp_error_ia_ra
259 #define _ARRAY2TYPE_ real
260 #include <mpp_error_a_a.h>
264 !#####################################################################
265 #define _SUBNAME_ mpp_error_ra_ia
266 #define _ARRAY1TYPE_ real
268 #include <mpp_error_a_a.h>
272 !#####################################################################
273 #define _SUBNAME_ mpp_error_ra_ra
274 #define _ARRAY1TYPE_ real
275 #define _ARRAY2TYPE_ real
276 #include <mpp_error_a_a.h>
280 !#####################################################################
281 #define _SUBNAME_ mpp_error_ia_is
284 #include <mpp_error_a_s.h>
288 !#####################################################################
289 #define _SUBNAME_ mpp_error_ia_rs
291 #define _ARRAY2TYPE_ real
292 #include <mpp_error_a_s.h>
296 !#####################################################################
297 #define _SUBNAME_ mpp_error_ra_is
298 #define _ARRAY1TYPE_ real
300 #include <mpp_error_a_s.h>
304 !#####################################################################
305 #define _SUBNAME_ mpp_error_ra_rs
306 #define _ARRAY1TYPE_ real
307 #define _ARRAY2TYPE_ real
308 #include <mpp_error_a_s.h>
312 !#####################################################################
313 #define _SUBNAME_ mpp_error_is_ia
316 #include <mpp_error_s_a.h>
320 !#####################################################################
321 #define _SUBNAME_ mpp_error_is_ra
323 #define _ARRAY2TYPE_ real
324 #include <mpp_error_s_a.h>
328 !#####################################################################
329 #define _SUBNAME_ mpp_error_rs_ia
330 #define _ARRAY1TYPE_ real
332 #include <mpp_error_s_a.h>
336 !#####################################################################
337 #define _SUBNAME_ mpp_error_rs_ra
338 #define _ARRAY1TYPE_ real
339 #define _ARRAY2TYPE_ real
340 #include <mpp_error_s_a.h>
344 !#####################################################################
345 #define _SUBNAME_ mpp_error_is_is
348 #include <mpp_error_s_s.h>
352 !#####################################################################
353 #define _SUBNAME_ mpp_error_is_rs
355 #define _ARRAY2TYPE_ real
356 #include <mpp_error_s_s.h>
360 !#####################################################################
361 #define _SUBNAME_ mpp_error_rs_is
362 #define _ARRAY1TYPE_ real
364 #include <mpp_error_s_s.h>
368 !#####################################################################
369 #define _SUBNAME_ mpp_error_rs_rs
370 #define _ARRAY1TYPE_ real
371 #define _ARRAY2TYPE_ real
372 #include <mpp_error_s_s.h>
376 !#####################################################################
377 function iarray_to_char(iarray) result(
string)
378 integer, intent(in) :: iarray(:)
379 character(
len=256) ::
string 380 character(
len=32) :: chtmp
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) =
',' 392 len_string = len_trim(
string)
393 string(len_string:len_string) =
' ' !
remove trailing
comma 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
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) =
',' 412 len_string = len_trim(
string)
413 string(len_string:len_string) =
' ' !
remove trailing
comma 415 end function rarray_to_char
417 !#####################################################################
418 ! <FUNCTION NAME=
"mpp_pe">
420 ! Returns processor ID.
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.
435 if( .NOT.module_is_initialized )call
mpp_error( FATAL,
'MPP_PE: You must first call mpp_init.' )
440 !#####################################################################
442 !calls mld_id from threadloc.c on sgi, which returns the hardware node ID from /hw/nodenum/...
446 if( .NOT.module_is_initialized )call
mpp_error( FATAL,
'MPP_NODE: You must first call mpp_init.' )
449 end function mpp_node
451 !#####################################################################
452 ! <FUNCTION NAME=
"mpp_npes">
454 ! Returns processor count
for current
pelist.
457 ! This returns the number of PEs in the current
pelist. For
a 458 ! uniprocessor application,
this will always
return 1.
467 if( .NOT.module_is_initialized )call
mpp_error( FATAL,
'MPP_NPES: You must first call mpp_init.' )
470 end function mpp_npes
472 !#####################################################################
473 function mpp_root_pe()
474 integer :: mpp_root_pe
476 if( .NOT.module_is_initialized )call
mpp_error( FATAL,
'MPP_ROOT_PE: You must first call mpp_init.' )
479 end function mpp_root_pe
481 !#####################################################################
482 subroutine mpp_set_root_pe(num)
486 if( .NOT.module_is_initialized )call
mpp_error( FATAL,
'MPP_SET_ROOT_PE: You must first call mpp_init.' )
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:
491 !
if( num.NE.root_pe )then !
root_pe has changed
492 !
if(
pe.EQ.num )then
498 !
else if(
pe.EQ.root_pe )then
509 end subroutine mpp_set_root_pe
511 !#####################################################################
512 ! <SUBROUTINE NAME=
"mpp_declare_pelist">
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>.
525 ! The restriction does
not apply to SMA but to have uniform code, you
526 ! may as well call it.
528 ! This call implies synchronization across the PEs in the current
534 ! <IN NAME=
"pelist" DIM=
"(:)" TYPE=
"integer"></IN>
539 character(
len=*), intent(in), optional ::
name 547 end subroutine mpp_declare_pelist
549 !#####################################################################
550 ! <SUBROUTINE NAME=
"mpp_set_current_pelist">
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.
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>.
565 !
set to the
"world" pelist, of all PEs in the job.
568 ! call mpp_set_current_pelist(
pelist )
570 ! <IN NAME=
"pliest" TYPE=
"integer"></IN>
573 subroutine mpp_set_current_pelist(
pelist, no_sync )
574 !Once we branch off into
a PE subset, we want subsequent
"global" calls to
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.
582 logical, intent(in), optional :: no_sync
587 if( .NOT.ANY(
pe.EQ.
pelist) )call
mpp_error( FATAL,
'MPP_SET_CURRENT_PELIST: pe must be in pelist.' )
593 if(.
not.PRESENT(no_sync))call mpp_sync() !this
is called to make sure everyone in the current
pelist is here.
596 end subroutine mpp_set_current_pelist
598 !#####################################################################
599 function mpp_get_current_pelist_name()
604 end function mpp_get_current_pelist_name
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 )
611 character(
len=*), intent(
out), optional ::
name 615 call
mpp_error( FATAL,
'MPP_GET_CURRENT_PELIST: size(pelist) is wrong.' )
623 end subroutine mpp_get_current_pelist
625 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
627 ! PERFORMANCE PROFILING CALLS !
629 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
630 ! <SUBROUTINE NAME=
"mpp_clock_set_grain">
632 ! Set the level of granularity of timing measurements.
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:
645 !
id = mpp_clock_id(
'Atmosphere' )
646 ! call mpp_clock_begin(
id)
648 ! call mpp_clock_end()
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>.
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
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
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
683 ! Timings are done using the <TT>f90</TT> standard
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
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.
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
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.
710 !The following grain levels are pre-defined:
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
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
725 ! optional <TT>grain</TT> argument
is absent, the clock
is always
726 ! triggered. This guarantees backward compatibility.
729 ! call mpp_clock_set_grain( grain )
731 ! <IN NAME=
"grain" TYPE=
"integer"></IN>
734 subroutine mpp_clock_set_grain( grain )
736 !
set the granularity of times: only
clocks whose grain
is lower than
739 !are triggered
if this
is never called.
744 end subroutine mpp_clock_set_grain
746 !#####################################################################
747 subroutine clock_init(
id,
name, flags, grain )
749 character(
len=*), intent(in) ::
name 750 integer, intent(in), optional :: flags, grain
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.
766 allocate(
clocks(
id)%events(MAX_EVENT_TYPES) )
772 do
i=1,MAX_EVENT_TYPES
783 do
i=1,MAX_EVENT_TYPES
793 end subroutine clock_init
795 !#####################################################################
796 !return an ID for
a new or existing clock
797 function mpp_clock_id(
name, flags, grain )
799 character(
len=*), intent(in) ::
name 800 integer, intent(in), optional :: flags, grain
805 !
if grain
is present, the clock
is only triggered
if it
807 !finer-grained
clocks are dormant.
808 !
if grain
is absent, clock
is triggered.
809 if( PRESENT(grain) )then
819 call clock_init(mpp_clock_id,
name,flags)
821 FIND_CLOCK: do while( trim(
name).NE.trim(
clocks(mpp_clock_id)%
name) )
822 mpp_clock_id = mpp_clock_id + 1
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.')
829 call clock_init(mpp_clock_id,
name,flags,grain)
836 end function mpp_clock_id
838 !#####################################################################
839 subroutine mpp_clock_begin(
id)
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 ' 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.
869 end subroutine mpp_clock_begin
871 !#####################################################################
872 subroutine mpp_clock_end(
id)
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 ' 887 call
mpp_error( FATAL,
'MPP_CLOCK_END: cannot change pelist context of a clock.' )
891 write( errunit,* )
'pe, id, start_tick, end_tick, delta, max_ticks=',
pe,
id,
clocks(
id)%
tick,
end_tick, delta,
max_ticks 893 call
mpp_error( WARNING,
'MPP_CLOCK_END: Clock rollover, assumed single roll.' )
904 end subroutine mpp_clock_end
906 !#####################################################################
907 subroutine mpp_record_time_start()
911 end subroutine mpp_record_time_start
913 !#####################################################################
914 subroutine mpp_record_time_end()
918 end subroutine mpp_record_time_end
921 !#####################################################################
922 subroutine increment_current_clock( event_id, bytes )
923 integer, intent(in) :: event_id
924 integer, intent(in), optional :: bytes
937 'MPP_CLOCK: events exceed MAX_EVENTS, ignore detailed profiling data for clock ' 938 if(
n.GT.MAX_EVENTS )return
944 write( errunit,* )
'pe, event_id, start_tick, end_tick, delta, max_ticks=', &
947 call
mpp_error( WARNING,
'MPP_CLOCK_END: Clock rollover, assumed single roll.' )
952 end subroutine increment_current_clock
954 !#####################################################################
956 subroutine dump_clock_summary()
958 real :: total_time,total_time_all,total_data
959 real :: msg_size,eff_BW,s
960 integer :: SD_UNIT, total_calls
962 character(
len=2) :: u
963 character(
len=20) :: filename
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: '/
988 write( filename,
'(a,i6.6)' )
'mpp_clock.out.',
pe 991 open(SD_UNIT,file=trim(filename),
form=
'formatted')
1000 write(SD_UNIT,*)
' ' 1002 total_time_all = 0.0
1003 EVENT_TYPE: do
k = 1,MAX_EVENT_TYPES-1
1008 total_time_all = total_time_all + total_time
1014 write(SD_UNIT,1001)
'Total Data: ',total_data*1.0
e-6, &
1015 'MB; Total Time: ', total_time, &
1016 'secs; Total Calls: ',total_calls
1018 write(SD_UNIT,*)
' ' 1019 write(SD_UNIT,1002)
' Bin Counts Avg Size Eff B/W' 1020 write(SD_UNIT,*)
' ' 1022 BIN_LOOP: do
j=1,MAX_BINS
1043 write(SD_UNIT,1003) bin(
j),msg_cnt,msg_size,u,eff_BW
1047 write(SD_UNIT,*)
' ' 1048 write(SD_UNIT,*)
' ' 1056 total_time_all = total_time_all + total_time
1061 write(SD_UNIT,1004)
'Total Calls: ',total_calls,
'; Total Time: ', &
1066 write(SD_UNIT,*)
' ' 1067 write(SD_UNIT,1005)
'Total communication time spent for ' 1069 write(SD_UNIT,*)
' ' 1070 write(SD_UNIT,*)
' ' 1071 write(SD_UNIT,*)
' ' 1080 1003
format(
a,
i6,
' ',
' ',f9.1,
a,
' ',f9.2,
'MB/sec')
1084 end subroutine dump_clock_summary
1086 !#####################################################################
1095 inquire(
unit=
i,opened=l_open)
1100 call
mpp_error(FATAL,
'Unable to get I/O unit')
1106 end function get_unit
1108 !#####################################################################
1110 subroutine sum_clock_data()
1117 EVENT_TYPE: do
j=1,MAX_EVENT_TYPES-1
1119 EVENT_SUMMARY: do
i=1,event_cnt
1126 k = find_bin(event_size)
1148 end do EVENT_SUMMARY
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. 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 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 1163 clock_summary(ct)%event(j)%total_time = clock_summary(ct)%event(j)%msg_time_sums(1) 1169 integer function find_bin(event_size) 1171 integer,intent(in) :: event_size 1172 integer :: k,msg_size 1176 do while(event_size>msg_size .and. k<MAX_BINS) 1178 msg_size = msg_size*2 1182 end function find_bin 1184 end subroutine sum_clock_data 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(:) 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") 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 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) 1215 ! create the new peset 1216 current_peset_max = min(PESET_MAX, 2*old_peset_max) 1217 allocate(peset(0:current_peset_max)) 1222 peset(:)%log2stride = -1 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 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) 1238 deallocate(peset_old) 1240 call mpp_error(NOTE, "mpp_mod(expand_peset): size of peset is expanded to ", current_peset_max) 1242 end subroutine expand_peset 1243 !##################################################################### 1245 function uppercase (cs) 1246 character(len=*), intent(in) :: cs 1247 character(len=len(cs)),target :: uppercase 1249 character, pointer :: ca 1250 integer, parameter :: co=iachar('A
')-iachar('a') ! case offset 1251 !The transfer function truncates the string with xlf90_r 1253 if(tlen <= 0) then ! catch IBM compiler bug 1254 uppercase = cs ! simply return input blank string 1256 uppercase = cs(1:tlen) 1260 if(uppercase(k:k) >= "a" .and. uppercase(k:k) <= 'z
') uppercase(k:k) = achar(ichar(uppercase(k:k))+co) 1264 ca => uppercase(k:k) 1265 if(ca >= "a" .and. ca <= "z") ca = achar(ichar(ca)+co) 1269 end function uppercase 1271 !####################################################################### 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 1278 character, pointer :: ca 1279 ! The transfer function truncates the string with xlf90_r 1281 if(tlen <= 0) then ! catch IBM compiler bug 1282 lowercase = cs ! simply return input blank string 1284 lowercase = cs(1:tlen) 1288 if(lowercase(k:k) >= "A" .and. lowercase(k:k) <= 'Z
') lowercase(k:k) = achar(ichar(lowercase(k:k))+co) 1292 ca => lowercase(k:k) 1293 if(ca >= "A" .and. ca <= "Z") ca = achar(ichar(ca)+co) 1297 end function lowercase 1300 !####################################################################### 1302 !----------------------------------------------------------------------- 1304 ! AUTHOR: Rusty Benson (rusty.benson@noaa.gov) 1307 ! THESE LINES MUST BE PRESENT IN MPP.F90 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 1315 !----------------------------------------------------------------------- 1316 ! subroutine READ_INPUT_NML 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) 1323 ! read(input_nml_file, nml=<name_nml>, iostat=status) 1326 subroutine read_input_nml(pelist_name_in) 1328 ! Include variable "version" to be written to log file. 1329 #include<file_version.h> 1331 character(len=*), intent(in), optional :: pelist_name_in 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 1339 ! check the status of input_nml_file 1340 if ( allocated(input_nml_file) ) then 1341 deallocate(input_nml_file) 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") 1351 pelist_name = pelist_name_in 1354 pelist_name = mpp_get_current_pelist_name() 1356 filename='input_
'//trim(pelist_name)//'.nml
' 1357 inquire(FILE=filename, EXIST=file_exist) 1358 if (.not. file_exist ) then 1359 filename='input.nml
' 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) 1365 ! write info logfile 1366 if (pe == root_pe) then 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)//' ' 1372 write(log_unit,*) trim(input_nml_file(i)) 1375 end subroutine read_input_nml 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 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 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") 1395 read_ascii_file_on = .true. 1398 get_ascii_file_num_lines = -1 1400 if ( pe == root_pe ) then 1401 inquire(FILE=FILENAME, EXIST=file_exist) 1403 if ( file_exist ) then 1405 open(UNIT=f_unit, FILE=FILENAME, ACTION='READ
', STATUS='OLD
', IOSTAT=status) 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)//')
') 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)//'.
') 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.
') 1426 num_lines = num_lines + 1 1431 call mpp_error(FATAL, 'get_ascii_file_num_lines: File
'//trim(FILENAME)//' does
not exist.
') 1435 ! Broadcast number of lines 1436 call mpp_broadcast(num_lines, from_pe, PELIST=PELIST) 1437 get_ascii_file_num_lines = num_lines 1439 end function get_ascii_file_num_lines 1441 !----------------------------------------------------------------------- 1443 ! AUTHOR: Rusty Benson <rusty.benson@noaa.gov>, 1444 ! Seth Underwood <Seth.Underwood@noaa.gov> 1446 !----------------------------------------------------------------------- 1447 ! subroutine READ_ASCII_FILE 1450 ! Reads any ascii file into a character array and broadcasts 1451 ! it to the non-root mpi-tasks. Based off READ_INPUT_NML. 1453 ! Passed in 'Content
' array, must be of the form: 1454 ! character(len=LENGTH), dimension(:), allocatable :: array_name 1456 ! Reads from this array must be done in a do loop over the number of 1460 ! read (UNIT=array_name(i), FMT=*) var1, var2, ... 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 1469 ! Include variable "version" to be written to log file. 1470 #include<file_version.h> 1472 character(len=5) :: text 1473 logical :: file_exist 1474 integer :: status, i, f_unit, log_unit 1476 integer :: pnum_lines, num_lines 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") 1482 read_ascii_file_on = .false. 1485 num_lines = size(Content(:)) 1487 if ( pe == root_pe ) then 1488 ! write info logfile 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) 1494 inquire(FILE=FILENAME, EXIST=file_exist) 1496 if ( file_exist ) then 1498 open(UNIT=f_unit, FILE=FILENAME, ACTION='READ
', STATUS='OLD
', IOSTAT=status) 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)//')
') 1505 if ( num_lines .gt. 0 ) then 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 =
'& 1514 ! A second 'sanity
' check on the file 1518 read (UNIT=f_unit, FMT='(A)
', IOSTAT=status) Content(pnum_lines) 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)//'.
') 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(:)).
') 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.
') 1534 pnum_lines = pnum_lines + 1 1536 if(num_lines .NE. pnum_lines) then 1537 call mpp_error(FATAL, 'READ_ASCII_FILE: number of lines in file
'//trim(FILENAME)// & 1545 call mpp_error(FATAL, 'READ_ASCII_FILE: File
'//trim(FILENAME)//' does
not exist.
') 1549 ! Broadcast character array 1550 call mpp_broadcast(Content, LENGTH, from_pe, PELIST=PELIST) 1552 end subroutine read_ascii_file
integer, parameter coarse
************************************************************************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
*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
integer, parameter, public note
integer, parameter, public warning
integer, parameter, public no
integer(long_kind) max_ticks
integer current_peset_num
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
logical, public mpp_record_timing_data
integer(long), parameter true
subroutine, public create(self, c_conf)
real(r8), dimension(cast_m, cast_n) p
character(len=32) etcfile
integer, parameter, public single
integer(long), parameter false
l_size ! loop over number of fields ke do j
type(summary_struct), dimension(max_clocks) clock_summary
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
character(len=128) version
real(fp), parameter, public e
l_size ! loop over number of fields ke do je do ie to is
type(communicator), dimension(:), allocatable peset
integer, parameter, public conserve
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
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
real, dimension(:,:,:), allocatable, private g
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)
real(r8), dimension(cast_m, cast_n) ct
real(fp), parameter three
real(double), parameter one
character(len=32) configfile
logical function received(this, seqno)
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)
************************************************************************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
*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
integer, dimension(max_clocks) previous_clock
integer(long_kind) start_tick
subroutine, public error_mesg(routine, message, level)
real per
Longitude of perihelion with respect to autumnal equinox in NH [degrees].
type(clock), dimension(max_clocks), save clocks
logical warnings_are_fatal
************************************************************************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
************************************************************************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