21 #include <fms_platform.h> 38 USE mpp_mod,
ONLY: mpp_npes, mpp_pe
47 USE netcdf,
ONLY: nf90_int, nf90_float, nf90_char
65 INTEGER,
PARAMETER ::
mxch = 128
66 INTEGER,
PARAMETER ::
mxchl = 256
68 INTEGER,
DIMENSION(2,2) ::
max_range = reshape((/ -32767, 32767, -127, 127 /),(/2,2/))
70 INTEGER,
DIMENSION(2) ::
missval = (/ -32768, -128 /)
81 #include<file_version.h> 107 & all_scalar_or_1d, domain, domainU, attributes)
108 CHARACTER(len=*),
INTENT(in) :: file_name, file_title
109 INTEGER ,
INTENT(in) :: format
110 INTEGER ,
INTENT(out) :: file_unit
111 LOGICAL ,
INTENT(in) :: all_scalar_or_1d
112 TYPE(
domain2d) ,
INTENT(in) :: domain
113 TYPE(
diag_atttype),
INTENT(in),
DIMENSION(:),
OPTIONAL :: attributes
114 TYPE(
domainug),
INTENT(in) :: domainu
116 INTEGER :: form, threading, fileset, i
123 CALL write_version_number(
"DIAG_OUTPUT_MOD", version)
130 threading = mpp_multi
134 CALL error_mesg(
'diag_output_init',
'invalid format', fatal)
137 IF(all_scalar_or_1d)
THEN 138 threading = mpp_single
144 if (domain .NE. null_domain2d .AND. domainu .NE. null_domainug)&
145 &
CALL error_mesg(
'diag_output_init',
"Domain2D and DomainUG can not be used at the same time in "//&
146 & trim(file_name), fatal)
149 IF ( domain .NE. null_domain2d )
THEN 150 CALL mpp_open(file_unit, file_name, action=mpp_overwr, form=form,&
151 & threading=threading, fileset=fileset, domain=domain)
152 ELSE IF (domainu .NE. null_domainug)
THEN 153 CALL mpp_open(file_unit, file_name, action=mpp_overwr, form=form,&
154 & threading=threading, fileset=fileset, domain_ug=domainu)
156 CALL mpp_open(file_unit, file_name, action=mpp_overwr, form=form,&
157 & threading=threading, fileset=fileset)
161 IF ( file_title(1:1) /=
' ' )
THEN 165 IF (
PRESENT(attributes) )
THEN 166 DO i=1,
SIZE(attributes)
167 SELECT CASE (attributes(i)%type)
169 CALL mpp_write_meta(file_unit, trim(attributes(i)%name), ival=attributes(i)%iatt)
171 CALL mpp_write_meta(file_unit, trim(attributes(i)%name), rval=attributes(i)%fatt)
173 CALL mpp_write_meta(file_unit, trim(attributes(i)%name), cval=trim(attributes(i)%catt))
179 CALL error_mesg(
'diag_output_mod::diag_output_init',
'Unknown attribute type for global attribute "'&
180 &//trim(attributes(i)%name)//
'" in file "'//trim(file_name)//
'". Contact the developers.', fatal)
186 CALL mpp_write_meta(file_unit,
'grid_type', cval=trim(gatt%grid_type))
187 CALL mpp_write_meta(file_unit,
'grid_tile', cval=trim(gatt%tile_name))
205 INTEGER,
INTENT(in) :: file_unit, axes(:)
206 LOGICAL,
INTENT(in),
OPTIONAL :: time_ops
212 CHARACTER(len=mxch) :: axis_name, axis_units
213 CHARACTER(len=mxchl) :: axis_long_name
214 CHARACTER(len=1) :: axis_cart_name
215 INTEGER :: axis_direction, axis_edges
216 REAL,
ALLOCATABLE :: axis_data(:)
217 INTEGER,
ALLOCATABLE :: axis_extent(:), pelist(:)
218 INTEGER :: num_attributes
219 TYPE(
diag_atttype),
DIMENSION(:),
ALLOCATABLE :: attributes
220 INTEGER :: calendar, id_axis, id_time_axis
221 INTEGER :: i, j, index, num, length, edges_index
222 INTEGER :: gbegin, gend, gsize, ndivs
224 CHARACTER(len=2048) :: err_msg
226 integer(INT_KIND) :: io_domain_npes
227 integer(INT_KIND),
dimension(:),
allocatable :: io_pelist
228 integer(INT_KIND),
dimension(:),
allocatable :: unstruct_axis_sizes
229 real,
dimension(:),
allocatable :: unstruct_axis_data
234 IF (
PRESENT(time_ops) )
THEN 246 IF ( num < 1 )
CALL error_mesg(
'write_axis_meta_data',
'number of axes < 1.', fatal)
250 &
'writing meta data out-of-order to different files.', fatal)
259 IF ( index > 0 ) cycle
266 ALLOCATE(axis_data(length))
268 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name,&
269 & axis_cart_name, axis_direction, axis_edges, domain, domainu, axis_data,&
270 & num_attributes, attributes)
272 IF ( domain .NE. null_domain1d )
THEN 273 IF ( length > 0 )
THEN 275 & axis_name, axis_units, axis_long_name, axis_cart_name,&
276 & axis_direction, domain, axis_data )
279 & axis_units, axis_long_name, axis_cart_name, axis_direction, domain)
282 IF ( length > 0 )
THEN 287 if (uppercase(trim(axis_cart_name)) .eq.
"U")
then 288 if (domainu .eq. null_domainug)
then 289 call error_mesg(
"diag_output_mod::write_axis_meta_data", &
290 "A non-nul domainUG is required to" &
291 //
" write unstructured axis metadata.", &
295 io_domain => mpp_get_ug_io_domain(domainu)
296 io_domain_npes = mpp_get_ug_domain_npes(io_domain)
297 allocate(io_pelist(io_domain_npes))
298 call mpp_get_ug_domain_pelist(io_domain, &
300 allocate(unstruct_axis_sizes(io_domain_npes))
301 unstruct_axis_sizes = 0
303 unstruct_axis_sizes, &
305 if (mpp_pe() .eq. io_pelist(1))
then 306 allocate(unstruct_axis_data(sum(unstruct_axis_sizes)))
308 allocate(unstruct_axis_data(1))
310 unstruct_axis_data = 0.0
313 unstruct_axis_data, &
314 unstruct_axis_sizes, &
323 data=unstruct_axis_data)
324 deallocate(io_pelist)
325 deallocate(unstruct_axis_sizes)
326 deallocate(unstruct_axis_data)
331 & axis_units, axis_long_name, axis_cart_name, axis_direction, data=axis_data)
336 & axis_units, axis_long_name, axis_cart_name, axis_direction)
343 IF ( len_trim(err_msg) .GT. 0 )
THEN 344 CALL error_mesg(
'diag_output_mod::write_axis_meta_data', trim(err_msg), fatal)
350 IF ( axis_cart_name ==
'T' )
THEN 356 IF ( time_ops1 )
THEN 357 CALL mpp_write_meta( file_unit, id_time_axis,
'bounds', cval = trim(axis_name)//
'_bnds')
363 DEALLOCATE(axis_data)
366 IF (
ALLOCATED(attributes) )
THEN 367 DO j=1, num_attributes
368 IF ( _allocated(attributes(j)%fatt ) )
THEN 369 DEALLOCATE(attributes(j)%fatt)
371 IF ( _allocated(attributes(j)%iatt ) )
THEN 372 DEALLOCATE(attributes(j)%iatt)
375 DEALLOCATE(attributes)
381 IF ( axis_edges <= 0 ) cycle
386 IF ( edges_index > 0 ) cycle
390 ALLOCATE(axis_data(length))
391 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name, axis_cart_name,&
392 & axis_direction, axis_edges, domain, domainu, axis_data, num_attributes, attributes)
396 &
'edges', cval=axis_name )
406 IF ( domain .NE. null_domain1d )
THEN 412 IF ( ndivs .EQ. 1 )
THEN 414 & axis_units, axis_long_name, axis_cart_name, axis_direction, data=axis_data )
416 IF (
ALLOCATED(axis_extent) )
DEALLOCATE(axis_extent)
417 ALLOCATE(axis_extent(0:ndivs-1))
420 axis_extent(ndivs-1)= axis_extent(ndivs-1)+1
421 IF (
ALLOCATED(pelist) )
DEALLOCATE(pelist)
422 ALLOCATE(pelist(0:ndivs-1))
425 & axis_name, axis_units, axis_long_name, axis_cart_name,&
426 & axis_direction, domain, data=axis_data)
430 & axis_long_name, axis_cart_name, axis_direction, data=axis_data)
436 IF ( len_trim(err_msg) .GT. 0 )
THEN 437 CALL error_mesg(
'diag_output_mod::write_axis_meta_data', trim(err_msg), fatal)
440 DEALLOCATE (axis_data)
442 IF (
ALLOCATED(attributes) )
THEN 443 DO j=1, num_attributes
444 IF ( _allocated(attributes(j)%fatt ) )
THEN 445 DEALLOCATE(attributes(j)%fatt)
447 IF ( _allocated(attributes(j)%iatt ) )
THEN 448 DEALLOCATE(attributes(j)%iatt)
451 DEALLOCATE(attributes)
495 & avg_name, time_method, standard_name, interp_method, attributes, num_attributes, &
496 & use_UGdomain)
result ( Field )
497 INTEGER,
INTENT(in) :: file_unit, axes(:)
498 CHARACTER(len=*),
INTENT(in) :: name, units, long_name
499 REAL,
OPTIONAL,
INTENT(in) :: range(2), mval
500 INTEGER,
OPTIONAL,
INTENT(in) :: pack
501 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: avg_name, time_method, standard_name
502 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: interp_method
503 TYPE(
diag_atttype),
DIMENSION(:), _allocatable,
OPTIONAL,
INTENT(in) :: attributes
504 INTEGER,
OPTIONAL,
INTENT(in) :: num_attributes
505 LOGICAL,
OPTIONAL,
INTENT(in) :: use_ugdomain
507 CHARACTER(len=256) :: standard_name2
508 CHARACTER(len=1280) :: att_str
510 LOGICAL :: coord_present
511 CHARACTER(len=40) :: aux_axes(
size(axes))
512 CHARACTER(len=160) :: coord_att
513 CHARACTER(len=1024) :: err_msg
516 INTEGER :: i, indexx, num, ipack, np, att_len
518 INTEGER :: axis_indices(
size(axes))
519 logical :: use_ugdomain_local
525 coord_present = .false.
526 IF(
PRESENT(standard_name) )
THEN 527 standard_name2 = standard_name
529 standard_name2 =
'none' 532 use_ugdomain_local = .false.
533 if(
present(use_ugdomain)) use_ugdomain_local = use_ugdomain
537 IF ( num < 1 )
CALL error_mesg (
'write_meta_data',
'number of axes < 1', fatal)
540 &
'writing meta data out-of-order to different files', fatal)
548 IF ( indexx > 0 )
THEN 549 axis_indices(i) = indexx
553 &
'axis data not written for field '//trim(name), fatal)
558 IF ( num >= 2 .OR. (num==1 .and. use_ugdomain_local) )
THEN 562 IF( trim(aux_axes(i)) /=
'none' )
THEN 563 IF(len_trim(coord_att) == 0)
THEN 564 coord_att = trim(aux_axes(i))
566 coord_att = trim(coord_att)//
' '//trim(aux_axes(i))
568 coord_present = .true.
577 IF (
PRESENT(pack) )
THEN 587 IF (
PRESENT(range) )
THEN 588 IF ( range(2) > range(1) )
THEN 591 IF ( ipack > 2 )
THEN 593 add = 0.5*(range(1)+range(2))
600 IF (
PRESENT(mval) )
THEN 602 field%miss_present = .true.
603 IF ( ipack > 2 )
THEN 605 field%miss_pack =
REAL(
missval(np))*scale+add
606 field%miss_pack_present = .true.
608 field%miss_pack = mval
609 field%miss_pack_present = .false.
612 field%miss_present = .false.
613 field%miss_pack_present = .false.
617 IF ( use_range )
THEN 618 IF ( field%miss_present )
THEN 621 & name, units, long_name,&
622 & range(1), range(2),&
623 & missing=field%miss_pack,&
624 & fill=field%miss_pack,&
625 & scale=scale, add=add, pack=ipack,&
626 & time_method=time_method)
630 & name, units, long_name,&
631 & range(1), range(2),&
634 & scale=scale, add=add, pack=ipack,&
635 & time_method=time_method)
638 IF ( field%miss_present )
THEN 641 & name, units, long_name,&
642 & missing=field%miss_pack,&
643 & fill=field%miss_pack,&
644 & pack=ipack, time_method=time_method)
648 & name, units, long_name,&
651 & pack=ipack, time_method=time_method)
656 IF (
PRESENT(num_attributes) )
THEN 657 IF (
PRESENT(attributes) )
THEN 658 IF ( num_attributes .GT. 0 .AND. _allocated(attributes) )
THEN 660 IF ( len_trim(err_msg) .GT. 0 )
THEN 661 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
662 & trim(err_msg)//
" Contact the developers.", fatal)
666 IF ( num_attributes .GT. 0 .AND. .NOT._allocated(attributes) )
THEN 667 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
668 &
'num_attributes > 0 but attributes is not allocated for attribute '&
669 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
670 ELSE IF ( num_attributes .EQ. 0 .AND. _allocated(attributes) )
THEN 671 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
672 &
'num_attributes == 0 but attributes is allocated for attribute '&
673 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
678 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
679 &
'num_attributes present but attributes missing for attribute '&
680 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
682 ELSE IF (
PRESENT(attributes) )
THEN 683 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
684 &
'attributes present but num_attributes missing for attribute '&
685 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
690 IF (
PRESENT(avg_name) )
THEN 691 IF ( avg_name(1:1) /=
' ' )
THEN 694 & cval=trim(avg_name)//
'_T1,'//trim(avg_name)//
'_T2,'//trim(avg_name)//
'_DT')
699 IF ( coord_present ) &
701 &
'coordinates', cval=trim(coord_att))
703 &
'standard_name', cval=trim(standard_name2))
706 IF(
PRESENT(interp_method) )
THEN 708 &
'interp_method', cval=trim(interp_method))
722 SUBROUTINE write_attribute_meta(file_unit, id, num_attributes, attributes, time_method, err_msg)
723 INTEGER,
INTENT(in) :: file_unit
724 INTEGER,
INTENT(in) :: id
725 INTEGER,
INTENT(in) :: num_attributes
726 TYPE(diag_atttype),
DIMENSION(:),
INTENT(in) :: attributes
727 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: time_method
728 CHARACTER(len=*),
INTENT(out),
OPTIONAL :: err_msg
730 INTEGER :: i, att_len
731 CHARACTER(len=1280) :: att_str
734 IF (
PRESENT(err_msg) ) err_msg =
'' 736 DO i = 1, num_attributes
737 SELECT CASE (attributes(i)%type)
739 IF ( .NOT._allocated(attributes(i)%iatt) )
THEN 741 &
'Integer attribute type indicated, but array not allocated for attribute '&
742 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN 747 & ival=attributes(i)%iatt)
749 IF ( .NOT._allocated(attributes(i)%fatt) )
THEN 751 &
'Real attribute type indicated, but array not allocated for attribute '&
752 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN 757 & rval=attributes(i)%fatt)
759 att_str = attributes(i)%catt
760 att_len = attributes(i)%len
761 IF ( trim(attributes(i)%name).EQ.
'cell_methods' .AND.
PRESENT(time_method) )
THEN 763 att_str = attributes(i)%catt(1:attributes(i)%len)//
' time: '//time_method
764 att_len = len_trim(att_str)
767 & cval=att_str(1:att_len))
769 IF (
fms_error_handler(
'diag_output_mod::write_attribute_meta',
'Invalid type for attribute '&
770 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN 791 INTEGER,
INTENT(in) :: file_unit
820 INTEGER,
INTENT(in) :: file_unit
822 REAL ,
INTENT(inout) :: data(:,:,:,:)
823 REAL,
OPTIONAL,
INTENT(in) :: time
828 IF ( field%miss_pack_present )
THEN 829 WHERE (
DATA == field%miss )
DATA = field%miss_pack
833 IF ( field%Domain .NE. null_domain2d )
THEN 834 IF( field%miss_present )
THEN 835 CALL mpp_write(file_unit, field%Field, field%Domain,
DATA, time, &
836 tile_count=field%tile_count, default_data=field%miss_pack)
838 CALL mpp_write(file_unit, field%Field, field%Domain,
DATA, time, &
841 ELSEIF ( field%DomainU .NE. null_domainug )
THEN 842 IF( field%miss_present )
THEN 844 default_data=field%miss_pack)
851 CALL mpp_write(file_unit, field%Field,
DATA, time)
869 INTEGER,
INTENT(in) :: file_unit
871 CALL mpp_flush (file_unit)
888 INTEGER,
INTENT(in) :: num
938 CHARACTER(len=*),
INTENT(in) :: component, gridtype, tilename
942 CHARACTER(len=64) :: component_tmp
943 component_tmp = component
real, parameter cmor_missing_value
CMOR standard missing value.
integer function, public get_tile_count(ids)
type(diag_global_att_type), save diag_global_att
subroutine, public diag_field_out(file_unit, Field, DATA, time)
subroutine write_attribute_meta(file_unit, id, num_attributes, attributes, time_method, err_msg)
Write out attribute meta data to file.
type(domainug) function, public get_domainug(id)
character(len=128) function, public get_axis_aux(id)
type(domain1d) function, public get_domain1d(id)
subroutine, public done_meta_data(file_unit)
subroutine, public diag_flush(file_unit)
integer, dimension(2, 2) max_range
logical function, public fms_error_handler(routine, message, err_msg)
subroutine, public diag_output_init(file_name, FORMAT, file_title, file_unit, all_scalar_or_1d, domain, domainU, attributes)
logical module_is_initialized
subroutine, public get_diag_axis(id, name, units, long_name, cart_name, direction, edges, Domain, DomainU, DATA, num_attributes, attributes)
subroutine, public write_axis_meta_data(file_unit, axes, time_ops)
integer function, public get_axis_global_length(id)
subroutine, public set_diag_global_att(component, gridType, tileName)
integer, parameter max_axis_num
subroutine, public get_diag_global_att(gAtt)
type(domain2d), save, public null_domain2d
logical, dimension(max_axis_num) edge_axis_flag
character(len=24) function, public valid_calendar_types(ncal, err_msg)
integer function, public get_calendar_type()
integer function, public diag_axis_init(name, DATA, units, cart_name, long_name, direction, set_name, edges, Domain, Domain2, DomainU, aux, req, tile_count)
type(axistype), dimension(max_axis_num), save axis_types
integer function, public get_axis_length(id)
type(domainug), save, public null_domainug
logical, dimension(max_axis_num) time_axis_flag
type(domain2d) function, public get_domain2d(ids)
integer, dimension(max_axis_num) axis_in_file
integer function get_axis_index(num)
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************subroutine READ_RECORD_CORE_(unit, field, nwords, data, start, axsiz) integer, intent(in) ::unit type(fieldtype), intent(in) ::field integer, intent(in) ::nwords MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in) ::start(:), axsiz(:) integer(SHORT_KIND) ::i2vals(nwords)!rab used in conjunction with transfer intrinsic to determine size of a variable integer(KIND=1) ::one_byte(8) integer ::word_sz!#ifdef __sgi integer(INT_KIND) ::ivals(nwords) real(FLOAT_KIND) ::rvals(nwords)!#else! integer ::ivals(nwords)! real ::rvals(nwords)!#endif real(DOUBLE_KIND) ::r8vals(nwords) pointer(ptr1, i2vals) pointer(ptr2, ivals) pointer(ptr3, rvals) pointer(ptr4, r8vals) if(mpp_io_stack_size< nwords) call mpp_io_set_stack_size(nwords) call mpp_error(FATAL, 'MPP_READ currently requires use_netCDF option') end subroutine READ_RECORD_CORE_ subroutine READ_RECORD_(unit, field, nwords, data, time_level, domain, position, tile_count, start_in, axsiz_in)!routine that is finally called by all mpp_read routines to perform the read!a non-netCDF record contains:! field ID! a set of 4 coordinates(is:ie, js:je) giving the data subdomain! a timelevel and a timestamp(=NULLTIME if field is static)! 3D real data(stored as 1D)!if you are using direct access I/O, the RECL argument to OPEN must be large enough for the above!in a global direct access file, record position on PE is given by %record.!Treatment of timestamp:! We assume that static fields have been passed without a timestamp.! Here that is converted into a timestamp of NULLTIME.! For non-netCDF fields, field is treated no differently, but is written! with a timestamp of NULLTIME. There is no check in the code to prevent! the user from repeatedly writing a static field. integer, intent(in) ::unit, nwords type(fieldtype), intent(in) ::field MPP_TYPE_, intent(inout) ::data(nwords) integer, intent(in), optional ::time_level type(domain2D), intent(in), optional ::domain integer, intent(in), optional ::position, tile_count integer, intent(in), optional ::start_in(:), axsiz_in(:) integer, dimension(size(field%axes(:))) ::start, axsiz integer ::tlevel !, subdomain(4) integer ::i, error, is, ie, js, je, isg, ieg, jsg, jeg type(domain2d), pointer ::io_domain=> tlevel if(PRESENT(start_in) .AND. PRESENT(axsiz_in)) then if(size(start(! the data domain and compute domain must refer to the subdomain being passed ! In this ! since that attempts to gather all data on PE size(field%axes(:)) axsiz(i)
integer, dimension(2) missval
type(diag_fieldtype) function, public write_field_meta_data(file_unit, name, axes, units, long_name, range, pack, mval, avg_name, time_method, standard_name, interp_method, attributes, num_attributes, use_UGdomain)
integer current_file_unit
subroutine, public error_mesg(routine, message, level)
integer, parameter netcdf1
type(domain1d), save, public null_domain1d