27 MODULE diag_output_mod
30 use,
intrinsic :: iso_fortran_env, only: real128
31 use,
intrinsic :: iso_c_binding, only: c_double,c_float,c_int64_t, &
32 c_int32_t,c_int16_t,c_intptr_t
46 USE netcdf,
ONLY: nf90_int, nf90_float, nf90_char
48 use mpp_domains_mod,
only: mpp_get_ug_io_domain
49 use mpp_domains_mod,
only: mpp_get_ug_domain_npes
50 use mpp_domains_mod,
only: mpp_get_ug_domain_pelist
51 use mpp_mod,
only: uppercase,lowercase
60 TYPE(diag_global_att_type),
SAVE :: diag_global_att
62 INTEGER,
PARAMETER :: NETCDF1 = 1
63 INTEGER,
PARAMETER :: mxch = 128
64 INTEGER,
PARAMETER :: mxchl = 256
65 INTEGER :: current_file_unit = -1
66 INTEGER,
DIMENSION(2,2) :: max_range = reshape((/ -32767, 32767, -127, 127 /),(/2,2/))
67 INTEGER,
DIMENSION(2) :: missval = (/ -32768, -128 /)
69 INTEGER,
PARAMETER :: max_axis_num = 20
70 INTEGER :: num_axis_in_file = 0
71 INTEGER,
DIMENSION(max_axis_num) :: axis_in_file
72 LOGICAL,
DIMENSION(max_axis_num) :: time_axis_flag, edge_axis_flag
74 LOGICAL :: module_is_initialized = .false.
77 character(len=*),
parameter :: version =
'2020.03'
86 & domain, domainU, fileobj, fileobjU, fileobjND, fnum_domain, &
88 CHARACTER(len=*),
INTENT(in) :: file_name
89 CHARACTER(len=*),
INTENT(in) :: file_title
90 INTEGER ,
INTENT(out) :: file_unit
93 TYPE(
domain2d) ,
INTENT(in) :: domain
94 TYPE(
domainug) ,
INTENT(in) :: domainu
95 type(fmsnetcdfdomainfile_t),
intent(inout),
target :: fileobj
96 type(fmsnetcdfunstructureddomainfile_t),
intent(inout),
target :: fileobju
97 type(fmsnetcdffile_t),
intent(inout),
target :: fileobjnd
98 character(*),
intent(out) :: fnum_domain
102 TYPE(
diag_atttype),
INTENT(in),
OPTIONAL :: attributes(:)
104 class(fmsnetcdffile_t),
pointer :: fileob => null()
107 integer,
allocatable,
dimension(:) :: current_pelist
109 character(len=9) :: mype_string
110 character(len=FMS_FILE_LEN) :: filename_tile
114 IF ( .NOT.module_is_initialized )
THEN
115 module_is_initialized = .true.
120 if (domain .NE. null_domain2d .AND. domainu .NE. null_domainug)&
121 &
CALL error_mesg(
'diag_output_init',
"Domain2D and DomainUG can not be used at the same time in "//&
122 & trim(file_name), fatal)
125 IF ( domain .NE. null_domain2d )
THEN
129 if (.not.check_if_open(fileob))
call open_check(
open_file(fileobj, trim(file_name)//
".nc",
"overwrite", &
130 domain, is_restart=.false.))
136 write(mype_string,
'(I0.4)') mype
139 call get_mosaic_tile_file(file_name, filename_tile, .true., domain)
140 filename_tile = trim(filename_tile)//
"."//trim(mype_string)
142 if (.not.check_if_open(fileob))
then
143 call open_check(
open_file(fileobjnd, trim(filename_tile),
"overwrite", &
147 call register_global_attribute(fileobjnd,
"NumFilesInSet", 0)
150 if (file_unit < 0) file_unit = 10
152 ELSE IF (domainu .NE. null_domainug)
THEN
154 if (.not.check_if_open(fileob))
call open_check(
open_file(fileobju, trim(file_name)//
".nc",
"overwrite", &
155 domainu, is_restart=.false.))
160 allocate(current_pelist(
mpp_npes()))
162 if (.not.check_if_open(fileob))
then
163 call open_check(
open_file(fileobjnd, trim(file_name)//
".nc",
"overwrite", &
164 pelist=current_pelist, is_restart=.false.))
167 if (file_unit < 0) file_unit = 10
168 deallocate(current_pelist)
172 IF ( file_title(1:1) /=
' ' )
THEN
173 call register_global_attribute(fileob,
'title', trim(file_title), str_len=len_trim(file_title))
176 IF (
PRESENT(attributes) )
THEN
177 DO i=1,
SIZE(attributes)
178 SELECT CASE (attributes(i)%type)
180 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%iatt)
183 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%fatt)
186 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%catt, &
187 & str_len=len_trim(attributes(i)%catt))
193 CALL error_mesg(
'diag_output_mod::diag_output_init',
'Unknown attribute type for global attribute "'&
194 &//trim(attributes(i)%name)//
'" in file "'//trim(file_name)//
'". Contact the developers.', fatal)
201 call register_global_attribute(fileob,
'grid_type', trim(gatt%grid_type), str_len=len_trim(gatt%grid_type))
203 call register_global_attribute(fileob,
'grid_tile', trim(gatt%tile_name), str_len=len_trim(gatt%tile_name))
209 INTEGER,
INTENT(in) :: file_unit
210 INTEGER,
INTENT(in) :: axes(:)
211 class(fmsnetcdffile_t) ,
intent(inout) :: fileob
212 LOGICAL,
INTENT(in),
OPTIONAL :: time_ops
213 logical,
intent(inout) ,
optional :: time_axis_registered
219 CHARACTER(len=mxch) :: axis_name, axis_units, axis_name_current
220 CHARACTER(len=mxchl) :: axis_long_name
221 CHARACTER(len=1) :: axis_cart_name
222 INTEGER :: axis_direction, axis_edges
223 REAL,
ALLOCATABLE :: axis_data(:)
225 INTEGER :: num_attributes
226 TYPE(
diag_atttype),
DIMENSION(:),
ALLOCATABLE :: attributes
227 INTEGER :: calendar, id_axis, id_time_axis
228 INTEGER :: i, j, index, num, length, edges_index
231 CHARACTER(len=2048) :: err_msg
232 integer :: id_axis_current
233 logical :: is_time_axis_registered
234 integer :: istart, iend
235 integer :: gstart, cstart, cend
237 character(len=32) :: type_str
241 IF (
PRESENT(time_ops) )
THEN
246 if (
present(time_axis_registered))
then
247 is_time_axis_registered = time_axis_registered
249 is_time_axis_registered = .false.
252 IF ( num_axis_in_file == 0 ) current_file_unit = file_unit
257 IF ( num < 1 )
CALL error_mesg(
'write_axis_meta_data',
'number of axes < 1.', fatal)
260 IF ( file_unit /= current_file_unit )
CALL error_mesg(
'write_axis_meta_data',&
261 &
'writing meta data out-of-order to different files.', fatal)
276 IF ( index > 0 ) cycle
279 num_axis_in_file = num_axis_in_file + 1
280 axis_in_file(num_axis_in_file) = id_axis
281 edge_axis_flag(num_axis_in_file) = .false.
283 ALLOCATE(axis_data(length))
285 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name,&
286 & axis_cart_name, axis_direction, axis_edges, domain, domainu, axis_data,&
287 & num_attributes, attributes, domain_position=axis_pos)
289 IF ( domain .NE. null_domain1d )
THEN
291 type is (fmsnetcdffile_t)
296 iend = cend - gstart + 1
297 istart = cstart - gstart + 1
298 call register_axis(fileob, axis_name, dimension_length=clength)
299 call register_field(fileob, axis_name, type_str, (/axis_name/) )
303 call register_variable_attribute(fileob, axis_name,
"domain_decomposition", &
304 (/gstart, gend, cstart, cend/))
305 type is (fmsnetcdfdomainfile_t)
309 call register_axis(fileob, axis_name, lowercase(trim(axis_cart_name)), domain_position=axis_pos )
310 call get_global_io_domain_indices(fileob, trim(axis_name), istart, iend)
311 call register_field(fileob, axis_name, type_str, (/axis_name/) )
314 ELSE IF ( domainu .NE. null_domainug)
THEN
316 type is (fmsnetcdfunstructureddomainfile_t)
320 call register_axis(fileob, axis_name )
322 call register_field(fileob, axis_name, type_str, (/axis_name/) )
323 istart = lbound(axis_data,1)
324 iend = ubound(axis_data,1)
327 call register_axis(fileob, axis_name, dimension_length=
size(axis_data))
328 call register_field(fileob, axis_name, type_str, (/axis_name/) )
329 istart = lbound(axis_data,1)
330 iend = ubound(axis_data,1)
333 if (length <= 0)
then
339 is_time_axis_registered = variable_exists(fileob,trim(axis_name),.true.)
340 if (.not. is_time_axis_registered)
then
341 call register_axis(fileob, trim(axis_name), unlimited )
342 call register_field(fileob, axis_name, type_str, (/axis_name/) )
343 is_time_axis_registered = .true.
344 if (
present(time_axis_registered)) time_axis_registered = is_time_axis_registered
349 if(trim(axis_units) .ne.
"none")
call register_variable_attribute(fileob, axis_name,
"units", &
350 & trim(axis_units), str_len=len_trim(axis_units))
351 call register_variable_attribute(fileob, axis_name,
"long_name", trim(axis_long_name), &
352 & str_len=len_trim(axis_long_name))
353 if(trim(axis_cart_name).ne.
"N")
call register_variable_attribute(fileob, axis_name,
"axis", &
354 & trim(axis_cart_name), str_len=len_trim(axis_cart_name))
356 if (length > 0 )
then
358 select case (axis_direction)
360 call register_variable_attribute(fileob, axis_name,
"positive",
"up", str_len=len_trim(
"up"))
362 call register_variable_attribute(fileob, axis_name,
"positive",
"down", str_len=len_trim(
"down"))
364 call write_data(fileob, axis_name, axis_data(istart:iend) )
368 CALL write_attribute_meta(file_unit, num_attributes, attributes, err_msg, varname=axis_name, fileob=fileob)
369 IF ( len_trim(err_msg) .GT. 0 )
THEN
370 CALL error_mesg(
'diag_output_mod::write_axis_meta_data', trim(err_msg), fatal)
376 IF ( axis_cart_name ==
'T' )
THEN
377 time_axis_flag(num_axis_in_file) = .true.
378 id_time_axis = num_axis_in_file
379 calendar = get_calendar_type()
382 call register_variable_attribute(fileob, axis_name,
"calendar_type", &
383 uppercase(trim(valid_calendar_types(calendar))), &
384 & str_len=len_trim(valid_calendar_types(calendar)) )
385 call register_variable_attribute(fileob, axis_name,
"calendar", &
386 lowercase(trim(valid_calendar_types(calendar))), &
387 & str_len=len_trim(valid_calendar_types(calendar)) )
388 IF ( time_ops1 )
THEN
389 call register_variable_attribute(fileob, axis_name,
'bounds', trim(axis_name)//
'_bnds', &
390 & str_len=len_trim(trim(axis_name)//
'_bnds'))
392 call set_fileobj_time_name(fileob, axis_name)
394 time_axis_flag(num_axis_in_file) = .false.
397 DEALLOCATE(axis_data)
400 IF (
ALLOCATED(attributes) )
THEN
401 DO j=1, num_attributes
402 IF (
allocated(attributes(j)%fatt ) )
THEN
403 DEALLOCATE(attributes(j)%fatt)
405 IF (
allocated(attributes(j)%iatt ) )
THEN
406 DEALLOCATE(attributes(j)%iatt)
409 DEALLOCATE(attributes)
415 IF ( axis_edges <= 0 ) cycle
418 id_axis_current = id_axis
419 axis_name_current = axis_name
422 IF ( edges_index > 0 ) cycle
425 length = get_axis_global_length( id_axis )
426 ALLOCATE(axis_data(length))
427 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name, axis_cart_name,&
428 & axis_direction, axis_edges, domain, domainu, axis_data)
431 call register_variable_attribute(fileob, axis_name_current,
"edges",trim(axis_name), &
432 & str_len=len_trim(axis_name))
435 num_axis_in_file = num_axis_in_file + 1
436 axis_in_file(num_axis_in_file) = id_axis
437 edge_axis_flag(num_axis_in_file) = .true.
438 time_axis_flag(num_axis_in_file) = .false.
441 if (.not.variable_exists(fileob, axis_name))
then
442 call register_axis(fileob, axis_name,
size(axis_data) )
443 call register_field(fileob, axis_name, type_str, (/axis_name/) )
444 if(trim(axis_units) .ne.
"none")
call register_variable_attribute(fileob, axis_name,
"units", &
445 & trim(axis_units), str_len=len_trim(axis_units))
446 call register_variable_attribute(fileob, axis_name,
"long_name", trim(axis_long_name), &
447 & str_len=len_trim(axis_long_name))
448 if(trim(axis_cart_name).ne.
"N")
call register_variable_attribute(fileob, axis_name,
"axis", &
449 & trim(axis_cart_name), str_len=len_trim(axis_cart_name))
450 select case (axis_direction)
452 call register_variable_attribute(fileob, axis_name,
"positive",
"up", str_len=len_trim(
"up"))
454 call register_variable_attribute(fileob, axis_name,
"positive",
"down", str_len=len_trim(
"down"))
456 call write_data(fileob, axis_name, axis_data)
459 DEALLOCATE (axis_data)
467 & avg_name, time_method, standard_name, interp_method, attributes, num_attributes, &
468 & use_UGdomain, fileob)
result ( Field )
469 INTEGER,
INTENT(in) :: file_unit
470 INTEGER,
INTENT(in) :: axes(:)
471 CHARACTER(len=*),
INTENT(in) :: name
472 CHARACTER(len=*),
INTENT(in) :: units
473 CHARACTER(len=*),
INTENT(in) :: long_name
474 REAL,
OPTIONAL,
INTENT(in) :: range(2)
475 REAL,
OPTIONAL,
INTENT(in) :: mval
476 INTEGER,
OPTIONAL,
INTENT(in) :: pack
483 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: avg_name
484 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: time_method
486 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: standard_name
487 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: interp_method
488 TYPE(diag_atttype),
DIMENSION(:),
allocatable,
OPTIONAL,
INTENT(in) :: attributes
489 INTEGER,
OPTIONAL,
INTENT(in) :: num_attributes
490 LOGICAL,
OPTIONAL,
INTENT(in) :: use_ugdomain
491 class(fmsnetcdffile_t),
intent(inout) :: fileob
493 logical :: is_time_bounds
494 CHARACTER(len=256) :: standard_name2
495 TYPE(diag_fieldtype) :: field
496 LOGICAL :: coord_present
497 CHARACTER(len=128) :: aux_axes(size(axes))
498 CHARACTER(len=160) :: coord_att
499 CHARACTER(len=1024) :: err_msg
501 character(len=128),
dimension(size(axes)) :: axis_names
503 INTEGER :: i, indexx, num, ipack, np
505 INTEGER :: axis_indices(size(axes))
506 logical :: use_ugdomain_local
511 coord_present = .false.
512 IF(
PRESENT(standard_name) )
THEN
513 standard_name2 = standard_name
515 standard_name2 =
'none'
518 use_ugdomain_local = .false.
519 if(
present(use_ugdomain)) use_ugdomain_local = use_ugdomain
523 IF ( num < 1 )
CALL error_mesg (
'write_meta_data',
'number of axes < 1', fatal)
525 IF ( file_unit /= current_file_unit )
CALL error_mesg (
'write_meta_data', &
526 &
'writing meta data out-of-order to different files', fatal)
528 IF (trim(name) .eq.
"time_bnds")
then
529 is_time_bounds = .true.
531 is_time_bounds = .false.
539 IF ( indexx > 0 )
THEN
540 axis_indices(i) = indexx
543 CALL error_mesg (
'write_field_meta_data',&
544 &
'axis data not written for field '//trim(name), fatal)
547 call get_diag_axis_name(axes(i),axis_names(i))
551 IF ( num >= 2 .OR. (num==1 .and. use_ugdomain_local) )
THEN
554 aux_axes(i) = get_axis_aux(axes(i))
555 IF( trim(aux_axes(i)) /=
'none' )
THEN
556 IF(len_trim(coord_att) == 0)
THEN
557 coord_att = trim(aux_axes(i))
559 coord_att = trim(coord_att)//
' '//trim(aux_axes(i))
561 coord_present = .true.
570 IF (
PRESENT(pack) )
THEN
580 IF (
PRESENT(range) )
THEN
581 IF ( range(2) > range(1) )
THEN
584 IF ( ipack > 2 )
THEN
586 add = 0.5*(range(1)+range(2))
587 scale = (range(2)-range(1)) / real(max_range(2,np)-max_range(1,np))
593 IF (
PRESENT(mval) )
THEN
595 field%miss_present = .true.
596 IF ( ipack > 2 )
THEN
598 field%miss_pack = real(missval(np))*scale+add
599 field%miss_pack_present = .true.
601 field%miss_pack = mval
602 field%miss_pack_present = .false.
605 field%miss_present = .false.
606 field%miss_pack_present = .false.
610 field%fieldname = name
612 if (.not. variable_exists(fileob,name))
then
620 call register_field(fileob,name,
"double",axis_names)
623 if (.not. is_time_bounds)
then
624 IF ( field%miss_present )
THEN
625 call register_variable_attribute(fileob,name,
"_FillValue",real(field%miss_pack,8))
626 call register_variable_attribute(fileob,name,
"missing_value",real(field%miss_pack,8))
628 call register_variable_attribute(fileob,name,
"_FillValue",real(cmor_missing_value,8))
629 call register_variable_attribute(fileob,name,
"missing_value",real(cmor_missing_value,8))
631 IF ( use_range )
then
632 call register_variable_attribute(fileob,name,
"valid_range", real(range,8))
636 call register_field(fileob,name,
"float",axis_names)
639 if (.not. is_time_bounds)
then
640 IF ( field%miss_present )
THEN
641 call register_variable_attribute(fileob,name,
"_FillValue",real(field%miss_pack,4))
642 call register_variable_attribute(fileob,name,
"missing_value",real(field%miss_pack,4))
644 call register_variable_attribute(fileob,name,
"_FillValue",real(cmor_missing_value,4))
645 call register_variable_attribute(fileob,name,
"missing_value",real(cmor_missing_value,4))
647 IF ( use_range )
then
648 call register_variable_attribute(fileob,name,
"valid_range", real(range,4))
652 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
653 &
"Pack values must be 1 or 2. Contact the developers.", fatal)
655 if (trim(units) .ne.
"none")
call register_variable_attribute(fileob,name,
"units",trim(units), &
656 & str_len=len_trim(units))
657 call register_variable_attribute(fileob,name,
"long_name",long_name, str_len=len_trim(long_name))
658 IF (
present(time_method) )
then
659 call register_variable_attribute(fileob,name,
'cell_methods',
'time: '//trim(time_method), &
660 & str_len=len_trim(
'time: '//trim(time_method)))
664 IF (
PRESENT(num_attributes) )
THEN
665 IF (
PRESENT(attributes) )
THEN
666 IF ( num_attributes .GT. 0 .AND.
allocated(attributes) )
THEN
668 & fileob=fileob, varname=name)
669 IF ( len_trim(err_msg) .GT. 0 )
THEN
670 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
671 & trim(err_msg)//
" Contact the developers.", fatal)
675 IF ( num_attributes .GT. 0 .AND. .NOT.
allocated(attributes) )
THEN
676 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
677 &
'num_attributes > 0 but attributes is not allocated for attribute '&
678 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
679 ELSE IF ( num_attributes .EQ. 0 .AND.
allocated(attributes) )
THEN
680 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
681 &
'num_attributes == 0 but attributes is allocated for attribute '&
682 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
687 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
688 &
'num_attributes present but attributes missing for attribute '&
689 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
691 ELSE IF (
PRESENT(attributes) )
THEN
692 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
693 &
'attributes present but num_attributes missing for attribute '&
694 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
698 IF (
PRESENT(avg_name) )
THEN
699 IF ( avg_name(1:1) /=
' ' )
THEN
700 call register_variable_attribute(fileob,name,
'time_avg_info',&
701 & trim(avg_name)//
'_T1,'//trim(avg_name)//
'_T2,'//trim(avg_name)//
'_DT', &
702 & str_len=len_trim(trim(avg_name)//
'_T1,'//trim(avg_name)//
'_T2,'//trim(avg_name)//
'_DT'))
707 IF ( coord_present )
then
708 call register_variable_attribute(fileob,name,
'coordinates',trim(coord_att), str_len=len_trim(coord_att))
710 IF ( trim(standard_name2) /=
'none' )
then
711 call register_variable_attribute(fileob,name,
'standard_name',trim(standard_name2), &
712 & str_len=len_trim(standard_name2))
715 IF(
PRESENT(interp_method) )
THEN
716 call register_variable_attribute(fileob,name,
'interp_method', trim(interp_method), &
717 & str_len=len_trim(interp_method))
721 field%Domain = get_domain2d( axes )
722 field%tile_count = get_tile_count( axes )
723 field%DomainU = get_domainug( axes(1) )
731 INTEGER,
INTENT(in) :: file_unit
732 INTEGER,
INTENT(in) :: num_attributes
733 TYPE(diag_atttype),
DIMENSION(:),
INTENT(in) :: attributes
734 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: time_method
735 CHARACTER(len=*),
INTENT(out),
OPTIONAL :: err_msg
736 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: varname
737 class(fmsnetcdffile_t),
intent(inout) :: fileob
739 INTEGER :: i, att_len
740 CHARACTER(len=1280) :: att_str
743 IF (
PRESENT(err_msg) ) err_msg =
''
745 DO i = 1, num_attributes
746 SELECT CASE (attributes(i)%type)
748 IF ( .NOT.
allocated(attributes(i)%iatt) )
THEN
749 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',&
750 &
'Integer attribute type indicated, but array not allocated for attribute '&
751 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
755 if (
present(varname))
call register_variable_attribute(fileob, varname,trim(attributes(i)%name), &
756 & attributes(i)%iatt)
758 IF ( .NOT.
allocated(attributes(i)%fatt) )
THEN
759 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',&
760 &
'Real attribute type indicated, but array not allocated for attribute '&
761 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
765 if (
present(varname))
call register_variable_attribute(fileob, varname,trim(attributes(i)%name), &
766 & real(attributes(i)%fatt,4) )
768 att_str = attributes(i)%catt
769 att_len = attributes(i)%len
770 IF ( trim(attributes(i)%name).EQ.
'cell_methods' .AND.
PRESENT(time_method) )
THEN
772 att_str = attributes(i)%catt(1:attributes(i)%len)//
' time: '//time_method
773 att_len = len_trim(att_str)
775 if (
present(varname))&
776 call register_variable_attribute(fileob, varname,trim(attributes(i)%name) , att_str(1:att_len), &
780 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',
'Invalid type for attribute '&
781 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
793 INTEGER,
INTENT(in) :: file_unit
800 subroutine diag_field_write (varname, buffer, static, file_num, fileobjU, fileobj, fileobjND, &
801 & fnum_for_domain, time_in)
802 CHARACTER(len=*),
INTENT(in) :: varname
803 REAL ,
INTENT(inout) :: buffer(:,:,:,:)
804 logical,
intent(in) :: static
805 integer,
intent(in) :: file_num
806 type(fmsnetcdfunstructureddomainfile_t),
intent(inout) :: fileobju(:)
807 type(fmsnetcdfdomainfile_t),
intent(inout) :: fileobj(:)
808 type(fmsnetcdffile_t),
intent(inout) :: fileobjnd(:)
809 character(len=2),
intent(in) :: fnum_for_domain
813 INTEGER,
OPTIONAL,
INTENT(in) :: time_in
816 real,
allocatable :: local_buffer(:,:,:,:)
821 elseif (
present(time_in))
then
827 if (
size(buffer,3) .eq. 1 .and.
size(buffer,2) .eq. 1)
then
830 allocate(local_buffer(
size(buffer,1),
size(buffer,4),
size(buffer,2),
size(buffer,3)))
831 local_buffer(:,:,1,1) = buffer(:,1,1,:)
832 else if (
size(buffer,3) .eq. 1)
then
835 allocate(local_buffer(
size(buffer,1),
size(buffer,2),
size(buffer,4),
size(buffer,3)))
836 local_buffer(:,:,:,1) = buffer(:,:,1,:)
838 allocate(local_buffer(
size(buffer,1),
size(buffer,2),
size(buffer,3),
size(buffer,4)))
839 local_buffer = buffer(:,:,:,:)
843 if (fnum_for_domain ==
"2d" )
then
844 if (check_if_open(fileobj(file_num)))
then
845 call write_data (fileobj(file_num), trim(varname), local_buffer, unlim_dim_level=time )
847 elseif (fnum_for_domain ==
"nd")
then
848 if (check_if_open(fileobjnd(file_num)) )
then
849 call write_data (fileobjnd(file_num), trim(varname), local_buffer, unlim_dim_level=time)
851 elseif (fnum_for_domain ==
"ug")
then
852 if (check_if_open(fileobju(file_num)))
then
853 call write_data (fileobju(file_num), trim(varname), local_buffer, unlim_dim_level=time)
856 call error_mesg(
"diag_field_write",
"fnum_for_domain must be '2d', 'nd', or 'ug'",fatal)
859 deallocate(local_buffer)
864 class(fmsnetcdffile_t),
intent(inout) :: fileob
865 real,
intent(in) :: rtime_value
866 integer,
intent(in) :: time_index
867 character(len=*),
intent(in),
optional :: time_name
868 character(len=:),
allocatable :: name_time
871 if (
present(time_name))
then
872 allocate(
character(len=len(time_name)) :: name_time)
873 name_time = time_name
875 allocate(
character(len=4) :: name_time)
879 call write_data (fileob, trim(name_time), rtime_value, unlim_dim_level=time_index)
881 if (
allocated(name_time))
deallocate(name_time)
887 INTEGER,
INTENT(in) :: num
896 DO i = 1, num_axis_in_file
897 IF ( num == axis_in_file(i) )
THEN
906 TYPE(diag_global_att_type),
INTENT(out) :: gatt
913 CHARACTER(len=*),
INTENT(in) :: component, gridtype, tilename
917 CHARACTER(len=64) :: component_tmp
918 component_tmp = component
922 diag_global_att%grid_type = gridtype
923 diag_global_att%tile_name = tilename
928 subroutine diag_flush(file_num, fileobjU, fileobj, fileobjND, fnum_for_domain)
929 integer,
intent(in) :: file_num
930 type(fmsnetcdfunstructureddomainfile_t),
intent(inout) :: fileobju(:)
931 type(fmsnetcdfdomainfile_t),
intent(inout) :: fileobj(:)
932 type(fmsnetcdffile_t),
intent(inout) :: fileobjnd(:)
933 character(len=2),
intent(in) :: fnum_for_domain
937 if (fnum_for_domain ==
"2d" )
then
938 call flush_file (fileobj(file_num))
939 elseif (fnum_for_domain ==
"nd")
then
940 call flush_file (fileobjnd(file_num))
941 elseif (fnum_for_domain ==
"ug")
then
942 call flush_file (fileobju(file_num))
944 call error_mesg(
"diag_field_write",
"No file object is associated with this file number",fatal)
947 END MODULE diag_output_mod
integer function, public get_axis_length(id)
Return the length of the axis.
subroutine, public get_diag_axis(id, name, units, long_name, cart_name, direction, edges, Domain, DomainU, array_data, num_attributes, attributes, domain_position)
Return information about the axis with index ID.
integer function, public get_axis_global_length(id)
Return the global length of the axis.
type(domain2d) function, public get_domain2d(ids)
Return the 2D domain for the axis IDs given.
type(domainug) function, public get_domainug(id)
Retrun the 1D domain for the axis ID given.
integer function, public get_tile_count(ids)
Return the tile count for the axis.
subroutine, public get_diag_axis_name(id, axis_name)
Return the short name of the axis.
character(len=128) function, public get_axis_aux(id)
Return the auxiliary name for the axis.
integer function, public diag_axis_init(name, array_data, units, cart_name, long_name, direction, set_name, edges, Domain, Domain2, DomainU, aux, req, tile_count, domain_position)
Initialize the axis, and return the axis ID.
type(domain1d) function, public get_domain1d(id)
Retrun the 1D domain for the axis ID given.
integer pack_size
1 for double and 2 for float
real(r8_kind), parameter cmor_missing_value
CMOR standard missing value.
Attribute type for diagnostic fields.
subroutine, public diag_field_write(varname, buffer, static, file_num, fileobjU, fileobj, fileobjND, fnum_for_domain, time_in)
Writes diagnostic data out using fms2_io routine.
subroutine, public diag_output_init(file_name, file_title, file_unit, domain, domainU, fileobj, fileobjU, fileobjND, fnum_domain, attributes)
Opens the output file.
subroutine, public get_diag_global_att(gAtt)
Return the global attribute type.
subroutine, public set_diag_global_att(component, gridType, tileName)
Set the global attribute type.
subroutine, public diag_flush(file_num, fileobjU, fileobj, fileobjND, fnum_for_domain)
Flushes the file into disk.
integer function get_axis_index(num)
Return the axis index number.
subroutine write_attribute_meta(file_unit, num_attributes, attributes, time_method, err_msg, varname, fileob)
Write out attribute meta data to file.
subroutine, public done_meta_data(file_unit)
Writes axis data to file.
subroutine, public diag_write_time(fileob, rtime_value, time_index, time_name)
Writes the time data to the history file.
subroutine, public write_axis_meta_data(file_unit, axes, fileob, time_ops, time_axis_registered)
Write the axis meta data to file.
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, fileob)
Write the field meta data to file.
Opens a NetCDF dataset on disk and initializes the file object.
subroutine, public write_version_number(version, tag, unit)
Prints to the log file (or a specified unit) the version id string and tag name.
logical function, public fms_error_handler(routine, message, err_msg)
Facilitates the control of fatal error conditions.
subroutine, public error_mesg(routine, message, level)
Print notes, warnings and error messages; terminates program for warning and error messages....
type(domain2d) function, pointer mpp_get_io_domain(domain)
Set user stack size.
Set up a domain decomposition.
These routines retrieve the axis specifications associated with the compute domains....
Retrieve the entire array of compute domain extents associated with a decomposition.
These routines retrieve the axis specifications associated with the global domains....
Retrieve layout associated with a domain decomposition The 1D version of this call returns the number...
Retrieve list of PEs associated with a domain decomposition. The 1D version of this call returns an a...
One dimensional domain used to manage shared data access between pes.
The domain2D type contains all the necessary information to define the global, compute and data domai...
Domain information for managing data on unstructured grids.
integer function mpp_npes()
Returns processor count for current pelist.
integer function mpp_pe()
Returns processor ID.
character(len=24) function, public valid_calendar_types(ncal, err_msg)
Returns a character string that describes the calendar type corresponding to the input integer.
integer function, public get_calendar_type()
Returns default calendar type for mapping from time to date.
Get the current pelist. The two flavors of this subroutine differ in the type of their comm/commID ar...