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
38 USE mpp_mod,
ONLY:
mpp_npes,
mpp_pe, mpp_root_pe, mpp_get_current_pelist
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
52 use mpp_mod,
only: uppercase,lowercase
61 TYPE(diag_global_att_type),
SAVE :: diag_global_att
63 INTEGER,
PARAMETER :: NETCDF1 = 1
64 INTEGER,
PARAMETER :: mxch = 128
65 INTEGER,
PARAMETER :: mxchl = 256
66 INTEGER :: current_file_unit = -1
67 INTEGER,
DIMENSION(2,2) :: max_range = reshape((/ -32767, 32767, -127, 127 /),(/2,2/))
68 INTEGER,
DIMENSION(2) :: missval = (/ -32768, -128 /)
70 INTEGER,
PARAMETER :: max_axis_num = 20
71 INTEGER :: num_axis_in_file = 0
72 INTEGER,
DIMENSION(max_axis_num) :: axis_in_file
73 LOGICAL,
DIMENSION(max_axis_num) :: time_axis_flag, edge_axis_flag
75 LOGICAL :: module_is_initialized = .false.
78 character(len=*),
parameter :: version =
'2020.03'
87 & domain, domainU, fileobj, fileobjU, fileobjND, fnum_domain, &
89 CHARACTER(len=*),
INTENT(in) :: file_name
90 CHARACTER(len=*),
INTENT(in) :: file_title
91 INTEGER ,
INTENT(out) :: file_unit
94 TYPE(
domain2d) ,
INTENT(in) :: domain
95 TYPE(
domainug) ,
INTENT(in) :: domainu
96 type(fmsnetcdfdomainfile_t),
intent(inout),
target :: fileobj
97 type(fmsnetcdfunstructureddomainfile_t),
intent(inout),
target :: fileobju
98 type(fmsnetcdffile_t),
intent(inout),
target :: fileobjnd
99 character(*),
intent(out) :: fnum_domain
103 TYPE(
diag_atttype),
INTENT(in),
OPTIONAL :: attributes(:)
105 class(fmsnetcdffile_t),
pointer :: fileob => null()
108 integer,
allocatable,
dimension(:) :: current_pelist
110 character(len=9) :: mype_string
111 character(len=FMS_FILE_LEN) :: filename_tile
115 IF ( .NOT.module_is_initialized )
THEN
116 module_is_initialized = .true.
121 if (domain .NE. null_domain2d .AND. domainu .NE. null_domainug)&
122 &
CALL error_mesg(
'diag_output_init',
"Domain2D and DomainUG can not be used at the same time in "//&
123 & trim(file_name), fatal)
126 IF ( domain .NE. null_domain2d )
THEN
130 if (.not.check_if_open(fileob))
call open_check(
open_file(fileobj, trim(file_name)//
".nc",
"overwrite", &
131 domain, is_restart=.false.))
137 write(mype_string,
'(I0.4)') mype
140 call get_mosaic_tile_file(file_name, filename_tile, .true., domain)
141 filename_tile = trim(filename_tile)//
"."//trim(mype_string)
143 if (.not.check_if_open(fileob))
then
144 call open_check(
open_file(fileobjnd, trim(filename_tile),
"overwrite", &
148 call register_global_attribute(fileobjnd,
"NumFilesInSet", 0)
151 if (file_unit < 0) file_unit = 10
153 ELSE IF (domainu .NE. null_domainug)
THEN
155 if (.not.check_if_open(fileob))
call open_check(
open_file(fileobju, trim(file_name)//
".nc",
"overwrite", &
156 domainu, is_restart=.false.))
161 allocate(current_pelist(
mpp_npes()))
162 call mpp_get_current_pelist(current_pelist)
163 if (.not.check_if_open(fileob))
then
164 call open_check(
open_file(fileobjnd, trim(file_name)//
".nc",
"overwrite", &
165 pelist=current_pelist, is_restart=.false.))
168 if (file_unit < 0) file_unit = 10
169 deallocate(current_pelist)
173 IF ( file_title(1:1) /=
' ' )
THEN
174 call register_global_attribute(fileob,
'title', trim(file_title), str_len=len_trim(file_title))
177 IF (
PRESENT(attributes) )
THEN
178 DO i=1,
SIZE(attributes)
179 SELECT CASE (attributes(i)%type)
181 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%iatt)
184 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%fatt)
187 call register_global_attribute(fileob, trim(attributes(i)%name), attributes(i)%catt, &
188 & str_len=len_trim(attributes(i)%catt))
194 CALL error_mesg(
'diag_output_mod::diag_output_init',
'Unknown attribute type for global attribute "'&
195 &//trim(attributes(i)%name)//
'" in file "'//trim(file_name)//
'". Contact the developers.', fatal)
202 call register_global_attribute(fileob,
'grid_type', trim(gatt%grid_type), str_len=len_trim(gatt%grid_type))
204 call register_global_attribute(fileob,
'grid_tile', trim(gatt%tile_name), str_len=len_trim(gatt%tile_name))
210 INTEGER,
INTENT(in) :: file_unit
211 INTEGER,
INTENT(in) :: axes(:)
212 class(fmsnetcdffile_t) ,
intent(inout) :: fileob
213 LOGICAL,
INTENT(in),
OPTIONAL :: time_ops
214 logical,
intent(inout) ,
optional :: time_axis_registered
220 CHARACTER(len=mxch) :: axis_name, axis_units, axis_name_current
221 CHARACTER(len=mxchl) :: axis_long_name
222 CHARACTER(len=1) :: axis_cart_name
223 INTEGER :: axis_direction, axis_edges
224 REAL,
ALLOCATABLE :: axis_data(:)
226 INTEGER :: num_attributes
227 TYPE(
diag_atttype),
DIMENSION(:),
ALLOCATABLE :: attributes
228 INTEGER :: calendar, id_axis, id_time_axis
229 INTEGER :: i, j, index, num, length, edges_index
232 CHARACTER(len=2048) :: err_msg
233 integer :: id_axis_current
234 logical :: is_time_axis_registered
235 integer :: istart, iend
236 integer :: gstart, cstart, cend
238 character(len=32) :: type_str
242 IF (
PRESENT(time_ops) )
THEN
247 if (
present(time_axis_registered))
then
248 is_time_axis_registered = time_axis_registered
250 is_time_axis_registered = .false.
253 IF ( num_axis_in_file == 0 ) current_file_unit = file_unit
258 IF ( num < 1 )
CALL error_mesg(
'write_axis_meta_data',
'number of axes < 1.', fatal)
261 IF ( file_unit /= current_file_unit )
CALL error_mesg(
'write_axis_meta_data',&
262 &
'writing meta data out-of-order to different files.', fatal)
277 IF ( index > 0 ) cycle
280 num_axis_in_file = num_axis_in_file + 1
281 axis_in_file(num_axis_in_file) = id_axis
282 edge_axis_flag(num_axis_in_file) = .false.
284 ALLOCATE(axis_data(length))
286 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name,&
287 & axis_cart_name, axis_direction, axis_edges, domain, domainu, axis_data,&
288 & num_attributes, attributes, domain_position=axis_pos)
290 IF ( domain .NE. null_domain1d )
THEN
292 type is (fmsnetcdffile_t)
297 iend = cend - gstart + 1
298 istart = cstart - gstart + 1
299 call register_axis(fileob, axis_name, dimension_length=clength)
300 call register_field(fileob, axis_name, type_str, (/axis_name/) )
304 call register_variable_attribute(fileob, axis_name,
"domain_decomposition", &
305 (/gstart, gend, cstart, cend/))
306 type is (fmsnetcdfdomainfile_t)
310 call register_axis(fileob, axis_name, lowercase(trim(axis_cart_name)), domain_position=axis_pos )
311 call get_global_io_domain_indices(fileob, trim(axis_name), istart, iend)
312 call register_field(fileob, axis_name, type_str, (/axis_name/) )
315 ELSE IF ( domainu .NE. null_domainug)
THEN
317 type is (fmsnetcdfunstructureddomainfile_t)
321 call register_axis(fileob, axis_name )
323 call register_field(fileob, axis_name, type_str, (/axis_name/) )
324 istart = lbound(axis_data,1)
325 iend = ubound(axis_data,1)
328 call register_axis(fileob, axis_name, dimension_length=
size(axis_data))
329 call register_field(fileob, axis_name, type_str, (/axis_name/) )
330 istart = lbound(axis_data,1)
331 iend = ubound(axis_data,1)
334 if (length <= 0)
then
340 is_time_axis_registered = variable_exists(fileob,trim(axis_name),.true.)
341 if (.not. is_time_axis_registered)
then
342 call register_axis(fileob, trim(axis_name), unlimited )
343 call register_field(fileob, axis_name, type_str, (/axis_name/) )
344 is_time_axis_registered = .true.
345 if (
present(time_axis_registered)) time_axis_registered = is_time_axis_registered
350 if(trim(axis_units) .ne.
"none")
call register_variable_attribute(fileob, axis_name,
"units", &
351 & trim(axis_units), str_len=len_trim(axis_units))
352 call register_variable_attribute(fileob, axis_name,
"long_name", trim(axis_long_name), &
353 & str_len=len_trim(axis_long_name))
354 if(trim(axis_cart_name).ne.
"N")
call register_variable_attribute(fileob, axis_name,
"axis", &
355 & trim(axis_cart_name), str_len=len_trim(axis_cart_name))
357 if (length > 0 )
then
359 select case (axis_direction)
361 call register_variable_attribute(fileob, axis_name,
"positive",
"up", str_len=len_trim(
"up"))
363 call register_variable_attribute(fileob, axis_name,
"positive",
"down", str_len=len_trim(
"down"))
365 call write_data(fileob, axis_name, axis_data(istart:iend) )
369 CALL write_attribute_meta(file_unit, num_attributes, attributes, err_msg, varname=axis_name, fileob=fileob)
370 IF ( len_trim(err_msg) .GT. 0 )
THEN
371 CALL error_mesg(
'diag_output_mod::write_axis_meta_data', trim(err_msg), fatal)
377 IF ( axis_cart_name ==
'T' )
THEN
378 time_axis_flag(num_axis_in_file) = .true.
379 id_time_axis = num_axis_in_file
380 calendar = get_calendar_type()
383 call register_variable_attribute(fileob, axis_name,
"calendar_type", &
384 uppercase(trim(valid_calendar_types(calendar))), &
385 & str_len=len_trim(valid_calendar_types(calendar)) )
386 call register_variable_attribute(fileob, axis_name,
"calendar", &
387 lowercase(trim(valid_calendar_types(calendar))), &
388 & str_len=len_trim(valid_calendar_types(calendar)) )
389 IF ( time_ops1 )
THEN
390 call register_variable_attribute(fileob, axis_name,
'bounds', trim(axis_name)//
'_bnds', &
391 & str_len=len_trim(trim(axis_name)//
'_bnds'))
393 call set_fileobj_time_name(fileob, axis_name)
395 time_axis_flag(num_axis_in_file) = .false.
398 DEALLOCATE(axis_data)
401 IF (
ALLOCATED(attributes) )
THEN
402 DO j=1, num_attributes
403 IF (
allocated(attributes(j)%fatt ) )
THEN
404 DEALLOCATE(attributes(j)%fatt)
406 IF (
allocated(attributes(j)%iatt ) )
THEN
407 DEALLOCATE(attributes(j)%iatt)
410 DEALLOCATE(attributes)
416 IF ( axis_edges <= 0 ) cycle
419 id_axis_current = id_axis
420 axis_name_current = axis_name
423 IF ( edges_index > 0 ) cycle
426 length = get_axis_global_length( id_axis )
427 ALLOCATE(axis_data(length))
428 CALL get_diag_axis(id_axis, axis_name, axis_units, axis_long_name, axis_cart_name,&
429 & axis_direction, axis_edges, domain, domainu, axis_data)
432 call register_variable_attribute(fileob, axis_name_current,
"edges",trim(axis_name), &
433 & str_len=len_trim(axis_name))
436 num_axis_in_file = num_axis_in_file + 1
437 axis_in_file(num_axis_in_file) = id_axis
438 edge_axis_flag(num_axis_in_file) = .true.
439 time_axis_flag(num_axis_in_file) = .false.
442 if (.not.variable_exists(fileob, axis_name))
then
443 call register_axis(fileob, axis_name,
size(axis_data) )
444 call register_field(fileob, axis_name, type_str, (/axis_name/) )
445 if(trim(axis_units) .ne.
"none")
call register_variable_attribute(fileob, axis_name,
"units", &
446 & trim(axis_units), str_len=len_trim(axis_units))
447 call register_variable_attribute(fileob, axis_name,
"long_name", trim(axis_long_name), &
448 & str_len=len_trim(axis_long_name))
449 if(trim(axis_cart_name).ne.
"N")
call register_variable_attribute(fileob, axis_name,
"axis", &
450 & trim(axis_cart_name), str_len=len_trim(axis_cart_name))
451 select case (axis_direction)
453 call register_variable_attribute(fileob, axis_name,
"positive",
"up", str_len=len_trim(
"up"))
455 call register_variable_attribute(fileob, axis_name,
"positive",
"down", str_len=len_trim(
"down"))
457 call write_data(fileob, axis_name, axis_data)
460 DEALLOCATE (axis_data)
468 & avg_name, time_method, standard_name, interp_method, attributes, num_attributes, &
469 & use_UGdomain, fileob)
result ( Field )
470 INTEGER,
INTENT(in) :: file_unit
471 INTEGER,
INTENT(in) :: axes(:)
472 CHARACTER(len=*),
INTENT(in) :: name
473 CHARACTER(len=*),
INTENT(in) :: units
474 CHARACTER(len=*),
INTENT(in) :: long_name
475 REAL,
OPTIONAL,
INTENT(in) :: range(2)
476 REAL,
OPTIONAL,
INTENT(in) :: mval
477 INTEGER,
OPTIONAL,
INTENT(in) :: pack
484 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: avg_name
485 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: time_method
487 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: standard_name
488 CHARACTER(len=*),
OPTIONAL,
INTENT(in) :: interp_method
489 TYPE(diag_atttype),
DIMENSION(:),
allocatable,
OPTIONAL,
INTENT(in) :: attributes
490 INTEGER,
OPTIONAL,
INTENT(in) :: num_attributes
491 LOGICAL,
OPTIONAL,
INTENT(in) :: use_ugdomain
492 class(fmsnetcdffile_t),
intent(inout) :: fileob
494 logical :: is_time_bounds
495 CHARACTER(len=256) :: standard_name2
496 TYPE(diag_fieldtype) :: field
497 LOGICAL :: coord_present
498 CHARACTER(len=128) :: aux_axes(size(axes))
499 CHARACTER(len=160) :: coord_att
500 CHARACTER(len=1024) :: err_msg
502 character(len=128),
dimension(size(axes)) :: axis_names
504 INTEGER :: i, indexx, num, ipack, np
506 INTEGER :: axis_indices(size(axes))
507 logical :: use_ugdomain_local
512 coord_present = .false.
513 IF(
PRESENT(standard_name) )
THEN
514 standard_name2 = standard_name
516 standard_name2 =
'none'
519 use_ugdomain_local = .false.
520 if(
present(use_ugdomain)) use_ugdomain_local = use_ugdomain
524 IF ( num < 1 )
CALL error_mesg (
'write_meta_data',
'number of axes < 1', fatal)
526 IF ( file_unit /= current_file_unit )
CALL error_mesg (
'write_meta_data', &
527 &
'writing meta data out-of-order to different files', fatal)
529 IF (trim(name) .eq.
"time_bnds")
then
530 is_time_bounds = .true.
532 is_time_bounds = .false.
540 IF ( indexx > 0 )
THEN
541 axis_indices(i) = indexx
544 CALL error_mesg (
'write_field_meta_data',&
545 &
'axis data not written for field '//trim(name), fatal)
548 call get_diag_axis_name(axes(i),axis_names(i))
552 IF ( num >= 2 .OR. (num==1 .and. use_ugdomain_local) )
THEN
555 aux_axes(i) = get_axis_aux(axes(i))
556 IF( trim(aux_axes(i)) /=
'none' )
THEN
557 IF(len_trim(coord_att) == 0)
THEN
558 coord_att = trim(aux_axes(i))
560 coord_att = trim(coord_att)//
' '//trim(aux_axes(i))
562 coord_present = .true.
571 IF (
PRESENT(pack) )
THEN
581 IF (
PRESENT(range) )
THEN
582 IF ( range(2) > range(1) )
THEN
585 IF ( ipack > 2 )
THEN
587 add = 0.5*(range(1)+range(2))
588 scale = (range(2)-range(1)) / real(max_range(2,np)-max_range(1,np))
594 IF (
PRESENT(mval) )
THEN
596 field%miss_present = .true.
597 IF ( ipack > 2 )
THEN
599 field%miss_pack = real(missval(np))*scale+add
600 field%miss_pack_present = .true.
602 field%miss_pack = mval
603 field%miss_pack_present = .false.
606 field%miss_present = .false.
607 field%miss_pack_present = .false.
611 field%fieldname = name
613 if (.not. variable_exists(fileob,name))
then
621 call register_field(fileob,name,
"double",axis_names)
624 if (.not. is_time_bounds)
then
625 IF ( field%miss_present )
THEN
626 call register_variable_attribute(fileob,name,
"_FillValue",real(field%miss_pack,8))
627 call register_variable_attribute(fileob,name,
"missing_value",real(field%miss_pack,8))
629 call register_variable_attribute(fileob,name,
"_FillValue",real(cmor_missing_value,8))
630 call register_variable_attribute(fileob,name,
"missing_value",real(cmor_missing_value,8))
632 IF ( use_range )
then
633 call register_variable_attribute(fileob,name,
"valid_range", real(range,8))
637 call register_field(fileob,name,
"float",axis_names)
640 if (.not. is_time_bounds)
then
641 IF ( field%miss_present )
THEN
642 call register_variable_attribute(fileob,name,
"_FillValue",real(field%miss_pack,4))
643 call register_variable_attribute(fileob,name,
"missing_value",real(field%miss_pack,4))
645 call register_variable_attribute(fileob,name,
"_FillValue",real(cmor_missing_value,4))
646 call register_variable_attribute(fileob,name,
"missing_value",real(cmor_missing_value,4))
648 IF ( use_range )
then
649 call register_variable_attribute(fileob,name,
"valid_range", real(range,4))
653 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
654 &
"Pack values must be 1 or 2. Contact the developers.", fatal)
656 if (trim(units) .ne.
"none")
call register_variable_attribute(fileob,name,
"units",trim(units), &
657 & str_len=len_trim(units))
658 call register_variable_attribute(fileob,name,
"long_name",long_name, str_len=len_trim(long_name))
659 IF (
present(time_method) )
then
660 call register_variable_attribute(fileob,name,
'cell_methods',
'time: '//trim(time_method), &
661 & str_len=len_trim(
'time: '//trim(time_method)))
665 IF (
PRESENT(num_attributes) )
THEN
666 IF (
PRESENT(attributes) )
THEN
667 IF ( num_attributes .GT. 0 .AND.
allocated(attributes) )
THEN
669 & fileob=fileob, varname=name)
670 IF ( len_trim(err_msg) .GT. 0 )
THEN
671 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
672 & trim(err_msg)//
" Contact the developers.", fatal)
676 IF ( num_attributes .GT. 0 .AND. .NOT.
allocated(attributes) )
THEN
677 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
678 &
'num_attributes > 0 but attributes is not allocated for attribute '&
679 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
680 ELSE IF ( num_attributes .EQ. 0 .AND.
allocated(attributes) )
THEN
681 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
682 &
'num_attributes == 0 but attributes is allocated for attribute '&
683 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
688 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
689 &
'num_attributes present but attributes missing for attribute '&
690 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
692 ELSE IF (
PRESENT(attributes) )
THEN
693 CALL error_mesg(
'diag_output_mod::write_field_meta_data',&
694 &
'attributes present but num_attributes missing for attribute '&
695 &//trim(attributes(i)%name)//
' for field '//trim(name)//
'. Contact the developers.', fatal)
699 IF (
PRESENT(avg_name) )
THEN
700 IF ( avg_name(1:1) /=
' ' )
THEN
701 call register_variable_attribute(fileob,name,
'time_avg_info',&
702 & trim(avg_name)//
'_T1,'//trim(avg_name)//
'_T2,'//trim(avg_name)//
'_DT', &
703 & str_len=len_trim(trim(avg_name)//
'_T1,'//trim(avg_name)//
'_T2,'//trim(avg_name)//
'_DT'))
708 IF ( coord_present )
then
709 call register_variable_attribute(fileob,name,
'coordinates',trim(coord_att), str_len=len_trim(coord_att))
711 IF ( trim(standard_name2) /=
'none' )
then
712 call register_variable_attribute(fileob,name,
'standard_name',trim(standard_name2), &
713 & str_len=len_trim(standard_name2))
716 IF(
PRESENT(interp_method) )
THEN
717 call register_variable_attribute(fileob,name,
'interp_method', trim(interp_method), &
718 & str_len=len_trim(interp_method))
722 field%Domain = get_domain2d( axes )
723 field%tile_count = get_tile_count( axes )
724 field%DomainU = get_domainug( axes(1) )
732 INTEGER,
INTENT(in) :: file_unit
733 INTEGER,
INTENT(in) :: num_attributes
734 TYPE(diag_atttype),
DIMENSION(:),
INTENT(in) :: attributes
735 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: time_method
736 CHARACTER(len=*),
INTENT(out),
OPTIONAL :: err_msg
737 CHARACTER(len=*),
INTENT(IN),
OPTIONAL :: varname
738 class(fmsnetcdffile_t),
intent(inout) :: fileob
740 INTEGER :: i, att_len
741 CHARACTER(len=1280) :: att_str
744 IF (
PRESENT(err_msg) ) err_msg =
''
746 DO i = 1, num_attributes
747 SELECT CASE (attributes(i)%type)
749 IF ( .NOT.
allocated(attributes(i)%iatt) )
THEN
750 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',&
751 &
'Integer attribute type indicated, but array not allocated for attribute '&
752 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
756 if (
present(varname))
call register_variable_attribute(fileob, varname,trim(attributes(i)%name), &
757 & attributes(i)%iatt)
759 IF ( .NOT.
allocated(attributes(i)%fatt) )
THEN
760 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',&
761 &
'Real attribute type indicated, but array not allocated for attribute '&
762 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
766 if (
present(varname))
call register_variable_attribute(fileob, varname,trim(attributes(i)%name), &
767 & real(attributes(i)%fatt,4) )
769 att_str = attributes(i)%catt
770 att_len = attributes(i)%len
771 IF ( trim(attributes(i)%name).EQ.
'cell_methods' .AND.
PRESENT(time_method) )
THEN
773 att_str = attributes(i)%catt(1:attributes(i)%len)//
' time: '//time_method
774 att_len = len_trim(att_str)
776 if (
present(varname))&
777 call register_variable_attribute(fileob, varname,trim(attributes(i)%name) , att_str(1:att_len), &
781 IF ( fms_error_handler(
'diag_output_mod::write_attribute_meta',
'Invalid type for attribute '&
782 &//trim(attributes(i)%name)//
'.', err_msg) )
THEN
794 INTEGER,
INTENT(in) :: file_unit
801 subroutine diag_field_write (varname, buffer, static, file_num, fileobjU, fileobj, fileobjND, &
802 & fnum_for_domain, time_in)
803 CHARACTER(len=*),
INTENT(in) :: varname
804 REAL ,
INTENT(inout) :: buffer(:,:,:,:)
805 logical,
intent(in) :: static
806 integer,
intent(in) :: file_num
807 type(fmsnetcdfunstructureddomainfile_t),
intent(inout) :: fileobju(:)
808 type(fmsnetcdfdomainfile_t),
intent(inout) :: fileobj(:)
809 type(fmsnetcdffile_t),
intent(inout) :: fileobjnd(:)
810 character(len=2),
intent(in) :: fnum_for_domain
814 INTEGER,
OPTIONAL,
INTENT(in) :: time_in
817 real,
allocatable :: local_buffer(:,:,:,:)
822 elseif (
present(time_in))
then
828 if (
size(buffer,3) .eq. 1 .and.
size(buffer,2) .eq. 1)
then
831 allocate(local_buffer(
size(buffer,1),
size(buffer,4),
size(buffer,2),
size(buffer,3)))
832 local_buffer(:,:,1,1) = buffer(:,1,1,:)
833 else if (
size(buffer,3) .eq. 1)
then
836 allocate(local_buffer(
size(buffer,1),
size(buffer,2),
size(buffer,4),
size(buffer,3)))
837 local_buffer(:,:,:,1) = buffer(:,:,1,:)
839 allocate(local_buffer(
size(buffer,1),
size(buffer,2),
size(buffer,3),
size(buffer,4)))
840 local_buffer = buffer(:,:,:,:)
844 if (fnum_for_domain ==
"2d" )
then
845 if (check_if_open(fileobj(file_num)))
then
846 call write_data (fileobj(file_num), trim(varname), local_buffer, unlim_dim_level=time )
848 elseif (fnum_for_domain ==
"nd")
then
849 if (check_if_open(fileobjnd(file_num)) )
then
850 call write_data (fileobjnd(file_num), trim(varname), local_buffer, unlim_dim_level=time)
852 elseif (fnum_for_domain ==
"ug")
then
853 if (check_if_open(fileobju(file_num)))
then
854 call write_data (fileobju(file_num), trim(varname), local_buffer, unlim_dim_level=time)
857 call error_mesg(
"diag_field_write",
"fnum_for_domain must be '2d', 'nd', or 'ug'",fatal)
860 deallocate(local_buffer)
865 class(fmsnetcdffile_t),
intent(inout) :: fileob
866 real,
intent(in) :: rtime_value
867 integer,
intent(in) :: time_index
868 character(len=*),
intent(in),
optional :: time_name
869 character(len=:),
allocatable :: name_time
872 if (
present(time_name))
then
873 allocate(
character(len=len(time_name)) :: name_time)
874 name_time = time_name
876 allocate(
character(len=4) :: name_time)
880 call write_data (fileob, trim(name_time), rtime_value, unlim_dim_level=time_index)
882 if (
allocated(name_time))
deallocate(name_time)
888 INTEGER,
INTENT(in) :: num
897 DO i = 1, num_axis_in_file
898 IF ( num == axis_in_file(i) )
THEN
907 TYPE(diag_global_att_type),
INTENT(out) :: gatt
914 CHARACTER(len=*),
INTENT(in) :: component, gridtype, tilename
918 CHARACTER(len=64) :: component_tmp
919 component_tmp = component
923 diag_global_att%grid_type = gridtype
924 diag_global_att%tile_name = tilename
929 subroutine diag_flush(file_num, fileobjU, fileobj, fileobjND, fnum_for_domain)
930 integer,
intent(in) :: file_num
931 type(fmsnetcdfunstructureddomainfile_t),
intent(inout) :: fileobju(:)
932 type(fmsnetcdfdomainfile_t),
intent(inout) :: fileobj(:)
933 type(fmsnetcdffile_t),
intent(inout) :: fileobjnd(:)
934 character(len=2),
intent(in) :: fnum_for_domain
938 if (fnum_for_domain ==
"2d" )
then
939 call flush_file (fileobj(file_num))
940 elseif (fnum_for_domain ==
"nd")
then
941 call flush_file (fileobjnd(file_num))
942 elseif (fnum_for_domain ==
"ug")
then
943 call flush_file (fileobju(file_num))
945 call error_mesg(
"diag_field_write",
"No file object is associated with this file number",fatal)
948 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 given netcdf or domain file.
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.
Gather data sent from pelist onto the root pe Wrapper for MPI_gather, can be used with and without in...
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.