00001 #ifndef key_noIO
00002 #ifndef __PARNETCDF
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 module mpp_io_mod_oa
00033 use mod_kinds_mpp
00034 use mpp_mod_oa
00035 use mpp_domains_mod_oa
00036 implicit none
00037 #include <os.h>
00038 private
00039
00040 character(len=128), private :: version=
00041 '$Id: mpp_io_mod_oa.F90 2905 2011-01-21 16:29:23Z coquart $'
00042 character(len=128), private :: tagname=
00043 '$Name$'
00044
00045 integer, private :: pe, npes
00046
00047 type, public :: axistype
00048 private
00049 character(len=128) :: name
00050 character(len=128) :: units
00051 character(len=256) :: longname
00052 character(len=8) :: cartesian
00053 integer :: sense, len
00054 type(domain1D) :: domain
00055 real, pointer :: data(:)
00056 character(len=64), pointer :: cdata(:)
00057 integer :: clenid
00058 integer :: id, did, type, natt
00059 type(atttype), pointer :: Att(:)
00060 end type axistype
00061
00062 type, public :: atttype
00063 integer :: type, len
00064 character(len=128) :: name
00065 character(len=256) :: catt
00066
00067 real, pointer :: fatt(:)
00068 end type atttype
00069
00070 type, public :: fieldtype
00071 private
00072 character(len=128) :: name
00073 character(len=128) :: units
00074 character(len=256) :: longname
00075 real :: min, max, missing, fill, scale, add
00076 integer :: pack
00077 type(axistype), pointer :: axes(:)
00078
00079
00080 integer, pointer :: size(:)
00081 integer :: time_axis_index
00082 integer :: id, type, natt, ndim
00083 type(atttype), pointer :: Att(:)
00084 end type fieldtype
00085
00086 type, private :: filetype
00087 character(len=256) :: name
00088 integer :: action, format, access, threading, fileset, record, ncid
00089 logical :: opened, initialized, nohdrs
00090 integer :: time_level
00091 real(DOUBLE_KIND) :: time
00092 integer :: id
00093 integer :: recdimid
00094
00095
00096
00097
00098 real(DOUBLE_KIND), pointer :: time_values(:)
00099
00100
00101 integer :: ndim, nvar, natt
00102
00103
00104 type(axistype), pointer :: axis(:)
00105 type(fieldtype), pointer :: var(:)
00106 type(atttype), pointer :: att(:)
00107 end type filetype
00108
00109 type(axistype), public :: default_axis
00110 type(fieldtype), public :: default_field
00111 type(atttype), public :: default_att
00112
00113 integer, parameter, public :: MPP_WRONLY=100, MPP_RDONLY=101, MPP_APPEND=102, MPP_OVERWR=103
00114
00115 integer, parameter, public :: MPP_ASCII=200, MPP_IEEE32=201, MPP_NATIVE=202, MPP_NETCDF=203
00116
00117 integer, parameter, public :: MPP_SEQUENTIAL=300, MPP_DIRECT=301
00118
00119 integer, parameter, public :: MPP_SINGLE=400, MPP_MULTI=401, MPP_PARALLEL=401
00120
00121 integer, parameter, public :: MPP_DELETE=501, MPP_COLLECT=502
00122
00123 type(filetype), private, allocatable :: mpp_file(:)
00124 integer, private :: records_per_pe
00125 integer, private :: maxunits, unit_begin, unit_end
00126 integer, private :: varnum=0
00127 integer, private :: error
00128 character(len=256) :: text
00129
00130 integer, parameter, private :: NULLUNIT=-1
00131 real(DOUBLE_KIND), parameter, private :: NULLTIME=-1.
00132 #ifdef DEBUG
00133 logical, private :: verbose=.FALSE., debug=.TRUE., module_is_initialized=.FALSE.
00134 #else
00135 logical, private :: verbose=.FALSE., debug=.FALSE., module_is_initialized=.FALSE.
00136 #endif
00137
00138 real(DOUBLE_KIND), private, allocatable :: mpp_io_stack(:)
00139 integer, private :: mpp_io_stack_size=0, mpp_io_stack_hwm=0
00140
00141 interface mpp_write_meta
00142 module procedure mpp_write_meta_var
00143 module procedure mpp_write_meta_scalar_r
00144 module procedure mpp_write_meta_scalar_i
00145 module procedure mpp_write_meta_axis
00146 module procedure mpp_write_meta_field
00147 module procedure mpp_write_meta_global
00148 module procedure mpp_write_meta_global_scalar_r
00149 module procedure mpp_write_meta_global_scalar_i
00150 end interface
00151
00152 interface mpp_copy_meta
00153 module procedure mpp_copy_meta_axis
00154 module procedure mpp_copy_meta_field
00155 module procedure mpp_copy_meta_global
00156 end interface
00157
00158 interface mpp_write
00159 module procedure mpp_write_2ddecomp_r1d
00160 module procedure mpp_write_2ddecomp_r2d
00161 module procedure mpp_write_2ddecomp_r3d
00162 module procedure mpp_write_2ddecomp_r4d
00163 module procedure mpp_write_r0D
00164 module procedure mpp_write_r1D
00165 module procedure mpp_write_r2D
00166 module procedure mpp_write_r3D
00167 module procedure mpp_write_r4D
00168 module procedure mpp_write_axis
00169 end interface
00170
00171 interface mpp_read
00172 module procedure mpp_read_2ddecomp_r1d
00173 module procedure mpp_read_2ddecomp_r2d
00174 module procedure mpp_read_2ddecomp_r3d
00175 module procedure mpp_read_2ddecomp_r4d
00176 module procedure mpp_read_r0D
00177 module procedure mpp_read_r1D
00178 module procedure mpp_read_r2D
00179 module procedure mpp_read_r3D
00180 module procedure mpp_read_r4D
00181 end interface
00182
00183 interface mpp_get_id
00184 module procedure mpp_get_axis_id
00185 module procedure mpp_get_field_id
00186 end interface
00187
00188 interface mpp_get_atts
00189 module procedure mpp_get_global_atts
00190 module procedure mpp_get_field_atts
00191 module procedure mpp_get_axis_atts
00192 end interface
00193
00194 interface mpp_modify_meta
00195
00196 module procedure mpp_modify_field_meta
00197 module procedure mpp_modify_axis_meta
00198 end interface
00199
00200 public :: mpp_close, mpp_flush, mpp_get_iospec, mpp_get_id, mpp_get_ncid, mpp_get_unit_range, mpp_io_init, mpp_io_exit, &
00201 mpp_open, mpp_set_unit_range, mpp_write, mpp_write_meta, mpp_read, mpp_get_info, mpp_get_atts, &
00202 mpp_get_fields, mpp_get_times, mpp_get_axes, mpp_copy_meta, mpp_get_recdimid, mpp_get_axis_data, mpp_modify_meta, &
00203 mpp_io_set_stack_size, mpp_get_field_index, mpp_nullify_axistype, mpp_nullify_axistype_array
00204
00205 private :: read_record, mpp_read_meta, lowercase
00206
00207 #ifdef use_netCDF
00208 #include <netcdf.inc>
00209 #endif
00210
00211 contains
00212
00213
00214
00215
00216
00217
00218 subroutine mpp_io_init( flags, maxunit,maxresunit )
00219 integer, intent(in), optional :: flags, maxunit ,maxresunit
00220
00221
00222
00223
00224
00225 integer::max_reserved_units
00226
00227
00228
00229 if( module_is_initialized )return
00230 call mpp_init(flags)
00231 pe = mpp_pe()
00232 npes = mpp_npes()
00233 call mpp_domains_init(flags)
00234
00235 maxunits = 64
00236 if( PRESENT(maxunit) )maxunits = maxunit
00237
00238 max_reserved_units=5
00239 if( PRESENT(maxresunit) )max_reserved_units = maxresunit
00240
00241 if( PRESENT(flags) )then
00242 debug = flags.EQ.MPP_DEBUG
00243 verbose = flags.EQ.MPP_VERBOSE .OR. debug
00244 end if
00245
00246 default_field%name = 'noname'
00247 default_field%units = 'nounits'
00248 default_field%longname = 'noname'
00249 default_field%id = -1
00250 default_field%type = -1
00251 default_field%natt = -1
00252 default_field%ndim = -1
00253
00254 default_field%min = -huge(1._ip_single_mpp)
00255 default_field%max = huge(1._ip_single_mpp)
00256 default_field%missing = -1e36
00257 default_field%fill = -1e36
00258 default_field%scale = 0.
00259 default_field%add = huge(1._ip_single_mpp)
00260 default_field%pack = 1
00261 default_field%time_axis_index = -1
00262 Nullify(default_field%axes)
00263 Nullify(default_field%size)
00264 Nullify(default_field%att)
00265
00266 default_axis%name = 'noname'
00267 default_axis%units = 'nounits'
00268 default_axis%longname = 'noname'
00269 default_axis%cartesian = 'none'
00270 default_axis%sense = 0
00271 default_axis%len = -1
00272 default_axis%id = -1
00273 default_axis%did = -1
00274 default_axis%type = -1
00275 default_axis%natt = -1
00276 Nullify(default_axis%data)
00277
00278 default_att%name = 'noname'
00279 default_att%type = -1
00280 default_att%len = -1
00281 default_att%catt = 'none'
00282 Nullify(default_att%fatt)
00283
00284
00285
00286
00287 allocate( mpp_file(NULLUNIT:2*maxunits) )
00288 mpp_file(:)%name = ' '
00289 mpp_file(:)%action = -1
00290 mpp_file(:)%format = -1
00291 mpp_file(:)%threading = -1
00292 mpp_file(:)%fileset = -1
00293 mpp_file(:)%record = -1
00294 mpp_file(:)%ncid = -1
00295 mpp_file(:)%opened = .FALSE.
00296 mpp_file(:)%initialized = .FALSE.
00297 mpp_file(:)%time_level = 0
00298 mpp_file(:)%time = NULLTIME
00299 mpp_file(:)%id = -1
00300
00301 mpp_file(:)%ndim = -1
00302 mpp_file(:)%nvar = -1
00303
00304 mpp_file(NULLUNIT)%threading = MPP_SINGLE
00305 mpp_file(NULLUNIT)%opened = .TRUE.
00306 mpp_file(NULLUNIT)%initialized = .TRUE.
00307
00308 mpp_file(stdin ())%opened = .TRUE.
00309 mpp_file(stdout())%opened = .TRUE.
00310 mpp_file(stderr())%opened = .TRUE.
00311 mpp_file(stdout())%opened = .TRUE.
00312
00313
00314
00315
00316
00317 if(present(maxunit)) then
00318 call mpp_set_unit_range( 7, maxunits-max_reserved_units )
00319 else
00320 call mpp_set_unit_range( 7, maxunits )
00321 endif
00322
00323
00324 if( pe.EQ.mpp_root_pe() )then
00325 write( stdout(),'(/a)' )'MPP_IO module '//trim(version)
00326 #ifdef use_netCDF
00327 text = NF_INQ_LIBVERS()
00328 write( stdout(),'(a)' )'Using netCDF library version '//trim(text)
00329 #endif
00330 endif
00331
00332 #ifdef CRAYPVP
00333
00334 call ASSIGN( 'assign -P thread p:%', error )
00335 #endif
00336
00337 call mpp_io_set_stack_size(131072)
00338 call mpp_sync()
00339 module_is_initialized = .TRUE.
00340 return
00341 end subroutine mpp_io_init
00342
00343 subroutine mpp_io_exit()
00344 integer :: unit
00345
00346 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_IO_EXIT: must first call mpp_io_init.' )
00347
00348 do unit = unit_begin,unit_end
00349 if( mpp_file(unit)%opened )call mpp_flushstd(unit)
00350 end do
00351 call mpp_sync()
00352 do unit = unit_begin,unit_end
00353 if( mpp_file(unit)%opened )close(unit)
00354 end do
00355 #ifdef use_netCDF
00356
00357 do unit = maxunits+1,2*maxunits
00358 if( mpp_file(unit)%opened )error = NF_CLOSE(mpp_file(unit)%ncid)
00359 end do
00360 #endif
00361
00362 call mpp_max(mpp_io_stack_hwm)
00363
00364 if( pe.EQ.mpp_root_pe() )then
00365
00366
00367 end if
00368 deallocate(mpp_file)
00369 module_is_initialized = .FALSE.
00370 return
00371 end subroutine mpp_io_exit
00372
00373 subroutine mpp_io_set_stack_size(n)
00374
00375 integer, intent(in) :: n
00376 character(len=8) :: text
00377
00378 if( n.GT.mpp_io_stack_size .AND. allocated(mpp_io_stack) )deallocate(mpp_io_stack)
00379 if( .NOT.allocated(mpp_io_stack) )then
00380 allocate( mpp_io_stack(n) )
00381 mpp_io_stack_size = n
00382 write( text,'(i8)' )n
00383 if( pe.EQ.mpp_root_pe() ) &
00384 call mpp_error( NOTE, 'MPP_IO_SET_STACK_SIZE: stack size set to '//text//'.' )
00385 end if
00386
00387 return
00388 end subroutine mpp_io_set_stack_size
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 subroutine mpp_open( unit, file, action, form, access, threading, &
00434 fileset, iospec, nohdrs, recl, pelist )
00435 integer, intent(out) :: unit
00436 character(len=*), intent(in) :: file
00437 integer, intent(in), optional :: action, form, access, threading,
00438 fileset, recl
00439 character(len=*), intent(in), optional :: iospec
00440 logical, intent(in), optional :: nohdrs
00441 integer, intent(in), optional :: pelist(:)
00442
00443 character(len=16) :: act, acc, for, pos
00444 integer :: action_flag, form_flag, access_flag, threading_flag, fileset_flag, length
00445 logical :: exists
00446 character(len=64) :: filespec
00447 type(axistype) :: unlim
00448
00449 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_OPEN: must first call mpp_io_init.' )
00450
00451 action_flag = MPP_WRONLY
00452 if( PRESENT(action) )action_flag = action
00453 form_flag = MPP_ASCII
00454 if( PRESENT(form) )form_flag = form
00455 #ifndef use_netCDF
00456 if( form_flag.EQ.MPP_NETCDF ) &
00457 call mpp_error( FATAL, 'MPP_OPEN: To open a file with form=MPP_NETCDF, you must compile mpp_io with -Duse_netCDF.' )
00458 #endif
00459 access_flag = MPP_SEQUENTIAL
00460 if( PRESENT(access) )access_flag = access
00461 threading_flag = MPP_SINGLE
00462 if( npes.GT.1 .AND. PRESENT(threading) )threading_flag = threading
00463 fileset_flag = MPP_MULTI
00464 if( PRESENT(fileset) )fileset_flag = fileset
00465 if( threading_flag.EQ.MPP_SINGLE )fileset_flag = MPP_SINGLE
00466
00467
00468 if( threading_flag.EQ.MPP_SINGLE )then
00469 if( pe.NE.mpp_root_pe() .AND. action_flag.NE.MPP_RDONLY )then
00470 unit = NULLUNIT
00471 return
00472 end if
00473 end if
00474 if( form_flag.EQ.MPP_NETCDF )then
00475 do unit = maxunits+1,2*maxunits
00476 if( .NOT.mpp_file(unit)%opened )exit
00477 end do
00478 if( unit.GT.2*maxunits )call mpp_error( FATAL, 'MPP_OPEN: too many open netCDF files.' )
00479 else
00480 do unit = unit_begin, unit_end
00481 inquire( unit,OPENED=mpp_file(unit)%opened )
00482 if( .NOT.mpp_file(unit)%opened )exit
00483 end do
00484 if( unit.GT.unit_end )call mpp_error( FATAL, 'MPP_OPEN: no available units.' )
00485 end if
00486
00487
00488 text = file
00489 length = len(file)
00490
00491
00492
00493
00494
00495
00496 if( fileset_flag.EQ.MPP_MULTI )write( text,'(a,i4.4)' )trim(text)//'.', pe
00497 mpp_file(unit)%name = text
00498 if( verbose ) write (stdout(), '(a,2i3,1x,a,5i5)') &
00499 'MPP_OPEN: PE, unit, filename, action, format, access, threading, fileset=', &
00500 pe, unit, trim(mpp_file(unit)%name), action_flag, form_flag, access_flag, threading_flag, fileset_flag
00501
00502
00503 if( action_flag.EQ.MPP_RDONLY )then
00504 act = 'READ'
00505 pos = 'REWIND'
00506
00507 else if( action_flag.EQ.MPP_WRONLY .OR. action_flag.EQ.MPP_OVERWR )then
00508 act = 'WRITE'
00509 pos = 'REWIND'
00510 else if( action_flag.EQ.MPP_APPEND )then
00511 act = 'WRITE'
00512 pos = 'APPEND'
00513 else
00514 call mpp_error( FATAL, 'MPP_OPEN: action must be one of MPP_WRONLY, MPP_APPEND or MPP_RDONLY.' )
00515 end if
00516
00517
00518 if( form_flag.NE.MPP_NETCDF )then
00519 if( access_flag.EQ.MPP_SEQUENTIAL )then
00520 acc = 'SEQUENTIAL'
00521 else if( access_flag.EQ.MPP_DIRECT )then
00522 acc = 'DIRECT'
00523 if( form_flag.EQ.MPP_ASCII )call mpp_error( FATAL, 'MPP_OPEN: formatted direct access I/O is prohibited.' )
00524 if( .NOT.PRESENT(recl) ) &
00525 call mpp_error( FATAL, 'MPP_OPEN: recl (record length in bytes) must be specified with access=MPP_DIRECT.' )
00526 mpp_file(unit)%record = 1
00527 records_per_pe = 1
00528 else
00529 call mpp_error( FATAL, 'MPP_OPEN: access must be one of MPP_SEQUENTIAL or MPP_DIRECT.' )
00530 end if
00531 end if
00532
00533
00534 if( threading_flag.EQ.MPP_MULTI )then
00535
00536 if( fileset_flag.EQ.MPP_SINGLE )then
00537 if( form_flag.EQ.MPP_NETCDF .AND. act.EQ.'WRITE' ) &
00538 call mpp_error( FATAL, 'MPP_OPEN: netCDF currently does not support single-file multi-threaded output.' )
00539
00540 #ifdef _CRAYT3E
00541 call ASSIGN( 'assign -I -F global.privpos f:'//trim(mpp_file(unit)%name), error )
00542 #endif
00543 else if( fileset_flag.NE.MPP_MULTI )then
00544 call mpp_error( FATAL, 'MPP_OPEN: fileset must be one of MPP_MULTI or MPP_SINGLE.' )
00545 end if
00546 else if( threading_flag.NE.MPP_SINGLE )then
00547 call mpp_error( FATAL, 'MPP_OPEN: threading must be one of MPP_SINGLE or MPP_MULTI.' )
00548 end if
00549
00550
00551
00552 #ifdef CRAYPVP
00553 call ASSIGN( 'assign -I -P thread f:'//trim(mpp_file(unit)%name), error )
00554 #endif
00555 #ifdef _CRAYT3E
00556 call ASSIGN( 'assign -I -P private f:'//trim(mpp_file(unit)%name), error )
00557 #endif
00558 if( PRESENT(iospec) )then
00559
00560
00561
00562
00563 #ifdef SGICRAY
00564 call ASSIGN( 'assign -I '//trim(iospec)//' f:'//trim(mpp_file(unit)%name), error )
00565 if( form_flag.EQ.MPP_NETCDF )then
00566
00567
00568
00569
00570 call PXFSETENV( 'NETCDF_XFFIOSPEC', 0, trim(iospec), 0, 1, error )
00571 end if
00572 #endif
00573 end if
00574
00575
00576 if( form_flag.EQ.MPP_NETCDF )then
00577 #ifdef use_netCDF
00578 if( action_flag.EQ.MPP_WRONLY )then
00579 error = NF_CREATE( trim(mpp_file(unit)%name), NF_NOCLOBBER, mpp_file(unit)%ncid ); call netcdf_err(error)
00580 if( verbose ) write (stdout(), '(a,i3,i16)') 'MPP_OPEN: new netCDF file: pe, ncid=', pe, mpp_file(unit)%ncid
00581 else if( action_flag.EQ.MPP_OVERWR )then
00582 error = NF_CREATE( trim(mpp_file(unit)%name), NF_CLOBBER, mpp_file(unit)%ncid ); call netcdf_err(error)
00583 action_flag = MPP_WRONLY
00584 if( verbose ) write (stdout(), '(a,i3,i16)') 'MPP_OPEN: overwrite netCDF file: pe, ncid=', pe, mpp_file(unit)%ncid
00585 else if( action_flag.EQ.MPP_APPEND )then
00586 error = NF_OPEN( trim(mpp_file(unit)%name), NF_WRITE, mpp_file(unit)%ncid ); call netcdf_err(error)
00587
00588 error = NF_INQ_UNLIMDIM( mpp_file(unit)%ncid, unlim%did )
00589 if( error.EQ.NF_NOERR )then
00590 error = NF_INQ_DIM( mpp_file(unit)%ncid, unlim%did, unlim%name, mpp_file(unit)%time_level )
00591 call netcdf_err(error)
00592 error = NF_INQ_VARID( mpp_file(unit)%ncid, unlim%name, mpp_file(unit)%id ); call netcdf_err(error)
00593 end if
00594 if( verbose ) write (stdout(), '(a,i3,i16,i4)') 'MPP_OPEN: append to existing netCDF file: pe, ncid, time_axis_id=',&
00595 pe, mpp_file(unit)%ncid, mpp_file(unit)%id
00596 else if( action_flag.EQ.MPP_RDONLY )then
00597 error = NF_OPEN( trim(mpp_file(unit)%name), NF_NOWRITE, mpp_file(unit)%ncid ); call netcdf_err(error)
00598 if( verbose ) write (stdout(), '(a,i3,i16,i4)') 'MPP_OPEN: opening existing netCDF file: pe, ncid, time_axis_id=',&
00599 pe, mpp_file(unit)%ncid, mpp_file(unit)%id
00600 mpp_file(unit)%format=form_flag
00601 call mpp_read_meta(unit)
00602 end if
00603 mpp_file(unit)%opened = .TRUE.
00604 #endif
00605 else
00606
00607 if( form_flag.EQ.MPP_ASCII )then
00608 for = 'FORMATTED'
00609 else if( form_flag.EQ.MPP_IEEE32 )then
00610 for = 'UNFORMATTED'
00611
00612 #ifdef _CRAY
00613 call ASSIGN( 'assign -I -N ieee_32 f:'//trim(mpp_file(unit)%name), error )
00614 #endif
00615 else if( form_flag.EQ.MPP_NATIVE )then
00616 for = 'UNFORMATTED'
00617 else
00618 call mpp_error( FATAL, 'MPP_OPEN: form must be one of MPP_ASCII, MPP_NATIVE, MPP_IEEE32 or MPP_NETCDF.' )
00619 end if
00620 inquire( file=trim(mpp_file(unit)%name), EXIST=exists )
00621 if( exists .AND. action_flag.EQ.MPP_WRONLY ) &
00622 call mpp_error( WARNING, 'MPP_OPEN: File '//trim(mpp_file(unit)%name)//' opened WRONLY already exists!' )
00623 if( action_flag.EQ.MPP_OVERWR )action_flag = MPP_WRONLY
00624
00625 if( PRESENT(recl) )then
00626 if( verbose ) write (stdout(), '(2(1x,a,i3),5(1x,a),a,i8)') 'MPP_OPEN: PE=', pe, &
00627 'unit=', unit, trim(mpp_file(unit)%name), 'attributes=', trim(acc), trim(for), trim(act), ' RECL=', recl
00628 open( unit, file=trim(mpp_file(unit)%name), access=acc, form=for, action=act, recl=recl )
00629 else
00630 if( verbose ) write (stdout(), '(2(1x,a,i3),6(1x,a))') 'MPP_OPEN: PE=', pe, &
00631 'unit=', unit, trim(mpp_file(unit)%name), 'attributes=', trim(acc), trim(for), trim(pos), trim(act)
00632 open( unit, file=trim(mpp_file(unit)%name), access=acc, form=for, action=act, position=pos )
00633 end if
00634
00635 inquire( unit,OPENED=mpp_file(unit)%opened )
00636 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_OPEN: error in OPEN() statement.' )
00637 end if
00638 mpp_file(unit)%action = action_flag
00639 mpp_file(unit)%format = form_flag
00640 mpp_file(unit)%access = access_flag
00641 mpp_file(unit)%threading = threading_flag
00642 mpp_file(unit)%fileset = fileset_flag
00643 if( PRESENT(nohdrs) )mpp_file(unit)%nohdrs = nohdrs
00644
00645 if( action_flag.EQ.MPP_WRONLY )then
00646 if( form_flag.NE.MPP_NETCDF .AND. access_flag.EQ.MPP_DIRECT )call mpp_write_meta( unit, 'record_length', ival=recl )
00647
00648 call mpp_write_meta( unit, 'filename', cval=mpp_file(unit)%name )
00649
00650 call mpp_write_meta( unit, 'MPP_IO_VERSION', cval=trim(version) )
00651
00652 if( threading_flag.EQ.MPP_MULTI .AND. fileset_flag.EQ.MPP_MULTI ) &
00653 call mpp_write_meta( unit, 'NumFilesInSet', ival=npes )
00654 end if
00655
00656 return
00657 end subroutine mpp_open
00658
00659 subroutine mpp_close( unit, action )
00660 integer, intent(in) :: unit
00661 integer, intent(in), optional :: action
00662 character(len=8) :: status
00663 logical :: collect
00664
00665 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_CLOSE: must first call mpp_io_init.' )
00666 if( unit.EQ.NULLUNIT )return
00667
00668
00669 status = 'KEEP'
00670
00671 collect = .FALSE.
00672 if( PRESENT(action) )then
00673 if( action.EQ.MPP_DELETE )then
00674 status = 'DELETE'
00675 else if( action.EQ.MPP_COLLECT )then
00676 collect = .FALSE.
00677 call mpp_error( WARNING, 'MPP_CLOSE: the COLLECT operation is not yet implemented.' )
00678 else
00679 call mpp_error( FATAL, 'MPP_CLOSE: action must be one of MPP_DELETE or MPP_COLLECT.' )
00680 end if
00681 end if
00682 if( mpp_file(unit)%fileset.NE.MPP_MULTI )collect = .FALSE.
00683 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
00684 #ifdef use_netCDF
00685 error = NF_CLOSE(mpp_file(unit)%ncid); call netcdf_err(error)
00686 #endif
00687 else
00688 close(unit,status=status)
00689 end if
00690 #ifdef SGICRAY
00691
00692
00693
00694 #endif
00695 mpp_file(unit)%name = ' '
00696 mpp_file(unit)%action = -1
00697 mpp_file(unit)%format = -1
00698 mpp_file(unit)%access = -1
00699 mpp_file(unit)%threading = -1
00700 mpp_file(unit)%fileset = -1
00701 mpp_file(unit)%record = -1
00702 mpp_file(unit)%ncid = -1
00703 mpp_file(unit)%opened = .FALSE.
00704 mpp_file(unit)%initialized = .FALSE.
00705 mpp_file(unit)%id = -1
00706 mpp_file(unit)%time_level = 0
00707 mpp_file(unit)%time = NULLTIME
00708 return
00709 end subroutine mpp_close
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 subroutine mpp_write_meta_global( unit, name, rval, ival, cval, pack )
00825
00826
00827
00828
00829
00830 integer, intent(in) :: unit
00831 character(len=*), intent(in) :: name
00832 real, intent(in), optional :: rval(:)
00833 integer, intent(in), optional :: ival(:)
00834 character(len=*), intent(in), optional :: cval
00835 integer, intent(in), optional :: pack
00836
00837 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
00838 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
00839 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00840 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00841 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
00842 if( mpp_file(unit)%initialized ) &
00843 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
00844
00845 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
00846 #ifdef use_netCDF
00847 call write_attribute_netcdf( unit, NF_GLOBAL, name, rval, ival, cval, pack )
00848 #endif
00849 else
00850 call write_attribute( unit, 'GLOBAL '//trim(name), rval, ival, cval, pack )
00851 end if
00852
00853 return
00854 end subroutine mpp_write_meta_global
00855
00856
00857 subroutine mpp_write_meta_global_scalar_r( unit, name, rval, pack )
00858 integer, intent(in) :: unit
00859 character(len=*), intent(in) :: name
00860 real, intent(in) :: rval
00861 integer, intent(in), optional :: pack
00862
00863 call mpp_write_meta_global( unit, name, rval=(/rval/), pack=pack )
00864 return
00865 end subroutine mpp_write_meta_global_scalar_r
00866
00867 subroutine mpp_write_meta_global_scalar_i( unit, name, ival )
00868 integer, intent(in) :: unit
00869 character(len=*), intent(in) :: name
00870 integer, intent(in) :: ival
00871
00872 call mpp_write_meta_global( unit, name, ival=(/ival/) )
00873 return
00874 end subroutine mpp_write_meta_global_scalar_i
00875
00876 subroutine mpp_write_meta_var( unit, id, name, rval, ival, cval, pack )
00877
00878
00879
00880
00881
00882 integer, intent(in) :: unit, id
00883 character(len=*), intent(in) :: name
00884 real, intent(in), optional :: rval(:)
00885 integer, intent(in), optional :: ival(:)
00886 character(len=*), intent(in), optional :: cval
00887 integer, intent(in), optional :: pack
00888
00889 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
00890 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
00891 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00892 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00893 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
00894 if( mpp_file(unit)%initialized ) &
00895 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
00896
00897 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
00898 call write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
00899 else
00900 write( text, '(a,i4,a)' )'VARIABLE ', id, ' '//name
00901 call write_attribute( unit, trim(text), rval, ival, cval, pack )
00902 end if
00903
00904 return
00905 end subroutine mpp_write_meta_var
00906
00907
00908 subroutine mpp_write_meta_scalar_r( unit, id, name, rval, pack )
00909 integer, intent(in) :: unit, id
00910 character(len=*), intent(in) :: name
00911 real, intent(in) :: rval
00912 integer, intent(in), optional :: pack
00913
00914 call mpp_write_meta( unit, id, name, rval=(/rval/), pack=pack )
00915 return
00916 end subroutine mpp_write_meta_scalar_r
00917
00918 subroutine mpp_write_meta_scalar_i( unit, id, name, ival )
00919 integer, intent(in) :: unit, id
00920 character(len=*), intent(in) :: name
00921 integer, intent(in) :: ival
00922
00923 call mpp_write_meta( unit, id, name, ival=(/ival/) )
00924 return
00925 end subroutine mpp_write_meta_scalar_i
00926
00927 subroutine mpp_write_meta_axis( unit, axis, name, units, longname, cartesian, sense, domain, data, cdata) !RV,bundles
00928
00929
00930
00931
00932 integer, intent(in) :: unit
00933 type(axistype), intent(inout) :: axis
00934 character(len=*), intent(in) :: name, units, longname
00935 character(len=*), intent(in), optional :: cartesian
00936 integer, intent(in), optional :: sense
00937 type(domain1D), intent(in), optional :: domain
00938 real, intent(in), optional :: data(:)
00939 character(len=*), intent(in), optional :: cdata(:)
00940 integer :: is, ie, isg, ieg
00941
00942 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
00943 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
00944 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00945 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
00946 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
00947 if( mpp_file(unit)%initialized ) &
00948 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
00949
00950
00951 if( ASSOCIATED(axis%data) )NULLIFY(axis%data)
00952 if( ASSOCIATED(axis%cdata) )NULLIFY(axis%cdata)
00953
00954 axis%name = name
00955 axis%units = units
00956 axis%longname = longname
00957 if( PRESENT(cartesian) )axis%cartesian = cartesian
00958 if( PRESENT(sense) )axis%sense = sense
00959 if( PRESENT(domain) )then
00960 axis%domain = domain
00961 call mpp_get_global_domain( domain, isg, ieg )
00962 call mpp_get_compute_domain( domain, is, ie )
00963 else
00964 axis%domain = NULL_DOMAIN1D
00965 if( PRESENT(data) )then
00966 isg=1; ieg=size(data); is=isg; ie=ieg
00967 endif
00968 if( PRESENT(cdata) )then
00969 isg=1; ieg=size(cdata); is=isg; ie=ieg
00970 endif
00971 end if
00972 if( PRESENT(data) )then
00973 if( PRESENT(domain) )then
00974 if( size(data).NE.ieg-isg+1 ) &
00975 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: size(data).NE.domain%global%size.' )
00976 allocate( axis%data(isg:ieg) )
00977 else
00978 allocate( axis%data(size(data)) )
00979 end if
00980 axis%data = data
00981 end if
00982 if( PRESENT(cdata) )then
00983 if( PRESENT(domain) )then
00984 if( size(cdata).NE.ieg-isg+1 ) &
00985 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: size(cdata).NE.domain%global%size.' )
00986 allocate( axis%cdata(isg:ieg) )
00987 allocate( axis%data(isg:ieg) )
00988 else
00989 allocate( axis%cdata(size(cdata)) )
00990 allocate( axis%data(size(cdata)) )
00991 end if
00992 axis%cdata = cdata
00993 end if
00994
00995
00996
00997 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
00998 #ifdef use_netCDF
00999
01000
01001 if( ASSOCIATED(axis%data).or. ASSOCIATED(axis%cdata) )then
01002 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
01003 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, ie-is+1, axis%did )
01004 else
01005 if( ASSOCIATED(axis%data).and.(.not.present(cdata)))then
01006 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, size(axis%data), axis%did )
01007 else
01008 error = NF_DEF_DIM( mpp_file(unit)%ncid, 'MAX_STRLEN', len(axis%cdata), axis%clenid )
01009 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, size(axis%cdata), axis%did )
01010 endif
01011 end if
01012 call netcdf_err(error)
01013 if(present(cdata)) then
01014 error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_CHAR, 2,(/axis%clenid, axis%did/), axis%id )
01015 call netcdf_err(error)
01016 else
01017 error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id ); call netcdf_err(error)
01018 endif
01019
01020 else
01021 if( mpp_file(unit)%id.NE.-1 ) &
01022 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
01023 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, NF_UNLIMITED, axis%did ); call netcdf_err(error)
01024 error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id ); call netcdf_err(error)
01025 mpp_file(unit)%id = axis%id
01026 end if
01027 #endif
01028 else
01029 varnum = varnum + 1
01030 axis%id = varnum
01031 axis%did = varnum
01032
01033 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
01034 call write_attribute( unit, trim(text), cval=axis%name )
01035 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
01036 if( ASSOCIATED(axis%data) )then
01037 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
01038 call write_attribute( unit, trim(text), ival=(/ie-is+1/) )
01039 else
01040 if(ASSOCIATED(axis%data).and.(.not.present(cdata))) then
01041
01042 call write_attribute( unit, trim(text), ival=(/size(axis%data)/) )
01043 else
01044 call write_attribute( unit, trim(text), ival=(/size(axis%cdata)/) )
01045 endif
01046 end if
01047 else
01048 if( mpp_file(unit)%id.NE.-1 ) &
01049 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
01050 call write_attribute( unit, trim(text), ival=(/0/) )
01051 mpp_file(unit)%id = axis%id
01052 end if
01053 end if
01054
01055 call mpp_write_meta( unit, axis%id, 'long_name', cval=axis%longname )
01056 call mpp_write_meta( unit, axis%id, 'units', cval=axis%units )
01057 if( PRESENT(cartesian) )call mpp_write_meta( unit, axis%id, 'cartesian_axis', cval=axis%cartesian )
01058 if( PRESENT(sense) )then
01059 if( sense.EQ.-1 )then
01060 call mpp_write_meta( unit, axis%id, 'positive', cval='down' )
01061 else if( sense.EQ.1 )then
01062 call mpp_write_meta( unit, axis%id, 'positive', cval='up' )
01063 end if
01064
01065 end if
01066 if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
01067 call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/) )
01068 end if
01069 if( verbose ) write (stdout(), '(a,2i3,1x,a,2i3)') &
01070 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
01071 pe, unit, trim(axis%name), axis%id, axis%did
01072
01073 return
01074 end subroutine mpp_write_meta_axis
01075
01076 subroutine mpp_write_meta_field( unit, field, axes, name, units, longname, min, max, missing, fill, scale, add, pack )
01077
01078 integer, intent(in) :: unit
01079 type(fieldtype), intent(out) :: field
01080 type(axistype), intent(in) :: axes(:)
01081 character(len=*), intent(in) :: name, units, longname
01082 real, intent(in), optional :: min, max, missing, fill, scale, add
01083 integer, intent(in), optional :: pack
01084
01085 integer, allocatable :: axis_id(:)
01086 real :: a, b
01087 integer :: i
01088
01089 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
01090 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
01091 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01092 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01093 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
01094 if( mpp_file(unit)%initialized ) &
01095 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
01096
01097
01098
01099
01100 field%name = name
01101 field%units = units
01102 field%longname = longname
01103 allocate( field%axes(size(axes)) )
01104 field%axes = axes
01105 field%time_axis_index = -1
01106
01107
01108 allocate( field%size(size(axes)) )
01109 do i = 1,size(axes)
01110 if( ASSOCIATED(axes(i)%data) )then
01111 field%size(i) = size(axes(i)%data)
01112 else
01113 field%size(i) = 1
01114 field%time_axis_index = i
01115 end if
01116 end do
01117
01118 if( PRESENT(min) )field%min = min
01119 if( PRESENT(max) )field%max = max
01120 if( PRESENT(missing) )field%missing = missing
01121 if( PRESENT(fill) )field%fill = fill
01122 if( PRESENT(scale) )field%scale = scale
01123 if( PRESENT(add) )field%add = add
01124
01125
01126 field%pack = 2
01127 if( PRESENT(pack) )field%pack = pack
01128 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
01129 #ifdef use_netCDF
01130 allocate( axis_id(size(field%axes)) )
01131 do i = 1,size(field%axes)
01132 axis_id(i) = field%axes(i)%did
01133 end do
01134
01135 select case (field%pack)
01136 case(1)
01137 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes), axis_id, field%id )
01138 case(2)
01139 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes), axis_id, field%id )
01140 case(4)
01141 if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
01142 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
01143 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes), axis_id, field%id )
01144 case(8)
01145 if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
01146 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
01147 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes), axis_id, field%id )
01148 case default
01149 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
01150 end select
01151 call netcdf_err(error)
01152 #endif
01153 else
01154 varnum = varnum + 1
01155 field%id = varnum
01156 if( PRESENT(pack) )call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
01157
01158 write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
01159 call write_attribute( unit, trim(text), cval=field%name )
01160 write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
01161 call write_attribute( unit, trim(text), ival=field%axes(:)%did )
01162 end if
01163
01164 call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname )
01165 call mpp_write_meta( unit, field%id, 'units', cval=field%units )
01166
01167 if( PRESENT(min) .AND. PRESENT(max) )then
01168 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
01169 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/min,max/), pack=pack )
01170 else
01171 a = nint((min-add)/scale)
01172 b = nint((max-add)/scale)
01173 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=pack )
01174 end if
01175 else if( PRESENT(min) )then
01176 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
01177 call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=pack )
01178 else
01179 a = nint((min-add)/scale)
01180 call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=pack )
01181 end if
01182 else if( PRESENT(max) )then
01183 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
01184 call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=pack )
01185 else
01186 a = nint((max-add)/scale)
01187 call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=pack )
01188 end if
01189 end if
01190 if( PRESENT(missing) )then
01191 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
01192 call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=pack )
01193 else
01194 a = nint((missing-add)/scale)
01195 call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=pack )
01196 end if
01197 end if
01198 if( PRESENT(fill) )then
01199 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
01200 call mpp_write_meta( unit, field%id, '_FillValue', rval=field%fill, pack=pack )
01201 else
01202 a = nint((fill-add)/scale)
01203 call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=pack )
01204 end if
01205 end if
01206 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
01207 call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
01208 if( PRESENT(scale) )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
01209 if( PRESENT(add) )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
01210 end if
01211 if( verbose ) write (stdout(), '(a,2i3,1x,a,i3)') 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
01212 pe, unit, trim(field%name), field%id
01213
01214 return
01215 end subroutine mpp_write_meta_field
01216
01217 subroutine write_attribute( unit, name, rval, ival, cval, pack )
01218
01219 integer, intent(in) :: unit
01220 character(len=*), intent(in) :: name
01221 real, intent(in), optional :: rval(:)
01222 integer, intent(in), optional :: ival(:)
01223 character(len=*), intent(in), optional :: cval
01224
01225 integer, intent(in), optional :: pack
01226
01227 if( mpp_file(unit)%nohdrs )return
01228
01229 if( PRESENT(rval) )then
01230 write( text,* )trim(name)//'=', rval
01231 else if( PRESENT(ival) )then
01232 write( text,* )trim(name)//'=', ival
01233 else if( PRESENT(cval) )then
01234 text = ' '//trim(name)//'='//trim(cval)
01235 else
01236 call mpp_error( FATAL, 'WRITE_ATTRIBUTE: one of rval, ival, cval must be present.' )
01237 end if
01238 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
01239
01240 write( unit,fmt='(a)' )trim(text)//char(10)
01241 else
01242 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
01243 write(unit)trim(text)//char(10)
01244 else
01245 write( unit,rec=mpp_file(unit)%record )trim(text)//char(10)
01246 if( verbose ) write (stdout(), '(a,i3,a,i3)') 'WRITE_ATTRIBUTE: PE=', pe, ' wrote record ', mpp_file(unit)%record
01247 mpp_file(unit)%record = mpp_file(unit)%record + 1
01248 end if
01249 end if
01250 return
01251 end subroutine write_attribute
01252
01253 subroutine write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
01254
01255 integer, intent(in) :: unit
01256 integer, intent(in) :: id
01257 character(len=*), intent(in) :: name
01258 real, intent(in), optional :: rval(:)
01259 integer, intent(in), optional :: ival(:)
01260 character(len=*), intent(in), optional :: cval
01261 integer, intent(in), optional :: pack
01262 integer :: lenc
01263 integer, allocatable :: rval_i(:)
01264 #ifdef use_netCDF
01265 integer :: ii, il_bytesize, il_iosize
01266 integer :: il_int_iosize, il_rbyt
01267
01268 if( PRESENT(rval) )then
01269
01270 il_bytesize = BIT_SIZE(ii)/8
01271 INQUIRE (iolength=il_iosize) ii
01272 il_int_iosize = il_iosize
01273 INQUIRE (iolength=il_iosize) rval(1)
01274 il_rbyt = il_iosize/il_int_iosize*il_bytesize
01275
01276 if( PRESENT(pack) )then
01277 if( pack.EQ.1 )then
01278 if( il_rbyt.EQ.DOUBLE_KIND )then
01279 error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval), rval )
01280 else if( il_rbyt.EQ.FLOAT_KIND )then
01281 call mpp_error( WARNING, &
01282 'WRITE_ATTRIBUTE_NETCDF: attempting to write internal 32-bit real as external 64-bit.' )
01283 error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_DOUBLE, size(rval), rval )
01284 end if
01285 call netcdf_err(error)
01286 else if( pack.EQ.2 )then
01287 if( il_rbyt.EQ.DOUBLE_KIND )then
01288 error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval), rval )
01289 else if( il_rbyt.EQ.FLOAT_KIND )then
01290 error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval), rval )
01291 end if
01292 call netcdf_err(error)
01293 else if( pack.EQ.4 )then
01294 allocate( rval_i(size(rval)) )
01295 rval_i = rval
01296 call mpp_flushstd(6)
01297 if( il_rbyt.EQ.DOUBLE_KIND )then
01298 error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_SHORT, size(rval_i), rval )
01299 else if( il_rbyt.EQ.FLOAT_KIND )then
01300 error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_SHORT, size(rval_i), rval )
01301 end if
01302 call netcdf_err(error)
01303 deallocate(rval_i)
01304 else if( pack.EQ.8 )then
01305 allocate( rval_i(size(rval)) )
01306 rval_i = rval
01307 if( il_rbyt.EQ.DOUBLE_KIND )then
01308 error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_BYTE, size(rval_i), rval )
01309 else if( il_rbyt.EQ.FLOAT_KIND )then
01310 error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_BYTE, size(rval_i), rval )
01311 end if
01312 call netcdf_err(error)
01313 deallocate(rval_i)
01314 else
01315 call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: only legal packing values are 1,2,4,8.' )
01316 end if
01317 else
01318
01319 if( il_rbyt.EQ.DOUBLE_KIND )then
01320 error = NF_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval), rval )
01321 else if( il_rbyt.EQ.FLOAT_KIND )then
01322 error = NF_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, size(rval), rval )
01323 end if
01324 call netcdf_err(error)
01325 end if
01326 else if( PRESENT(ival) )then
01327 error = NF_PUT_ATT_INT ( mpp_file(unit)%ncid, id, name, NF_INT, size(ival), ival ); call netcdf_err(error)
01328 else if( present(cval) )then
01329 error = NF_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, name, len_trim(cval), cval ); call netcdf_err(error)
01330 else
01331 call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: one of rval, ival, cval must be present.' )
01332 end if
01333 #endif /* use_netCDF */
01334 return
01335 end subroutine write_attribute_netcdf
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387 #define MPP_WRITE_2DDECOMP_1D_ mpp_write_2ddecomp_r1d
01388 #define MPP_WRITE_2DDECOMP_2D_ mpp_write_2ddecomp_r2d
01389 #define MPP_WRITE_2DDECOMP_3D_ mpp_write_2ddecomp_r3d
01390 #define MPP_WRITE_2DDECOMP_4D_ mpp_write_2ddecomp_r4d
01391 #define MPP_TYPE_ real
01392 #include <mpp_write_2Ddecomp.h>
01393
01394 #define MPP_WRITE_ mpp_write_r0D
01395 #define MPP_TYPE_ real
01396 #define MPP_RANK_ !
01397 #define MPP_WRITE_RECORD_ call write_record( unit, field, 1, (/data/), tstamp )
01398 #include <mpp_write.h>
01399
01400 #define MPP_WRITE_ mpp_write_r1D
01401 #define MPP_TYPE_ real
01402 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
01403 #define MPP_RANK_ (:)
01404 #include <mpp_write.h>
01405
01406 #define MPP_WRITE_ mpp_write_r2D
01407 #define MPP_TYPE_ real
01408 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
01409 #define MPP_RANK_ (:,:)
01410 #include <mpp_write.h>
01411
01412 #define MPP_WRITE_ mpp_write_r3D
01413 #define MPP_TYPE_ real
01414 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
01415 #define MPP_RANK_ (:,:,:)
01416 #include <mpp_write.h>
01417
01418 #define MPP_WRITE_ mpp_write_r4D
01419 #define MPP_TYPE_ real
01420 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
01421 #define MPP_RANK_ (:,:,:,:)
01422 #include <mpp_write.h>
01423
01424 subroutine mpp_write_axis( unit, axis )
01425 integer, intent(in) :: unit
01426 type(axistype), intent(in) :: axis
01427 type(fieldtype) :: field
01428 integer :: is, ie
01429
01430
01431 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
01432 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
01433 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01434 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01435
01436 field = default_field
01437 allocate( field%axes(1) )
01438 field%axes(1) = axis
01439 allocate( field%size(1) )
01440 field%id = axis%id
01441 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
01442 call mpp_get_compute_domain( axis%domain, is, ie )
01443 field%size(1) = ie-is+1
01444
01445 if(associated( axis%cdata)) then
01446 call write_record_c( unit, field, field%size(1), axis%cdata(is:) )
01447 else
01448 call write_record( unit, field, field%size(1), axis%data(is:) )
01449 endif
01450
01451 else
01452
01453 if(associated( axis%cdata)) then
01454 field%size(1) = size(axis%cdata)
01455 call write_record_c(unit,field, field%size(1), axis%cdata )
01456 else
01457 field%size(1) = size(axis%data)
01458 call write_record( unit, field, field%size(1), axis%data )
01459 endif
01460
01461 end if
01462 return
01463 end subroutine mpp_write_axis
01464
01465 subroutine write_record_c( unit, field, nwords, cdata, time_in, domain ) !!RV,bundles
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482 integer, intent(in) :: unit, nwords
01483 type(fieldtype), intent(in) :: field
01484
01485 character(len=64), intent(in) :: cdata(nwords)
01486 real(DOUBLE_KIND), intent(in), optional :: time_in
01487 type(domain2D), intent(in), optional :: domain
01488
01489
01490 integer,allocatable,dimension(:) :: start, axsiz
01491
01492 real :: time
01493 integer :: time_level
01494 logical :: newtime
01495 integer :: subdomain(4)
01496 integer :: packed_data(nwords)
01497 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
01498 #ifdef use_netCDF
01499 integer :: ii, il_bytesize, il_iosize
01500 integer :: il_int_iosize, il_rbyt
01501 #endif
01502
01503 #ifdef use_CRI_pointers
01504 real(FLOAT_KIND) :: data_r4(nwords)
01505 pointer( ptr1, data_r4)
01506 pointer( ptr2, packed_data)
01507
01508 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
01509
01510 ptr1 = LOC(mpp_io_stack(1))
01511 ptr2 = LOC(mpp_io_stack(nwords+1))
01512 #endif
01513
01514 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
01515 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
01516 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01517 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01518
01519
01520 allocate(start(size(field%axes)))
01521 allocate(axsiz(size(field%axes)))
01522
01523 if( .NOT.mpp_file(unit)%initialized )then
01524
01525
01526
01527 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
01528 #ifdef use_netCDF
01529
01530 error = NF_SET_FILL( mpp_file(unit)%ncid, NF_NOFILL, i ); call netcdf_err(error)
01531 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NF_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
01532 #endif
01533 else
01534 call mpp_write_meta( unit, 'END', cval='metadata' )
01535 end if
01536 mpp_file(unit)%initialized = .TRUE.
01537 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
01538 end if
01539
01540
01541 time = NULLTIME
01542 time_level = -1
01543 newtime = .FALSE.
01544 if( PRESENT(time_in) )time = time_in
01545
01546 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
01547 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
01548 mpp_file(unit)%time = time
01549 newtime = .TRUE.
01550 end if
01551 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
01552 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
01553
01554 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576 start = 1
01577 do i = 1,size(field%axes)
01578 axsiz(i) = field%size(i)
01579 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
01580 start(i) = max(start(i),1)
01581 end do
01582 if( PRESENT(domain) )then
01583 call mpp_get_compute_domain( domain, is, ie, js, je, xsize=isizc, ysize=jsizc )
01584 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg, xsize=isizg, ysize=jsizg )
01585 axsiz(1) = isizc
01586 axsiz(2) = jsizc
01587 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
01588 start(1) = is - isg + 1
01589 start(2) = js - jsg + 1
01590 else
01591 if( isizc.NE.ie-is+1 )then
01592 start(1) = is - isg + 1
01593 axsiz(1) = ie - is + 1
01594 end if
01595 if( jsizc.NE.je-js+1 )then
01596 start(2) = js - jsg + 1
01597 axsiz(2) = je - js + 1
01598 end if
01599 end if
01600 end if
01601 if( debug ) &
01602 write (stdout(), '(a,2i3,12i4)') 'a WRITE_RECORD: PE, unit, start, axsiz=', pe, unit, start, axsiz
01603 #ifdef use_netCDF
01604
01605 if( newtime )then
01606 il_bytesize = BIT_SIZE(ii)/8
01607 INQUIRE (iolength=il_iosize) ii
01608 il_int_iosize = il_iosize
01609 INQUIRE (iolength=il_iosize) time
01610 il_rbyt = il_iosize/il_int_iosize*il_bytesize
01611 if( il_rbyt.EQ.DOUBLE_KIND )then
01612 error = NF_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
01613 else if( il_rbyt.EQ.FLOAT_KIND )then
01614 error = NF_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
01615 end if
01616 end if
01617 if( field%pack.LE.2 )then
01618 write(6,*) ' Iam here 6!'
01619 call mpp_flushstd(6)
01620 error = NF_PUT_VARA_TEXT( mpp_file(unit)%ncid, field%id, (/1,start/), (/len(cdata),axsiz/), cdata )
01621 write(6,*) ' Iam here 7!'
01622 call mpp_flushstd(6)
01623 else
01624 write(6,*) ' Iam here 8!'
01625 call mpp_flushstd(6)
01626 call mpp_error( FATAL, 'MPP_WRITE_RECORD_C: pack on text !' )
01627 end if
01628 write(6,*) ' Iam here 9!',error
01629 call mpp_flushstd(6)
01630 call netcdf_err(error)
01631 #endif
01632 else
01633
01634 if( PRESENT(domain) )then
01635 subdomain(:) = (/ is, ie, js, je /)
01636 else
01637 subdomain(:) = -1
01638 end if
01639 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
01640
01641 write( unit,* )field%id, subdomain, time_level, time, cdata
01642 else
01643 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
01644 #ifdef __sgi
01645 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
01646 write(unit)field%id, subdomain, time_level, time, cdata
01647 else
01648 write(unit)field%id, subdomain, time_level, time, cdata
01649 end if
01650 #else
01651 write(unit)field%id, subdomain, time_level, time, cdata
01652 #endif
01653 else
01654 #ifdef __sgi
01655 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
01656 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
01657 else
01658 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
01659 end if
01660 #else
01661 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
01662 #endif
01663 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
01664 end if
01665 end if
01666 end if
01667
01668
01669 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
01670 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
01671
01672 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
01673 else
01674 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
01675 end if
01676 end if
01677
01678 deallocate(start)
01679 deallocate(axsiz)
01680
01681 return
01682 end subroutine write_record_c
01683
01684 subroutine write_record_b( unit, field, nwords, data, time_in, domain,block_id )
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710 integer, intent(in) :: unit, nwords
01711 type(fieldtype), intent(in) :: field
01712 real, intent(in) :: data(nwords)
01713 real(DOUBLE_KIND), intent(in), optional :: time_in
01714 integer,intent(in),optional :: block_id
01715 type(domain2D), intent(in), optional :: domain
01716
01717
01718 integer,allocatable,dimension(:) :: start, axsiz
01719
01720 real :: time
01721 integer :: time_level
01722 logical :: newtime
01723 integer :: subdomain(4)
01724 integer :: packed_data(nwords)
01725 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
01726 #ifdef use_netCDF
01727 integer :: ii, il_bytesize, il_iosize
01728 integer :: il_int_iosize, il_rbyt
01729 #endif
01730
01731 #ifdef use_CRI_pointers
01732 real(FLOAT_KIND) :: data_r4(nwords)
01733 pointer( ptr1, data_r4)
01734 pointer( ptr2, packed_data)
01735
01736 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
01737
01738 ptr1 = LOC(mpp_io_stack(1))
01739 ptr2 = LOC(mpp_io_stack(nwords+1))
01740 #endif
01741
01742 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
01743 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
01744 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01745 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01746
01747
01748 allocate(start(size(field%axes)))
01749 allocate(axsiz(size(field%axes)))
01750
01751 if( .NOT.mpp_file(unit)%initialized )then
01752
01753
01754
01755 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
01756 #ifdef use_netCDF
01757
01758 error = NF_SET_FILL( mpp_file(unit)%ncid, NF_NOFILL, i ); call netcdf_err(error)
01759 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NF_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
01760 #endif
01761 else
01762 call mpp_write_meta( unit, 'END', cval='metadata' )
01763 end if
01764 mpp_file(unit)%initialized = .TRUE.
01765 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
01766 end if
01767
01768
01769 time = NULLTIME
01770 time_level = -1
01771 newtime = .FALSE.
01772 if( PRESENT(time_in) )time = time_in
01773
01774 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
01775 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
01776 mpp_file(unit)%time = time
01777 newtime = .TRUE.
01778 end if
01779 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
01780 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
01781
01782 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805 start = 1
01806 do i = 1,size(field%axes)
01807 axsiz(i) = field%size(i)
01808 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
01809 start(i) = max(start(i),1)
01810 end do
01811 if( PRESENT(domain) )then
01812 call mpp_get_compute_domain( domain, is, ie, js, je, xsize=isizc, ysize=jsizc )
01813 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg, xsize=isizg, ysize=jsizg )
01814 axsiz(1) = isizc
01815 axsiz(2) = jsizc
01816 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
01817 start(1) = is - isg + 1
01818 start(2) = js - jsg + 1
01819 else
01820 if( isizc.NE.ie-is+1 )then
01821 start(1) = is - isg + 1
01822 axsiz(1) = ie - is + 1
01823 end if
01824 if( jsizc.NE.je-js+1 )then
01825 start(2) = js - jsg + 1
01826 axsiz(2) = je - js + 1
01827 end if
01828 end if
01829 end if
01830
01831 if( PRESENT(block_id) )then
01832 if (block_id.le.0) then
01833 call mpp_error( FATAL, 'MPP_RECORD_B: block_id <= 0!' )
01834 endif
01835 if( PRESENT(time_in) )then
01836
01837 if(block_id.gt. axsiz(size(field%axes)-1)) &
01838 call mpp_error( FATAL, 'MPP_RECORD_B: block_id > axis range!' )
01839
01840 start(size(field%axes)-1)=block_id
01841
01842 else
01843
01844 if(block_id.gt. axsiz(size(field%axes))) &
01845 call mpp_error( FATAL, 'MPP_RECORD_B: block_id > axis range!' )
01846
01847 start(size(field%axes))=block_id
01848
01849 endif
01850 endif
01851
01852 if( debug ) &
01853 write (stdout(), '(a,2i3,12i4)') 'b WRITE_RECORD: PE, unit, start, axsiz=', pe, unit, start, axsiz
01854 #ifdef use_netCDF
01855
01856 il_bytesize = BIT_SIZE(ii)/8
01857 INQUIRE (iolength=il_iosize) ii
01858 il_int_iosize = il_iosize
01859 if( newtime )then
01860 INQUIRE (iolength=il_iosize) time
01861 il_rbyt = il_iosize/il_int_iosize*il_bytesize
01862 if( il_rbyt .EQ. DOUBLE_KIND )then
01863 error = NF_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
01864 else if( il_rbyt .EQ. FLOAT_KIND )then
01865 error = NF_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
01866 end if
01867 end if
01868 if( field%pack.LE.2 )then
01869 INQUIRE (iolength=il_iosize) data(1)
01870 il_rbyt = il_iosize/il_int_iosize*il_bytesize
01871 if( il_rbyt .EQ. DOUBLE_KIND )then
01872
01873 error = NF_PUT_VARA_DOUBLE( mpp_file(unit)%ncid, field%id, start, axsiz, data )
01874 else if( il_rbyt .EQ. FLOAT_KIND )then
01875 error = NF_PUT_VARA_REAL ( mpp_file(unit)%ncid, field%id, start, axsiz, data )
01876 end if
01877 else
01878 packed_data = nint((data-field%add)/field%scale)
01879 error = NF_PUT_VARA_INT ( mpp_file(unit)%ncid, field%id, start, axsiz, packed_data )
01880 end if
01881 call netcdf_err(error)
01882 #endif
01883 else
01884
01885 if( PRESENT(domain) )then
01886 subdomain(:) = (/ is, ie, js, je /)
01887 else
01888 subdomain(:) = -1
01889 end if
01890 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
01891
01892 write( unit,* )field%id, subdomain, time_level, time, data
01893 else
01894 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
01895 #ifdef __sgi
01896 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
01897 data_r4 = data
01898 write(unit)field%id, subdomain, time_level, time, data_r4
01899 else
01900 write(unit)field%id, subdomain, time_level, time, data
01901 end if
01902 #else
01903 write(unit)field%id, subdomain, time_level, time, data
01904 #endif
01905 else
01906 #ifdef __sgi
01907 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
01908 data_r4 = data
01909 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data_r4
01910 else
01911 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
01912 end if
01913 #else
01914 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
01915 #endif
01916 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
01917 end if
01918 end if
01919 end if
01920
01921
01922 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
01923 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
01924
01925 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
01926 else
01927 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
01928 end if
01929 end if
01930
01931
01932 deallocate(start)
01933 deallocate(axsiz)
01934
01935 return
01936 end subroutine write_record_b
01937
01938 subroutine write_record( unit, field, nwords, data, time_in, domain )
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955 integer, intent(in) :: unit, nwords
01956 type(fieldtype), intent(in) :: field
01957 real, intent(in) :: data(nwords)
01958 real(DOUBLE_KIND), intent(in), optional :: time_in
01959 type(domain2D), intent(in), optional :: domain
01960
01961
01962
01963
01964 integer,allocatable,dimension(:) :: start, axsiz
01965
01966 real :: time
01967 integer :: time_level
01968 logical :: newtime
01969 integer :: subdomain(4)
01970 integer :: packed_data(nwords)
01971 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
01972
01973 integer :: icount_domains
01974
01975 #ifdef use_netCDF
01976 integer :: ii, il_bytesize, il_iosize
01977 integer :: il_int_iosize, il_rbyt
01978 #endif
01979
01980 #ifdef use_CRI_pointers
01981 real(FLOAT_KIND) :: data_r4(nwords)
01982 pointer( ptr1, data_r4)
01983 pointer( ptr2, packed_data)
01984
01985 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
01986
01987 ptr1 = LOC(mpp_io_stack(1))
01988 ptr2 = LOC(mpp_io_stack(nwords+1))
01989 #endif
01990
01991 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
01992 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
01993 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01994 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
01995
01996
01997 allocate(start(size(field%axes)))
01998 allocate(axsiz(size(field%axes)))
01999
02000 if( .NOT.mpp_file(unit)%initialized )then
02001
02002
02003
02004 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02005 #ifdef use_netCDF
02006
02007 error = NF_SET_FILL( mpp_file(unit)%ncid, NF_NOFILL, i ); call netcdf_err(error)
02008 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NF_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
02009 #endif
02010 else
02011 call mpp_write_meta( unit, 'END', cval='metadata' )
02012 end if
02013 mpp_file(unit)%initialized = .TRUE.
02014 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
02015 end if
02016
02017
02018 time = NULLTIME
02019 time_level = -1
02020 newtime = .FALSE.
02021 if( PRESENT(time_in) )time = time_in
02022
02023 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
02024 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
02025 mpp_file(unit)%time = time
02026 newtime = .TRUE.
02027 end if
02028 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
02029 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
02030
02031 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054 start = 1
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064 icount_domains=0
02065
02066 do i = 1,size(field%axes)
02067 axsiz(i) = field%size(i)
02068 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
02069 start(i) = max(start(i),1)
02070
02071 if((field%axes(i)%domain .ne. NULL_DOMAIN1D) .and. &
02072 (field%axes(1)%domain .eq. NULL_DOMAIN1D)) &
02073 icount_domains=icount_domains+1
02074
02075 end do
02076 if( PRESENT(domain) )then
02077 if(icount_domains .ne. 2 ) then
02078 call mpp_get_compute_domain( domain, is, ie, js, je &
02079 , xsize=isizc, ysize=jsizc )
02080 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg &
02081 , xsize=isizg, ysize=jsizg )
02082 axsiz(1) = isizc
02083 axsiz(2) = jsizc
02084 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
02085 start(1) = is - isg + 1
02086 start(2) = js - jsg + 1
02087 else
02088 if( isizc.NE.ie-is+1 )then
02089 start(1) = is - isg + 1
02090 axsiz(1) = ie - is + 1
02091 end if
02092 if( jsizc.NE.je-js+1 )then
02093 start(2) = js - jsg + 1
02094 axsiz(2) = je - js + 1
02095 end if
02096 end if
02097
02098 else
02099
02100 call mpp_get_compute_domain( field%axes(2)%domain, is, ie &
02101 , size=isizc)
02102 call mpp_get_global_domain ( field%axes(2)%domain, isg, ieg &
02103 , size=isizg )
02104 call mpp_get_compute_domain( field%axes(3)%domain, js, je &
02105 , size=jsizc)
02106 call mpp_get_global_domain ( field%axes(3)%domain, jsg, jeg &
02107 , size=jsizg )
02108 axsiz(2) = isizc
02109 axsiz(3) = jsizc
02110 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
02111 start(2) = is - isg + 1
02112 start(3) = js - jsg + 1
02113 else
02114 if( isizc.NE.ie-is+1 )then
02115 start(2) = is - isg + 1
02116 axsiz(2) = ie - is + 1
02117 end if
02118 if( jsizc.NE.je-js+1 )then
02119 start(3) = js - jsg + 1
02120 axsiz(3) = je - js + 1
02121 end if
02122 end if
02123
02124 endif
02125
02126 end if
02127 if( debug ) write (stdout(),'(a,3i3,12i4)') &
02128 'c WRITE_RECORD: PE, unit, icount_domains, start, axsiz=' &
02129 , pe, unit, icount_domains, start, axsiz
02130 #ifdef use_netCDF
02131
02132 il_bytesize = BIT_SIZE(ii)/8
02133 INQUIRE (iolength=il_iosize) ii
02134 il_int_iosize = il_iosize
02135 if( newtime )then
02136 INQUIRE (iolength=il_iosize) time
02137 il_rbyt = il_iosize/il_int_iosize*il_bytesize
02138 if( il_rbyt.EQ.DOUBLE_KIND )then
02139 error = NF_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
02140 else if( il_rbyt.EQ.FLOAT_KIND )then
02141 error = NF_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, mpp_file(unit)%time_level, time )
02142 end if
02143 end if
02144 if( field%pack.LE.2 )then
02145 INQUIRE (iolength=il_iosize) data(1)
02146 il_rbyt = il_iosize/il_int_iosize*il_bytesize
02147 if( il_rbyt .EQ. DOUBLE_KIND )then
02148 error = NF_PUT_VARA_DOUBLE( mpp_file(unit)%ncid, field%id, start, axsiz, data )
02149 else if( il_rbyt .EQ. FLOAT_KIND )then
02150 error = NF_PUT_VARA_REAL ( mpp_file(unit)%ncid, field%id, start, axsiz, data )
02151 end if
02152 else
02153 packed_data = nint((data-field%add)/field%scale)
02154 error = NF_PUT_VARA_INT ( mpp_file(unit)%ncid, field%id, start, axsiz, packed_data )
02155 end if
02156 call netcdf_err(error)
02157 #endif
02158 else
02159
02160 if( PRESENT(domain) )then
02161 subdomain(:) = (/ is, ie, js, je /)
02162 else
02163 subdomain(:) = -1
02164 end if
02165 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
02166
02167 write( unit,* )field%id, subdomain, time_level, time, data
02168 else
02169 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
02170 #ifdef __sgi
02171 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
02172 data_r4 = data
02173 write(unit)field%id, subdomain, time_level, time, data_r4
02174 else
02175 write(unit)field%id, subdomain, time_level, time, data
02176 end if
02177 #else
02178 write(unit)field%id, subdomain, time_level, time, data
02179 #endif
02180 else
02181 #ifdef __sgi
02182 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
02183 data_r4 = data
02184 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data_r4
02185 else
02186 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
02187 end if
02188 #else
02189 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
02190 #endif
02191 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
02192 end if
02193 end if
02194 end if
02195
02196
02197 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
02198 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
02199
02200 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
02201 else
02202 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
02203 end if
02204 end if
02205
02206 deallocate(start)
02207 deallocate(axsiz)
02208
02209
02210 return
02211 end subroutine write_record
02212
02213
02214
02215
02216
02217
02218 subroutine mpp_copy_meta_global( unit, gatt )
02219
02220
02221
02222
02223
02224 integer, intent(in) :: unit
02225 type(atttype), intent(in) :: gatt
02226 integer :: len
02227
02228 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
02229 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
02230 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02231 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02232 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
02233 if( mpp_file(unit)%initialized ) &
02234 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
02235 #ifdef use_netCDF
02236 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02237 if( gatt%type.EQ.NF_CHAR )then
02238 len = gatt%len
02239 call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, cval=gatt%catt(1:len) )
02240 else
02241 call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, rval=gatt%fatt )
02242 endif
02243 else
02244 if( gatt%type.EQ.NF_CHAR )then
02245 len=gatt%len
02246 call write_attribute( unit, 'GLOBAL '//trim(gatt%name), cval=gatt%catt(1:len) )
02247 else
02248 call write_attribute( unit, 'GLOBAL '//trim(gatt%name), rval=gatt%fatt )
02249 endif
02250 end if
02251 #else
02252 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
02253 #endif
02254 return
02255 end subroutine mpp_copy_meta_global
02256
02257 subroutine mpp_copy_meta_axis( unit, axis, domain )
02258
02259
02260
02261
02262 integer, intent(in) :: unit
02263 type(axistype), intent(inout) :: axis
02264 type(domain1D), intent(in), optional :: domain
02265 character(len=512) :: text
02266 integer :: i, len, is, ie, isg, ieg
02267
02268 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
02269 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
02270 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02271 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02272 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
02273 if( mpp_file(unit)%initialized ) &
02274 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
02275
02276
02277 if( PRESENT(domain) )then
02278 axis%domain = domain
02279 else
02280 axis%domain = NULL_DOMAIN1D
02281 end if
02282
02283 #ifdef use_netCDF
02284
02285 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02286
02287
02288 if( ASSOCIATED(axis%data) )then
02289 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
02290 call mpp_get_compute_domain( axis%domain, is, ie )
02291 call mpp_get_global_domain( axis%domain, isg, ieg )
02292 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, ie-is+1, axis%did )
02293 else
02294 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, size(axis%data), axis%did )
02295 end if
02296 call netcdf_err(error)
02297 error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id ); call netcdf_err(error)
02298 else
02299 error = NF_DEF_DIM( mpp_file(unit)%ncid, axis%name, NF_UNLIMITED, axis%did ); call netcdf_err(error)
02300 error = NF_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id ); call netcdf_err(error)
02301 mpp_file(unit)%id = axis%id
02302 mpp_file(unit)%recdimid = axis%did
02303 end if
02304 else
02305 varnum = varnum + 1
02306 axis%id = varnum
02307 axis%did = varnum
02308
02309 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
02310 call write_attribute( unit, trim(text), cval=axis%name )
02311 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
02312 if( ASSOCIATED(axis%data) )then
02313 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
02314 call write_attribute( unit, trim(text), ival=(/ie-is+1/) )
02315 else
02316 call write_attribute( unit, trim(text), ival=(/size(axis%data)/) )
02317 end if
02318 else
02319 if( mpp_file(unit)%id.NE.-1 ) &
02320 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
02321 call write_attribute( unit, trim(text), ival=(/0/) )
02322 mpp_file(unit)%id = axis%id
02323 end if
02324 end if
02325
02326
02327 do i=1,axis%natt
02328 if( axis%Att(i)%name.NE.default_att%name )then
02329 if( axis%Att(i)%type.EQ.NF_CHAR )then
02330 len = axis%Att(i)%len
02331 call mpp_write_meta( unit, axis%id, axis%Att(i)%name, cval=axis%Att(i)%catt(1:len) )
02332 else
02333 call mpp_write_meta( unit, axis%id, axis%Att(i)%name, rval=axis%Att(i)%fatt)
02334 endif
02335 endif
02336 enddo
02337
02338 if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
02339 call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/) )
02340 end if
02341 if( verbose ) write (stdout(), '(a,2i3,1x,a,2i3)') &
02342 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
02343 pe, unit, trim(axis%name), axis%id, axis%did
02344 #else
02345 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
02346 #endif
02347 return
02348 end subroutine mpp_copy_meta_axis
02349
02350 subroutine mpp_copy_meta_field( unit, field, axes )
02351
02352
02353 integer, intent(in) :: unit
02354 type(fieldtype), intent(inout) :: field
02355 type(axistype), intent(in), optional :: axes(:)
02356
02357 integer, allocatable :: axis_id(:)
02358 real :: a, b
02359 integer :: i
02360
02361 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
02362 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
02363 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02364 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02365 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
02366 if( mpp_file(unit)%initialized ) &
02367 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
02368
02369 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
02370 if( field%pack.NE.4 .AND. field%pack.NE.8 ) &
02371 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
02372 end if
02373
02374 if (PRESENT(axes)) then
02375 deallocate(field%axes)
02376 deallocate(field%size)
02377 allocate(field%axes(size(axes)))
02378 allocate(field%size(size(axes)))
02379 field%axes = axes
02380 do i=1,size(axes)
02381 if (ASSOCIATED(axes(i)%data)) then
02382 field%size(i) = size(axes(i)%data)
02383 else
02384 field%size(i) = 1
02385 field%time_axis_index = i
02386 endif
02387 enddo
02388 endif
02389
02390 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02391 #ifdef use_netCDF
02392 allocate( axis_id(size(field%axes)) )
02393 do i = 1,size(field%axes)
02394 axis_id(i) = field%axes(i)%did
02395 end do
02396
02397 select case (field%pack)
02398 case(1)
02399 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes), axis_id, field%id )
02400 case(2)
02401 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes), axis_id, field%id )
02402 case(4)
02403 if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
02404 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
02405 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes), axis_id, field%id )
02406 case(8)
02407 if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
02408 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
02409 error = NF_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes), axis_id, field%id )
02410 case default
02411 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
02412 end select
02413 #endif
02414 else
02415 varnum = varnum + 1
02416 field%id = varnum
02417 if( field%pack.NE.default_field%pack ) &
02418 call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
02419
02420 write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
02421 call write_attribute( unit, trim(text), cval=field%name )
02422 write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
02423 call write_attribute( unit, trim(text), ival=field%axes(:)%did )
02424 end if
02425
02426 call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname )
02427 call mpp_write_meta( unit, field%id, 'units', cval=field%units )
02428
02429 if( (field%min.NE.default_field%min) .AND. (field%max.NE.default_field%max) )then
02430 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
02431 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/field%min,field%max/), pack=field%pack )
02432 else
02433 a = nint((field%min-field%add)/field%scale)
02434 b = nint((field%max-field%add)/field%scale)
02435 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=field%pack )
02436 end if
02437 else if( field%min.NE.default_field%min )then
02438 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
02439 call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=field%pack )
02440 else
02441 a = nint((field%min-field%add)/field%scale)
02442 call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=field%pack )
02443 end if
02444 else if( field%max.NE.default_field%max )then
02445 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
02446 call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=field%pack )
02447 else
02448 a = nint((field%max-field%add)/field%scale)
02449 call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=field%pack )
02450 end if
02451 end if
02452 if( field%missing.NE.default_field%missing )then
02453 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
02454 call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=field%pack )
02455 else
02456 a = nint((field%missing-field%add)/field%scale)
02457 call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=field%pack )
02458 end if
02459 end if
02460 if( field%fill.NE.default_field%fill )then
02461 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
02462 call mpp_write_meta( unit, field%id, '_FillValue', rval=field%fill, pack=field%pack )
02463 else
02464 a = nint((field%fill-field%add)/field%scale)
02465 call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=field%pack )
02466 end if
02467 end if
02468 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
02469 call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
02470 if( field%scale.NE.default_field%scale )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
02471 if( field%add.NE.default_field%add )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
02472 end if
02473 if( verbose ) write (stdout(), '(a,2i3,1x,a,i3)') 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
02474 pe, unit, trim(field%name), field%id
02475
02476 return
02477 end subroutine mpp_copy_meta_field
02478
02479
02480
02481
02482
02483
02484
02485 #define MPP_READ_2DDECOMP_1D_ mpp_read_2ddecomp_r1d
02486 #define MPP_READ_2DDECOMP_2D_ mpp_read_2ddecomp_r2d
02487 #define MPP_READ_2DDECOMP_3D_ mpp_read_2ddecomp_r3d
02488 #define MPP_READ_2DDECOMP_4D_ mpp_read_2ddecomp_r4d
02489 #define MPP_TYPE_ real
02490 #include <mpp_read_2Ddecomp.h>
02491
02492 subroutine read_record( unit, field, nwords, data, time_level, domain )
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509 integer, intent(in) :: unit, nwords
02510 type(fieldtype), intent(in) :: field
02511 real, intent(inout) :: data(nwords)
02512 integer, intent(in), optional :: time_level
02513 type(domain2D), intent(in), optional :: domain
02514 integer, dimension(size(field%axes)) :: start, axsiz
02515 real :: time
02516
02517 logical :: newtime
02518 integer :: subdomain(4), tlevel
02519
02520 integer(SHORT_KIND) :: i2vals(nwords)
02521
02522 integer(INT_KIND) :: ivals(nwords)
02523 real(FLOAT_KIND) :: rvals(nwords)
02524
02525
02526
02527
02528
02529 real(DOUBLE_KIND) :: r8vals(nwords)
02530
02531 integer :: i, error, is, ie, js, je, isg, ieg, jsg, jeg
02532
02533 #ifdef use_CRI_pointers
02534 pointer( ptr1, i2vals )
02535 pointer( ptr2, ivals )
02536 pointer( ptr3, rvals )
02537 pointer( ptr4, r8vals )
02538
02539 if (mpp_io_stack_size < 4*nwords) call mpp_io_set_stack_size(4*nwords)
02540
02541 ptr1 = LOC(mpp_io_stack(1))
02542 ptr2 = LOC(mpp_io_stack(nwords+1))
02543 ptr3 = LOC(mpp_io_stack(2*nwords+1))
02544 ptr4 = LOC(mpp_io_stack(3*nwords+1))
02545 #endif
02546 if (.not.PRESENT(time_level)) then
02547 tlevel = 0
02548 else
02549 tlevel = time_level
02550 endif
02551
02552 #ifdef use_netCDF
02553 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'READ_RECORD: must first call mpp_io_init.' )
02554 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'READ_RECORD: invalid unit number.' )
02555 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02556
02557 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .and. present(domain)) &
02558 call mpp_error( FATAL, 'READ_RECORD: multiple filesets not supported for MPP_READ' )
02559
02560 if( .NOT.mpp_file(unit)%initialized ) call mpp_error( FATAL, 'MPP_READ: must first call mpp_read_meta.' )
02561
02562
02563
02564 if( verbose ) write (stdout(), '(a,2i3,2i5)') 'MPP_READ: PE, unit, %id, %time_level =',&
02565 pe, unit, mpp_file(unit)%id, tlevel
02566
02567 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02568
02569
02570
02571
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590 start = 1
02591 do i = 1,size(field%axes)
02592 axsiz(i) = field%size(i)
02593 if( field%axes(i)%did.EQ.field%time_axis_index )start(i) = tlevel
02594 end do
02595 if( PRESENT(domain) )then
02596 call mpp_get_compute_domain( domain, is, ie, js, je )
02597 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg )
02598 axsiz(1) = ie-is+1
02599 axsiz(2) = je-js+1
02600 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
02601 start(1) = is - isg + 1
02602 start(2) = js - jsg + 1
02603 else
02604 if( ie-is+1.NE.ie-is+1 )then
02605 start(1) = is - isg + 1
02606 axsiz(1) = ie - is + 1
02607 end if
02608 if( je-js+1.NE.je-js+1 )then
02609 start(2) = js - jsg + 1
02610 axsiz(2) = je - js + 1
02611 end if
02612 end if
02613 end if
02614
02615 if( verbose ) write (stdout(), '(a,2i3,i6,12i4)') 'READ_RECORD: PE, unit, nwords, start, axsiz=', &
02616 pe, unit, nwords, start, axsiz
02617
02618 select case (field%type)
02619 case(NF_BYTE)
02620
02621 call mpp_error( FATAL, 'MPP_READ: does not support NF_BYTE packing' )
02622 case(NF_SHORT)
02623 error = NF_GET_VARA_INT2 ( mpp_file(unit)%ncid, field%id, start, axsiz, i2vals ); call netcdf_err(error)
02624 data(:)=i2vals(:)*field%scale + field%add
02625 case(NF_INT)
02626 error = NF_GET_VARA_INT ( mpp_file(unit)%ncid, field%id, start, axsiz, ivals ); call netcdf_err(error)
02627 data(:)=ivals(:)
02628 case(NF_FLOAT)
02629 error = NF_GET_VARA_REAL ( mpp_file(unit)%ncid, field%id, start, axsiz, rvals ); call netcdf_err(error)
02630 data(:)=rvals(:)
02631 case(NF_DOUBLE)
02632 error = NF_GET_VARA_DOUBLE( mpp_file(unit)%ncid, field%id, start, axsiz, r8vals ); call netcdf_err(error)
02633 data(:)=r8vals(:)
02634 case default
02635 call mpp_error( FATAL, 'MPP_READ: invalid pack value' )
02636 end select
02637 else
02638
02639 call mpp_error( FATAL, 'Currently dont support non-NetCDF mpp read' )
02640
02641 end if
02642 #else
02643 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
02644 #endif
02645 return
02646 end subroutine read_record
02647 subroutine read_record_b(unit,field,nwords,data,time_level,domain,block_id)
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664 integer, intent(in) :: unit, nwords
02665 type(fieldtype), intent(in) :: field
02666 real, intent(inout) :: data(nwords)
02667 integer, intent(in), optional :: time_level
02668
02669 integer, intent(in), optional :: block_id
02670
02671 type(domain2D), intent(in), optional :: domain
02672 integer, dimension(size(field%axes)) :: start, axsiz
02673 real :: time
02674
02675 logical :: newtime
02676 integer :: subdomain(4), tlevel
02677
02678 integer(SHORT_KIND) :: i2vals(nwords)
02679
02680 integer(INT_KIND) :: ivals(nwords)
02681 real(FLOAT_KIND) :: rvals(nwords)
02682
02683
02684
02685
02686
02687 real(DOUBLE_KIND) :: r8vals(nwords)
02688
02689 integer :: i, error, is, ie, js, je, isg, ieg, jsg, jeg
02690
02691 #ifdef use_CRI_pointers
02692 pointer( ptr1, i2vals )
02693 pointer( ptr2, ivals )
02694 pointer( ptr3, rvals )
02695 pointer( ptr4, r8vals )
02696
02697 if (mpp_io_stack_size < 4*nwords) call mpp_io_set_stack_size(4*nwords)
02698
02699 ptr1 = LOC(mpp_io_stack(1))
02700 ptr2 = LOC(mpp_io_stack(nwords+1))
02701 ptr3 = LOC(mpp_io_stack(2*nwords+1))
02702 ptr4 = LOC(mpp_io_stack(3*nwords+1))
02703 #endif
02704 if (.not.PRESENT(time_level)) then
02705 tlevel = 0
02706 else
02707 tlevel = time_level
02708 endif
02709
02710 #ifdef use_netCDF
02711 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'READ_RECORD: must first call mpp_io_init.' )
02712 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'READ_RECORD: invalid unit number.' )
02713 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
02714
02715 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .and. present(domain)) &
02716 call mpp_error( FATAL, 'READ_RECORD: multiple filesets not supported for MPP_READ' )
02717
02718 if( .NOT.mpp_file(unit)%initialized ) call mpp_error( FATAL, 'MPP_READ: must first call mpp_read_meta.' )
02719
02720
02721
02722 if( verbose ) write (stdout(), '(a,2i3,2i5)') 'MPP_READ: PE, unit, %id, %time_level =',&
02723 pe, unit, mpp_file(unit)%id, tlevel
02724
02725 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748 start = 1
02749 do i = 1,size(field%axes)
02750 axsiz(i) = field%size(i)
02751 if( field%axes(i)%did.EQ.field%time_axis_index )start(i) = tlevel
02752 end do
02753 if( PRESENT(domain) )then
02754 call mpp_get_compute_domain( domain, is, ie, js, je )
02755 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg )
02756 axsiz(1) = ie-is+1
02757 axsiz(2) = je-js+1
02758 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
02759 start(1) = is - isg + 1
02760 start(2) = js - jsg + 1
02761 else
02762 if( ie-is+1.NE.ie-is+1 )then
02763 start(1) = is - isg + 1
02764 axsiz(1) = ie - is + 1
02765 end if
02766 if( je-js+1.NE.je-js+1 )then
02767 start(2) = js - jsg + 1
02768 axsiz(2) = je - js + 1
02769 end if
02770 end if
02771 end if
02772
02773 if( PRESENT(block_id) )then
02774 if (block_id.le.0) then
02775 call mpp_error( FATAL, 'READ_RECORD_B: block_id <= 0!' )
02776 endif
02777 if( PRESENT(time_level) )then
02778
02779 if(block_id.gt. axsiz(size(field%axes)-1)) &
02780 call mpp_error( FATAL, 'READ_RECORD_B: block_id > axis range!' )
02781 start(size(field%axes)-1)=block_id
02782
02783 else
02784
02785 if(block_id.gt. axsiz(size(field%axes))) &
02786 call mpp_error( FATAL, 'READ_RECORD_B: block_id > axis range!' )
02787 start(size(field%axes))=block_id
02788
02789 endif
02790 endif
02791
02792
02793
02794 if( verbose ) write (stdout(), '(a,2i3,i6,12i4)') 'READ_RECORD: PE, unit, nwords, start, axsiz=', &
02795 pe, unit, nwords, start, axsiz
02796
02797 select case (field%type)
02798 case(NF_BYTE)
02799
02800 call mpp_error( FATAL, 'MPP_READ: does not support NF_BYTE packing' )
02801 case(NF_SHORT)
02802 error = NF_GET_VARA_INT2 ( mpp_file(unit)%ncid, field%id, start, axsiz, i2vals ); call netcdf_err(error)
02803 data(:)=i2vals(:)*field%scale + field%add
02804 case(NF_INT)
02805 error = NF_GET_VARA_INT ( mpp_file(unit)%ncid, field%id, start, axsiz, ivals ); call netcdf_err(error)
02806 data(:)=ivals(:)
02807 case(NF_FLOAT)
02808 error = NF_GET_VARA_REAL ( mpp_file(unit)%ncid, field%id, start, axsiz, rvals ); call netcdf_err(error)
02809 data(:)=rvals(:)
02810 case(NF_DOUBLE)
02811 error = NF_GET_VARA_DOUBLE( mpp_file(unit)%ncid, field%id, start, axsiz, r8vals ); call netcdf_err(error)
02812 data(:)=r8vals(:)
02813 case default
02814 call mpp_error( FATAL, 'MPP_READ: invalid pack value' )
02815 end select
02816 else
02817
02818 call mpp_error( FATAL, 'Currently dont support non-NetCDF mpp read' )
02819
02820 end if
02821 #else
02822 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
02823 #endif
02824 return
02825 end subroutine read_record_b
02826
02827 subroutine mpp_read_r4D( unit, field, data, tindex,blockid)
02828 integer, intent(in) :: unit
02829 type(fieldtype), intent(in) :: field
02830 real, intent(inout) :: data(:,:,:,:)
02831 integer, intent(in), optional :: tindex
02832 integer, intent(in), optional :: blockid
02833
02834 if(present(blockid)) then
02835 call read_record_b(unit,field,size(data),data,tindex,block_id=blockid )
02836 else
02837 call read_record( unit, field, size(data), data, tindex )
02838 endif
02839 end subroutine mpp_read_r4D
02840
02841 subroutine mpp_read_r3D( unit, field, data, tindex,blockid)
02842 integer, intent(in) :: unit
02843 type(fieldtype), intent(in) :: field
02844 real, intent(inout) :: data(:,:,:)
02845 integer, intent(in), optional :: tindex
02846 integer, intent(in), optional :: blockid
02847
02848 if(present(blockid)) then
02849 call read_record_b(unit,field,size(data),data,tindex,block_id=blockid )
02850 else
02851 call read_record( unit, field, size(data), data, tindex )
02852 endif
02853 end subroutine mpp_read_r3D
02854
02855 subroutine mpp_read_r2D( unit, field, data, tindex )
02856 integer, intent(in) :: unit
02857 type(fieldtype), intent(in) :: field
02858 real, intent(inout) :: data(:,:)
02859 integer, intent(in), optional :: tindex
02860
02861 call read_record( unit, field, size(data), data, tindex )
02862 end subroutine mpp_read_r2D
02863
02864 subroutine mpp_read_r1D( unit, field, data, tindex )
02865 integer, intent(in) :: unit
02866 type(fieldtype), intent(in) :: field
02867 real, intent(inout) :: data(:)
02868 integer, intent(in), optional :: tindex
02869
02870 call read_record( unit, field, size(data), data, tindex )
02871 end subroutine mpp_read_r1D
02872
02873 subroutine mpp_read_r0D( unit, field, data, tindex )
02874 integer, intent(in) :: unit
02875 type(fieldtype), intent(in) :: field
02876 real, intent(inout) :: data
02877 integer, intent(in), optional :: tindex
02878 real, dimension(1) :: data_tmp
02879
02880 data_tmp(1)=data
02881 call read_record( unit, field, 1, data_tmp, tindex )
02882 data=data_tmp(1)
02883 end subroutine mpp_read_r0D
02884
02885 subroutine mpp_read_meta(unit)
02886
02887
02888
02889
02890
02891
02892
02893
02894 integer, parameter :: MAX_DIMVALS = 100000
02895 integer, intent(in) :: unit
02896
02897 integer :: ncid,ndim,nvar_total,natt,recdim,nv,nvar,len
02898 integer :: error,i,j
02899 integer :: type,nvdims,nvatts, dimid
02900 integer, allocatable, dimension(:) :: dimids
02901 type(axistype) , allocatable, dimension(:) :: Axis
02902 character(len=128) :: name, attname, unlimname, attval
02903 logical :: isdim
02904
02905 integer(SHORT_KIND) :: i2vals(MAX_DIMVALS)
02906
02907 integer(INT_KIND) :: ivals(MAX_DIMVALS)
02908 real(FLOAT_KIND) :: rvals(MAX_DIMVALS)
02909
02910
02911
02912
02913 real(DOUBLE_KIND) :: r8vals(MAX_DIMVALS)
02914
02915 #ifdef use_netCDF
02916
02917 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
02918 ncid = mpp_file(unit)%ncid
02919 error = NF_INQ(ncid,ndim, nvar_total,&
02920 natt, recdim);call netcdf_err(error)
02921
02922
02923 mpp_file(unit)%ndim = ndim
02924 mpp_file(unit)%natt = natt
02925 mpp_file(unit)%recdimid = recdim
02926
02927
02928
02929
02930 if( recdim.NE.-1 )then
02931 error = NF_INQ_DIM( ncid, recdim, unlimname, mpp_file(unit)%time_level );call netcdf_err(error)
02932 error = NF_INQ_VARID( ncid, unlimname, mpp_file(unit)%id ); call netcdf_err(error)
02933 else
02934 mpp_file(unit)%time_level = -1
02935 endif
02936
02937 if ( natt .gt. 0 ) allocate(mpp_file(unit)%Att(natt))
02938 allocate(Axis(ndim))
02939 allocate(dimids(ndim))
02940 allocate(mpp_file(unit)%Axis(ndim))
02941
02942
02943
02944
02945
02946
02947 do i=1,ndim
02948 Axis(i) = default_axis
02949 mpp_file(unit)%Axis(i) = default_axis
02950 enddo
02951
02952 do i=1,natt
02953 mpp_file(unit)%Att(i) = default_att
02954 enddo
02955
02956
02957
02958
02959 do i=1,natt
02960 error=NF_INQ_ATTNAME(ncid,NF_GLOBAL,i,name);call netcdf_err(error)
02961 error=NF_INQ_ATT(ncid,NF_GLOBAL,trim(name),type,len);call netcdf_err(error)
02962 mpp_file(unit)%Att(i)%name = name
02963 mpp_file(unit)%Att(i)%len = len
02964 mpp_file(unit)%Att(i)%type = type
02965
02966
02967
02968 select case (type)
02969 case (NF_CHAR)
02970 if (len.gt.512) then
02971 call mpp_error(NOTE,'GLOBAL ATT too long - not reading this metadata')
02972 len=7
02973 mpp_file(unit)%Att(i)%len=len
02974 mpp_file(unit)%Att(i)%catt = 'unknown'
02975 else
02976 error=NF_GET_ATT_TEXT(ncid,NF_GLOBAL,name,mpp_file(unit)%Att(i)%catt);call netcdf_err(error)
02977 if (verbose.and.pe == 0) write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%catt(1:len)
02978 endif
02979
02980
02981
02982 case (NF_SHORT)
02983 allocate(mpp_file(unit)%Att(i)%fatt(len))
02984 error=NF_GET_ATT_INT2(ncid,NF_GLOBAL,name,i2vals);call netcdf_err(error)
02985 if( verbose .and. pe == 0 )write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',i2vals(1:len)
02986 mpp_file(unit)%Att(i)%fatt(1:len)=i2vals(1:len)
02987 case (NF_INT)
02988 allocate(mpp_file(unit)%Att(i)%fatt(len))
02989 error=NF_GET_ATT_INT(ncid,NF_GLOBAL,name,ivals);call netcdf_err(error)
02990 if( verbose .and. pe == 0 )write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',ivals(1:len)
02991 mpp_file(unit)%Att(i)%fatt(1:len)=ivals(1:len)
02992 case (NF_FLOAT)
02993 allocate(mpp_file(unit)%Att(i)%fatt(len))
02994 error=NF_GET_ATT_REAL(ncid,NF_GLOBAL,name,rvals);call netcdf_err(error)
02995 mpp_file(unit)%Att(i)%fatt(1:len)=rvals(1:len)
02996 if( verbose .and. pe == 0)write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%fatt(1:len)
02997 case (NF_DOUBLE)
02998 allocate(mpp_file(unit)%Att(i)%fatt(len))
02999 error=NF_GET_ATT_DOUBLE(ncid,NF_GLOBAL,name,r8vals);call netcdf_err(error)
03000 mpp_file(unit)%Att(i)%fatt(1:len)=r8vals(1:len)
03001 if( verbose .and. pe == 0)write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%fatt(1:len)
03002 end select
03003
03004 enddo
03005
03006
03007
03008 do i=1,ndim
03009 error = NF_INQ_DIM(ncid,i,name,len);call netcdf_err(error)
03010 Axis(i)%name = name
03011 Axis(i)%len = len
03012 enddo
03013
03014 nvar=0
03015 do i=1, nvar_total
03016 error=NF_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
03017 isdim=.false.
03018 do j=1,ndim
03019 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
03020 enddo
03021 if (.not.isdim) nvar=nvar+1
03022 enddo
03023 mpp_file(unit)%nvar = nvar
03024 allocate(mpp_file(unit)%Var(nvar))
03025
03026 do i=1,nvar
03027 mpp_file(unit)%Var(i) = default_field
03028 enddo
03029
03030
03031
03032
03033 do i=1, nvar_total
03034 error=NF_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
03035 isdim=.false.
03036 do j=1,ndim
03037 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
03038 enddo
03039
03040 if( isdim )then
03041 error=NF_INQ_DIMID(ncid,name,dimid);call netcdf_err(error)
03042 Axis(dimid)%type = type
03043 Axis(dimid)%did = dimid
03044 Axis(dimid)%id = i
03045 Axis(dimid)%natt = nvatts
03046
03047 if( i.NE.mpp_file(unit)%id )then
03048 select case (type)
03049 case (NF_INT)
03050 len=Axis(dimid)%len
03051 allocate(Axis(dimid)%data(len))
03052 error = NF_GET_VAR_INT(ncid,i,ivals);call netcdf_err(error)
03053 Axis(dimid)%data(1:len)=ivals(1:len)
03054 case (NF_FLOAT)
03055 len=Axis(dimid)%len
03056 allocate(Axis(dimid)%data(len))
03057 error = NF_GET_VAR_REAL(ncid,i,rvals);call netcdf_err(error)
03058 Axis(dimid)%data(1:len)=rvals(1:len)
03059 case (NF_DOUBLE)
03060 len=Axis(dimid)%len
03061 allocate(Axis(dimid)%data(len))
03062 error = NF_GET_VAR_DOUBLE(ncid,i,r8vals);call netcdf_err(error)
03063 Axis(dimid)%data(1:len) = r8vals(1:len)
03064 case (NF_CHAR)
03065 len=Axis(dimid)%len
03066 allocate(Axis(dimid)%cdata(len))
03067 error = NF_GET_VAR_TEXT(ncid,i,Axis(dimid)%cdata)
03068 print*,'cdata',Axis(dimid)%cdata
03069 call netcdf_err(error)
03070 case default
03071 call mpp_error( FATAL, 'Invalid data type for dimension' )
03072 end select
03073 else
03074 len = mpp_file(unit)%time_level
03075 allocate(mpp_file(unit)%time_values(len))
03076 select case (type)
03077 case (NF_FLOAT)
03078 error = NF_GET_VAR_REAL(ncid,i,rvals);call netcdf_err(error)
03079 mpp_file(unit)%time_values(1:len) = rvals(1:len)
03080 case (NF_DOUBLE)
03081 error = NF_GET_VAR_DOUBLE(ncid,i,r8vals);call netcdf_err(error)
03082 mpp_file(unit)%time_values(1:len) = r8vals(1:len)
03083 case default
03084 call mpp_error( FATAL, 'Invalid data type for dimension' )
03085 end select
03086 endif
03087
03088 if( nvatts.GT.0 )allocate(Axis(dimid)%Att(nvatts))
03089
03090 do j=1,nvatts
03091 Axis(dimid)%Att(j) = default_att
03092 enddo
03093
03094 do j=1,nvatts
03095 error=NF_INQ_ATTNAME(ncid,i,j,attname);call netcdf_err(error)
03096 error=NF_INQ_ATT(ncid,i,trim(attname),type,len);call netcdf_err(error)
03097
03098 Axis(dimid)%Att(j)%name = trim(attname)
03099 Axis(dimid)%Att(j)%type = type
03100 Axis(dimid)%Att(j)%len = len
03101
03102 select case (type)
03103 case (NF_CHAR)
03104 if (len.gt.512) call mpp_error(FATAL,'DIM ATT too long')
03105 error=NF_GET_ATT_TEXT(ncid,i,trim(attname),Axis(dimid)%Att(j)%catt);call netcdf_err(error)
03106 if( verbose .and. pe == 0 ) &
03107 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%catt(1:len)
03108
03109
03110 case (NF_SHORT)
03111 allocate(Axis(dimid)%Att(j)%fatt(len))
03112 error=NF_GET_ATT_INT2(ncid,i,trim(attname),i2vals);call netcdf_err(error)
03113 Axis(dimid)%Att(j)%fatt(1:len)=i2vals(1:len)
03114 if( verbose .and. pe == 0 ) &
03115 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
03116 case (NF_INT)
03117 allocate(Axis(dimid)%Att(j)%fatt(len))
03118 error=NF_GET_ATT_INT(ncid,i,trim(attname),ivals);call netcdf_err(error)
03119 Axis(dimid)%Att(j)%fatt(1:len)=ivals(1:len)
03120 if( verbose .and. pe == 0 ) &
03121 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
03122 case (NF_FLOAT)
03123 allocate(Axis(dimid)%Att(j)%fatt(len))
03124 error=NF_GET_ATT_REAL(ncid,i,trim(attname),rvals);call netcdf_err(error)
03125 Axis(dimid)%Att(j)%fatt(1:len)=rvals(1:len)
03126 if( verbose .and. pe == 0 ) &
03127 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
03128 case (NF_DOUBLE)
03129 allocate(Axis(dimid)%Att(j)%fatt(len))
03130 error=NF_GET_ATT_DOUBLE(ncid,i,trim(attname),r8vals);call netcdf_err(error)
03131 Axis(dimid)%Att(j)%fatt(1:len)=r8vals(1:len)
03132 if( verbose .and. pe == 0 ) &
03133 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
03134 case default
03135 call mpp_error( FATAL, 'Invalid data type for dimension at' )
03136 end select
03137
03138 select case(trim(attname))
03139 case('long_name')
03140 Axis(dimid)%longname=Axis(dimid)%Att(j)%catt(1:len)
03141 case('units')
03142 Axis(dimid)%units=Axis(dimid)%Att(j)%catt(1:len)
03143 case('cartesian_axis')
03144 Axis(dimid)%cartesian=Axis(dimid)%Att(j)%catt(1:len)
03145 case('positive')
03146 attval = Axis(dimid)%Att(j)%catt(1:len)
03147 if( attval.eq.'down' )then
03148 Axis(dimid)%sense=-1
03149 else if( attval.eq.'up' )then
03150 Axis(dimid)%sense=1
03151 endif
03152 end select
03153
03154 enddo
03155
03156 mpp_file(unit)%Axis(dimid) = Axis(dimid)
03157 endif
03158 enddo
03159
03160 nv = 0
03161 do i=1, nvar_total
03162 error=NF_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
03163
03164
03165
03166 isdim=.false.
03167 do j=1,ndim
03168 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
03169 enddo
03170
03171 if( .not.isdim )then
03172
03173 nv=nv+1; if( nv.GT.mpp_file(unit)%nvar )call mpp_error( FATAL, 'variable index exceeds number of defined variables' )
03174 mpp_file(unit)%Var(nv)%type = type
03175 mpp_file(unit)%Var(nv)%id = i
03176 mpp_file(unit)%Var(nv)%name = name
03177 mpp_file(unit)%Var(nv)%natt = nvatts
03178
03179 select case (type)
03180 case(NF_SHORT)
03181 mpp_file(unit)%Var(nv)%pack = 4
03182 case(NF_FLOAT)
03183 mpp_file(unit)%Var(nv)%pack = 2
03184 case(NF_DOUBLE)
03185 mpp_file(unit)%Var(nv)%pack = 1
03186 case (NF_INT)
03187 mpp_file(unit)%Var(nv)%pack = 2
03188 case default
03189 call mpp_error( FATAL, 'Invalid variable type in NetCDF file' )
03190 end select
03191
03192 mpp_file(unit)%Var(nv)%ndim = nvdims
03193 allocate(mpp_file(unit)%Var(nv)%axes(nvdims))
03194 do j=1,nvdims
03195 mpp_file(unit)%Var(nv)%axes(j) = Axis(dimids(j))
03196 enddo
03197 allocate(mpp_file(unit)%Var(nv)%size(nvdims))
03198
03199 do j=1,nvdims
03200 if( dimids(j).eq.mpp_file(unit)%recdimid )then
03201 mpp_file(unit)%Var(nv)%time_axis_index = dimids(j)
03202 mpp_file(unit)%Var(nv)%size(j)=1
03203 else
03204 mpp_file(unit)%Var(nv)%size(j)=Axis(dimids(j))%len
03205 endif
03206 enddo
03207
03208 if( nvatts.GT.0 )allocate(mpp_file(unit)%Var(nv)%Att(nvatts))
03209
03210 do j=1,nvatts
03211 mpp_file(unit)%Var(nv)%Att(j) = default_att
03212 enddo
03213
03214 do j=1,nvatts
03215 error=NF_INQ_ATTNAME(ncid,i,j,attname);call netcdf_err(error)
03216 error=NF_INQ_ATT(ncid,i,attname,type,len);call netcdf_err(error)
03217 mpp_file(unit)%Var(nv)%Att(j)%name = trim(attname)
03218 mpp_file(unit)%Var(nv)%Att(j)%type = type
03219 mpp_file(unit)%Var(nv)%Att(j)%len = len
03220
03221 select case (type)
03222 case (NF_CHAR)
03223 if (len.gt.512) call mpp_error(FATAL,'VAR ATT too long')
03224 error=NF_GET_ATT_TEXT(ncid,i,trim(attname),mpp_file(unit)%Var(nv)%Att(j)%catt(1:len));call netcdf_err(error)
03225 if (verbose .and. pe == 0 )&
03226 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
03227
03228 case (NF_SHORT)
03229 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
03230 error=NF_GET_ATT_INT2(ncid,i,trim(attname),i2vals);call netcdf_err(error)
03231 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)= i2vals(1:len)
03232 if( verbose .and. pe == 0 )&
03233 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
03234 case (NF_INT)
03235 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
03236 error=NF_GET_ATT_INT(ncid,i,trim(attname),ivals);call netcdf_err(error)
03237 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=ivals(1:len)
03238 if( verbose .and. pe == 0 )&
03239 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
03240 case (NF_FLOAT)
03241 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
03242 error=NF_GET_ATT_REAL(ncid,i,trim(attname),rvals);call netcdf_err(error)
03243 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=rvals(1:len)
03244 if( verbose .and. pe == 0 )&
03245 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
03246 case (NF_DOUBLE)
03247 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
03248 error=NF_GET_ATT_DOUBLE(ncid,i,trim(attname),r8vals);call netcdf_err(error)
03249 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=r8vals(1:len)
03250 if( verbose .and. pe == 0 ) &
03251 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
03252 case default
03253 call mpp_error( FATAL, 'Invalid data type for variable att' )
03254 end select
03255
03256 select case (trim(attname))
03257 case ('long_name')
03258 mpp_file(unit)%Var(nv)%longname=mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
03259 case('units')
03260 mpp_file(unit)%Var(nv)%units=mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
03261 case('scale_factor')
03262 mpp_file(unit)%Var(nv)%scale=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
03263 case('missing')
03264 mpp_file(unit)%Var(nv)%missing=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
03265 case('add_offset')
03266 mpp_file(unit)%Var(nv)%add=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
03267 case('valid_range')
03268 mpp_file(unit)%Var(nv)%min=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
03269 mpp_file(unit)%Var(nv)%max=mpp_file(unit)%Var(nv)%Att(j)%fatt(2)
03270 end select
03271 enddo
03272 endif
03273 enddo
03274 else
03275 call mpp_error( FATAL, 'MPP READ CURRENTLY DOES NOT SUPPORT NON-NETCDF' )
03276 endif
03277
03278 mpp_file(unit)%initialized = .TRUE.
03279 #else
03280 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
03281 #endif
03282 return
03283 end subroutine mpp_read_meta
03284
03285
03286 subroutine mpp_get_info( unit, ndim, nvar, natt, ntime )
03287
03288 integer, intent(in) :: unit
03289 integer, intent(out) :: ndim, nvar, natt, ntime
03290
03291
03292 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_INFO: must first call mpp_io_init.' )
03293 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_INFO: invalid unit number.' )
03294
03295 ndim = mpp_file(unit)%ndim
03296 nvar = mpp_file(unit)%nvar
03297 natt = mpp_file(unit)%natt
03298 ntime = mpp_file(unit)%time_level
03299
03300 return
03301
03302 end subroutine mpp_get_info
03303
03304
03305 subroutine mpp_get_global_atts( unit, global_atts )
03306
03307
03308
03309
03310
03311
03312 integer, intent(in) :: unit
03313 type(atttype), intent(inout) :: global_atts(:)
03314 integer :: natt,i
03315
03316 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_INFO: must first call mpp_io_init.' )
03317 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_INFO: invalid unit number.' )
03318
03319 if (size(global_atts).lt.mpp_file(unit)%natt) &
03320 call mpp_error(FATAL, 'MPP_GET_ATTS: atttype not dimensioned properly in calling routine')
03321
03322 natt = mpp_file(unit)%natt
03323 global_atts = default_att
03324
03325 do i=1,natt
03326 global_atts(i) = mpp_file(unit)%Att(i)
03327 enddo
03328
03329 return
03330 end subroutine mpp_get_global_atts
03331
03332 subroutine mpp_get_field_atts( field, name, units, longname, min, max, missing, ndim, siz, axes, atts )
03333
03334 type(fieldtype), intent(in) :: field
03335 character(len=*), intent(out) , optional :: name, units
03336 character(len=*), intent(out), optional :: longname
03337 real,intent(out), optional :: min,max,missing
03338 integer, intent(out), optional :: ndim
03339 integer, intent(out), dimension(:), optional :: siz
03340
03341 type(atttype), intent(out), optional, dimension(:) :: atts
03342 type(axistype), intent(out), optional, dimension(:) :: axes
03343
03344 integer :: n,m
03345
03346 if (PRESENT(name)) name = field%name
03347 if (PRESENT(units)) units = field%units
03348 if (PRESENT(longname)) longname = field%longname
03349 if (PRESENT(min)) min = field%min
03350 if (PRESENT(max)) max = field%max
03351 if (PRESENT(missing)) missing = field%missing
03352 if (PRESENT(ndim)) ndim = field%ndim
03353 if (PRESENT(atts)) then
03354 atts = default_att
03355 n = size(atts);m=size(field%Att)
03356 if (n.LT.m) call mpp_error(FATAL,'attribute array not large enough in mpp_get_field_atts')
03357 atts(1:m) = field%Att(1:m)
03358 end if
03359 if (PRESENT(axes)) then
03360 axes = default_axis
03361 n = size(axes);m=field%ndim
03362 if (n.LT.m) call mpp_error(FATAL,'axis array not large enough in mpp_get_field_atts')
03363 axes(1:m) = field%axes(1:m)
03364 end if
03365 if (PRESENT(siz)) then
03366 siz = -1
03367 n = size(siz);m=field%ndim
03368 if (n.LT.m) call mpp_error(FATAL,'size array not large enough in mpp_get_field_atts')
03369 siz(1:m) = field%size(1:m)
03370 end if
03371 return
03372 end subroutine mpp_get_field_atts
03373
03374 subroutine mpp_get_axis_atts( axis, name, units, longname, cartesian, sense, len, natts, atts )
03375
03376 type(axistype), intent(in) :: axis
03377 character(len=*), intent(out) , optional :: name, units
03378 character(len=*), intent(out), optional :: longname, cartesian
03379 integer,intent(out), optional :: sense, len , natts
03380 type(atttype), intent(out), optional, dimension(:) :: atts
03381
03382 integer :: n,m
03383
03384 if (PRESENT(name)) name = axis%name
03385 if (PRESENT(units)) units = axis%units
03386 if (PRESENT(longname)) longname = axis%longname
03387 if (PRESENT(cartesian)) cartesian = axis%cartesian
03388 if (PRESENT(sense)) sense = axis%sense
03389 if (PRESENT(len)) len = axis%len
03390 if (PRESENT(atts)) then
03391 atts = default_att
03392 n = size(atts);m=size(axis%Att)
03393 if (n.LT.m) call mpp_error(FATAL,'attribute array not large enough in mpp_get_field_atts')
03394 atts(1:m) = axis%Att(1:m)
03395 end if
03396 if (PRESENT(natts)) natts = size(axis%Att)
03397
03398 return
03399 end subroutine mpp_get_axis_atts
03400
03401
03402 subroutine mpp_get_fields( unit, variables )
03403
03404
03405
03406
03407
03408 integer, intent(in) :: unit
03409 type(fieldtype), intent(inout) :: variables(:)
03410
03411 integer :: nvar,i
03412
03413 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_FIELDS: must first call mpp_io_init.' )
03414 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_FIELDS: invalid unit number.' )
03415
03416 if (size(variables).ne.mpp_file(unit)%nvar) &
03417 call mpp_error(FATAL, 'MPP_GET_FIELDS: fieldtype not dimensioned properly in calling routine')
03418
03419 nvar = mpp_file(unit)%nvar
03420
03421 do i=1,nvar
03422 variables(i) = mpp_file(unit)%Var(i)
03423 enddo
03424
03425 return
03426 end subroutine mpp_get_fields
03427
03428 subroutine mpp_get_axes( unit, axes, time_axis )
03429
03430
03431
03432
03433
03434 integer, intent(in) :: unit
03435 type(axistype), intent(out) :: axes(:)
03436 type(axistype), intent(out), optional :: time_axis
03437 character(len=128) :: name
03438 logical :: save
03439 integer :: ndim,i, nvar, j, num_dims, k
03440
03441 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_AXES: must first call mpp_io_init.' )
03442 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_AXES: invalid unit number.' )
03443
03444 if (size(axes).ne.mpp_file(unit)%ndim) &
03445 call mpp_error(FATAL, 'MPP_GET_AXES: axistype not dimensioned properly in calling routine')
03446
03447
03448 if (PRESENT(time_axis)) time_axis = default_axis
03449 ndim = mpp_file(unit)%ndim
03450 do i=1,ndim
03451 if (ASSOCIATED(mpp_file(unit)%Axis(i)%data)) then
03452 axes(i)=mpp_file(unit)%Axis(i)
03453 else
03454 axes(i)=mpp_file(unit)%Axis(i)
03455 if (PRESENT(time_axis)) time_axis = mpp_file(unit)%Axis(i)
03456 endif
03457 enddo
03458
03459 return
03460 end subroutine mpp_get_axes
03461
03462 subroutine mpp_get_times( unit, time_values )
03463
03464
03465
03466 integer, intent(in) :: unit
03467 real(DOUBLE_KIND), intent(inout) :: time_values(:)
03468
03469 integer :: ntime,i
03470
03471 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_TIMES: must first call mpp_io_init.' )
03472 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_TIMES: invalid unit number.' )
03473
03474 if (size(time_values).ne.mpp_file(unit)%time_level) &
03475 call mpp_error(FATAL, 'MPP_GET_TIMES: time_values not dimensioned properly in calling routine')
03476
03477 ntime = mpp_file(unit)%time_level
03478
03479 do i=1,ntime
03480 time_values(i) = mpp_file(unit)%time_values(i)
03481 enddo
03482
03483
03484
03485 return
03486 end subroutine mpp_get_times
03487
03488 function mpp_get_field_index(fields,fieldname)
03489
03490 type(fieldtype), dimension(:) :: fields
03491 character(len=*) :: fieldname
03492 integer :: mpp_get_field_index
03493
03494 integer :: n
03495
03496 mpp_get_field_index = -1
03497
03498 do n=1,size(fields)
03499 if (lowercase(fields(n)%name) == lowercase(fieldname)) then
03500 mpp_get_field_index = n
03501 exit
03502 endif
03503 enddo
03504
03505 return
03506 end function mpp_get_field_index
03507
03508 function mpp_get_field_size(field)
03509
03510 type(fieldtype) :: field
03511 integer :: mpp_get_field_size(4)
03512
03513 integer :: n
03514
03515 mpp_get_field_size = -1
03516
03517 mpp_get_field_size(1) = field%size(1)
03518 mpp_get_field_size(2) = field%size(2)
03519 mpp_get_field_size(3) = field%size(3)
03520 mpp_get_field_size(4) = field%size(4)
03521
03522 return
03523 end function mpp_get_field_size
03524
03525
03526 subroutine mpp_get_axis_data( axis, data )
03527
03528 type(axistype), intent(in) :: axis
03529 real, dimension(:), intent(out) :: data
03530
03531
03532 if (size(data).lt.axis%len) call mpp_error(FATAL,'MPP_GET_AXIS_DATA: data array not large enough')
03533 if (.NOT.ASSOCIATED(axis%data)) then
03534 call mpp_error(NOTE,'MPP_GET_AXIS_DATA: use mpp_get_times for record dims')
03535 data = 0.
03536 else
03537 data(1:axis%len) = axis%data
03538 endif
03539
03540 return
03541 end subroutine mpp_get_axis_data
03542
03543
03544 function mpp_get_recdimid(unit)
03545
03546 integer, intent(in) :: unit
03547 integer :: mpp_get_recdimid
03548
03549
03550 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_RECDIMID: must first call mpp_io_init.' )
03551 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_RECDIMID: invalid unit number.' )
03552
03553 mpp_get_recdimid = mpp_file(unit)%recdimid
03554
03555 return
03556 end function mpp_get_recdimid
03557
03558
03559
03560
03561
03562
03563
03564 subroutine mpp_flush(unit)
03565
03566 integer, intent(in) :: unit
03567
03568 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_FLUSH: must first call mpp_io_init.' )
03569 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_FLUSH: invalid unit number.' )
03570 if( .NOT.mpp_file(unit)%initialized )call mpp_error( FATAL, 'MPP_FLUSH: cannot flush a file during writing of metadata.' )
03571 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
03572
03573 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
03574 #ifdef use_netCDF
03575 error = NF_SYNC(mpp_file(unit)%ncid); call netcdf_err(error)
03576 #endif
03577 else
03578 call mpp_flushstd(unit)
03579 end if
03580 return
03581 end subroutine mpp_flush
03582
03583 subroutine mpp_get_iospec( unit, iospec )
03584 integer, intent(in) :: unit
03585 character(len=*), intent(out) :: iospec
03586
03587 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_IOSPEC: must first call mpp_io_init.' )
03588 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_IOSPEC: invalid unit number.' )
03589 #ifdef SGICRAY
03590
03591 call ASSIGN( 'assign -V f:'//trim(mpp_file(unit)%name), error )
03592 #endif
03593 return
03594 end subroutine mpp_get_iospec
03595
03596
03597
03598
03599
03600
03601
03602 function mpp_get_ncid(unit)
03603 integer :: mpp_get_ncid
03604 integer, intent(in) :: unit
03605
03606 mpp_get_ncid = mpp_file(unit)%ncid
03607 return
03608 end function mpp_get_ncid
03609
03610 function mpp_get_axis_id(axis)
03611 integer mpp_get_axis_id
03612 type(axistype), intent(in) :: axis
03613 mpp_get_axis_id = axis%id
03614 return
03615 end function mpp_get_axis_id
03616
03617 function mpp_get_field_id(field)
03618 integer mpp_get_field_id
03619 type(fieldtype), intent(in) :: field
03620 mpp_get_field_id = field%id
03621 return
03622 end function mpp_get_field_id
03623
03624 subroutine netcdf_err(err)
03625 integer, intent(in) :: err
03626 character(len=80) :: errmsg
03627 integer :: unit
03628
03629 #ifdef use_netCDF
03630 if( err.EQ.NF_NOERR )return
03631 errmsg = NF_STRERROR(err)
03632 call mpp_io_exit()
03633 call mpp_error( FATAL, 'NETCDF ERROR: '//trim(errmsg) )
03634 #endif
03635 return
03636 end subroutine netcdf_err
03637
03638
03639
03640
03641
03642
03643
03644 subroutine mpp_get_unit_range( unit_begin_out, unit_end_out )
03645 integer, intent(out) :: unit_begin_out, unit_end_out
03646
03647 unit_begin_out = unit_begin; unit_end_out = unit_end
03648 return
03649 end subroutine mpp_get_unit_range
03650
03651 subroutine mpp_set_unit_range( unit_begin_in, unit_end_in )
03652 integer, intent(in) :: unit_begin_in, unit_end_in
03653
03654 if( unit_begin_in.GT.unit_end_in )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_begin_in.GT.unit_end_in.' )
03655 if( unit_begin_in.LT.0 )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_begin_in.LT.0.' )
03656 if( unit_end_in .GT.maxunits )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_end_in.GT.maxunits.' )
03657 unit_begin = unit_begin_in; unit_end = unit_end_in
03658 return
03659 end subroutine mpp_set_unit_range
03660
03661 subroutine mpp_modify_axis_meta( axis, name, units, longname, cartesian, data )
03662
03663 type(axistype), intent(inout) :: axis
03664 character(len=*), intent(in), optional :: name, units, longname, cartesian
03665 real, dimension(:), intent(in), optional :: data
03666
03667 if (PRESENT(name)) axis%name = trim(name)
03668 if (PRESENT(units)) axis%units = trim(units)
03669 if (PRESENT(longname)) axis%longname = trim(longname)
03670 if (PRESENT(cartesian)) axis%cartesian = trim(cartesian)
03671 if (PRESENT(data)) then
03672 axis%len = size(data)
03673 if (ASSOCIATED(axis%data)) deallocate(axis%data)
03674 allocate(axis%data(axis%len))
03675 axis%data = data
03676 endif
03677
03678 return
03679 end subroutine mpp_modify_axis_meta
03680
03681 subroutine mpp_modify_field_meta( field, name, units, longname, min, max, missing, axes )
03682
03683 type(fieldtype), intent(inout) :: field
03684 character(len=*), intent(in), optional :: name, units, longname
03685 real, intent(in), optional :: min, max, missing
03686 type(axistype), dimension(:), intent(inout), optional :: axes
03687
03688 if (PRESENT(name)) field%name = trim(name)
03689 if (PRESENT(units)) field%units = trim(units)
03690 if (PRESENT(longname)) field%longname = trim(longname)
03691 if (PRESENT(min)) field%min = min
03692 if (PRESENT(max)) field%max = max
03693 if (PRESENT(missing)) field%missing = missing
03694
03695
03696
03697
03698
03699
03700
03701 return
03702 end subroutine mpp_modify_field_meta
03703
03704 function lowercase (cs)
03705 implicit none
03706 character(len=*), intent(in) :: cs
03707 character(len=len(cs)) :: lowercase
03708
03709 integer, parameter :: co=iachar('a')-iachar('A')
03710 integer :: i
03711 character :: ca
03712
03713 lowercase = cs
03714 do i = 1, len(cs)
03715 ca = cs(i:i)
03716 if (ca >= "A" .and. ca <= "Z") then
03717 lowercase(i:i) = achar(iachar(ca)+co)
03718 endif
03719 enddo
03720
03721 end function lowercase
03722
03723
03724
03725
03726
03727
03728
03729
03730 subroutine mpp_nullify_axistype(axis)
03731 type(axistype), intent(inout) :: axis
03732
03733 Nullify(axis%data)
03734 Nullify(axis%cdata)
03735 Nullify(axis%Att)
03736 end subroutine mpp_nullify_axistype
03737
03738 subroutine mpp_nullify_axistype_array(axis)
03739 type(axistype), intent(inout), dimension(:) :: axis
03740 integer :: i
03741
03742 do i=1, size(axis)
03743 Nullify(axis(i)%data)
03744 Nullify(axis(i)%cdata)
03745 Nullify(axis(i)%Att)
03746 enddo
03747 end subroutine mpp_nullify_axistype_array
03748
03749 end module mpp_io_mod_oa
03750
03751 #else
03752
03753
03754
03755 module mpp_io_mod_oa
03756 use mod_kinds_mpp
03757 use mpp_mod_oa
03758 use mpp_domains_mod_oa
03759 implicit none
03760 #include <os.h>
03761 private
03762
03763 character(len=128), private :: version=
03764 '$Id: mpp_io_mod_oa.F90 2905 2011-01-21 16:29:23Z coquart $'
03765 character(len=128), private :: tagname=
03766 '$Name$'
03767
03768 integer, private :: pe, npes
03769
03770 type, public :: axistype
03771 private
03772 character(len=128) :: name
03773 character(len=128) :: units
03774 character(len=256) :: longname
03775 character(len=8) :: cartesian
03776 integer :: sense, len
03777 type(domain1D) :: domain
03778 real, pointer :: data(:)
03779 character(len=64), pointer :: cdata(:)
03780 integer :: clenid
03781 integer :: id, did, type, natt
03782 type(atttype), pointer :: Att(:)
03783 end type axistype
03784
03785 type, public :: atttype
03786 integer :: type, len
03787 character(len=128) :: name
03788 character(len=256) :: catt
03789
03790 real, pointer :: fatt(:)
03791 end type atttype
03792
03793 type, public :: fieldtype
03794 private
03795 character(len=128) :: name
03796 character(len=128) :: units
03797 character(len=256) :: longname
03798 real :: min, max, missing, fill, scale, add
03799 integer :: pack
03800 type(axistype), pointer :: axes(:)
03801
03802
03803 integer, pointer :: size(:)
03804 integer :: time_axis_index
03805 integer :: id, type, natt, ndim
03806 type(atttype), pointer :: Att(:)
03807 end type fieldtype
03808
03809 type, private :: filetype
03810 character(len=256) :: name
03811 integer :: action, format, access, threading, fileset, record, ncid
03812 logical :: opened, initialized, nohdrs
03813 integer :: time_level
03814 real(DOUBLE_KIND) :: time
03815 integer :: id
03816 integer :: recdimid
03817
03818
03819
03820
03821 real(DOUBLE_KIND), pointer :: time_values(:)
03822
03823
03824 integer :: ndim, nvar, natt
03825
03826
03827 type(axistype), pointer :: axis(:)
03828 type(fieldtype), pointer :: var(:)
03829 type(atttype), pointer :: att(:)
03830 end type filetype
03831
03832 type(axistype), public :: default_axis
03833 type(fieldtype), public :: default_field
03834 type(atttype), public :: default_att
03835
03836 integer, parameter, public :: MPP_WRONLY=100, MPP_RDONLY=101, MPP_APPEND=102, MPP_OVERWR=103
03837
03838 integer, parameter, public :: MPP_ASCII=200, MPP_IEEE32=201, MPP_NATIVE=202, MPP_NETCDF=203
03839
03840 integer, parameter, public :: MPP_SEQUENTIAL=300, MPP_DIRECT=301
03841
03842 integer, parameter, public :: MPP_SINGLE=400, MPP_MULTI=401, MPP_PARALLEL=402
03843
03844 integer, parameter, public :: MPP_DELETE=501, MPP_COLLECT=502
03845
03846 type(filetype), private, allocatable :: mpp_file(:)
03847 integer, private :: records_per_pe
03848 integer, private :: maxunits, unit_begin, unit_end
03849 integer, private :: varnum=0
03850 integer, private :: error
03851 character(len=256) :: text
03852
03853 integer, parameter, private :: NULLUNIT=-1
03854 real(DOUBLE_KIND), parameter, private :: NULLTIME=-1.
03855 #ifdef DEBUG
03856 logical, private :: verbose=.FALSE., debug=.TRUE., module_is_initialized=.FALSE.
03857 #else
03858 logical, private :: verbose=.FALSE., debug=.FALSE., module_is_initialized=.FALSE.
03859 #endif
03860
03861 real(DOUBLE_KIND), private, allocatable :: mpp_io_stack(:)
03862 integer, private :: mpp_io_stack_size=0, mpp_io_stack_hwm=0
03863
03864 interface mpp_write_meta
03865 module procedure mpp_write_meta_var
03866 module procedure mpp_write_meta_scalar_r
03867 module procedure mpp_write_meta_scalar_i
03868 module procedure mpp_write_meta_axis
03869 module procedure mpp_write_meta_field
03870 module procedure mpp_write_meta_global
03871 module procedure mpp_write_meta_global_scalar_r
03872 module procedure mpp_write_meta_global_scalar_i
03873 end interface
03874
03875 interface mpp_copy_meta
03876 module procedure mpp_copy_meta_axis
03877 module procedure mpp_copy_meta_field
03878 module procedure mpp_copy_meta_global
03879 end interface
03880
03881 interface mpp_write
03882 module procedure mpp_write_2ddecomp_r1d
03883 module procedure mpp_write_2ddecomp_r2d
03884 module procedure mpp_write_2ddecomp_r3d
03885 module procedure mpp_write_2ddecomp_r4d
03886 module procedure mpp_write_r0D
03887 module procedure mpp_write_r1D
03888 module procedure mpp_write_r2D
03889 module procedure mpp_write_r3D
03890 module procedure mpp_write_r4D
03891 module procedure mpp_write_axis
03892 end interface
03893
03894 interface mpp_read
03895 module procedure mpp_read_2ddecomp_r1d
03896 module procedure mpp_read_2ddecomp_r2d
03897 module procedure mpp_read_2ddecomp_r3d
03898 module procedure mpp_read_2ddecomp_r4d
03899 module procedure mpp_read_r0D
03900 module procedure mpp_read_r1D
03901 module procedure mpp_read_r2D
03902 module procedure mpp_read_r3D
03903 module procedure mpp_read_r4D
03904 end interface
03905
03906 interface mpp_get_id
03907 module procedure mpp_get_axis_id
03908 module procedure mpp_get_field_id
03909 end interface
03910
03911 interface mpp_get_atts
03912 module procedure mpp_get_global_atts
03913 module procedure mpp_get_field_atts
03914 module procedure mpp_get_axis_atts
03915 end interface
03916
03917 interface mpp_modify_meta
03918
03919 module procedure mpp_modify_field_meta
03920 module procedure mpp_modify_axis_meta
03921 end interface
03922
03923 public :: mpp_close, mpp_flush, mpp_get_iospec, mpp_get_id, mpp_get_ncid, mpp_get_unit_range, mpp_io_init, mpp_io_exit, &
03924 mpp_open, mpp_set_unit_range, mpp_write, mpp_write_meta, mpp_read, mpp_get_info, mpp_get_atts, &
03925 mpp_get_fields, mpp_get_times, mpp_get_axes, mpp_copy_meta, mpp_get_recdimid, mpp_get_axis_data, mpp_modify_meta, &
03926 mpp_io_set_stack_size, mpp_get_field_index, mpp_nullify_axistype, mpp_nullify_axistype_array
03927
03928 private :: read_record, mpp_read_meta, lowercase
03929
03930 #ifdef use_netCDF
03931 #include <pnetcdf.inc>
03932
03933 #ifdef NAG_COMPILER
03934 use mpi
03935 #else
03936 #include <mpif.h>
03937
03938 #endif
03939
03940 integer(kind=MPI_OFFSET_KIND), private :: idim
03941 #endif
03942
03943 contains
03944
03945
03946
03947
03948
03949
03950 subroutine mpp_io_init( flags, maxunit,maxresunit )
03951 integer, intent(in), optional :: flags, maxunit ,maxresunit
03952
03953
03954
03955
03956
03957 integer::max_reserved_units
03958
03959
03960
03961 if( module_is_initialized )return
03962 call mpp_init(flags)
03963 pe = mpp_pe()
03964 npes = mpp_npes()
03965 call mpp_domains_init(flags)
03966
03967 maxunits = 64
03968 if( PRESENT(maxunit) )maxunits = maxunit
03969
03970 max_reserved_units=5
03971 if( PRESENT(maxresunit) )max_reserved_units = maxresunit
03972
03973 if( PRESENT(flags) )then
03974 debug = flags.EQ.MPP_DEBUG
03975 verbose = flags.EQ.MPP_VERBOSE .OR. debug
03976 end if
03977
03978 default_field%name = 'noname'
03979 default_field%units = 'nounits'
03980 default_field%longname = 'noname'
03981 default_field%id = -1
03982 default_field%type = -1
03983 default_field%natt = -1
03984 default_field%ndim = -1
03985
03986 default_field%min = -huge(1._ip_single_mpp)
03987 default_field%max = huge(1._ip_single_mpp)
03988 default_field%missing = -1e36
03989 default_field%fill = -1e36
03990 default_field%scale = 0.
03991 default_field%add = huge(1._ip_single_mpp)
03992 default_field%pack = 1
03993 default_field%time_axis_index = -1
03994 Nullify(default_field%axes)
03995 Nullify(default_field%size)
03996 Nullify(default_field%att)
03997
03998 default_axis%name = 'noname'
03999 default_axis%units = 'nounits'
04000 default_axis%longname = 'noname'
04001 default_axis%cartesian = 'none'
04002 default_axis%sense = 0
04003 default_axis%len = -1
04004 default_axis%id = -1
04005 default_axis%did = -1
04006 default_axis%type = -1
04007 default_axis%natt = -1
04008 Nullify(default_axis%data)
04009
04010 default_att%name = 'noname'
04011 default_att%type = -1
04012 default_att%len = -1
04013 default_att%catt = 'none'
04014 Nullify(default_att%fatt)
04015
04016
04017
04018
04019 allocate( mpp_file(NULLUNIT:2*maxunits) )
04020 mpp_file(:)%name = ' '
04021 mpp_file(:)%action = -1
04022 mpp_file(:)%format = -1
04023 mpp_file(:)%threading = -1
04024 mpp_file(:)%fileset = -1
04025 mpp_file(:)%record = -1
04026 mpp_file(:)%ncid = -1
04027 mpp_file(:)%opened = .FALSE.
04028 mpp_file(:)%initialized = .FALSE.
04029 mpp_file(:)%time_level = 0
04030 mpp_file(:)%time = NULLTIME
04031 mpp_file(:)%id = -1
04032
04033 mpp_file(:)%ndim = -1
04034 mpp_file(:)%nvar = -1
04035
04036 mpp_file(NULLUNIT)%threading = MPP_SINGLE
04037 mpp_file(NULLUNIT)%opened = .TRUE.
04038 mpp_file(NULLUNIT)%initialized = .TRUE.
04039
04040 mpp_file(stdin ())%opened = .TRUE.
04041 mpp_file(stdout())%opened = .TRUE.
04042 mpp_file(stderr())%opened = .TRUE.
04043 mpp_file(stdout())%opened = .TRUE.
04044
04045
04046
04047
04048
04049 if(present(maxunit)) then
04050 call mpp_set_unit_range( 7, maxunits-max_reserved_units )
04051 else
04052 call mpp_set_unit_range( 7, maxunits )
04053 endif
04054
04055
04056
04057 write( stdout(),'(/a)' )'MPP_IO module '//trim(version)
04058 #ifdef use_netCDF
04059
04060
04061
04062 #endif
04063
04064
04065 #ifdef CRAYPVP
04066
04067 call ASSIGN( 'assign -P thread p:%', error )
04068 #endif
04069
04070 call mpp_io_set_stack_size(131072)
04071 call mpp_sync()
04072 module_is_initialized = .TRUE.
04073 return
04074 end subroutine mpp_io_init
04075
04076 subroutine mpp_io_exit()
04077 integer :: unit
04078
04079 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_IO_EXIT: must first call mpp_io_init.' )
04080
04081 do unit = unit_begin,unit_end
04082 if( mpp_file(unit)%opened )call FLUSH(unit)
04083 end do
04084 call mpp_sync()
04085 do unit = unit_begin,unit_end
04086 if( mpp_file(unit)%opened )close(unit)
04087 end do
04088 #ifdef use_netCDF
04089
04090 do unit = maxunits+1,2*maxunits
04091 if( mpp_file(unit)%opened )error = NFMPI_CLOSE(mpp_file(unit)%ncid)
04092 end do
04093 #endif
04094
04095 call mpp_max(mpp_io_stack_hwm)
04096
04097
04098
04099
04100
04101 deallocate(mpp_file)
04102 module_is_initialized = .FALSE.
04103 return
04104 end subroutine mpp_io_exit
04105
04106 subroutine mpp_io_set_stack_size(n)
04107
04108 integer, intent(in) :: n
04109 character(len=8) :: text
04110
04111 if( n.GT.mpp_io_stack_size .AND. allocated(mpp_io_stack) )deallocate(mpp_io_stack)
04112 if( .NOT.allocated(mpp_io_stack) )then
04113 allocate( mpp_io_stack(n) )
04114 mpp_io_stack_size = n
04115 write( text,'(i8)' )n
04116
04117 call mpp_error( NOTE, 'MPP_IO_SET_STACK_SIZE: stack size set to '//text//'.' )
04118 end if
04119
04120 return
04121 end subroutine mpp_io_set_stack_size
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165
04166 subroutine mpp_open( unit, file, action, mpp_comm, form, access, threading, &
04167 fileset, iospec, nohdrs, recl, pelist )
04168
04169 integer, intent(out) :: unit
04170 character(len=*), intent(in) :: file
04171 integer, intent(in), optional :: action, form, access, threading,
04172 fileset, recl, mpp_comm
04173 character(len=*), intent(in), optional :: iospec
04174 logical, intent(in), optional :: nohdrs
04175 integer, intent(in), optional :: pelist(:)
04176
04177 character(len=16) :: act, acc, for, pos
04178 integer :: action_flag, form_flag, access_flag, threading_flag, fileset_flag, length
04179 logical :: exists
04180 character(len=64) :: filespec
04181 type(axistype) :: unlim
04182
04183 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_OPEN: must first call mpp_io_init.' )
04184
04185 action_flag = MPP_WRONLY
04186 if( PRESENT(action) )action_flag = action
04187 form_flag = MPP_ASCII
04188 if( PRESENT(form) )form_flag = form
04189 #ifndef use_netCDF
04190 if( form_flag.EQ.MPP_NETCDF ) &
04191 call mpp_error( FATAL, 'MPP_OPEN: To open a file with form=MPP_NETCDF, you must compile mpp_io with -Duse_netCDF.' )
04192 #endif
04193 access_flag = MPP_SEQUENTIAL
04194 if( PRESENT(access) )access_flag = access
04195 threading_flag = MPP_SINGLE
04196 if( npes.GT.1 .AND. PRESENT(threading) )threading_flag = threading
04197 fileset_flag = MPP_MULTI
04198 if( PRESENT(fileset) )fileset_flag = fileset
04199 if( threading_flag.EQ.MPP_SINGLE )fileset_flag = MPP_SINGLE
04200
04201 fileset_flag = MPP_PARALLEL
04202 threading_flag = MPP_PARALLEL
04203
04204
04205 if( threading_flag.EQ.MPP_SINGLE )then
04206 if( pe.NE.mpp_root_pe() .AND. action_flag.NE.MPP_RDONLY )then
04207 unit = NULLUNIT
04208 return
04209 end if
04210 end if
04211 if( form_flag.EQ.MPP_NETCDF )then
04212 do unit = maxunits+1,2*maxunits
04213 if( .NOT.mpp_file(unit)%opened )exit
04214 end do
04215 if( unit.GT.2*maxunits )call mpp_error( FATAL, 'MPP_OPEN: too many open netCDF files.' )
04216 else
04217 do unit = unit_begin, unit_end
04218 inquire( unit,OPENED=mpp_file(unit)%opened )
04219 if( .NOT.mpp_file(unit)%opened )exit
04220 end do
04221 if( unit.GT.unit_end )call mpp_error( FATAL, 'MPP_OPEN: no available units.' )
04222 end if
04223
04224
04225 text = file
04226 length = len(file)
04227
04228
04229
04230
04231
04232
04233 if( fileset_flag.EQ.MPP_MULTI )write( text,'(a,i4.4)' )trim(text)//'.', pe
04234 mpp_file(unit)%name = text
04235 if( verbose ) write (stdout(), '(a,2i3,1x,a,5i5)') &
04236 'MPP_OPEN: PE, unit, filename, action, format, access, threading, fileset=', &
04237 pe, unit, trim(mpp_file(unit)%name), action_flag, form_flag, access_flag, threading_flag, fileset_flag
04238
04239
04240 if( action_flag.EQ.MPP_RDONLY )then
04241 act = 'READ'
04242 pos = 'REWIND'
04243
04244 else if( action_flag.EQ.MPP_WRONLY .OR. action_flag.EQ.MPP_OVERWR )then
04245 act = 'WRITE'
04246 pos = 'REWIND'
04247 else if( action_flag.EQ.MPP_APPEND )then
04248 act = 'WRITE'
04249 pos = 'APPEND'
04250 else
04251 call mpp_error( FATAL, 'MPP_OPEN: action must be one of MPP_WRONLY, MPP_APPEND or MPP_RDONLY.' )
04252 end if
04253
04254
04255 if( form_flag.NE.MPP_NETCDF )then
04256 if( access_flag.EQ.MPP_SEQUENTIAL )then
04257 acc = 'SEQUENTIAL'
04258 else if( access_flag.EQ.MPP_DIRECT )then
04259 acc = 'DIRECT'
04260 if( form_flag.EQ.MPP_ASCII )call mpp_error( FATAL, 'MPP_OPEN: formatted direct access I/O is prohibited.' )
04261 if( .NOT.PRESENT(recl) ) &
04262 call mpp_error( FATAL, 'MPP_OPEN: recl (record length in bytes) must be specified with access=MPP_DIRECT.' )
04263 mpp_file(unit)%record = 1
04264 records_per_pe = 1
04265 else
04266 call mpp_error( FATAL, 'MPP_OPEN: access must be one of MPP_SEQUENTIAL or MPP_DIRECT.' )
04267 end if
04268 end if
04269
04270
04271 if( threading_flag.EQ.MPP_MULTI )then
04272
04273 if( fileset_flag.EQ.MPP_SINGLE )then
04274 if( form_flag.EQ.MPP_NETCDF .AND. act.EQ.'WRITE' ) &
04275 call mpp_error( FATAL, 'MPP_OPEN: netCDF currently does not support single-file multi-threaded output.' )
04276
04277 #ifdef _CRAYT3E
04278 call ASSIGN( 'assign -I -F global.privpos f:'//trim(mpp_file(unit)%name), error )
04279 #endif
04280 else if( fileset_flag.NE.MPP_PARALLEL )then
04281 call mpp_error( FATAL, 'MPP_OPEN: fileset must be one of MPP_PARALLEL.' )
04282 end if
04283 else if( threading_flag.NE.MPP_PARALLEL )then
04284 call mpp_error( FATAL, 'MPP_OPEN: threading must be MPP_PARALLEL.' )
04285 end if
04286
04287
04288
04289 #ifdef CRAYPVP
04290 call ASSIGN( 'assign -I -P thread f:'//trim(mpp_file(unit)%name), error )
04291 #endif
04292 #ifdef _CRAYT3E
04293 call ASSIGN( 'assign -I -P private f:'//trim(mpp_file(unit)%name), error )
04294 #endif
04295 if( PRESENT(iospec) )then
04296
04297
04298
04299
04300 #ifdef SGICRAY
04301 call ASSIGN( 'assign -I '//trim(iospec)//' f:'//trim(mpp_file(unit)%name), error )
04302 if( form_flag.EQ.MPP_NETCDF )then
04303
04304
04305
04306
04307 call PXFSETENV( 'NETCDF_XFFIOSPEC', 0, trim(iospec), 0, 1, error )
04308 end if
04309 #endif
04310 end if
04311
04312
04313 if( form_flag.EQ.MPP_NETCDF )then
04314 #ifdef use_netCDF
04315 if( action_flag.EQ.MPP_WRONLY )then
04316 error = NFMPI_CREATE( mpp_comm, trim(mpp_file(unit)%name), NF_NOCLOBBER, MPI_INFO_NULL, mpp_file(unit)%ncid )
04317 call netcdf_err(error)
04318 if( verbose ) write (stdout(), '(a,i3,i16)') 'MPP_OPEN: new netCDF file: pe, ncid=', pe, mpp_file(unit)%ncid
04319 else if( action_flag.EQ.MPP_OVERWR )then
04320 error = NFMPI_CREATE( mpp_comm, trim(mpp_file(unit)%name), NF_CLOBBER, MPI_INFO_NULL, mpp_file(unit)%ncid )
04321 call netcdf_err(error)
04322 action_flag = MPP_WRONLY
04323 if( verbose ) write (stdout(), '(a,i3,i16)') 'MPP_OPEN: overwrite netCDF file: pe, ncid=', pe, mpp_file(unit)%ncid
04324 else if( action_flag.EQ.MPP_APPEND )then
04325 error = NFMPI_OPEN( mpp_comm, trim(mpp_file(unit)%name), NF_WRITE, MPI_INFO_NULL, mpp_file(unit)%ncid )
04326 call netcdf_err(error)
04327
04328 error = NFMPI_INQ_UNLIMDIM( mpp_file(unit)%ncid, unlim%did )
04329 if( error.EQ.NF_NOERR )then
04330 error = NFMPI_INQ_DIM( mpp_file(unit)%ncid, unlim%did, unlim%name, idim )
04331 mpp_file(unit)%time_level = idim
04332 call netcdf_err(error)
04333 error = NFMPI_INQ_VARID( mpp_file(unit)%ncid, unlim%name, mpp_file(unit)%id ); call netcdf_err(error)
04334 end if
04335 if( verbose ) write (stdout(), '(a,i3,i16,i4)') 'MPP_OPEN: append to existing netCDF file: pe, ncid, time_axis_id=',&
04336 pe, mpp_file(unit)%ncid, mpp_file(unit)%id
04337 else if( action_flag.EQ.MPP_RDONLY )then
04338 error = NFMPI_OPEN( mpp_comm, trim(mpp_file(unit)%name), NF_NOWRITE, MPI_INFO_NULL, mpp_file(unit)%ncid )
04339 call netcdf_err(error)
04340 if( verbose ) write (stdout(), '(a,i3,i16,i4)') 'MPP_OPEN: opening existing netCDF file: pe, ncid, time_axis_id=',&
04341 pe, mpp_file(unit)%ncid, mpp_file(unit)%id
04342 mpp_file(unit)%format=form_flag
04343 call mpp_read_meta(unit)
04344 end if
04345 mpp_file(unit)%opened = .TRUE.
04346 #endif
04347 else
04348
04349 if( form_flag.EQ.MPP_ASCII )then
04350 for = 'FORMATTED'
04351 else if( form_flag.EQ.MPP_IEEE32 )then
04352 for = 'UNFORMATTED'
04353
04354 #ifdef _CRAY
04355 call ASSIGN( 'assign -I -N ieee_32 f:'//trim(mpp_file(unit)%name), error )
04356 #endif
04357 else if( form_flag.EQ.MPP_NATIVE )then
04358 for = 'UNFORMATTED'
04359 else
04360 call mpp_error( FATAL, 'MPP_OPEN: form must be one of MPP_ASCII, MPP_NATIVE, MPP_IEEE32 or MPP_NETCDF.' )
04361 end if
04362 inquire( file=trim(mpp_file(unit)%name), EXIST=exists )
04363 if( exists .AND. action_flag.EQ.MPP_WRONLY ) &
04364 call mpp_error( WARNING, 'MPP_OPEN: File '//trim(mpp_file(unit)%name)//' opened WRONLY already exists!' )
04365 if( action_flag.EQ.MPP_OVERWR )action_flag = MPP_WRONLY
04366
04367 if( PRESENT(recl) )then
04368 if( verbose ) write (stdout(), '(2(1x,a,i3),5(1x,a),a,i8)') 'MPP_OPEN: PE=', pe, &
04369 'unit=', unit, trim(mpp_file(unit)%name), 'attributes=', trim(acc), trim(for), trim(act), ' RECL=', recl
04370 open( unit, file=trim(mpp_file(unit)%name), access=acc, form=for, action=act, recl=recl )
04371 else
04372 if( verbose ) write (stdout(), '(2(1x,a,i3),6(1x,a))') 'MPP_OPEN: PE=', pe, &
04373 'unit=', unit, trim(mpp_file(unit)%name), 'attributes=', trim(acc), trim(for), trim(pos), trim(act)
04374 open( unit, file=trim(mpp_file(unit)%name), access=acc, form=for, action=act, position=pos )
04375 end if
04376
04377 inquire( unit,OPENED=mpp_file(unit)%opened )
04378 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_OPEN: error in OPEN() statement.' )
04379 end if
04380 mpp_file(unit)%action = action_flag
04381 mpp_file(unit)%format = form_flag
04382 mpp_file(unit)%access = access_flag
04383 mpp_file(unit)%threading = threading_flag
04384 mpp_file(unit)%fileset = fileset_flag
04385 if( PRESENT(nohdrs) )mpp_file(unit)%nohdrs = nohdrs
04386
04387 if( action_flag.EQ.MPP_WRONLY )then
04388 if( form_flag.NE.MPP_NETCDF .AND. access_flag.EQ.MPP_DIRECT )call mpp_write_meta( unit, 'record_length', ival=recl )
04389
04390 call mpp_write_meta( unit, 'filename', cval=mpp_file(unit)%name )
04391
04392 call mpp_write_meta( unit, 'MPP_IO_VERSION', cval=trim(version) )
04393
04394 if( threading_flag.EQ.MPP_MULTI .AND. fileset_flag.EQ.MPP_MULTI ) &
04395 call mpp_write_meta( unit, 'NumFilesInSet', ival=npes )
04396 end if
04397
04398 return
04399 end subroutine mpp_open
04400
04401 subroutine mpp_close( unit, action )
04402 integer, intent(in) :: unit
04403 integer, intent(in), optional :: action
04404 character(len=8) :: status
04405 logical :: collect
04406
04407 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_CLOSE: must first call mpp_io_init.' )
04408 if( unit.EQ.NULLUNIT )return
04409
04410
04411 status = 'KEEP'
04412
04413 collect = .FALSE.
04414 if( PRESENT(action) )then
04415 if( action.EQ.MPP_DELETE )then
04416 status = 'DELETE'
04417 else if( action.EQ.MPP_COLLECT )then
04418 collect = .FALSE.
04419 call mpp_error( WARNING, 'MPP_CLOSE: the COLLECT operation is not yet implemented.' )
04420 else
04421 call mpp_error( FATAL, 'MPP_CLOSE: action must be one of MPP_DELETE or MPP_COLLECT.' )
04422 end if
04423 end if
04424 if( mpp_file(unit)%fileset.NE.MPP_MULTI )collect = .FALSE.
04425 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
04426 #ifdef use_netCDF
04427 error = NFMPI_CLOSE(mpp_file(unit)%ncid); call netcdf_err(error)
04428 #endif
04429 else
04430 close(unit,status=status)
04431 end if
04432 #ifdef SGICRAY
04433
04434
04435
04436 #endif
04437 mpp_file(unit)%name = ' '
04438 mpp_file(unit)%action = -1
04439 mpp_file(unit)%format = -1
04440 mpp_file(unit)%access = -1
04441 mpp_file(unit)%threading = -1
04442 mpp_file(unit)%fileset = -1
04443 mpp_file(unit)%record = -1
04444 mpp_file(unit)%ncid = -1
04445 mpp_file(unit)%opened = .FALSE.
04446 mpp_file(unit)%initialized = .FALSE.
04447 mpp_file(unit)%id = -1
04448 mpp_file(unit)%time_level = 0
04449 mpp_file(unit)%time = NULLTIME
04450 return
04451 end subroutine mpp_close
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562
04563
04564
04565
04566 subroutine mpp_write_meta_global( unit, name, rval, ival, cval, pack )
04567
04568
04569
04570
04571
04572 integer, intent(in) :: unit
04573 character(len=*), intent(in) :: name
04574 real, intent(in), optional :: rval(:)
04575 integer, intent(in), optional :: ival(:)
04576 character(len=*), intent(in), optional :: cval
04577 integer, intent(in), optional :: pack
04578
04579 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
04580 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
04581 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04582 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04583 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
04584 if( mpp_file(unit)%initialized ) &
04585 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
04586
04587 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
04588 #ifdef use_netCDF
04589 call write_attribute_netcdf( unit, NF_GLOBAL, name, rval, ival, cval, pack )
04590 #endif
04591 else
04592 call write_attribute( unit, 'GLOBAL '//trim(name), rval, ival, cval, pack )
04593 end if
04594
04595 return
04596 end subroutine mpp_write_meta_global
04597
04598
04599 subroutine mpp_write_meta_global_scalar_r( unit, name, rval, pack )
04600 integer, intent(in) :: unit
04601 character(len=*), intent(in) :: name
04602 real, intent(in) :: rval
04603 integer, intent(in), optional :: pack
04604
04605 call mpp_write_meta_global( unit, name, rval=(/rval/), pack=pack )
04606 return
04607 end subroutine mpp_write_meta_global_scalar_r
04608
04609 subroutine mpp_write_meta_global_scalar_i( unit, name, ival )
04610 integer, intent(in) :: unit
04611 character(len=*), intent(in) :: name
04612 integer, intent(in) :: ival
04613
04614 call mpp_write_meta_global( unit, name, ival=(/ival/) )
04615 return
04616 end subroutine mpp_write_meta_global_scalar_i
04617
04618 subroutine mpp_write_meta_var( unit, id, name, rval, ival, cval, pack )
04619
04620
04621
04622
04623
04624 integer, intent(in) :: unit, id
04625 character(len=*), intent(in) :: name
04626 real, intent(in), optional :: rval(:)
04627 integer, intent(in), optional :: ival(:)
04628 character(len=*), intent(in), optional :: cval
04629 integer, intent(in), optional :: pack
04630
04631 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
04632 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
04633 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04634 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04635 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
04636 if( mpp_file(unit)%initialized ) &
04637 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
04638
04639 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
04640 call write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
04641 else
04642 write( text, '(a,i4,a)' )'VARIABLE ', id, ' '//name
04643 call write_attribute( unit, trim(text), rval, ival, cval, pack )
04644 end if
04645
04646 return
04647 end subroutine mpp_write_meta_var
04648
04649
04650 subroutine mpp_write_meta_scalar_r( unit, id, name, rval, pack )
04651 integer, intent(in) :: unit, id
04652 character(len=*), intent(in) :: name
04653 real, intent(in) :: rval
04654 integer, intent(in), optional :: pack
04655
04656 call mpp_write_meta( unit, id, name, rval=(/rval/), pack=pack )
04657 return
04658 end subroutine mpp_write_meta_scalar_r
04659
04660 subroutine mpp_write_meta_scalar_i( unit, id, name, ival )
04661 integer, intent(in) :: unit, id
04662 character(len=*), intent(in) :: name
04663 integer, intent(in) :: ival
04664
04665 call mpp_write_meta( unit, id, name, ival=(/ival/) )
04666 return
04667 end subroutine mpp_write_meta_scalar_i
04668
04669 subroutine mpp_write_meta_axis( unit, axis, name, units, longname, cartesian, sense, domain, data, cdata) !RV,bundles
04670
04671
04672
04673
04674 integer, intent(in) :: unit
04675 type(axistype), intent(inout) :: axis
04676 character(len=*), intent(in) :: name, units, longname
04677 character(len=*), intent(in), optional :: cartesian
04678 integer, intent(in), optional :: sense
04679 type(domain1D), intent(in), optional :: domain
04680 real, intent(in), optional :: data(:)
04681 character(len=*), intent(in), optional :: cdata(:)
04682 integer :: is, ie, isg, ieg
04683
04684 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
04685 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
04686 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04687 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04688 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
04689 if( mpp_file(unit)%initialized ) &
04690 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
04691
04692
04693 if( ASSOCIATED(axis%data) )NULLIFY(axis%data)
04694 if( ASSOCIATED(axis%cdata) )NULLIFY(axis%cdata)
04695
04696 axis%name = name
04697 axis%units = units
04698 axis%longname = longname
04699 if( PRESENT(cartesian) )axis%cartesian = cartesian
04700 if( PRESENT(sense) )axis%sense = sense
04701 if( PRESENT(domain) )then
04702 axis%domain = domain
04703 call mpp_get_global_domain( domain, isg, ieg )
04704 call mpp_get_compute_domain( domain, is, ie )
04705 else
04706 axis%domain = NULL_DOMAIN1D
04707 if( PRESENT(data) )then
04708 isg=1; ieg=size(data); is=isg; ie=ieg
04709 endif
04710 if( PRESENT(cdata) )then
04711 isg=1; ieg=size(cdata); is=isg; ie=ieg
04712 endif
04713 end if
04714 if( PRESENT(data) )then
04715 if( PRESENT(domain) )then
04716 if( size(data).NE.ieg-isg+1 ) &
04717 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: size(data).NE.domain%global%size.' )
04718 allocate( axis%data(isg:ieg) )
04719 else
04720 allocate( axis%data(size(data)) )
04721 end if
04722 axis%data = data
04723 end if
04724 if( PRESENT(cdata) )then
04725 if( PRESENT(domain) )then
04726 if( size(cdata).NE.ieg-isg+1 ) &
04727 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: size(cdata).NE.domain%global%size.' )
04728 allocate( axis%cdata(isg:ieg) )
04729 allocate( axis%data(isg:ieg) )
04730 else
04731 allocate( axis%cdata(size(cdata)) )
04732 allocate( axis%data(size(cdata)) )
04733 end if
04734 axis%cdata = cdata
04735 end if
04736
04737
04738
04739 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
04740 #ifdef use_netCDF
04741
04742
04743 if( ASSOCIATED(axis%data).or. ASSOCIATED(axis%cdata) )then
04744 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
04745 idim = ie-is+1
04746 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did )
04747 else
04748 if( ASSOCIATED(axis%data).and.(.not.present(cdata)))then
04749 idim = size(axis%data)
04750 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did )
04751 else
04752 idim = len(axis%cdata)
04753 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, 'MAX_STRLEN', idim, axis%clenid )
04754 call netcdf_err(error)
04755 idim = size(axis%cdata)
04756 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did )
04757 endif
04758 end if
04759 call netcdf_err(error)
04760 if(present(cdata)) then
04761 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_CHAR, 2,(/axis%clenid, axis%did/), axis%id )
04762 call netcdf_err(error)
04763 else
04764 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id ); call netcdf_err(error)
04765 endif
04766
04767 else
04768 if( mpp_file(unit)%id.NE.-1 ) &
04769 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
04770 idim = NF_UNLIMITED
04771 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did ); call netcdf_err(error)
04772 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id ); call netcdf_err(error)
04773 mpp_file(unit)%id = axis%id
04774 end if
04775 #endif
04776 else
04777 varnum = varnum + 1
04778 axis%id = varnum
04779 axis%did = varnum
04780
04781 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
04782 call write_attribute( unit, trim(text), cval=axis%name )
04783 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
04784 if( ASSOCIATED(axis%data) )then
04785 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
04786 call write_attribute( unit, trim(text), ival=(/ie-is+1/) )
04787 else
04788 if(ASSOCIATED(axis%data).and.(.not.present(cdata))) then
04789
04790 call write_attribute( unit, trim(text), ival=(/size(axis%data)/) )
04791 else
04792 call write_attribute( unit, trim(text), ival=(/size(axis%cdata)/) )
04793 endif
04794 end if
04795 else
04796 if( mpp_file(unit)%id.NE.-1 ) &
04797 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
04798 call write_attribute( unit, trim(text), ival=(/0/) )
04799 mpp_file(unit)%id = axis%id
04800 end if
04801 end if
04802
04803
04804 call mpp_write_meta( unit, axis%id, 'long_name', cval=axis%longname )
04805 call mpp_write_meta( unit, axis%id, 'units', cval=axis%units )
04806 if( PRESENT(cartesian) )call mpp_write_meta( unit, axis%id, 'cartesian_axis', cval=axis%cartesian )
04807 if( PRESENT(sense) )then
04808 if( sense.EQ.-1 )then
04809 call mpp_write_meta( unit, axis%id, 'positive', cval='down' )
04810 else if( sense.EQ.1 )then
04811 call mpp_write_meta( unit, axis%id, 'positive', cval='up' )
04812 end if
04813
04814 end if
04815 if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
04816 call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/) )
04817 end if
04818 if( verbose ) write (stdout(), '(a,2i3,1x,a,2i3)') &
04819 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
04820 pe, unit, trim(axis%name), axis%id, axis%did
04821
04822 return
04823 end subroutine mpp_write_meta_axis
04824
04825 subroutine mpp_write_meta_field( unit, field, axes, name, units, longname, min, max, missing, fill, scale, add, pack )
04826
04827 integer, intent(in) :: unit
04828 type(fieldtype), intent(out) :: field
04829 type(axistype), intent(in) :: axes(:)
04830 character(len=*), intent(in) :: name, units, longname
04831 real, intent(in), optional :: min, max, missing, fill, scale, add
04832 integer, intent(in), optional :: pack
04833
04834 integer, allocatable :: axis_id(:)
04835 real :: a, b
04836 integer :: i
04837
04838 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
04839 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
04840 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04841 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
04842 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
04843 if( mpp_file(unit)%initialized ) &
04844 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
04845
04846
04847 if( ASSOCIATED(field%axes) )NULLIFY(field%axes)
04848
04849 field%name = name
04850 field%units = units
04851 field%longname = longname
04852 allocate( field%axes(size(axes)) )
04853 field%axes = axes
04854 field%time_axis_index = -1
04855
04856
04857 allocate( field%size(size(axes)) )
04858 do i = 1,size(axes)
04859 if( ASSOCIATED(axes(i)%data) )then
04860 field%size(i) = size(axes(i)%data)
04861 else
04862 field%size(i) = 1
04863 field%time_axis_index = i
04864 end if
04865 end do
04866
04867 if( PRESENT(min) )field%min = min
04868 if( PRESENT(max) )field%max = max
04869 if( PRESENT(missing) )field%missing = missing
04870 if( PRESENT(fill) )field%fill = fill
04871 if( PRESENT(scale) )field%scale = scale
04872 if( PRESENT(add) )field%add = add
04873
04874
04875 field%pack = 2
04876 if( PRESENT(pack) )field%pack = pack
04877 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
04878 #ifdef use_netCDF
04879 allocate( axis_id(size(field%axes)) )
04880 do i = 1,size(field%axes)
04881 axis_id(i) = field%axes(i)%did
04882 end do
04883
04884 select case (field%pack)
04885 case(1)
04886 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes), axis_id, field%id )
04887 case(2)
04888 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes), axis_id, field%id )
04889 case(4)
04890 if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
04891 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
04892 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes), axis_id, field%id )
04893 case(8)
04894 if( .NOT.PRESENT(scale) .OR. .NOT.PRESENT(add) ) &
04895 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
04896 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes), axis_id, field%id )
04897 case default
04898 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
04899 end select
04900 call netcdf_err(error)
04901 #endif
04902 else
04903 varnum = varnum + 1
04904 field%id = varnum
04905 if( PRESENT(pack) )call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
04906
04907 write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
04908 call write_attribute( unit, trim(text), cval=field%name )
04909 write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
04910 call write_attribute( unit, trim(text), ival=field%axes(:)%did )
04911 end if
04912
04913 call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname )
04914 call mpp_write_meta( unit, field%id, 'units', cval=field%units )
04915
04916 if( PRESENT(min) .AND. PRESENT(max) )then
04917 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
04918 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/min,max/), pack=pack )
04919 else
04920 a = nint((min-add)/scale)
04921 b = nint((max-add)/scale)
04922 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=pack )
04923 end if
04924 else if( PRESENT(min) )then
04925 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
04926 call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=pack )
04927 else
04928 a = nint((min-add)/scale)
04929 call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=pack )
04930 end if
04931 else if( PRESENT(max) )then
04932 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
04933 call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=pack )
04934 else
04935 a = nint((max-add)/scale)
04936 call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=pack )
04937 end if
04938 end if
04939 if( PRESENT(missing) )then
04940 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
04941 call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=pack )
04942 else
04943 a = nint((missing-add)/scale)
04944 call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=pack )
04945 end if
04946 end if
04947 if( PRESENT(fill) )then
04948 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
04949 call mpp_write_meta( unit, field%id, '_FillValue', rval=field%fill, pack=pack )
04950 else
04951 a = nint((fill-add)/scale)
04952 call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=pack )
04953 end if
04954 end if
04955 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
04956 call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
04957 if( PRESENT(scale) )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
04958 if( PRESENT(add) )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
04959 end if
04960 if( verbose ) write (stdout(), '(a,2i3,1x,a,i3)') 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
04961 pe, unit, trim(field%name), field%id
04962
04963 return
04964 end subroutine mpp_write_meta_field
04965
04966 subroutine write_attribute( unit, name, rval, ival, cval, pack )
04967
04968 integer, intent(in) :: unit
04969 character(len=*), intent(in) :: name
04970 real, intent(in), optional :: rval(:)
04971 integer, intent(in), optional :: ival(:)
04972 character(len=*), intent(in), optional :: cval
04973
04974 integer, intent(in), optional :: pack
04975
04976 if( mpp_file(unit)%nohdrs )return
04977
04978 if( PRESENT(rval) )then
04979 write( text,* )trim(name)//'=', rval
04980 else if( PRESENT(ival) )then
04981 write( text,* )trim(name)//'=', ival
04982 else if( PRESENT(cval) )then
04983 text = ' '//trim(name)//'='//trim(cval)
04984 else
04985 call mpp_error( FATAL, 'WRITE_ATTRIBUTE: one of rval, ival, cval must be present.' )
04986 end if
04987 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
04988
04989 write( unit,fmt='(a)' )trim(text)//char(10)
04990 else
04991 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
04992 write(unit)trim(text)//char(10)
04993 else
04994 write( unit,rec=mpp_file(unit)%record )trim(text)//char(10)
04995 if( verbose ) write (stdout(), '(a,i3,a,i3)') 'WRITE_ATTRIBUTE: PE=', pe, ' wrote record ', mpp_file(unit)%record
04996 mpp_file(unit)%record = mpp_file(unit)%record + 1
04997 end if
04998 end if
04999 return
05000 end subroutine write_attribute
05001
05002 subroutine write_attribute_netcdf( unit, id, name, rval, ival, cval, pack )
05003
05004 integer, intent(in) :: unit
05005 integer, intent(in) :: id
05006 character(len=*), intent(in) :: name
05007 real, intent(in), optional :: rval(:)
05008 integer, intent(in), optional :: ival(:)
05009 character(len=*), intent(in), optional :: cval
05010 integer, intent(in), optional :: pack
05011 integer :: lenc
05012 integer, allocatable :: rval_i(:)
05013 #ifdef use_netCDF
05014 integer :: ii, il_bytesize, il_iosize
05015 integer :: il_int_iosize, il_rbyt
05016
05017 if( PRESENT(rval) )then
05018 il_bytesize = BIT_SIZE(ii)/8
05019 INQUIRE (iolength=il_iosize) ii
05020 il_int_iosize = il_iosize
05021 INQUIRE (iolength=il_iosize) rval(1)
05022 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05023
05024 if( PRESENT(pack) )then
05025 if( pack.EQ.1 )then
05026 idim = size(rval)
05027 if( il_rbyt .EQ. DOUBLE_KIND )then
05028 error = NFMPI_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_DOUBLE, idim, rval )
05029 else if( il_rbyt .EQ. FLOAT_KIND )then
05030 call mpp_error( WARNING, &
05031 'WRITE_ATTRIBUTE_NETCDF: attempting to write internal 32-bit real as external 64-bit.' )
05032 error = NFMPI_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_DOUBLE, idim, rval )
05033 end if
05034 call netcdf_err(error)
05035 else if( pack.EQ.2 )then
05036 idim = size(rval)
05037 if( il_rbyt.EQ.DOUBLE_KIND )then
05038 error = NFMPI_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, idim, rval )
05039 else if( il_rbyt.EQ.FLOAT_KIND )then
05040 error = NFMPI_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, idim, rval )
05041 end if
05042 call netcdf_err(error)
05043 else if( pack.EQ.4 )then
05044 allocate( rval_i(size(rval)) )
05045 rval_i = rval
05046 idim = size(rval_i)
05047 if( il_rbyt.EQ.DOUBLE_KIND )then
05048 error = NFMPI_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_SHORT, idim, rval )
05049 else if( il_rbyt.EQ.FLOAT_KIND )then
05050 error = NFMPI_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_SHORT, idim, rval )
05051 end if
05052 call netcdf_err(error)
05053 deallocate(rval_i)
05054 else if( pack.EQ.8 )then
05055 allocate( rval_i(size(rval)) )
05056 rval_i = rval
05057 idim = size(rval_i)
05058 if( il_rbyt.EQ.DOUBLE_KIND )then
05059 error = NFMPI_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_BYTE, idim, rval )
05060 else if( il_rbyt.EQ.FLOAT_KIND )then
05061 error = NFMPI_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_BYTE, idim, rval )
05062 end if
05063 call netcdf_err(error)
05064 deallocate(rval_i)
05065 else
05066 call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: only legal packing values are 1,2,4,8.' )
05067 end if
05068 else
05069
05070 idim = size(rval)
05071 if( il_rbyt.EQ.DOUBLE_KIND )then
05072 error = NFMPI_PUT_ATT_DOUBLE( mpp_file(unit)%ncid, id, name, NF_FLOAT, idim, rval )
05073 else if( il_rbyt.EQ.FLOAT_KIND )then
05074 error = NFMPI_PUT_ATT_REAL ( mpp_file(unit)%ncid, id, name, NF_FLOAT, idim, rval )
05075 end if
05076 call netcdf_err(error)
05077 end if
05078 else if( PRESENT(ival) )then
05079 idim = size(ival)
05080 error = NFMPI_PUT_ATT_INT ( mpp_file(unit)%ncid, id, name, NF_INT, idim, ival ); call netcdf_err(error)
05081 else if( present(cval) )then
05082 idim = len_trim(cval)
05083 error = NFMPI_PUT_ATT_TEXT( mpp_file(unit)%ncid, id, name, idim, cval ); call netcdf_err(error)
05084 else
05085 call mpp_error( FATAL, 'WRITE_ATTRIBUTE_NETCDF: one of rval, ival, cval must be present.' )
05086 end if
05087 #endif /* use_netCDF */
05088 return
05089 end subroutine write_attribute_netcdf
05090
05091
05092
05093
05094
05095
05096
05097
05098
05099
05100
05101
05102
05103
05104
05105
05106
05107
05108
05109
05110
05111
05112
05113
05114
05115
05116
05117
05118
05119
05120
05121
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131
05132
05133
05134
05135
05136
05137
05138
05139
05140
05141 #define MPP_WRITE_2DDECOMP_1D_ mpp_write_2ddecomp_r1d
05142 #define MPP_WRITE_2DDECOMP_2D_ mpp_write_2ddecomp_r2d
05143 #define MPP_WRITE_2DDECOMP_3D_ mpp_write_2ddecomp_r3d
05144 #define MPP_WRITE_2DDECOMP_4D_ mpp_write_2ddecomp_r4d
05145 #define MPP_TYPE_ real
05146 #include <mpp_write_2Ddecomp.h>
05147
05148 #define MPP_WRITE_ mpp_write_r0D
05149 #define MPP_TYPE_ real
05150 #define MPP_RANK_ !
05151 #define MPP_WRITE_RECORD_ call write_record( unit, field, 1, (/data/), tstamp )
05152 #include <mpp_write.h>
05153
05154 #define MPP_WRITE_ mpp_write_r1D
05155 #define MPP_TYPE_ real
05156 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
05157 #define MPP_RANK_ (:)
05158 #include <mpp_write.h>
05159
05160 #define MPP_WRITE_ mpp_write_r2D
05161 #define MPP_TYPE_ real
05162 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
05163 #define MPP_RANK_ (:,:)
05164 #include <mpp_write.h>
05165
05166 #define MPP_WRITE_ mpp_write_r3D
05167 #define MPP_TYPE_ real
05168 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
05169 #define MPP_RANK_ (:,:,:)
05170 #include <mpp_write.h>
05171
05172 #define MPP_WRITE_ mpp_write_r4D
05173 #define MPP_TYPE_ real
05174 #define MPP_WRITE_RECORD_ call write_record( unit, field, size(data), data, tstamp )
05175 #define MPP_RANK_ (:,:,:,:)
05176 #include <mpp_write.h>
05177
05178 subroutine mpp_write_axis( unit, axis )
05179 integer, intent(in) :: unit
05180 type(axistype), intent(in) :: axis
05181 type(fieldtype) :: field
05182 integer :: is, ie
05183
05184
05185 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
05186 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
05187 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05188 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05189
05190 field = default_field
05191 allocate( field%axes(1) )
05192 field%axes(1) = axis
05193 allocate( field%size(1) )
05194 field%id = axis%id
05195 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
05196 call mpp_get_compute_domain( axis%domain, is, ie )
05197 field%size(1) = ie-is+1
05198
05199 if(associated( axis%cdata)) then
05200 call write_record_c( unit, field, field%size(1), axis%cdata(is:) )
05201 else
05202 call write_record( unit, field, field%size(1), axis%data(is:) )
05203 endif
05204
05205 else
05206
05207 if(associated( axis%cdata)) then
05208 field%size(1) = size(axis%cdata)
05209 call write_record_c(unit,field, field%size(1), axis%cdata )
05210 else
05211 field%size(1) = size(axis%data)
05212 call write_record( unit, field, field%size(1), axis%data )
05213 endif
05214
05215 end if
05216 return
05217 end subroutine mpp_write_axis
05218
05219 subroutine write_record_c( unit, field, nwords, cdata, time_in, domain ) !!RV,bundles
05220
05221
05222
05223
05224
05225
05226
05227
05228
05229
05230
05231
05232
05233
05234
05235
05236 integer, intent(in) :: unit, nwords
05237 type(fieldtype), intent(in) :: field
05238
05239 character(len=64), intent(in) :: cdata(nwords)
05240 real(DOUBLE_KIND), intent(in), optional :: time_in
05241 type(domain2D), intent(in), optional :: domain
05242
05243
05244 integer,allocatable,dimension(:) :: start, axsiz
05245
05246 real :: time
05247 integer :: time_level
05248 logical :: newtime
05249 integer :: subdomain(4)
05250 integer :: packed_data(nwords)
05251 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
05252 #ifdef use_netCDF
05253 integer :: ii, il_bytesize, il_iosize
05254 integer :: il_int_iosize, il_rbyt
05255 #endif
05256
05257 #ifdef use_CRI_pointers
05258 real(FLOAT_KIND) :: data_r4(nwords)
05259 pointer( ptr1, data_r4)
05260 pointer( ptr2, packed_data)
05261
05262 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
05263
05264 ptr1 = LOC(mpp_io_stack(1))
05265 ptr2 = LOC(mpp_io_stack(nwords+1))
05266 #endif
05267
05268 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
05269 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
05270 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05271 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05272
05273
05274 allocate(start(size(field%axes)))
05275 allocate(axsiz(size(field%axes)))
05276
05277 if( .NOT.mpp_file(unit)%initialized )then
05278
05279
05280
05281 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05282 #ifdef use_netCDF
05283
05284
05285
05286 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NFMPI_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
05287 #endif
05288 else
05289 call mpp_write_meta( unit, 'END', cval='metadata' )
05290 end if
05291 mpp_file(unit)%initialized = .TRUE.
05292 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
05293 end if
05294
05295
05296 time = NULLTIME
05297 time_level = -1
05298 newtime = .FALSE.
05299 if( PRESENT(time_in) )time = time_in
05300
05301 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
05302 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
05303 mpp_file(unit)%time = time
05304 newtime = .TRUE.
05305 end if
05306 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
05307 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
05308
05309 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330
05331 start = 1
05332 do i = 1,size(field%axes)
05333 axsiz(i) = field%size(i)
05334 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
05335 start(i) = max(start(i),1)
05336 end do
05337 if( PRESENT(domain) )then
05338 call mpp_get_compute_domain( domain, is, ie, js, je, xsize=isizc, ysize=jsizc )
05339 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg, xsize=isizg, ysize=jsizg )
05340 axsiz(1) = isizc
05341 axsiz(2) = jsizc
05342 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05343 start(1) = is - isg + 1
05344 start(2) = js - jsg + 1
05345 else
05346 if( isizc.NE.ie-is+1 )then
05347 start(1) = is - isg + 1
05348 axsiz(1) = ie - is + 1
05349 end if
05350 if( jsizc.NE.je-js+1 )then
05351 start(2) = js - jsg + 1
05352 axsiz(2) = je - js + 1
05353 end if
05354 end if
05355 end if
05356 if( debug ) &
05357 write (stdout(), '(a,2i3,12i4)') 'd WRITE_RECORD: PE, unit, start, axsiz=', pe, unit, start, axsiz
05358 #ifdef use_netCDF
05359
05360 if( newtime )then
05361 il_bytesize = BIT_SIZE(ii)/8
05362 INQUIRE (iolength=il_iosize) ii
05363 il_int_iosize = il_iosize
05364 INQUIRE (iolength=il_iosize) time
05365 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05366 if( il_rbyt.EQ.DOUBLE_KIND )then
05367 idim = mpp_file(unit)%time_level
05368 error = NFMPI_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, idim, time )
05369 else if( il_rbyt.EQ.FLOAT_KIND )then
05370 idim = mpp_file(unit)%time_level
05371 error = NFMPI_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, idim , time )
05372 end if
05373 end if
05374 if( field%pack.LE.2 )then
05375 write(6,*) ' Iam here 6!'
05376 call mpp_flushstd(6)
05377 error = NFMPI_PUT_VARA_TEXT_ALL( mpp_file(unit)%ncid, field%id, (/1,start/), (/len(cdata),axsiz/), cdata )
05378 write(6,*) ' Iam here 7!'
05379 call mpp_flushstd(6)
05380 else
05381 write(6,*) ' Iam here 8!'
05382 call mpp_flushstd(6)
05383 call mpp_error( FATAL, 'MPP_WRITE_RECORD_C: pack on text !' )
05384 end if
05385 write(6,*) ' Iam here 9!',error
05386 call mpp_flushstd(6)
05387 call netcdf_err(error)
05388 #endif
05389 else
05390
05391 if( PRESENT(domain) )then
05392 subdomain(:) = (/ is, ie, js, je /)
05393 else
05394 subdomain(:) = -1
05395 end if
05396 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
05397
05398 write( unit,* )field%id, subdomain, time_level, time, cdata
05399 else
05400 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
05401 #ifdef __sgi
05402 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05403 write(unit)field%id, subdomain, time_level, time, cdata
05404 else
05405 write(unit)field%id, subdomain, time_level, time, cdata
05406 end if
05407 #else
05408 write(unit)field%id, subdomain, time_level, time, cdata
05409 #endif
05410 else
05411 #ifdef __sgi
05412 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05413 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
05414 else
05415 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
05416 end if
05417 #else
05418 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, cdata
05419 #endif
05420 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
05421 end if
05422 end if
05423 end if
05424
05425
05426 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
05427 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05428
05429 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
05430 else
05431 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
05432 end if
05433 end if
05434
05435 deallocate(start)
05436 deallocate(axsiz)
05437
05438 return
05439 end subroutine write_record_c
05440
05441 subroutine write_record_b( unit, field, nwords, data, time_in, domain,block_id )
05442
05443
05444
05445
05446
05447
05448
05449
05450
05451
05452
05453
05454
05455
05456
05457
05458
05459
05460
05461
05462
05463
05464
05465
05466
05467 integer, intent(in) :: unit, nwords
05468 type(fieldtype), intent(in) :: field
05469 real, intent(in) :: data(nwords)
05470 real(DOUBLE_KIND), intent(in), optional :: time_in
05471 integer,intent(in),optional :: block_id
05472 type(domain2D), intent(in), optional :: domain
05473
05474
05475 integer,allocatable,dimension(:) :: start, axsiz
05476
05477 real :: time
05478 integer :: time_level
05479 logical :: newtime
05480 integer :: subdomain(4)
05481 integer :: packed_data(nwords)
05482 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
05483 #ifdef use_netCDF
05484 integer :: ii, il_bytesize, il_iosize
05485 integer :: il_int_iosize, il_rbyt
05486 #endif
05487
05488 #ifdef use_CRI_pointers
05489 real(FLOAT_KIND) :: data_r4(nwords)
05490 pointer( ptr1, data_r4)
05491 pointer( ptr2, packed_data)
05492
05493 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
05494
05495 ptr1 = LOC(mpp_io_stack(1))
05496 ptr2 = LOC(mpp_io_stack(nwords+1))
05497 #endif
05498
05499 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
05500 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
05501 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05502 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05503
05504
05505 allocate(start(size(field%axes)))
05506 allocate(axsiz(size(field%axes)))
05507
05508 if( .NOT.mpp_file(unit)%initialized )then
05509
05510
05511
05512 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05513 #ifdef use_netCDF
05514
05515
05516
05517 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NFMPI_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
05518 #endif
05519 else
05520 call mpp_write_meta( unit, 'END', cval='metadata' )
05521 end if
05522 mpp_file(unit)%initialized = .TRUE.
05523 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
05524 end if
05525
05526
05527 time = NULLTIME
05528 time_level = -1
05529 newtime = .FALSE.
05530 if( PRESENT(time_in) )time = time_in
05531
05532 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
05533 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
05534 mpp_file(unit)%time = time
05535 newtime = .TRUE.
05536 end if
05537 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
05538 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
05539
05540 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05541
05542
05543
05544
05545
05546
05547
05548
05549
05550
05551
05552
05553
05554
05555
05556
05557
05558
05559
05560
05561
05562
05563 start = 1
05564 do i = 1,size(field%axes)
05565 axsiz(i) = field%size(i)
05566 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
05567 start(i) = max(start(i),1)
05568 end do
05569 if( PRESENT(domain) )then
05570 call mpp_get_compute_domain( domain, is, ie, js, je, xsize=isizc, ysize=jsizc )
05571 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg, xsize=isizg, ysize=jsizg )
05572 axsiz(1) = isizc
05573 axsiz(2) = jsizc
05574 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05575 start(1) = is - isg + 1
05576 start(2) = js - jsg + 1
05577 else
05578 if( isizc.NE.ie-is+1 )then
05579 start(1) = is - isg + 1
05580 axsiz(1) = ie - is + 1
05581 end if
05582 if( jsizc.NE.je-js+1 )then
05583 start(2) = js - jsg + 1
05584 axsiz(2) = je - js + 1
05585 end if
05586 end if
05587 end if
05588
05589 if( PRESENT(block_id) )then
05590 if (block_id.le.0) then
05591 call mpp_error( FATAL, 'MPP_RECORD_B: block_id <= 0!' )
05592 endif
05593 if( PRESENT(time_in) )then
05594
05595 if(block_id.gt. axsiz(size(field%axes)-1)) &
05596 call mpp_error( FATAL, 'MPP_RECORD_B: block_id > axis range!' )
05597
05598 start(size(field%axes)-1)=block_id
05599
05600 else
05601
05602 if(block_id.gt. axsiz(size(field%axes))) &
05603 call mpp_error( FATAL, 'MPP_RECORD_B: block_id > axis range!' )
05604
05605 start(size(field%axes))=block_id
05606
05607 endif
05608 endif
05609
05610 if( debug ) &
05611 write (stdout(), '(a,2i3,12i4)') 'e WRITE_RECORD: PE, unit, start, axsiz=', pe, unit, start, axsiz
05612 #ifdef use_netCDF
05613
05614 if( newtime )then
05615 il_bytesize = BIT_SIZE(ii)/8
05616 INQUIRE (iolength=il_iosize) ii
05617 il_int_iosize = il_iosize
05618 INQUIRE (iolength=il_iosize) time
05619 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05620 if( il_rbyt .EQ. DOUBLE_KIND )then
05621 idim = mpp_file(unit)%time_level
05622 error = NFMPI_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, idim, time )
05623 else if( il_rbyt .EQ. FLOAT_KIND )then
05624 idim = mpp_file(unit)%time_level
05625 error = NFMPI_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, idim, time )
05626 end if
05627 end if
05628 if( field%pack.LE.2 )then
05629 INQUIRE (iolength=il_iosize) data(1)
05630 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05631 if( il_rbyt.EQ.DOUBLE_KIND )then
05632
05633 error = NFMPI_PUT_VARA_DOUBLE_ALL( mpp_file(unit)%ncid, field%id, start, axsiz, data )
05634 else if( il_rbyt.EQ.FLOAT_KIND )then
05635 error = NFMPI_PUT_VARA_REAL_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, data )
05636 end if
05637 else
05638 packed_data = nint((data-field%add)/field%scale)
05639 error = NFMPI_PUT_VARA_INT_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, packed_data )
05640 end if
05641 call netcdf_err(error)
05642 #endif
05643 else
05644
05645 if( PRESENT(domain) )then
05646 subdomain(:) = (/ is, ie, js, je /)
05647 else
05648 subdomain(:) = -1
05649 end if
05650 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
05651
05652 write( unit,* )field%id, subdomain, time_level, time, data
05653 else
05654 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
05655 #ifdef __sgi
05656 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05657 data_r4 = data
05658 write(unit)field%id, subdomain, time_level, time, data_r4
05659 else
05660 write(unit)field%id, subdomain, time_level, time, data
05661 end if
05662 #else
05663 write(unit)field%id, subdomain, time_level, time, data
05664 #endif
05665 else
05666 #ifdef __sgi
05667 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05668 data_r4 = data
05669 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data_r4
05670 else
05671 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
05672 end if
05673 #else
05674 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
05675 #endif
05676 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
05677 end if
05678 end if
05679 end if
05680
05681
05682 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
05683 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05684
05685 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
05686 else
05687 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
05688 end if
05689 end if
05690
05691
05692 deallocate(start)
05693 deallocate(axsiz)
05694
05695 return
05696 end subroutine write_record_b
05697
05698 subroutine write_record( unit, field, nwords, data, time_in, domain )
05699
05700
05701
05702
05703
05704
05705
05706
05707
05708
05709
05710
05711
05712
05713
05714
05715 integer, intent(in) :: unit, nwords
05716 type(fieldtype), intent(in) :: field
05717 real, intent(in) :: data(nwords)
05718 real(DOUBLE_KIND), intent(in), optional :: time_in
05719 type(domain2D), intent(in), optional :: domain
05720
05721
05722
05723
05724
05725 integer(kind=MPI_OFFSET_KIND),allocatable,dimension(:) :: start, axsiz
05726
05727 real :: time
05728 integer :: time_level
05729 logical :: newtime
05730 integer :: subdomain(4)
05731 integer :: packed_data(nwords)
05732 integer :: i, is, ie, js, je, isg, ieg, jsg, jeg, isizc, jsizc, isizg, jsizg
05733
05734 integer :: icount_domains
05735
05736 #ifdef use_netCDF
05737 integer :: ii, il_bytesize, il_iosize
05738 integer :: il_int_iosize, il_rbyt
05739 #endif
05740
05741 #ifdef use_CRI_pointers
05742 real(FLOAT_KIND) :: data_r4(nwords)
05743 pointer( ptr1, data_r4)
05744 pointer( ptr2, packed_data)
05745
05746 if (mpp_io_stack_size < 2*nwords) call mpp_io_set_stack_size(2*nwords)
05747
05748 ptr1 = LOC(mpp_io_stack(1))
05749 ptr2 = LOC(mpp_io_stack(nwords+1))
05750 #endif
05751
05752 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE: must first call mpp_io_init.' )
05753 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE: invalid unit number.' )
05754 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05755 if( mpp_file(unit)%fileset .EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
05756
05757
05758 allocate(start(size(field%axes)))
05759 allocate(axsiz(size(field%axes)))
05760
05761 if( .NOT.mpp_file(unit)%initialized )then
05762
05763
05764
05765 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05766 #ifdef use_netCDF
05767
05768
05769
05770 if( mpp_file(unit)%action.EQ.MPP_WRONLY )error = NFMPI_ENDDEF(mpp_file(unit)%ncid); call netcdf_err(error)
05771 #endif
05772 else
05773 call mpp_write_meta( unit, 'END', cval='metadata' )
05774 end if
05775 mpp_file(unit)%initialized = .TRUE.
05776 if( verbose ) write (stdout(), '(a,i3,a)') 'MPP_WRITE: PE=', pe, ' initialized file '//trim(mpp_file(unit)%name)//'.'
05777 end if
05778
05779
05780 time = NULLTIME
05781 time_level = -1
05782 newtime = .FALSE.
05783 if( PRESENT(time_in) )time = time_in
05784
05785 if( time.GT.mpp_file(unit)%time+EPSILON(time) )then
05786 mpp_file(unit)%time_level = mpp_file(unit)%time_level + 1
05787 mpp_file(unit)%time = time
05788 newtime = .TRUE.
05789 end if
05790 if( verbose ) write (stdout(), '(a,2i3,2i5,es13.5)') 'MPP_WRITE: PE, unit, %id, %time_level, %time=',&
05791 pe, unit, mpp_file(unit)%id, mpp_file(unit)%time_level, mpp_file(unit)%time
05792
05793 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
05794
05795
05796
05797
05798
05799
05800
05801
05802
05803
05804
05805
05806
05807
05808
05809
05810
05811
05812
05813
05814
05815
05816 start = 1
05817
05818
05819
05820
05821
05822
05823
05824
05825
05826 icount_domains=0
05827
05828 do i = 1,size(field%axes)
05829 axsiz(i) = field%size(i)
05830 if( i.EQ.field%time_axis_index )start(i) = mpp_file(unit)%time_level
05831
05832 start(i) = max(start(i),1)
05833 if ( start(i) < 1 ) start(i) = 1
05834
05835 if((field%axes(i)%domain .ne. NULL_DOMAIN1D) .and. &
05836 (field%axes(1)%domain .eq. NULL_DOMAIN1D)) &
05837 icount_domains=icount_domains+1
05838
05839 end do
05840 if( PRESENT(domain) )then
05841 if(icount_domains .ne. 2 ) then
05842 call mpp_get_compute_domain( domain, is, ie, js, je &
05843 , xsize=isizc, ysize=jsizc )
05844 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg &
05845 , xsize=isizg, ysize=jsizg )
05846 #ifdef __PARNETCDF
05847
05848 start(1) = is - isg + 1
05849 start(2) = js - jsg + 1
05850 #endif
05851 axsiz(1) = isizc
05852 axsiz(2) = jsizc
05853 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05854 start(1) = is - isg + 1
05855 start(2) = js - jsg + 1
05856 else
05857 if( isizc.NE.ie-is+1 )then
05858 start(1) = is - isg + 1
05859 axsiz(1) = ie - is + 1
05860 end if
05861 if( jsizc.NE.je-js+1 )then
05862 start(2) = js - jsg + 1
05863 axsiz(2) = je - js + 1
05864 end if
05865 end if
05866
05867 else
05868
05869 call mpp_get_compute_domain( field%axes(2)%domain, is, ie &
05870 , size=isizc)
05871 call mpp_get_global_domain ( field%axes(2)%domain, isg, ieg &
05872 , size=isizg )
05873 call mpp_get_compute_domain( field%axes(3)%domain, js, je &
05874 , size=jsizc)
05875 call mpp_get_global_domain ( field%axes(3)%domain, jsg, jeg &
05876 , size=jsizg )
05877
05878
05879 #ifdef __PARNETCDF
05880
05881
05882 start(2) = is - isg + 1
05883 start(3) = js - jsg + 1
05884 #endif
05885
05886 axsiz(2) = isizc
05887 axsiz(3) = jsizc
05888 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05889 start(2) = is - isg + 1
05890 start(3) = js - jsg + 1
05891 else
05892 if( isizc.NE.ie-is+1 )then
05893 start(2) = is - isg + 1
05894 axsiz(2) = ie - is + 1
05895 end if
05896 if( jsizc.NE.je-js+1 )then
05897 start(3) = js - jsg + 1
05898 axsiz(3) = je - js + 1
05899 end if
05900 end if
05901
05902 endif
05903
05904 end if
05905 if( debug ) write (stdout(),'(a,3i5,12i4)') &
05906 'f WRITE_RECORD: PE, unit, icount_domains, start, axsiz=' &
05907 , pe, unit, icount_domains, start, axsiz
05908 #ifdef use_netCDF
05909
05910 il_bytesize = BIT_SIZE(ii)/8
05911 INQUIRE (iolength=il_iosize) ii
05912 il_int_iosize = il_iosize
05913 if( newtime )then
05914 INQUIRE (iolength=il_iosize) time
05915 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05916 if( il_rbyt .EQ. DOUBLE_KIND )then
05917 idim = mpp_file(unit)%time_level
05918 error = NFMPI_PUT_VAR1_DOUBLE( mpp_file(unit)%ncid, mpp_file(unit)%id, idim, time )
05919 else if( il_rbyt .EQ. FLOAT_KIND )then
05920 idim = mpp_file(unit)%time_level
05921 error = NFMPI_PUT_VAR1_REAL ( mpp_file(unit)%ncid, mpp_file(unit)%id, idim, time )
05922 end if
05923 end if
05924 if( field%pack.LE.2 )then
05925 INQUIRE (iolength=il_iosize) data(1)
05926 il_rbyt = il_iosize/il_int_iosize*il_bytesize
05927 if( il_rbyt.EQ.DOUBLE_KIND )then
05928 error = NFMPI_PUT_VARA_DOUBLE_ALL( mpp_file(unit)%ncid, field%id, start, axsiz, data )
05929 else if( il_rbyt.EQ.FLOAT_KIND )then
05930 error = NFMPI_PUT_VARA_REAL_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, data )
05931 end if
05932 else
05933 packed_data = nint((data-field%add)/field%scale)
05934 error = NFMPI_PUT_VARA_INT_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, packed_data )
05935 end if
05936 call netcdf_err(error)
05937 #endif
05938 else
05939
05940 if( PRESENT(domain) )then
05941 subdomain(:) = (/ is, ie, js, je /)
05942 else
05943 subdomain(:) = -1
05944 end if
05945 if( mpp_file(unit)%format.EQ.MPP_ASCII )then
05946
05947 write( unit,* )field%id, subdomain, time_level, time, data
05948 else
05949 if( mpp_file(unit)%access.EQ.MPP_SEQUENTIAL )then
05950 #ifdef __sgi
05951 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05952 data_r4 = data
05953 write(unit)field%id, subdomain, time_level, time, data_r4
05954 else
05955 write(unit)field%id, subdomain, time_level, time, data
05956 end if
05957 #else
05958 write(unit)field%id, subdomain, time_level, time, data
05959 #endif
05960 else
05961 #ifdef __sgi
05962 if( mpp_file(unit)%format.EQ.MPP_IEEE32 )then
05963 data_r4 = data
05964 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data_r4
05965 else
05966 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
05967 end if
05968 #else
05969 write( unit, rec=mpp_file(unit)%record )field%id, subdomain, time_level, time, data
05970 #endif
05971 if( debug ) write (stdout(), '(a,i3,a,i3)') 'MPP_WRITE: PE=', pe, ' wrote record ', mpp_file(unit)%record
05972 end if
05973 end if
05974 end if
05975
05976
05977 if( mpp_file(unit)%access.EQ.MPP_DIRECT )then
05978 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
05979
05980 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe*npes
05981 else
05982 mpp_file(unit)%record = mpp_file(unit)%record + records_per_pe
05983 end if
05984 end if
05985
05986 deallocate(start)
05987 deallocate(axsiz)
05988
05989
05990 return
05991 end subroutine write_record
05992
05993
05994
05995
05996
05997
05998 subroutine mpp_copy_meta_global( unit, gatt )
05999
06000
06001
06002
06003
06004 integer, intent(in) :: unit
06005 type(atttype), intent(in) :: gatt
06006 integer :: len
06007
06008 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
06009 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
06010 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06011 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06012 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
06013 if( mpp_file(unit)%initialized ) &
06014 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
06015 #ifdef use_netCDF
06016 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06017 if( gatt%type.EQ.NF_CHAR )then
06018 len = gatt%len
06019 call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, cval=gatt%catt(1:len) )
06020 else
06021 call write_attribute_netcdf( unit, NF_GLOBAL, gatt%name, rval=gatt%fatt )
06022 endif
06023 else
06024 if( gatt%type.EQ.NF_CHAR )then
06025 len=gatt%len
06026 call write_attribute( unit, 'GLOBAL '//trim(gatt%name), cval=gatt%catt(1:len) )
06027 else
06028 call write_attribute( unit, 'GLOBAL '//trim(gatt%name), rval=gatt%fatt )
06029 endif
06030 end if
06031 #else
06032 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
06033 #endif
06034 return
06035 end subroutine mpp_copy_meta_global
06036
06037 subroutine mpp_copy_meta_axis( unit, axis, domain )
06038
06039
06040
06041
06042 integer, intent(in) :: unit
06043 type(axistype), intent(inout) :: axis
06044 type(domain1D), intent(in), optional :: domain
06045 character(len=512) :: text
06046 integer :: i, len, is, ie, isg, ieg
06047
06048 integer(kind=mpi_offset_kind) :: idim
06049
06050 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
06051 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
06052 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06053 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06054 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
06055 if( mpp_file(unit)%initialized ) &
06056 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
06057
06058
06059 if( PRESENT(domain) )then
06060 axis%domain = domain
06061 else
06062 axis%domain = NULL_DOMAIN1D
06063 end if
06064
06065 #ifdef use_netCDF
06066
06067 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06068
06069
06070 if( ASSOCIATED(axis%data) )then
06071 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
06072 call mpp_get_compute_domain( axis%domain, is, ie )
06073 call mpp_get_global_domain( axis%domain, isg, ieg )
06074 idim = ie-is+1
06075 else
06076 idim = size(axis%data)
06077 end if
06078 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did )
06079 call netcdf_err(error)
06080 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_FLOAT, 1, axis%did, axis%id ); call netcdf_err(error)
06081 else
06082 idim = NF_UNLIMITED
06083 error = NFMPI_DEF_DIM( mpp_file(unit)%ncid, axis%name, idim, axis%did ); call netcdf_err(error)
06084 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, axis%name, NF_DOUBLE, 1, axis%did, axis%id ); call netcdf_err(error)
06085 mpp_file(unit)%id = axis%id
06086 mpp_file(unit)%recdimid = axis%did
06087 end if
06088 else
06089 varnum = varnum + 1
06090 axis%id = varnum
06091 axis%did = varnum
06092
06093 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' name'
06094 call write_attribute( unit, trim(text), cval=axis%name )
06095 write( text, '(a,i4,a)' )'AXIS ', axis%id, ' size'
06096 if( ASSOCIATED(axis%data) )then
06097 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
06098 call write_attribute( unit, trim(text), ival=(/ie-is+1/) )
06099 else
06100 call write_attribute( unit, trim(text), ival=(/size(axis%data)/) )
06101 end if
06102 else
06103 if( mpp_file(unit)%id.NE.-1 ) &
06104 call mpp_error( FATAL, 'MPP_WRITE_META_AXIS: There is already a time axis for this file.' )
06105 call write_attribute( unit, trim(text), ival=(/0/) )
06106 mpp_file(unit)%id = axis%id
06107 end if
06108 end if
06109
06110
06111 do i=1,axis%natt
06112 if( axis%Att(i)%name.NE.default_att%name )then
06113 if( axis%Att(i)%type.EQ.NF_CHAR )then
06114 len = axis%Att(i)%len
06115 call mpp_write_meta( unit, axis%id, axis%Att(i)%name, cval=axis%Att(i)%catt(1:len) )
06116 else
06117 call mpp_write_meta( unit, axis%id, axis%Att(i)%name, rval=axis%Att(i)%fatt)
06118 endif
06119 endif
06120 enddo
06121
06122 if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. axis%domain.NE.NULL_DOMAIN1D )then
06123 call mpp_write_meta( unit, axis%id, 'domain_decomposition', ival=(/isg,ieg,is,ie/) )
06124 end if
06125 if( verbose ) write (stdout(), '(a,2i3,1x,a,2i3)') &
06126 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', &
06127 pe, unit, trim(axis%name), axis%id, axis%did
06128 #else
06129 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
06130 #endif
06131 return
06132 end subroutine mpp_copy_meta_axis
06133
06134 subroutine mpp_copy_meta_field( unit, field, axes )
06135
06136
06137 integer, intent(in) :: unit
06138 type(fieldtype), intent(inout) :: field
06139 type(axistype), intent(in), optional :: axes(:)
06140
06141 integer, allocatable :: axis_id(:)
06142 real :: a, b
06143 integer :: i
06144
06145 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_WRITE_META: must first call mpp_io_init.' )
06146 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_WRITE_META: invalid unit number.' )
06147 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06148 if( mpp_file(unit)%fileset.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06149 if( mpp_file(unit)%action.NE.MPP_WRONLY )return
06150 if( mpp_file(unit)%initialized ) &
06151 call mpp_error( FATAL, 'MPP_WRITE_META: cannot write metadata to file after an mpp_write.' )
06152
06153 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
06154 if( field%pack.NE.4 .AND. field%pack.NE.8 ) &
06155 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
06156 end if
06157
06158 if (PRESENT(axes)) then
06159 deallocate(field%axes)
06160 deallocate(field%size)
06161 allocate(field%axes(size(axes)))
06162 allocate(field%size(size(axes)))
06163 field%axes = axes
06164 do i=1,size(axes)
06165 if (ASSOCIATED(axes(i)%data)) then
06166 field%size(i) = size(axes(i)%data)
06167 else
06168 field%size(i) = 1
06169 field%time_axis_index = i
06170 endif
06171 enddo
06172 endif
06173
06174 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06175 #ifdef use_netCDF
06176 allocate( axis_id(size(field%axes)) )
06177 do i = 1,size(field%axes)
06178 axis_id(i) = field%axes(i)%did
06179 end do
06180
06181 select case (field%pack)
06182 case(1)
06183 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_DOUBLE, size(field%axes), axis_id, field%id )
06184 case(2)
06185 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_FLOAT, size(field%axes), axis_id, field%id )
06186 case(4)
06187 if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
06188 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=4.' )
06189 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_SHORT, size(field%axes), axis_id, field%id )
06190 case(8)
06191 if( field%scale.EQ.default_field%scale .OR. field%add.EQ.default_field%add ) &
06192 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: scale and add must be supplied when pack=8.' )
06193 error = NFMPI_DEF_VAR( mpp_file(unit)%ncid, field%name, NF_BYTE, size(field%axes), axis_id, field%id )
06194 case default
06195 call mpp_error( FATAL, 'MPP_WRITE_META_FIELD: only legal packing values are 1,2,4,8.' )
06196 end select
06197 #endif
06198 else
06199 varnum = varnum + 1
06200 field%id = varnum
06201 if( field%pack.NE.default_field%pack ) &
06202 call mpp_error( WARNING, 'MPP_WRITE_META: Packing is currently available only on netCDF files.' )
06203
06204 write( text, '(a,i4,a)' )'FIELD ', field%id, ' name'
06205 call write_attribute( unit, trim(text), cval=field%name )
06206 write( text, '(a,i4,a)' )'FIELD ', field%id, ' axes'
06207 call write_attribute( unit, trim(text), ival=field%axes(:)%did )
06208 end if
06209
06210 call mpp_write_meta( unit, field%id, 'long_name', cval=field%longname )
06211 call mpp_write_meta( unit, field%id, 'units', cval=field%units )
06212
06213 if( (field%min.NE.default_field%min) .AND. (field%max.NE.default_field%max) )then
06214 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
06215 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/field%min,field%max/), pack=field%pack )
06216 else
06217 a = nint((field%min-field%add)/field%scale)
06218 b = nint((field%max-field%add)/field%scale)
06219 call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=field%pack )
06220 end if
06221 else if( field%min.NE.default_field%min )then
06222 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
06223 call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=field%pack )
06224 else
06225 a = nint((field%min-field%add)/field%scale)
06226 call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=field%pack )
06227 end if
06228 else if( field%max.NE.default_field%max )then
06229 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
06230 call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=field%pack )
06231 else
06232 a = nint((field%max-field%add)/field%scale)
06233 call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=field%pack )
06234 end if
06235 end if
06236 if( field%missing.NE.default_field%missing )then
06237 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
06238 call mpp_write_meta( unit, field%id, 'missing_value', rval=field%missing, pack=field%pack )
06239 else
06240 a = nint((field%missing-field%add)/field%scale)
06241 call mpp_write_meta( unit, field%id, 'missing_value', rval=a, pack=field%pack )
06242 end if
06243 end if
06244 if( field%fill.NE.default_field%fill )then
06245 if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then
06246 call mpp_write_meta( unit, field%id, '_FillValue', rval=field%fill, pack=field%pack )
06247 else
06248 a = nint((field%fill-field%add)/field%scale)
06249 call mpp_write_meta( unit, field%id, '_FillValue', rval=a, pack=field%pack )
06250 end if
06251 end if
06252 if( field%pack.NE.1 .AND. field%pack.NE.2 )then
06253 call mpp_write_meta( unit, field%id, 'packing', ival=field%pack )
06254 if( field%scale.NE.default_field%scale )call mpp_write_meta( unit, field%id, 'scale_factor', rval=field%scale )
06255 if( field%add.NE.default_field%add )call mpp_write_meta( unit, field%id, 'add_offset', rval=field%add )
06256 end if
06257 if( verbose ) write (stdout(), '(a,2i3,1x,a,i3)') 'MPP_WRITE_META: Wrote field metadata: pe, unit, field%name, field%id=', &
06258 pe, unit, trim(field%name), field%id
06259
06260 return
06261 end subroutine mpp_copy_meta_field
06262
06263
06264
06265
06266
06267
06268
06269 #define MPP_READ_2DDECOMP_1D_ mpp_read_2ddecomp_r1d
06270 #define MPP_READ_2DDECOMP_2D_ mpp_read_2ddecomp_r2d
06271 #define MPP_READ_2DDECOMP_3D_ mpp_read_2ddecomp_r3d
06272 #define MPP_READ_2DDECOMP_4D_ mpp_read_2ddecomp_r4d
06273 #define MPP_TYPE_ real
06274 #include <mpp_read_2Ddecomp.h>
06275
06276 subroutine read_record( unit, field, nwords, data, time_level, domain )
06277
06278
06279
06280
06281
06282
06283
06284
06285
06286
06287
06288
06289
06290
06291
06292
06293 integer, intent(in) :: unit, nwords
06294 type(fieldtype), intent(in) :: field
06295 real, intent(inout) :: data(nwords)
06296 integer, intent(in), optional :: time_level
06297 type(domain2D), intent(in), optional :: domain
06298 integer(kind=MPI_OFFSET_KIND), dimension(size(field%axes)) :: start, axsiz
06299 real :: time
06300
06301 logical :: newtime
06302 integer :: subdomain(4), tlevel
06303
06304 integer(SHORT_KIND) :: i2vals(nwords)
06305
06306 integer(INT_KIND) :: ivals(nwords)
06307 real(FLOAT_KIND) :: rvals(nwords)
06308
06309
06310
06311
06312
06313 real(DOUBLE_KIND) :: r8vals(nwords)
06314
06315 integer :: i, error, is, ie, js, je, isg, ieg, jsg, jeg
06316
06317 #ifdef use_CRI_pointers
06318 pointer( ptr1, i2vals )
06319 pointer( ptr2, ivals )
06320 pointer( ptr3, rvals )
06321 pointer( ptr4, r8vals )
06322
06323 if (mpp_io_stack_size < 4*nwords) call mpp_io_set_stack_size(4*nwords)
06324
06325 ptr1 = LOC(mpp_io_stack(1))
06326 ptr2 = LOC(mpp_io_stack(nwords+1))
06327 ptr3 = LOC(mpp_io_stack(2*nwords+1))
06328 ptr4 = LOC(mpp_io_stack(3*nwords+1))
06329 #endif
06330 if (.not.PRESENT(time_level)) then
06331 tlevel = 0
06332 else
06333 tlevel = time_level
06334 endif
06335
06336 #ifdef use_netCDF
06337 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'READ_RECORD: must first call mpp_io_init.' )
06338 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'READ_RECORD: invalid unit number.' )
06339 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06340
06341 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .and. present(domain)) &
06342 call mpp_error( FATAL, 'READ_RECORD: multiple filesets not supported for MPP_READ' )
06343
06344 if( .NOT.mpp_file(unit)%initialized ) call mpp_error( FATAL, 'MPP_READ: must first call mpp_read_meta.' )
06345
06346
06347
06348 if( verbose ) write (stdout(), '(a,2i3,2i5)') 'MPP_READ: PE, unit, %id, %time_level =',&
06349 pe, unit, mpp_file(unit)%id, tlevel
06350
06351 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06352
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369
06370
06371
06372
06373
06374 start = 1
06375 do i = 1,size(field%axes)
06376 axsiz(i) = field%size(i)
06377 if( field%axes(i)%did.EQ.field%time_axis_index )start(i) = tlevel
06378 end do
06379 if( PRESENT(domain) )then
06380 call mpp_get_compute_domain( domain, is, ie, js, je )
06381 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg )
06382 axsiz(1) = ie-is+1
06383 axsiz(2) = je-js+1
06384 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
06385 start(1) = is - isg + 1
06386 start(2) = js - jsg + 1
06387 else
06388 if( ie-is+1.NE.ie-is+1 )then
06389 start(1) = is - isg + 1
06390 axsiz(1) = ie - is + 1
06391 end if
06392 if( je-js+1.NE.je-js+1 )then
06393 start(2) = js - jsg + 1
06394 axsiz(2) = je - js + 1
06395 end if
06396 end if
06397 end if
06398
06399 if( verbose ) write (stdout(), '(a,2i3,i6,12i4)') 'READ_RECORD: PE, unit, nwords, start, axsiz=', &
06400 pe, unit, nwords, start, axsiz
06401
06402 select case (field%type)
06403 case(NF_BYTE)
06404
06405 call mpp_error( FATAL, 'MPP_READ: does not support NF_BYTE packing' )
06406 case(NF_SHORT)
06407 error = NFMPI_GET_VARA_INT2_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, i2vals ); call netcdf_err(error)
06408 data(:)=i2vals(:)*field%scale + field%add
06409 case(NF_INT)
06410 error = NFMPI_GET_VARA_INT_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, ivals ); call netcdf_err(error)
06411 data(:)=ivals(:)
06412 case(NF_FLOAT)
06413 error = NFMPI_GET_VARA_REAL_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, rvals ); call netcdf_err(error)
06414 data(:)=rvals(:)
06415 case(NF_DOUBLE)
06416 error = NFMPI_GET_VARA_DOUBLE_ALL( mpp_file(unit)%ncid, field%id, start, axsiz, r8vals ); call netcdf_err(error)
06417 data(:)=r8vals(:)
06418 case default
06419 call mpp_error( FATAL, 'MPP_READ: invalid pack value' )
06420 end select
06421 else
06422
06423 call mpp_error( FATAL, 'Currently dont support non-NetCDF mpp read' )
06424
06425 end if
06426 #else
06427 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
06428 #endif
06429 return
06430 end subroutine read_record
06431 subroutine read_record_b(unit,field,nwords,data,time_level,domain,block_id)
06432
06433
06434
06435
06436
06437
06438
06439
06440
06441
06442
06443
06444
06445
06446
06447
06448 integer, intent(in) :: unit, nwords
06449 type(fieldtype), intent(in) :: field
06450 real, intent(inout) :: data(nwords)
06451 integer, intent(in), optional :: time_level
06452
06453 integer, intent(in), optional :: block_id
06454
06455 type(domain2D), intent(in), optional :: domain
06456 integer(kind=MPI_OFFSET_KIND), dimension(size(field%axes)) :: start, axsiz
06457 real :: time
06458
06459 logical :: newtime
06460 integer :: subdomain(4), tlevel
06461
06462 integer(SHORT_KIND) :: i2vals(nwords)
06463
06464 integer(INT_KIND) :: ivals(nwords)
06465 real(FLOAT_KIND) :: rvals(nwords)
06466
06467
06468
06469
06470
06471 real(DOUBLE_KIND) :: r8vals(nwords)
06472
06473 integer :: i, error, is, ie, js, je, isg, ieg, jsg, jeg
06474
06475 #ifdef use_CRI_pointers
06476 pointer( ptr1, i2vals )
06477 pointer( ptr2, ivals )
06478 pointer( ptr3, rvals )
06479 pointer( ptr4, r8vals )
06480
06481 if (mpp_io_stack_size < 4*nwords) call mpp_io_set_stack_size(4*nwords)
06482
06483 ptr1 = LOC(mpp_io_stack(1))
06484 ptr2 = LOC(mpp_io_stack(nwords+1))
06485 ptr3 = LOC(mpp_io_stack(2*nwords+1))
06486 ptr4 = LOC(mpp_io_stack(3*nwords+1))
06487 #endif
06488 if (.not.PRESENT(time_level)) then
06489 tlevel = 0
06490 else
06491 tlevel = time_level
06492 endif
06493
06494 #ifdef use_netCDF
06495 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'READ_RECORD: must first call mpp_io_init.' )
06496 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'READ_RECORD: invalid unit number.' )
06497 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
06498
06499 if( mpp_file(unit)%fileset.EQ.MPP_MULTI .and. present(domain)) &
06500 call mpp_error( FATAL, 'READ_RECORD: multiple filesets not supported for MPP_READ' )
06501
06502 if( .NOT.mpp_file(unit)%initialized ) call mpp_error( FATAL, 'MPP_READ: must first call mpp_read_meta.' )
06503
06504
06505
06506 if( verbose ) write (stdout(), '(a,2i3,2i5)') 'MPP_READ: PE, unit, %id, %time_level =',&
06507 pe, unit, mpp_file(unit)%id, tlevel
06508
06509 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06510
06511
06512
06513
06514
06515
06516
06517
06518
06519
06520
06521
06522
06523
06524
06525
06526
06527
06528
06529
06530
06531
06532 start = 1
06533 do i = 1,size(field%axes)
06534 axsiz(i) = field%size(i)
06535 if( field%axes(i)%did.EQ.field%time_axis_index )start(i) = tlevel
06536 end do
06537 if( PRESENT(domain) )then
06538 call mpp_get_compute_domain( domain, is, ie, js, je )
06539 call mpp_get_global_domain ( domain, isg, ieg, jsg, jeg )
06540 axsiz(1) = ie-is+1
06541 axsiz(2) = je-js+1
06542 if( npes.GT.1 .AND. mpp_file(unit)%fileset.EQ.MPP_SINGLE )then
06543 start(1) = is - isg + 1
06544 start(2) = js - jsg + 1
06545 else
06546 if( ie-is+1.NE.ie-is+1 )then
06547 start(1) = is - isg + 1
06548 axsiz(1) = ie - is + 1
06549 end if
06550 if( je-js+1.NE.je-js+1 )then
06551 start(2) = js - jsg + 1
06552 axsiz(2) = je - js + 1
06553 end if
06554 end if
06555 end if
06556
06557 if( PRESENT(block_id) )then
06558 if (block_id.le.0) then
06559 call mpp_error( FATAL, 'READ_RECORD_B: block_id <= 0!' )
06560 endif
06561 if( PRESENT(time_level) )then
06562
06563 if(block_id.gt. axsiz(size(field%axes)-1)) &
06564 call mpp_error( FATAL, 'READ_RECORD_B: block_id > axis range!' )
06565 start(size(field%axes)-1)=block_id
06566
06567 else
06568
06569 if(block_id.gt. axsiz(size(field%axes))) &
06570 call mpp_error( FATAL, 'READ_RECORD_B: block_id > axis range!' )
06571 start(size(field%axes))=block_id
06572
06573 endif
06574 endif
06575
06576
06577
06578 if( verbose ) write (stdout(), '(a,2i3,i6,12i4)') 'READ_RECORD: PE, unit, nwords, start, axsiz=', &
06579 pe, unit, nwords, start, axsiz
06580
06581 select case (field%type)
06582 case(NF_BYTE)
06583
06584 call mpp_error( FATAL, 'MPP_READ: does not support NF_BYTE packing' )
06585 case(NF_SHORT)
06586 error = NFMPI_GET_VARA_INT2_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, i2vals ); call netcdf_err(error)
06587 data(:)=i2vals(:)*field%scale + field%add
06588 case(NF_INT)
06589 error = NFMPI_GET_VARA_INT_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, ivals ); call netcdf_err(error)
06590 data(:)=ivals(:)
06591 case(NF_FLOAT)
06592 error = NFMPI_GET_VARA_REAL_ALL ( mpp_file(unit)%ncid, field%id, start, axsiz, rvals ); call netcdf_err(error)
06593 data(:)=rvals(:)
06594 case(NF_DOUBLE)
06595 error = NFMPI_GET_VARA_DOUBLE_ALL( mpp_file(unit)%ncid, field%id, start, axsiz, r8vals ); call netcdf_err(error)
06596 data(:)=r8vals(:)
06597 case default
06598 call mpp_error( FATAL, 'MPP_READ: invalid pack value' )
06599 end select
06600 else
06601
06602 call mpp_error( FATAL, 'Currently dont support non-NetCDF mpp read' )
06603
06604 end if
06605 #else
06606 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
06607 #endif
06608 return
06609 end subroutine read_record_b
06610
06611 subroutine mpp_read_r4D( unit, field, data, tindex,blockid)
06612 integer, intent(in) :: unit
06613 type(fieldtype), intent(in) :: field
06614 real, intent(inout) :: data(:,:,:,:)
06615 integer, intent(in), optional :: tindex
06616 integer, intent(in), optional :: blockid
06617
06618 if(present(blockid)) then
06619 call read_record_b(unit,field,size(data),data,tindex,block_id=blockid )
06620 else
06621 call read_record( unit, field, size(data), data, tindex )
06622 endif
06623 end subroutine mpp_read_r4D
06624
06625 subroutine mpp_read_r3D( unit, field, data, tindex,blockid)
06626 integer, intent(in) :: unit
06627 type(fieldtype), intent(in) :: field
06628 real, intent(inout) :: data(:,:,:)
06629 integer, intent(in), optional :: tindex
06630 integer, intent(in), optional :: blockid
06631
06632 if(present(blockid)) then
06633 call read_record_b(unit,field,size(data),data,tindex,block_id=blockid )
06634 else
06635 call read_record( unit, field, size(data), data, tindex )
06636 endif
06637 end subroutine mpp_read_r3D
06638
06639 subroutine mpp_read_r2D( unit, field, data, tindex )
06640 integer, intent(in) :: unit
06641 type(fieldtype), intent(in) :: field
06642 real, intent(inout) :: data(:,:)
06643 integer, intent(in), optional :: tindex
06644
06645 call read_record( unit, field, size(data), data, tindex )
06646 end subroutine mpp_read_r2D
06647
06648 subroutine mpp_read_r1D( unit, field, data, tindex )
06649 integer, intent(in) :: unit
06650 type(fieldtype), intent(in) :: field
06651 real, intent(inout) :: data(:)
06652 integer, intent(in), optional :: tindex
06653
06654 call read_record( unit, field, size(data), data, tindex )
06655 end subroutine mpp_read_r1D
06656
06657 subroutine mpp_read_r0D( unit, field, data, tindex )
06658 integer, intent(in) :: unit
06659 type(fieldtype), intent(in) :: field
06660 real, intent(inout) :: data
06661 integer, intent(in), optional :: tindex
06662 real, dimension(1) :: data_tmp
06663
06664 data_tmp(1)=data
06665 call read_record( unit, field, 1, data_tmp, tindex )
06666 data=data_tmp(1)
06667 end subroutine mpp_read_r0D
06668
06669 subroutine mpp_read_meta(unit)
06670
06671
06672
06673
06674
06675
06676
06677
06678 integer, parameter :: MAX_DIMVALS = 100000
06679 integer, intent(in) :: unit
06680
06681 integer :: ncid,ndim,nvar_total,natt,recdim,nv,nvar,len
06682 integer :: error,i,j
06683 integer :: type,nvdims,nvatts, dimid
06684 integer, allocatable, dimension(:) :: dimids
06685 type(axistype) , allocatable, dimension(:) :: Axis
06686 character(len=128) :: name, attname, unlimname, attval
06687 logical :: isdim
06688
06689 integer(SHORT_KIND) :: i2vals(MAX_DIMVALS)
06690
06691 integer(INT_KIND) :: ivals(MAX_DIMVALS)
06692 real(FLOAT_KIND) :: rvals(MAX_DIMVALS)
06693
06694
06695
06696
06697 real(DOUBLE_KIND) :: r8vals(MAX_DIMVALS)
06698
06699 #ifdef use_netCDF
06700
06701 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
06702 ncid = mpp_file(unit)%ncid
06703 error = NFMPI_INQ(ncid,ndim, nvar_total,&
06704 natt, recdim);call netcdf_err(error)
06705
06706
06707 mpp_file(unit)%ndim = ndim
06708 mpp_file(unit)%natt = natt
06709 mpp_file(unit)%recdimid = recdim
06710
06711
06712
06713
06714 if( recdim.NE.-1 )then
06715 error = NFMPI_INQ_DIM( ncid, recdim, unlimname, idim );call netcdf_err(error)
06716 mpp_file(unit)%time_level = idim
06717 error = NFMPI_INQ_VARID( ncid, unlimname, mpp_file(unit)%id ); call netcdf_err(error)
06718 else
06719 mpp_file(unit)%time_level = -1
06720 endif
06721
06722 if ( natt .gt. 0 ) allocate(mpp_file(unit)%Att(natt))
06723 allocate(Axis(ndim))
06724 allocate(dimids(ndim))
06725 allocate(mpp_file(unit)%Axis(ndim))
06726
06727
06728
06729
06730
06731
06732 do i=1,ndim
06733 Axis(i) = default_axis
06734 mpp_file(unit)%Axis(i) = default_axis
06735 enddo
06736
06737 do i=1,natt
06738 mpp_file(unit)%Att(i) = default_att
06739 enddo
06740
06741
06742
06743
06744 do i=1,natt
06745 error=NFMPI_INQ_ATTNAME(ncid,NF_GLOBAL,i,name);call netcdf_err(error)
06746 error=NFMPI_INQ_ATT(ncid,NF_GLOBAL,trim(name),type,idim);call netcdf_err(error)
06747 len = idim
06748 mpp_file(unit)%Att(i)%name = name
06749 mpp_file(unit)%Att(i)%len = len
06750 mpp_file(unit)%Att(i)%type = type
06751
06752
06753
06754 select case (type)
06755
06756 case (NF_CHAR)
06757 if (len.gt.512) then
06758 call mpp_error(NOTE,'GLOBAL ATT too long - not reading this metadata')
06759 len=7
06760 mpp_file(unit)%Att(i)%len=len
06761 mpp_file(unit)%Att(i)%catt = 'unknown'
06762 else
06763 error=NFMPI_GET_ATT_TEXT(ncid,NF_GLOBAL,name,mpp_file(unit)%Att(i)%catt);call netcdf_err(error)
06764 if (verbose.and.pe == 0) write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%catt(1:len)
06765 endif
06766
06767
06768
06769 case (NF_SHORT)
06770 allocate(mpp_file(unit)%Att(i)%fatt(len))
06771 error=NFMPI_GET_ATT_INT2(ncid,NF_GLOBAL,name,i2vals);call netcdf_err(error)
06772 if( verbose .and. pe == 0 )write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',i2vals(1:len)
06773 mpp_file(unit)%Att(i)%fatt(1:len)=i2vals(1:len)
06774 case (NF_INT)
06775 allocate(mpp_file(unit)%Att(i)%fatt(len))
06776 error=NFMPI_GET_ATT_INT(ncid,NF_GLOBAL,name,ivals);call netcdf_err(error)
06777 if( verbose .and. pe == 0 )write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',ivals(1:len)
06778 mpp_file(unit)%Att(i)%fatt(1:len)=ivals(1:len)
06779 case (NF_FLOAT)
06780 allocate(mpp_file(unit)%Att(i)%fatt(len))
06781 error=NFMPI_GET_ATT_REAL(ncid,NF_GLOBAL,name,rvals);call netcdf_err(error)
06782 mpp_file(unit)%Att(i)%fatt(1:len)=rvals(1:len)
06783 if( verbose .and. pe == 0)write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%fatt(1:len)
06784 case (NF_DOUBLE)
06785 allocate(mpp_file(unit)%Att(i)%fatt(len))
06786 error=NFMPI_GET_ATT_DOUBLE(ncid,NF_GLOBAL,name,r8vals);call netcdf_err(error)
06787 mpp_file(unit)%Att(i)%fatt(1:len)=r8vals(1:len)
06788 if( verbose .and. pe == 0)write (stdout(),*) 'GLOBAL ATT ',trim(name),' ',mpp_file(unit)%Att(i)%fatt(1:len)
06789 end select
06790
06791 enddo
06792
06793
06794
06795 do i=1,ndim
06796 error = NFMPI_INQ_DIM(ncid,i,name,idim);call netcdf_err(error)
06797 len = idim
06798 Axis(i)%name = name
06799 Axis(i)%len = len
06800 enddo
06801
06802 nvar=0
06803 do i=1, nvar_total
06804 error=NFMPI_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
06805 isdim=.false.
06806 do j=1,ndim
06807 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
06808 enddo
06809 if (.not.isdim) nvar=nvar+1
06810 enddo
06811 mpp_file(unit)%nvar = nvar
06812 allocate(mpp_file(unit)%Var(nvar))
06813
06814 do i=1,nvar
06815 mpp_file(unit)%Var(i) = default_field
06816 enddo
06817
06818
06819
06820
06821 do i=1, nvar_total
06822 error=NFMPI_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
06823 isdim=.false.
06824 do j=1,ndim
06825 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
06826 enddo
06827
06828 if( isdim )then
06829 error=NFMPI_INQ_DIMID(ncid,name,dimid);call netcdf_err(error)
06830 Axis(dimid)%type = type
06831 Axis(dimid)%did = dimid
06832 Axis(dimid)%id = i
06833 Axis(dimid)%natt = nvatts
06834
06835 if( i.NE.mpp_file(unit)%id )then
06836 select case (type)
06837 case (NF_INT)
06838 len=Axis(dimid)%len
06839 allocate(Axis(dimid)%data(len))
06840 error = NFMPI_GET_VAR_INT_ALL(ncid,i,ivals);call netcdf_err(error)
06841 Axis(dimid)%data(1:len)=ivals(1:len)
06842 case (NF_FLOAT)
06843 len=Axis(dimid)%len
06844 allocate(Axis(dimid)%data(len))
06845 error = NFMPI_GET_VAR_REAL_ALL(ncid,i,rvals);call netcdf_err(error)
06846 Axis(dimid)%data(1:len)=rvals(1:len)
06847 case (NF_DOUBLE)
06848 len=Axis(dimid)%len
06849 allocate(Axis(dimid)%data(len))
06850 error = NFMPI_GET_VAR_DOUBLE_ALL(ncid,i,r8vals);call netcdf_err(error)
06851 Axis(dimid)%data(1:len) = r8vals(1:len)
06852 case (NF_CHAR)
06853 len=Axis(dimid)%len
06854 allocate(Axis(dimid)%cdata(len))
06855 error = NFMPI_GET_VAR_TEXT_ALL(ncid,i,Axis(dimid)%cdata)
06856 print*,'cdata',Axis(dimid)%cdata
06857 call netcdf_err(error)
06858 case default
06859 call mpp_error( FATAL, 'Invalid data type for dimension' )
06860 end select
06861 else
06862 len = mpp_file(unit)%time_level
06863 allocate(mpp_file(unit)%time_values(len))
06864 select case (type)
06865 case (NF_FLOAT)
06866 error = NFMPI_GET_VAR_REAL_ALL(ncid,i,rvals);call netcdf_err(error)
06867 mpp_file(unit)%time_values(1:len) = rvals(1:len)
06868 case (NF_DOUBLE)
06869 error = NFMPI_GET_VAR_DOUBLE_ALL(ncid,i,r8vals);call netcdf_err(error)
06870 mpp_file(unit)%time_values(1:len) = r8vals(1:len)
06871 case default
06872 call mpp_error( FATAL, 'Invalid data type for dimension' )
06873 end select
06874 endif
06875
06876 if( nvatts.GT.0 )allocate(Axis(dimid)%Att(nvatts))
06877
06878 do j=1,nvatts
06879 Axis(dimid)%Att(j) = default_att
06880 enddo
06881
06882 do j=1,nvatts
06883 error=NFMPI_INQ_ATTNAME(ncid,i,j,attname);call netcdf_err(error)
06884 error=NFMPI_INQ_ATT(ncid,i,trim(attname),type,idim);call netcdf_err(error)
06885 len = idim
06886
06887 Axis(dimid)%Att(j)%name = trim(attname)
06888 Axis(dimid)%Att(j)%type = type
06889 Axis(dimid)%Att(j)%len = len
06890
06891 select case (type)
06892 case (NF_CHAR)
06893 if (len.gt.512) call mpp_error(FATAL,'DIM ATT too long')
06894 error=NFMPI_GET_ATT_TEXT(ncid,i,trim(attname),Axis(dimid)%Att(j)%catt);call netcdf_err(error)
06895 if( verbose .and. pe == 0 ) &
06896 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%catt(1:len)
06897
06898
06899 case (NF_SHORT)
06900 allocate(Axis(dimid)%Att(j)%fatt(len))
06901 error=NFMPI_GET_ATT_INT2(ncid,i,trim(attname),i2vals);call netcdf_err(error)
06902 Axis(dimid)%Att(j)%fatt(1:len)=i2vals(1:len)
06903 if( verbose .and. pe == 0 ) &
06904 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
06905 case (NF_INT)
06906 allocate(Axis(dimid)%Att(j)%fatt(len))
06907 error=NFMPI_GET_ATT_INT(ncid,i,trim(attname),ivals);call netcdf_err(error)
06908 Axis(dimid)%Att(j)%fatt(1:len)=ivals(1:len)
06909 if( verbose .and. pe == 0 ) &
06910 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
06911 case (NF_FLOAT)
06912 allocate(Axis(dimid)%Att(j)%fatt(len))
06913 error=NFMPI_GET_ATT_REAL(ncid,i,trim(attname),rvals);call netcdf_err(error)
06914 Axis(dimid)%Att(j)%fatt(1:len)=rvals(1:len)
06915 if( verbose .and. pe == 0 ) &
06916 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
06917 case (NF_DOUBLE)
06918 allocate(Axis(dimid)%Att(j)%fatt(len))
06919 error=NFMPI_GET_ATT_DOUBLE(ncid,i,trim(attname),r8vals);call netcdf_err(error)
06920 Axis(dimid)%Att(j)%fatt(1:len)=r8vals(1:len)
06921 if( verbose .and. pe == 0 ) &
06922 write (stdout(),*) 'AXIS ',trim(Axis(dimid)%name),' ATT ',trim(attname),' ',Axis(dimid)%Att(j)%fatt
06923 case default
06924 call mpp_error( FATAL, 'Invalid data type for dimension at' )
06925 end select
06926
06927 select case(trim(attname))
06928 case('long_name')
06929 Axis(dimid)%longname=Axis(dimid)%Att(j)%catt(1:len)
06930 case('units')
06931 Axis(dimid)%units=Axis(dimid)%Att(j)%catt(1:len)
06932 case('cartesian_axis')
06933 Axis(dimid)%cartesian=Axis(dimid)%Att(j)%catt(1:len)
06934 case('positive')
06935 attval = Axis(dimid)%Att(j)%catt(1:len)
06936 if( attval.eq.'down' )then
06937 Axis(dimid)%sense=-1
06938 else if( attval.eq.'up' )then
06939 Axis(dimid)%sense=1
06940 endif
06941 end select
06942
06943 enddo
06944
06945 mpp_file(unit)%Axis(dimid) = Axis(dimid)
06946 endif
06947 enddo
06948
06949 nv = 0
06950 do i=1, nvar_total
06951 error=NFMPI_INQ_VAR(ncid,i,name,type,nvdims,dimids,nvatts);call netcdf_err(error)
06952
06953
06954
06955 isdim=.false.
06956 do j=1,ndim
06957 if( trim(lowercase(name)).EQ.trim(lowercase(Axis(j)%name)) )isdim=.true.
06958 enddo
06959
06960 if( .not.isdim )then
06961
06962 nv=nv+1; if( nv.GT.mpp_file(unit)%nvar )call mpp_error( FATAL, 'variable index exceeds number of defined variables' )
06963 mpp_file(unit)%Var(nv)%type = type
06964 mpp_file(unit)%Var(nv)%id = i
06965 mpp_file(unit)%Var(nv)%name = name
06966 mpp_file(unit)%Var(nv)%natt = nvatts
06967
06968 select case (type)
06969 case(NF_SHORT)
06970 mpp_file(unit)%Var(nv)%pack = 4
06971 case(NF_FLOAT)
06972 mpp_file(unit)%Var(nv)%pack = 2
06973 case(NF_DOUBLE)
06974 mpp_file(unit)%Var(nv)%pack = 1
06975 case (NF_INT)
06976 mpp_file(unit)%Var(nv)%pack = 2
06977 case default
06978 call mpp_error( FATAL, 'Invalid variable type in NetCDF file' )
06979 end select
06980
06981 mpp_file(unit)%Var(nv)%ndim = nvdims
06982 allocate(mpp_file(unit)%Var(nv)%axes(nvdims))
06983 do j=1,nvdims
06984 mpp_file(unit)%Var(nv)%axes(j) = Axis(dimids(j))
06985 enddo
06986 allocate(mpp_file(unit)%Var(nv)%size(nvdims))
06987
06988 do j=1,nvdims
06989 if( dimids(j).eq.mpp_file(unit)%recdimid )then
06990 mpp_file(unit)%Var(nv)%time_axis_index = dimids(j)
06991 mpp_file(unit)%Var(nv)%size(j)=1
06992 else
06993 mpp_file(unit)%Var(nv)%size(j)=Axis(dimids(j))%len
06994 endif
06995 enddo
06996
06997 if( nvatts.GT.0 )allocate(mpp_file(unit)%Var(nv)%Att(nvatts))
06998
06999 do j=1,nvatts
07000 mpp_file(unit)%Var(nv)%Att(j) = default_att
07001 enddo
07002
07003 do j=1,nvatts
07004 error=NFMPI_INQ_ATTNAME(ncid,i,j,attname);call netcdf_err(error)
07005 error=NFMPI_INQ_ATT(ncid,i,attname,type,idim);call netcdf_err(error)
07006 len = idim
07007 mpp_file(unit)%Var(nv)%Att(j)%name = trim(attname)
07008 mpp_file(unit)%Var(nv)%Att(j)%type = type
07009 mpp_file(unit)%Var(nv)%Att(j)%len = len
07010
07011 select case (type)
07012 case (NF_CHAR)
07013 if (len.gt.512) call mpp_error(FATAL,'VAR ATT too long')
07014 error=NFMPI_GET_ATT_TEXT(ncid,i,trim(attname),mpp_file(unit)%Var(nv)%Att(j)%catt(1:len));call netcdf_err(error)
07015 if (verbose .and. pe == 0 )&
07016 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
07017
07018 case (NF_SHORT)
07019 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
07020 error=NFMPI_GET_ATT_INT2(ncid,i,trim(attname),i2vals);call netcdf_err(error)
07021 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)= i2vals(1:len)
07022 if( verbose .and. pe == 0 )&
07023 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
07024 case (NF_INT)
07025 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
07026 error=NFMPI_GET_ATT_INT(ncid,i,trim(attname),ivals);call netcdf_err(error)
07027 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=ivals(1:len)
07028 if( verbose .and. pe == 0 )&
07029 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
07030 case (NF_FLOAT)
07031 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
07032 error=NFMPI_GET_ATT_REAL(ncid,i,trim(attname),rvals);call netcdf_err(error)
07033 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=rvals(1:len)
07034 if( verbose .and. pe == 0 )&
07035 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
07036 case (NF_DOUBLE)
07037 allocate(mpp_file(unit)%Var(nv)%Att(j)%fatt(len))
07038 error=NFMPI_GET_ATT_DOUBLE(ncid,i,trim(attname),r8vals);call netcdf_err(error)
07039 mpp_file(unit)%Var(nv)%Att(j)%fatt(1:len)=r8vals(1:len)
07040 if( verbose .and. pe == 0 ) &
07041 write (stdout(),*) 'Var ',nv,' ATT ',trim(attname),' ',mpp_file(unit)%Var(nv)%Att(j)%fatt
07042 case default
07043 call mpp_error( FATAL, 'Invalid data type for variable att' )
07044 end select
07045
07046 select case (trim(attname))
07047 case ('long_name')
07048 mpp_file(unit)%Var(nv)%longname=mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
07049 case('units')
07050 mpp_file(unit)%Var(nv)%units=mpp_file(unit)%Var(nv)%Att(j)%catt(1:len)
07051 case('scale_factor')
07052 mpp_file(unit)%Var(nv)%scale=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
07053 case('missing')
07054 mpp_file(unit)%Var(nv)%missing=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
07055 case('add_offset')
07056 mpp_file(unit)%Var(nv)%add=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
07057 case('valid_range')
07058 mpp_file(unit)%Var(nv)%min=mpp_file(unit)%Var(nv)%Att(j)%fatt(1)
07059 mpp_file(unit)%Var(nv)%max=mpp_file(unit)%Var(nv)%Att(j)%fatt(2)
07060 end select
07061 enddo
07062 endif
07063 enddo
07064 else
07065 call mpp_error( FATAL, 'MPP READ CURRENTLY DOES NOT SUPPORT NON-NETCDF' )
07066 endif
07067
07068 mpp_file(unit)%initialized = .TRUE.
07069 #else
07070 call mpp_error( FATAL, 'MPP_READ currently requires use_netCDF option' )
07071 #endif
07072 return
07073 end subroutine mpp_read_meta
07074
07075
07076 subroutine mpp_get_info( unit, ndim, nvar, natt, ntime )
07077
07078 integer, intent(in) :: unit
07079 integer, intent(out) :: ndim, nvar, natt, ntime
07080
07081
07082 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_INFO: must first call mpp_io_init.' )
07083 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_INFO: invalid unit number.' )
07084
07085 ndim = mpp_file(unit)%ndim
07086 nvar = mpp_file(unit)%nvar
07087 natt = mpp_file(unit)%natt
07088 ntime = mpp_file(unit)%time_level
07089
07090 return
07091
07092 end subroutine mpp_get_info
07093
07094
07095 subroutine mpp_get_global_atts( unit, global_atts )
07096
07097
07098
07099
07100
07101
07102 integer, intent(in) :: unit
07103 type(atttype), intent(inout) :: global_atts(:)
07104 integer :: natt,i
07105
07106 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_INFO: must first call mpp_io_init.' )
07107 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_INFO: invalid unit number.' )
07108
07109 if (size(global_atts).lt.mpp_file(unit)%natt) &
07110 call mpp_error(FATAL, 'MPP_GET_ATTS: atttype not dimensioned properly in calling routine')
07111
07112 natt = mpp_file(unit)%natt
07113 global_atts = default_att
07114
07115 do i=1,natt
07116 global_atts(i) = mpp_file(unit)%Att(i)
07117 enddo
07118
07119 return
07120 end subroutine mpp_get_global_atts
07121
07122 subroutine mpp_get_field_atts( field, name, units, longname, min, max, missing, ndim, siz, axes, atts )
07123
07124 type(fieldtype), intent(in) :: field
07125 character(len=*), intent(out) , optional :: name, units
07126 character(len=*), intent(out), optional :: longname
07127 real,intent(out), optional :: min,max,missing
07128 integer, intent(out), optional :: ndim
07129 integer, intent(out), dimension(:), optional :: siz
07130
07131 type(atttype), intent(out), optional, dimension(:) :: atts
07132 type(axistype), intent(out), optional, dimension(:) :: axes
07133
07134 integer :: n,m
07135
07136 if (PRESENT(name)) name = field%name
07137 if (PRESENT(units)) units = field%units
07138 if (PRESENT(longname)) longname = field%longname
07139 if (PRESENT(min)) min = field%min
07140 if (PRESENT(max)) max = field%max
07141 if (PRESENT(missing)) missing = field%missing
07142 if (PRESENT(ndim)) ndim = field%ndim
07143 if (PRESENT(atts)) then
07144 atts = default_att
07145 n = size(atts);m=size(field%Att)
07146 if (n.LT.m) call mpp_error(FATAL,'attribute array not large enough in mpp_get_field_atts')
07147 atts(1:m) = field%Att(1:m)
07148 end if
07149 if (PRESENT(axes)) then
07150 axes = default_axis
07151 n = size(axes);m=field%ndim
07152 if (n.LT.m) call mpp_error(FATAL,'axis array not large enough in mpp_get_field_atts')
07153 axes(1:m) = field%axes(1:m)
07154 end if
07155 if (PRESENT(siz)) then
07156 siz = -1
07157 n = size(siz);m=field%ndim
07158 if (n.LT.m) call mpp_error(FATAL,'size array not large enough in mpp_get_field_atts')
07159 siz(1:m) = field%size(1:m)
07160 end if
07161 return
07162 end subroutine mpp_get_field_atts
07163
07164 subroutine mpp_get_axis_atts( axis, name, units, longname, cartesian, sense, len, natts, atts )
07165
07166 type(axistype), intent(in) :: axis
07167 character(len=*), intent(out) , optional :: name, units
07168 character(len=*), intent(out), optional :: longname, cartesian
07169 integer,intent(out), optional :: sense, len , natts
07170 type(atttype), intent(out), optional, dimension(:) :: atts
07171
07172 integer :: n,m
07173
07174 if (PRESENT(name)) name = axis%name
07175 if (PRESENT(units)) units = axis%units
07176 if (PRESENT(longname)) longname = axis%longname
07177 if (PRESENT(cartesian)) cartesian = axis%cartesian
07178 if (PRESENT(sense)) sense = axis%sense
07179 if (PRESENT(len)) len = axis%len
07180 if (PRESENT(atts)) then
07181 atts = default_att
07182 n = size(atts);m=size(axis%Att)
07183 if (n.LT.m) call mpp_error(FATAL,'attribute array not large enough in mpp_get_field_atts')
07184 atts(1:m) = axis%Att(1:m)
07185 end if
07186 if (PRESENT(natts)) natts = size(axis%Att)
07187
07188 return
07189 end subroutine mpp_get_axis_atts
07190
07191
07192 subroutine mpp_get_fields( unit, variables )
07193
07194
07195
07196
07197
07198 integer, intent(in) :: unit
07199 type(fieldtype), intent(inout) :: variables(:)
07200
07201 integer :: nvar,i
07202
07203 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_FIELDS: must first call mpp_io_init.' )
07204 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_FIELDS: invalid unit number.' )
07205
07206 if (size(variables).ne.mpp_file(unit)%nvar) &
07207 call mpp_error(FATAL, 'MPP_GET_FIELDS: fieldtype not dimensioned properly in calling routine')
07208
07209 nvar = mpp_file(unit)%nvar
07210
07211 do i=1,nvar
07212 variables(i) = mpp_file(unit)%Var(i)
07213 enddo
07214
07215 return
07216 end subroutine mpp_get_fields
07217
07218 subroutine mpp_get_axes( unit, axes, time_axis )
07219
07220
07221
07222
07223
07224 integer, intent(in) :: unit
07225 type(axistype), intent(out) :: axes(:)
07226 type(axistype), intent(out), optional :: time_axis
07227 character(len=128) :: name
07228 logical :: save
07229 integer :: ndim,i, nvar, j, num_dims, k
07230
07231 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_AXES: must first call mpp_io_init.' )
07232 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_AXES: invalid unit number.' )
07233
07234 if (size(axes).ne.mpp_file(unit)%ndim) &
07235 call mpp_error(FATAL, 'MPP_GET_AXES: axistype not dimensioned properly in calling routine')
07236
07237
07238 if (PRESENT(time_axis)) time_axis = default_axis
07239 ndim = mpp_file(unit)%ndim
07240 do i=1,ndim
07241 if (ASSOCIATED(mpp_file(unit)%Axis(i)%data)) then
07242 axes(i)=mpp_file(unit)%Axis(i)
07243 else
07244 axes(i)=mpp_file(unit)%Axis(i)
07245 if (PRESENT(time_axis)) time_axis = mpp_file(unit)%Axis(i)
07246 endif
07247 enddo
07248
07249 return
07250 end subroutine mpp_get_axes
07251
07252 subroutine mpp_get_times( unit, time_values )
07253
07254
07255
07256 integer, intent(in) :: unit
07257 real(DOUBLE_KIND), intent(inout) :: time_values(:)
07258
07259 integer :: ntime,i
07260
07261 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_TIMES: must first call mpp_io_init.' )
07262 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_TIMES: invalid unit number.' )
07263
07264 if (size(time_values).ne.mpp_file(unit)%time_level) &
07265 call mpp_error(FATAL, 'MPP_GET_TIMES: time_values not dimensioned properly in calling routine')
07266
07267 ntime = mpp_file(unit)%time_level
07268
07269 do i=1,ntime
07270 time_values(i) = mpp_file(unit)%time_values(i)
07271 enddo
07272
07273
07274
07275 return
07276 end subroutine mpp_get_times
07277
07278 function mpp_get_field_index(fields,fieldname)
07279
07280 type(fieldtype), dimension(:) :: fields
07281 character(len=*) :: fieldname
07282 integer :: mpp_get_field_index
07283
07284 integer :: n
07285
07286 mpp_get_field_index = -1
07287
07288 do n=1,size(fields)
07289 if (lowercase(fields(n)%name) == lowercase(fieldname)) then
07290 mpp_get_field_index = n
07291 exit
07292 endif
07293 enddo
07294
07295 return
07296 end function mpp_get_field_index
07297
07298 function mpp_get_field_size(field)
07299
07300 type(fieldtype) :: field
07301 integer :: mpp_get_field_size(4)
07302
07303 integer :: n
07304
07305 mpp_get_field_size = -1
07306
07307 mpp_get_field_size(1) = field%size(1)
07308 mpp_get_field_size(2) = field%size(2)
07309 mpp_get_field_size(3) = field%size(3)
07310 mpp_get_field_size(4) = field%size(4)
07311
07312 return
07313 end function mpp_get_field_size
07314
07315
07316 subroutine mpp_get_axis_data( axis, data )
07317
07318 type(axistype), intent(in) :: axis
07319 real, dimension(:), intent(out) :: data
07320
07321
07322 if (size(data).lt.axis%len) call mpp_error(FATAL,'MPP_GET_AXIS_DATA: data array not large enough')
07323 if (.NOT.ASSOCIATED(axis%data)) then
07324 call mpp_error(NOTE,'MPP_GET_AXIS_DATA: use mpp_get_times for record dims')
07325 data = 0.
07326 else
07327 data(1:axis%len) = axis%data
07328 endif
07329
07330 return
07331 end subroutine mpp_get_axis_data
07332
07333
07334 function mpp_get_recdimid(unit)
07335
07336 integer, intent(in) :: unit
07337 integer :: mpp_get_recdimid
07338
07339
07340 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_RECDIMID: must first call mpp_io_init.' )
07341 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_RECDIMID: invalid unit number.' )
07342
07343 mpp_get_recdimid = mpp_file(unit)%recdimid
07344
07345 return
07346 end function mpp_get_recdimid
07347
07348
07349
07350
07351
07352
07353
07354 subroutine mpp_flush(unit)
07355
07356 integer, intent(in) :: unit
07357
07358 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_FLUSH: must first call mpp_io_init.' )
07359 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_FLUSH: invalid unit number.' )
07360 if( .NOT.mpp_file(unit)%initialized )call mpp_error( FATAL, 'MPP_FLUSH: cannot flush a file during writing of metadata.' )
07361 if( mpp_file(unit)%threading.EQ.MPP_SINGLE .AND. pe.NE.mpp_root_pe() )return
07362
07363 if( mpp_file(unit)%format.EQ.MPP_NETCDF )then
07364 #ifdef use_netCDF
07365 error = NFMPI_SYNC(mpp_file(unit)%ncid); call netcdf_err(error)
07366 #endif
07367 else
07368 call FLUSH(unit)
07369 end if
07370 return
07371 end subroutine mpp_flush
07372
07373 subroutine mpp_get_iospec( unit, iospec )
07374 integer, intent(in) :: unit
07375 character(len=*), intent(out) :: iospec
07376
07377 if( .NOT.module_is_initialized )call mpp_error( FATAL, 'MPP_GET_IOSPEC: must first call mpp_io_init.' )
07378 if( .NOT.mpp_file(unit)%opened )call mpp_error( FATAL, 'MPP_GET_IOSPEC: invalid unit number.' )
07379 #ifdef SGICRAY
07380
07381 call ASSIGN( 'assign -V f:'//trim(mpp_file(unit)%name), error )
07382 #endif
07383 return
07384 end subroutine mpp_get_iospec
07385
07386
07387
07388
07389
07390
07391
07392 function mpp_get_ncid(unit)
07393 integer :: mpp_get_ncid
07394 integer, intent(in) :: unit
07395
07396 mpp_get_ncid = mpp_file(unit)%ncid
07397 return
07398 end function mpp_get_ncid
07399
07400 function mpp_get_axis_id(axis)
07401 integer mpp_get_axis_id
07402 type(axistype), intent(in) :: axis
07403 mpp_get_axis_id = axis%id
07404 return
07405 end function mpp_get_axis_id
07406
07407 function mpp_get_field_id(field)
07408 integer mpp_get_field_id
07409 type(fieldtype), intent(in) :: field
07410 mpp_get_field_id = field%id
07411 return
07412 end function mpp_get_field_id
07413
07414 subroutine netcdf_err(err)
07415 integer, intent(in) :: err
07416 character(len=80) :: errmsg
07417 integer :: unit
07418
07419 #ifdef use_netCDF
07420 if( err.EQ.NF_NOERR )return
07421 errmsg = NFMPI_STRERROR(err)
07422 call mpp_io_exit()
07423 call mpp_error( FATAL, 'NETCDF ERROR: '//trim(errmsg) )
07424 #endif
07425 return
07426 end subroutine netcdf_err
07427
07428
07429
07430
07431
07432
07433
07434 subroutine mpp_get_unit_range( unit_begin_out, unit_end_out )
07435 integer, intent(out) :: unit_begin_out, unit_end_out
07436
07437 unit_begin_out = unit_begin; unit_end_out = unit_end
07438 return
07439 end subroutine mpp_get_unit_range
07440
07441 subroutine mpp_set_unit_range( unit_begin_in, unit_end_in )
07442 integer, intent(in) :: unit_begin_in, unit_end_in
07443
07444 if( unit_begin_in.GT.unit_end_in )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_begin_in.GT.unit_end_in.' )
07445 if( unit_begin_in.LT.0 )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_begin_in.LT.0.' )
07446 if( unit_end_in .GT.maxunits )call mpp_error( FATAL, 'MPP_SET_UNIT_RANGE: unit_end_in.GT.maxunits.' )
07447 unit_begin = unit_begin_in; unit_end = unit_end_in
07448 return
07449 end subroutine mpp_set_unit_range
07450
07451 subroutine mpp_modify_axis_meta( axis, name, units, longname, cartesian, data )
07452
07453 type(axistype), intent(inout) :: axis
07454 character(len=*), intent(in), optional :: name, units, longname, cartesian
07455 real, dimension(:), intent(in), optional :: data
07456
07457 if (PRESENT(name)) axis%name = trim(name)
07458 if (PRESENT(units)) axis%units = trim(units)
07459 if (PRESENT(longname)) axis%longname = trim(longname)
07460 if (PRESENT(cartesian)) axis%cartesian = trim(cartesian)
07461 if (PRESENT(data)) then
07462 axis%len = size(data)
07463 if (ASSOCIATED(axis%data)) deallocate(axis%data)
07464 allocate(axis%data(axis%len))
07465 axis%data = data
07466 endif
07467
07468 return
07469 end subroutine mpp_modify_axis_meta
07470
07471 subroutine mpp_modify_field_meta( field, name, units, longname, min, max, missing, axes )
07472
07473 type(fieldtype), intent(inout) :: field
07474 character(len=*), intent(in), optional :: name, units, longname
07475 real, intent(in), optional :: min, max, missing
07476 type(axistype), dimension(:), intent(inout), optional :: axes
07477
07478 if (PRESENT(name)) field%name = trim(name)
07479 if (PRESENT(units)) field%units = trim(units)
07480 if (PRESENT(longname)) field%longname = trim(longname)
07481 if (PRESENT(min)) field%min = min
07482 if (PRESENT(max)) field%max = max
07483 if (PRESENT(missing)) field%missing = missing
07484
07485
07486
07487
07488
07489
07490
07491 return
07492 end subroutine mpp_modify_field_meta
07493
07494 function lowercase (cs)
07495 character(len=*), intent(in) :: cs
07496 #ifdef __crayx1
07497 character(len=128) :: lowercase
07498 integer :: ido, i
07499 integer, save ::
07500
07501 & down_map_ascii(0:127)=(/ (ido, ido=0,64), (ido+32, ido=65,90), (ido, ido=91,127) /)
07502 do i = 1, len( cs )
07503 lowercase(i:i) = achar(down_map_ascii(iachar(cs(i:i))))
07504 end do
07505 #else
07506 character(len=len(cs)) :: lowercase
07507 character :: ca(len(cs))
07508
07509 integer, parameter :: co=iachar('a')-iachar('A')
07510
07511 ca = transfer(cs,"x",len(cs))
07512 where (ca >= "A" .and. ca <= "Z") ca = achar(iachar(ca)+co)
07513 lowercase = transfer(ca,cs)
07514 #endif
07515 end function lowercase
07516
07517
07518
07519
07520
07521
07522
07523
07524 subroutine mpp_nullify_axistype(axis)
07525 type(axistype), intent(inout) :: axis
07526
07527 Nullify(axis%data)
07528 Nullify(axis%cdata)
07529 Nullify(axis%Att)
07530 end subroutine mpp_nullify_axistype
07531
07532 subroutine mpp_nullify_axistype_array(axis)
07533 type(axistype), intent(inout), dimension(:) :: axis
07534 integer :: i
07535
07536 do i=1, size(axis)
07537 Nullify(axis(i)%data)
07538 Nullify(axis(i)%cdata)
07539 Nullify(axis(i)%Att)
07540 enddo
07541 end subroutine mpp_nullify_axistype_array
07542
07543 end module mpp_io_mod_oa
07544
07545
07546 #endif
07547 #endif