3 !***********************************************************************
4 !* GNU Lesser General Public License
6 !* This file
is part of the GFDL Flexible Modeling System (FMS).
8 !* FMS
is free software: you can redistribute it and/or modify it under
9 !* the terms of the GNU Lesser General Public License as published by
10 !* the Free Software Foundation, either
version 3 of the License, or (at
11 !* your option) any later
version.
13 !* FMS
is distributed in the hope that it
will be useful, but WITHOUT
14 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 !* You should have
received a copy of the GNU Lesser General Public
19 !* License along with FMS. If
not, see <http:
20 !***********************************************************************
22 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
26 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 ! <SUBROUTINE NAME=
"mpp_io_init">
34 ! of valid fortran
units and initializes the <TT>
mpp_file</TT> array of
35 ! <TT>
type(
filetype)</TT>. <TT>mpp_io_init</TT>
will call <TT>mpp_init</TT> and
36 ! <TT>mpp_domains_init</TT>, to make sure its parent modules have been
37 ! initialized. (Repeated calls to the <TT>
init</TT> routines
do no harm,
38 ! so don
't worry if you already called it). 41 ! call mpp_io_init( flags, maxunit ) 43 ! <IN NAME="flags" TYPE="integer"></IN> 44 ! <IN NAME="maxunit" TYPE="integer"></IN> 47 subroutine mpp_io_init( flags, maxunit ) 48 integer, intent(in), optional :: flags, maxunit 49 integer :: unit_nml, io_status, iunit 50 integer :: logunit, outunit, inunit, errunit 52 real(DOUBLE_KIND) :: doubledata = 0 55 if( module_is_initialized )return 57 !initialize IO package: initialize mpp_file array, set valid range of units for fortran IO 59 call mpp_init(flags) !if mpp_init has been called, this call will merely return 62 call mpp_domains_init(flags) 64 maxunits = _MAX_FILE_UNITS 65 if( PRESENT(maxunit) )maxunits = maxunit 66 if( PRESENT(flags) )then 67 debug = flags.EQ.MPP_DEBUG 68 verbose = flags.EQ.MPP_VERBOSE .OR. debug 71 !set range of allowed fortran unit numbers: could be compiler-dependent (should not overlap stdin/out/err) 72 call mpp_set_unit_range( 103, maxunits ) 75 #ifdef INTERNAL_FILE_NML 76 read (input_nml_file, mpp_io_nml, iostat=io_status) 78 do unit_nml = unit_begin, unit_end 79 inquire( unit_nml,OPENED=opened ) 82 open(unit_nml,file='input.nml
') 83 read(unit_nml,mpp_io_nml,iostat=io_status) 87 if (io_status > 0) then 88 call mpp_error(FATAL,'=>mpp_io_init:
Error reading input.nml
') 92 outunit = stdout(); logunit=stdlog() 93 write(outunit, mpp_io_nml) 94 write(logunit, mpp_io_nml) 96 !--- check the deflate level, set deflate = 1 if deflate_level is greater than equal to 0 97 if(deflate_level .GE. 0) deflate = 1 98 if(deflate .NE. 0) then 99 if(deflate_level <0 .OR. deflate > 9) then 100 call mpp_error(FATAL, "mpp_io_mod(mpp_io_init): mpp_io_nml variable must be between 0 and 9 when set") 104 ! determine the pack_size 105 pack_size = size(transfer(doubledata, realarray)) 106 if( pack_size .NE. 1 .AND. pack_size .NE. 2) call mpp_error(FATAL,'mpp_io_mod(mpp_io_init):
pack_size should be 1 or 2
') 108 !initialize default_field 109 default_field%name = 'noname
' 110 default_field%units = 'nounits
' 111 default_field%longname = 'noname
' 112 default_field%id = -1 113 default_field%type = -1 114 default_field%natt = -1 115 default_field%ndim = -1 116 default_field%checksum = 0 117 !largest possible 4-byte reals 118 default_field%min = -huge(1._4) 119 default_field%max = huge(1._4) 120 default_field%missing = MPP_FILL_DOUBLE ! now using netcdf:NF_FILL_DOUBLE instead of -1e36 121 default_field%fill = MPP_FILL_DOUBLE ! now using netcdf:NF_FILL_DOUBLE instead of -1e36 122 default_field%scale = 1.0 123 default_field%add = 0.0 124 default_field%pack = 1 125 default_field%time_axis_index = -1 !this value will never match any index 126 ! Initialize default axis 127 default_axis%name = 'noname
' 128 default_axis%units = 'nounits
' 129 default_axis%longname = 'noname
' 130 default_axis%cartesian = 'none' 131 default_axis%compressed = 'unspecified
' 132 default_axis%calendar = 'unspecified
' 133 default_axis%sense = 0 134 default_axis%len = -1 136 default_axis%did = -1 137 default_axis%type = -1 138 default_axis%natt = -1 139 ! Initialize default attribute 140 default_att%name = 'noname
' 141 default_att%type = -1 143 default_att%catt = 'none' 145 !up to MAXUNITS fortran units and MAXUNITS netCDF units are supported 146 !file attributes (opened, format, access, threading, fileset) are saved against the unit number 147 !external handles to netCDF units are saved from maxunits+1:2*maxunits 148 allocate( mpp_file(NULLUNIT:2*maxunits) ) !starts at NULLUNIT=-1, used by non-participant PEs in single-threaded I/O 149 mpp_file(:)%name = ' ' 150 mpp_file(:)%action = -1 151 mpp_file(:)%format = -1 152 mpp_file(:)%threading = -1 153 mpp_file(:)%fileset = -1 154 mpp_file(:)%record = -1 155 mpp_file(:)%ncid = -1 156 mpp_file(:)%opened = .FALSE. 157 mpp_file(:)%initialized = .FALSE. 158 mpp_file(:)%write_on_this_pe = .FALSE. 159 mpp_file(:)%io_domain_exist = .FALSE. 160 mpp_file(:)%time_level = 0 161 mpp_file(:)%time = NULLTIME 163 mpp_file(:)%valid = .FALSE. 164 mpp_file(:)%ndim = -1 165 mpp_file(:)%nvar = -1 166 !NULLUNIT "file" is always single-threaded, open and initialized (to pass checks in mpp_write) 167 mpp_file(NULLUNIT)%threading = MPP_SINGLE 168 mpp_file(NULLUNIT)%opened = .TRUE. 169 mpp_file(NULLUNIT)%valid = .TRUE. 170 mpp_file(NULLUNIT)%initialized = .TRUE. 171 !declare the stdunits to be open 172 mpp_file(outunit)%opened = .TRUE. 173 mpp_file(logunit)%opened = .TRUE. 174 inunit = stdin() ; mpp_file(inunit)%opened = .TRUE. 175 errunit = stderr() ; mpp_file(errunit)%opened = .TRUE. 177 if( pe.EQ.mpp_root_pe() )then 178 iunit = stdlog() ! PGI compiler does not like stdlog() doing I/O within write call 179 write( iunit,'(/
a)
' )'MPP_IO
module '//trim(version) 181 text = NF_INQ_LIBVERS() 182 write( iunit,'(/
a)
' )'Using netCDF library
version '//trim(text) 187 !we require every file to be assigned threadwise: PVPs default to global, and are reset here 188 call ASSIGN( 'assign -P thread
p:%
', error ) 191 call mpp_io_set_stack_size(131072) ! default initial value 193 if( io_clocks_on )then 194 mpp_read_clock = mpp_clock_id( 'mpp_read
') 195 mpp_write_clock = mpp_clock_id( 'mpp_write
') 196 mpp_open_clock = mpp_clock_id( 'mpp_open
') 197 mpp_close_clock = mpp_clock_id( 'mpp_close
') 199 module_is_initialized = .TRUE. 201 end subroutine mpp_io_init 204 ! <SUBROUTINE NAME="mpp_io_exit"> 206 ! Exit <TT>mpp_io_mod</TT>. 209 ! It is recommended, though not at present required, that you call this 210 ! near the end of a run. This will close all open files that were opened 211 ! with <LINK SRC="#mpp_open"><TT>mpp_open</TT></LINK>. Files opened otherwise 219 subroutine mpp_io_exit(string) 220 character(len=*), optional :: string 221 integer :: unit,istat 224 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_IO_EXIT: must first call mpp_io_init.
' ) 226 if( PRESENT(string) )then 227 dosync = .NOT.( trim(string).EQ.'NOSYNC
' ) 229 !close all open fortran units 230 do unit = unit_begin,unit_end 231 if( mpp_file(unit)%opened )call FLUSH(unit) 233 if( dosync )call mpp_sync() 234 do unit = unit_begin,unit_end 235 if( mpp_file(unit)%opened )close(unit) 238 !close all open netCDF units 239 do unit = maxunits+1,2*maxunits 240 if( mpp_file(unit)%opened )error = NF_CLOSE(mpp_file(unit)%ncid) 244 ! call mpp_max(mpp_io_stack_hwm) 246 if( pe.EQ.mpp_root_pe() )then 247 ! write( stdout,'(/
a)
' )'Exiting MPP_IO
module...
' 248 ! write( stdout,* )'MPP_IO_STACK high water mark=
', mpp_io_stack_hwm 251 module_is_initialized = .FALSE. 253 end subroutine mpp_io_exit 256 subroutine netcdf_err( err, file, axis, field, attr, string ) 257 integer, intent(in) :: err 258 type(filetype), optional :: file 259 type(axistype), optional :: axis 260 type(fieldtype), optional :: field 261 type(atttype), optional :: attr 262 character(len=*), optional :: string 263 character(len=256) :: errmsg 266 if( err.EQ.NF_NOERR )return 267 errmsg = NF_STRERROR(err) 268 if( PRESENT(file) )errmsg = trim(errmsg)//' File=
'//file%name 269 if( PRESENT(axis) )errmsg = trim(errmsg)//' Axis=
'//axis%name 270 if( PRESENT(field) )errmsg = trim(errmsg)//' Field=
'//field%name 271 if( PRESENT(attr) )errmsg = trim(errmsg)//' Attribute=
'//attr%name 272 if( PRESENT(string) )errmsg = trim(errmsg)//string 273 call mpp_io_exit('NOSYNC
') !make sure you close all open files 274 call mpp_error( FATAL, 'NETCDF ERROR:
'//trim(errmsg) ) 277 end subroutine netcdf_err 280 subroutine mpp_flush(unit) 281 !flush the output on a unit, syncing with disk 282 integer, intent(in) :: unit 284 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_FLUSH: must first call mpp_io_init.
' ) 285 if( .NOT.mpp_file(unit)%write_on_this_pe) return 286 if( .NOT.mpp_file(unit)%opened ) call mpp_error( FATAL, 'MPP_FLUSH: invalid
unit number.
' ) 287 if( .NOT.mpp_file(unit)%initialized )call mpp_error( FATAL, 'MPP_FLUSH: cannot flush
a file during writing of metadata.
' ) 289 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then 291 error = NF_SYNC(mpp_file(unit)%ncid); call netcdf_err( error, mpp_file(unit) ) 297 end subroutine mpp_flush 299 !> Return the maximum number of MPP file units available. 301 !! maxunits is a mpp_io_mod module variable and defines the maximum number 302 !! of Fortran file units that can be open simultaneously. mpp_get_maxunits 303 !! simply returns this number. 304 integer function mpp_get_maxunits() 305 mpp_get_maxunits = maxunits 306 end function mpp_get_maxunits 308 logical function do_cf_compliance() 309 do_cf_compliance = cf_compliance 310 end function do_cf_compliance ************************************************************************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
************************************************************************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
integer, parameter, public no
subroutine, public copy(self, rhs)
character(len=32) units
No description.
integer, parameter, public none
real(r8), dimension(cast_m, cast_n) p
character(len=128) version
l_size ! loop over number of fields ke do je do ie to is
************************************************************************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=> mpp_file(unit)%id
subroutine, private initialize
def Error(filename, linenum, category, confidence, message)
logical function received(this, seqno)
************************************************************************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 not