35 & north, east, center, &
42 use fms_diag_object_mod,
only:fms_diag_object
43 USE netcdf,
ONLY: nf90_int, nf90_float, nf90_char
58 #include<file_version.h>
61 integer(I4_KIND),
parameter,
public :: DIAG_AXIS_NODOMAIN = 0
67 INTEGER :: num_def_axes = 0
69 CHARACTER(len=128),
DIMENSION(:),
ALLOCATABLE,
SAVE ::
axis_sets
70 INTEGER :: num_axis_sets = 0
73 LOGICAL :: module_is_initialized = .false.
89 MODULE PROCEDURE diag_axis_add_attribute_scalar_r
90 MODULE PROCEDURE diag_axis_add_attribute_scalar_i
91 MODULE PROCEDURE diag_axis_add_attribute_scalar_c
92 MODULE PROCEDURE diag_axis_add_attribute_r1d
93 MODULE PROCEDURE diag_axis_add_attribute_i1d
108 INTEGER FUNCTION diag_axis_init(name, array_data, units, cart_name, long_name, direction,&
109 & set_name, edges, Domain, Domain2, DomainU, aux, req, tile_count, domain_position )
110 CHARACTER(len=*),
INTENT(in) :: name
111 CLASS(*),
DIMENSION(:),
INTENT(in) :: array_data
112 CHARACTER(len=*),
INTENT(in) :: units
113 CHARACTER(len=*),
INTENT(in) :: cart_name
114 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: long_name
115 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: set_name
116 INTEGER,
INTENT(in),
OPTIONAL :: direction
117 INTEGER,
INTENT(in),
OPTIONAL :: edges
118 TYPE(
domain1d),
INTENT(in),
OPTIONAL :: domain
119 TYPE(
domain2d),
INTENT(in),
OPTIONAL :: domain2
120 TYPE(
domainug),
INTENT(in),
OPTIONAL :: domainu
121 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: aux
122 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: req
123 INTEGER,
INTENT(in),
OPTIONAL :: tile_count
124 INTEGER,
INTENT(in),
OPTIONAL :: domain_position
127 TYPE(
domain1d) :: domain_x, domain_y
128 INTEGER :: ierr, axlen
129 INTEGER :: i, set, tile
130 INTEGER :: isc, iec, isg, ieg
131 CHARACTER(len=128) :: emsg
133 IF ( .NOT.module_is_initialized )
THEN
140 diag_axis_init = fms_diag_object%fms_diag_axis_init(name, array_data, units, cart_name,
size(array_data(:)), &
141 & long_name=long_name, direction=direction, set_name=set_name, edges=edges, domain=domain, domain2=domain2, &
142 & domainu=domainu, aux=aux, req=req, tile_count=tile_count, domain_position=domain_position)
145 IF (
PRESENT(tile_count))
THEN
160 IF (
PRESENT(set_name) )
THEN
164 num_axis_sets = num_axis_sets + 1
165 IF ( num_axis_sets > max_num_axis_sets )
THEN
166 WRITE (emsg, fmt=
'("num_axis_sets (",I2,") exceeds max_num_axis_sets (",I2,"). ")')&
167 & num_axis_sets, max_num_axis_sets
172 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
173 & trim(emsg)//
' Increase max_num_axis_sets via diag_manager_nml.', fatal)
185 DO i = 1, num_def_axes
186 IF ( trim(name) ==
axes(i)%name )
THEN
187 IF ( trim(name) ==
'Stations' .OR. trim(name) ==
'Levels')
THEN
190 ELSE IF ( set ==
axes(i)%set )
THEN
191 IF ( trim(lowercase(name)) ==
'time' .OR.&
192 & trim(lowercase(cart_name)) ==
't' .OR.&
193 & trim(lowercase(name)) ==
'nv' .OR.&
194 & trim(lowercase(cart_name)) ==
'n' )
THEN
197 ELSE IF ( (lowercase(cart_name) /=
'x' .AND. lowercase(cart_name) /=
'y')&
198 & .OR. tile /=
axes(i)%tile_count)
THEN
200 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
201 &
'axis_name '//trim(name)//
' and axis_set already exist.', fatal)
208 num_def_axes = num_def_axes + 1
211 &
'max_axes exceeded, increase via diag_manager_nml', fatal)
215 IF ( trim(uppercase(cart_name)) ==
'X' .OR.&
216 & trim(uppercase(cart_name)) ==
'Y' .OR.&
217 & trim(uppercase(cart_name)) ==
'Z' .OR.&
218 & trim(uppercase(cart_name)) ==
'T' .OR.&
219 & trim(uppercase(cart_name)) ==
'U' .OR.&
220 & trim(uppercase(cart_name)) ==
'N' )
THEN
224 CALL error_mesg(
'diag_axis_mod::diag_axis_init',
'Invalid cart_name name. '//trim(uppercase(cart_name)), fatal)
231 axlen =
SIZE(array_data(:))
237 SELECT TYPE (array_data)
238 TYPE IS (real(kind=r4_kind))
240 TYPE IS (real(kind=r8_kind))
243 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
244 &
'The axis data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
256 IF (
PRESENT(long_name) )
THEN
262 IF (
PRESENT(aux) )
THEN
268 IF (
PRESENT(req) )
THEN
273 IF (
PRESENT(domain_position) )
THEN
274 if (domain_position == north .or. domain_position == east .or. domain_position == center)
then
277 CALL error_mesg(
'diag_axis_mod::diag_axis_init',
"Position must be NORTH, EAST, or CENTER" ,&
285 IF (
PRESENT(direction) )
THEN
286 IF ( abs(direction) /= 1 .AND. direction /= 0 )&
288 &
CALL error_mesg(
'diag_axis_mod::diag_axis_init',
'direction must be 0, +1 or -1', fatal)
295 IF (
present(domainu) .AND. (
PRESENT(domain2) .OR.
PRESENT(domain)) )
THEN
297 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
298 &
'Presence of DomainU and another Domain at the same time is prohibited', fatal)
300 ELSE IF (
PRESENT(domain2) .AND.
PRESENT(domain))
THEN
302 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
303 &
'Presence of both Domain and Domain2 at the same time is prohibited', fatal)
304 ELSE IF (
PRESENT(domain2) .OR.
PRESENT(domain))
THEN
307 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
308 &
'A Structured Domain must not be present for an axis which is not in the X or Y direction', fatal)
311 CALL error_mesg(
'diag_axis_mod::diag_axis_init',&
312 &
'In the unstructured domain, the axis cart_name must be U', fatal)
317 IF (
PRESENT(domain2) )
THEN
323 ELSE IF (
PRESENT(domain))
THEN
328 ELSE IF (
present(domainu))
THEN
349 IF (
PRESENT(edges) )
THEN
350 IF ( edges > 0 .AND. edges < num_def_axes )
THEN
357 WRITE (emsg,
'("Edges axis does not match axis (code ",I1,").")') ierr
358 CALL error_mesg(
'diag_axis_mod::diag_axis_init', emsg, fatal)
363 CALL error_mesg(
'diag_axis_mod::diag_axis_init',
'Edges axis is not defined', fatal)
368 module_is_initialized = .true.
382 INTEGER,
INTENT(in) :: axis
383 REAL,
DIMENSION(:),
INTENT(in) :: subdata
384 INTEGER,
INTENT(in) :: start_indx
385 INTEGER,
INTENT(in) :: end_indx
386 TYPE(
domain2d),
INTENT(in),
OPTIONAL :: domain_2d
388 INTEGER :: i, nsub_axis, direction
389 INTEGER :: xbegin, xend, ybegin, yend
390 INTEGER :: ad_xbegin, ad_xend, ad_ybegin, ad_yend
391 CHARACTER(len=128) :: name, nsub_name
392 CHARACTER(len=128) :: units
393 CHARACTER(len=128) :: cart_name
394 CHARACTER(len=128) :: long_name
395 CHARACTER(len=128) :: emsg
396 LOGICAL :: subaxis_set, hasdomain
400 subaxis_set = .false.
402 IF (
PRESENT(domain_2d) )
THEN
409 IF ( start_indx ==
axes(axis)%start(i) .AND. end_indx ==
axes(axis)%end(i) )
THEN
410 IF ( hasdomain )
THEN
412 IF ( .NOT.((xbegin == ad_xbegin .AND. xend == ad_xend) .AND.&
413 & (ybegin == ad_ybegin .AND. yend == ad_yend)) )
THEN
419 name = trim(
axes(axis)%subaxis_name(nsub_axis))
424 IF ( nsub_axis == 0 )
THEN
428 WRITE (emsg,
'("max_subaxes (value ",I4,") is too small. Consider increasing max_subaxes.")') max_subaxes
429 CALL error_mesg(
'diag_axis_mod::diag_subaxes_init', emsg, fatal)
432 axes(axis)%start(nsub_axis) = start_indx
433 axes(axis)%end(nsub_axis) = end_indx
434 if ( hasdomain )
axes(axis)%subaxis_domain2(nsub_axis) = domain_2d
440 IF (
axes(axis)%set > 0 )
THEN
448 WRITE (nsub_name,
'(I2.2)') nsub_axis
449 name = trim(
axes(axis)%name)//
'_sub'//trim(nsub_name)
450 axes(axis)%subaxis_name(nsub_axis) = name
451 long_name = trim(
axes(axis)%long_name)
452 units = trim(
axes(axis)%units)
453 cart_name = trim(
axes(axis)%cart_name)
454 direction =
axes(axis)%direction
455 IF (
axes(axis)%set > 0)
THEN
457 & set_name=trim(
axis_sets(
axes(axis)%set)), direction=direction, domain2=domain_2d)
460 & direction=direction, domain2=domain_2d)
466 & direction, edges, Domain, DomainU, array_data, num_attributes, attributes, domain_position)
467 CHARACTER(len=*),
INTENT(out) :: name, units, long_name, cart_name
468 INTEGER,
INTENT(in) :: id
469 TYPE(
domain1d),
INTENT(out) :: domain
470 TYPE(
domainug),
INTENT(out) :: domainu
471 INTEGER,
INTENT(out) :: direction
473 INTEGER,
INTENT(out) :: edges
474 CLASS(*),
DIMENSION(:),
INTENT(out) :: array_data
475 INTEGER,
INTENT(out),
OPTIONAL :: num_attributes
476 TYPE(
diag_atttype),
ALLOCATABLE,
DIMENSION(:),
INTENT(out),
OPTIONAL :: attributes
477 INTEGER,
INTENT(out),
OPTIONAL :: domain_position
479 INTEGER :: i, j, istat
483 units =
axes(id)%units
484 long_name =
axes(id)%long_name
485 cart_name =
axes(id)%cart_name
486 direction =
axes(id)%direction
487 edges =
axes(id)%edges
488 domain =
axes(id)%Domain
489 domainu =
axes(id)%DomainUG
490 if (
present(domain_position)) domain_position =
axes(id)%domain_position
491 IF (
axes(id)%length >
SIZE(array_data(:)) )
THEN
493 CALL error_mesg(
'diag_axis_mod::get_diag_axis',
'array data is too small', fatal)
495 SELECT TYPE (array_data)
496 TYPE IS (real(kind=r4_kind))
497 array_data(1:
axes(id)%length) = real(
axes(id)%diag_type_data(1:
axes(id)%length), kind=r4_kind)
498 TYPE IS (real(kind=r8_kind))
499 array_data(1:
axes(id)%length) =
axes(id)%diag_type_data(1:
axes(id)%length)
501 CALL error_mesg(
'diag_axis_mod::get_diag_axis',&
502 &
'The axis data is not one of the supported types of real(kind=4) or real(kind=8)', fatal)
505 IF (
PRESENT(num_attributes) )
THEN
506 num_attributes =
axes(id)%num_attributes
508 IF (
PRESENT(attributes) )
THEN
509 IF (
allocated(
axes(id)%attributes) )
THEN
510 IF (
ALLOCATED(attributes) )
THEN
512 IF (
axes(id)%num_attributes .GT.
SIZE(attributes(:)) )
THEN
513 CALL error_mesg(
'diag_axis_mod::get_diag_axis',
'array attribute is too small', fatal)
517 ALLOCATE(attributes(
axes(id)%num_attributes), stat=istat)
518 IF ( istat .NE. 0 )
THEN
519 CALL error_mesg(
'diag_axis_mod::get_diag_axis',
'Unable to allocate memory for attribute', fatal)
522 DO i=1,
axes(id)%num_attributes
524 IF (
allocated(attributes(i)%fatt) )
THEN
525 DEALLOCATE(attributes(i)%fatt)
527 IF (
allocated(attributes(i)%iatt) )
THEN
528 DEALLOCATE(attributes(i)%iatt)
532 attributes(i)%type =
axes(id)%attributes(i)%type
533 attributes(i)%len =
axes(id)%attributes(i)%len
534 attributes(i)%name =
axes(id)%attributes(i)%name
535 attributes(i)%catt =
axes(id)%attributes(i)%catt
537 IF (
allocated(
axes(id)%attributes(i)%fatt) )
THEN
538 ALLOCATE(attributes(i)%fatt(
SIZE(
axes(id)%attributes(i)%fatt(:))), stat=istat)
539 IF ( istat .NE. 0 )
THEN
540 CALL error_mesg(
'diag_axis_mod::get_diag_axis', &
541 &
'Unable to allocate memory for attribute%fatt', fatal)
543 DO j=1,
SIZE(attributes(i)%fatt(:))
544 attributes(i)%fatt(j) =
axes(id)%attributes(i)%fatt(j)
548 IF (
allocated(
axes(id)%attributes(i)%iatt) )
THEN
549 ALLOCATE(attributes(i)%iatt(
SIZE(
axes(id)%attributes(i)%iatt(:))), stat=istat)
550 IF ( istat .NE. 0 )
THEN
551 CALL error_mesg(
'diag_axis_mod::get_diag_axis', &
552 &
'Unable to allocate memory for attribute%iatt', fatal)
554 DO j=1,
SIZE(attributes(i)%iatt(:))
555 attributes(i)%iatt(j) =
axes(id)%attributes(i)%iatt(j)
565 INTEGER,
INTENT(in) :: id
566 CHARACTER(len=*),
INTENT(out) :: cart_name
569 cart_name =
axes(id)%cart_name
574 INTEGER,
INTENT(in) :: id
575 REAL,
DIMENSION(:),
INTENT(out) :: axis_data
578 IF (
axes(id)%length >
SIZE(axis_data(:)))
THEN
580 CALL error_mesg(
'diag_axis_mod::get_diag_axis_data',
'array data is too small', fatal)
582 axis_data(1:
axes(id)%length) =
axes(id)%diag_type_data
588 INTEGER ,
INTENT(in) :: id
589 CHARACTER(len=*),
INTENT(out) :: axis_name
592 axis_name = fms_diag_object%fms_get_axis_name_from_id(id)
595 axis_name =
axes(id)%name
601 INTEGER,
INTENT(in) :: id
602 CHARACTER(len=*),
INTENT(out) :: name
611 INTEGER,
INTENT(in) :: id
618 IF (
axes(id)%Domain .NE. null_domain1d )
THEN
631 INTEGER,
INTENT(in) :: id
640 INTEGER,
INTENT(in) :: id
649 INTEGER,
INTENT(in) :: id
658 INTEGER,
DIMENSION(:),
INTENT(in) :: ids
661 INTEGER :: i, id, flag
663 IF (
SIZE(ids(:)) < 1 )
THEN
665 CALL error_mesg(
'diag_axis_mod::get_tile_count',
'input argument has incorrect size', fatal)
669 DO i = 1,
SIZE(ids(:))
672 IF (
axes(id)%cart_name ==
'X' .OR. &
673 axes(id)%cart_name ==
'Y' ) flag = flag + 1
675 IF ( flag == 2 )
THEN
685 INTEGER,
INTENT(in) :: id
688 IF (
axes(id)%Domain .NE. null_domain1d)
THEN
698 INTEGER,
DIMENSION(:),
INTENT(in) :: ids
701 INTEGER :: i, id, flag
703 IF (
SIZE(ids(:)) < 1 )
THEN
705 CALL error_mesg(
'diag_axis_mod::get_domain2d',
'input argument has incorrect size', fatal)
708 if (use_modern_diag)
then
715 DO i = 1,
SIZE(ids(:))
718 IF (
axes(id)%cart_name ==
'X' .OR.
axes(id)%cart_name ==
'Y' ) flag = flag + 1
720 IF ( flag == 2 )
THEN
730 INTEGER,
INTENT(in) :: id
733 IF (
axes(id)%DomainUG .NE. null_domainug)
THEN
746 integer,
dimension(:),
intent(in) :: id
747 character(*),
intent(in),
optional :: varname
748 integer(I4_KIND) :: domain_type
756 logical :: uses_domain2d
757 logical :: uses_domainug
762 uses_domain2d = .false.
763 uses_domainug = .false.
769 "axis_compatible_check")
770 if (
axes(id(n))%cart_name .eq.
"X" .or. &
771 axes(id(n))%cart_name .eq.
"Y")
then
773 elseif (
axes(id(n))%cart_name .eq.
"U")
then
776 if (
axes(id(n))%Domain2 .ne. null_domain2d)
then
777 uses_domain2d = .true.
778 elseif (
axes(id(n))%DomainUG .ne. null_domainug)
then
779 uses_domainug = .true.
782 if (ug .and. xory)
then
783 if (
present(varname))
then
784 call error_mesg(
"axis_compatible_check", &
785 "Can not use an unstructured grid with a "// &
786 "horizontal cartesian coordinate for the field " &
790 call error_mesg(
"axis_compatible_check", &
791 "Can not use an unstructured grid with a horizontal "// &
792 "cartesian coordinate", &
796 if (uses_domain2d .and. uses_domainug)
then
797 if (
present(varname))
then
798 call error_mesg(
"axis_compatible_check", &
799 "Can not use an unstructured grid with a"// &
800 "structured grid for the field "//trim(varname), &
803 call error_mesg(
"axis_compatible_check", &
804 "Can not use an unstructured grid with a"// &
805 "structured grid.", &
809 if (uses_domain2d)
then
811 elseif (uses_domainug)
then
814 domain_type = diag_axis_nodomain
822 INTEGER,
DIMENSION(:),
INTENT(in) :: ids
823 INTEGER,
INTENT(out) :: ishift
824 INTEGER,
INTENT(out) :: jshift
831 DO i = 1,
SIZE(ids(:))
834 SELECT CASE (
axes(id)%cart_name)
836 ishift =
axes(id)%shift
838 jshift =
axes(id)%shift
846 CHARACTER(len=*),
INTENT(in) :: axis_name
847 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: set_name
851 IF (
PRESENT(set_name) )
THEN
857 DO n = 1, num_def_axes
858 IF ( trim(axis_name) == trim(
axes(n)%name) .AND.
axes(n)%set == set )
THEN
868 CHARACTER(len=*),
INTENT(in) :: set_name
873 DO iset = 1, num_axis_sets
884 INTEGER,
INTENT(in) :: id
885 CHARACTER(len=*),
INTENT(in) :: routine_name
887 CHARACTER(len=5) :: emsg
889 IF ( id < 1 .OR. id > num_def_axes)
THEN
893 WRITE (emsg,
'(I2)') id
894 CALL error_mesg(
'diag_axis_mod::'//trim(routine_name),&
895 &
'Illegal value for axis_id used (value '//trim(emsg)//
').', fatal)
900 INTEGER,
INTENT(in) :: diag_axis_id
901 CHARACTER(len=*) :: name
902 INTEGER,
INTENT(in) ::
type
903 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: cval
904 INTEGER,
DIMENSION(:),
INTENT(in),
OPTIONAL :: ival
905 REAL,
DIMENSION(:),
INTENT(in),
OPTIONAL :: rval
907 INTEGER :: istat, length, i, this_attribute
908 CHARACTER(len=1024) :: err_msg
910 IF ( .NOT.first_send_data_call )
THEN
916 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',
'Attempting to add attribute "'&
917 &//trim(name)//
'" to axis after first send_data call. Too late.', fatal)
921 IF ( diag_axis_id .LE. 0 )
THEN
923 ELSE IF ( diag_axis_id .GT. num_def_axes )
THEN
928 WRITE(err_msg,
'(I5)') diag_axis_id
929 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',
'Attempting to add attribute "'&
930 &//trim(name)//
'" to axis ID "'//trim(err_msg)//
'", however ID unknown.', fatal)
938 DO i=1,
axes(diag_axis_id)%num_attributes
939 IF ( trim(
axes(diag_axis_id)%attributes(i)%name) .EQ. trim(name) )
THEN
945 IF ( this_attribute.NE.0 .AND. (type.EQ.nf90_int .OR. type.EQ.nf90_float) )
THEN
950 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
951 &
'Attribute "'//trim(name)//
'" already defined for axis "'&
952 &//trim(
axes(diag_axis_id)%name)//
'". Contact the developers.', fatal)
953 ELSE IF ( this_attribute.NE.0 .AND. type.EQ.nf90_char .AND. debug_diag_manager )
THEN
958 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
959 &
'Attribute "'//trim(name)//
'" already defined for axis"'&
960 &//trim(
axes(diag_axis_id)%name)//
'". Prepending.', note)
964 this_attribute =
axes(diag_axis_id)%num_attributes + 1
966 IF ( this_attribute .GT. max_axis_attributes )
THEN
971 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
972 &
'Number of attributes exceeds max_axis_attributes for attribute "'&
973 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
974 & //
'". Increase diag_manager_nml:max_axis_attributes.',&
977 axes(diag_axis_id)%num_attributes = this_attribute
979 axes(diag_axis_id)%attributes(this_attribute)%name = name
980 axes(diag_axis_id)%attributes(this_attribute)%type =
type
982 axes(diag_axis_id)%attributes(this_attribute)%catt =
''
988 IF ( .NOT.
PRESENT(ival) )
THEN
993 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
994 &
'Attribute type claims INTEGER, but ival not present for attribute "'&
995 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
996 & //
'". Contact the developers.', fatal)
1000 ALLOCATE(
axes(diag_axis_id)%attributes(this_attribute)%iatt(length), stat=istat)
1001 IF ( istat.NE.0 )
THEN
1005 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',
'Unable to allocate iatt for attribute "'&
1006 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)//
'"', fatal)
1009 axes(diag_axis_id)%attributes(this_attribute)%len = length
1010 axes(diag_axis_id)%attributes(this_attribute)%iatt = ival
1012 IF ( .NOT.
PRESENT(rval) )
THEN
1017 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
1018 &
'Attribute type claims REAL, but rval not present for attribute "'&
1019 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
1020 & //
'". Contact the developers.', fatal)
1024 ALLOCATE(
axes(diag_axis_id)%attributes(this_attribute)%fatt(length), stat=istat)
1025 IF ( istat.NE.0 )
THEN
1029 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',
'Unable to allocate fatt for attribute "'&
1030 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
1034 axes(diag_axis_id)%attributes(this_attribute)%len = length
1035 axes(diag_axis_id)%attributes(this_attribute)%fatt = rval
1037 IF ( .NOT.
PRESENT(cval) )
THEN
1042 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',&
1043 &
'Attribute type claims CHARACTER, but cval not present for attribute "'&
1044 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
1045 & //
'". Contact the developers.', fatal)
1053 CALL error_mesg(
'diag_manager_mod::diag_axis_add_attribute',
'Unknown attribute type for attribute "'&
1054 & //trim(name)//
'" for axis "'//trim(
axes(diag_axis_id)%name)&
1055 & //
'". Contact the developers.', fatal)
1060 SUBROUTINE diag_axis_add_attribute_scalar_r(diag_axis_id, att_name, att_value)
1061 INTEGER,
INTENT(in) :: diag_axis_id
1062 CHARACTER(len=*),
INTENT(in) :: att_name
1063 REAL,
INTENT(in) :: att_value
1065 if (use_modern_diag)
then
1066 call fms_diag_object%fms_diag_axis_add_attribute(diag_axis_id, att_name, (/ att_value /))
1068 CALL diag_axis_add_attribute_r1d(diag_axis_id, att_name, (/ att_value /))
1070 END SUBROUTINE diag_axis_add_attribute_scalar_r
1072 SUBROUTINE diag_axis_add_attribute_scalar_i(diag_axis_id, att_name, att_value)
1073 INTEGER,
INTENT(in) :: diag_axis_id
1074 CHARACTER(len=*),
INTENT(in) :: att_name
1075 INTEGER,
INTENT(in) :: att_value
1077 if (use_modern_diag)
then
1078 call fms_diag_object%fms_diag_axis_add_attribute(diag_axis_id, att_name, (/ att_value /))
1080 CALL diag_axis_add_attribute_i1d(diag_axis_id, att_name, (/ att_value /))
1082 END SUBROUTINE diag_axis_add_attribute_scalar_i
1084 SUBROUTINE diag_axis_add_attribute_scalar_c(diag_axis_id, att_name, att_value)
1085 INTEGER,
INTENT(in) :: diag_axis_id
1086 CHARACTER(len=*),
INTENT(in) :: att_name
1087 CHARACTER(len=*),
INTENT(in) :: att_value
1089 if (use_modern_diag)
then
1090 call fms_diag_object%fms_diag_axis_add_attribute(diag_axis_id, att_name, (/ att_value /))
1094 END SUBROUTINE diag_axis_add_attribute_scalar_c
1096 SUBROUTINE diag_axis_add_attribute_r1d(diag_axis_id, att_name, att_value)
1097 INTEGER,
INTENT(in) :: diag_axis_id
1098 CHARACTER(len=*),
INTENT(in) :: att_name
1099 REAL,
DIMENSION(:),
INTENT(in) :: att_value
1101 if (use_modern_diag)
then
1102 call fms_diag_object%fms_diag_axis_add_attribute(diag_axis_id, att_name, att_value)
1106 END SUBROUTINE diag_axis_add_attribute_r1d
1108 SUBROUTINE diag_axis_add_attribute_i1d(diag_axis_id, att_name, att_value)
1109 INTEGER,
INTENT(in) :: diag_axis_id
1110 CHARACTER(len=*),
INTENT(in) :: att_name
1111 INTEGER,
DIMENSION(:),
INTENT(in) :: att_value
1112 if (use_modern_diag)
then
1113 call fms_diag_object%fms_diag_axis_add_attribute(diag_axis_id, att_name, att_value)
1117 END SUBROUTINE diag_axis_add_attribute_i1d
1122 TYPE(diag_axis_type),
INTENT(inout) :: out_axis
1123 CHARACTER(LEN=*),
INTENT(out),
OPTIONAL :: err_msg
1128 IF (
PRESENT(err_msg) ) err_msg =
''
1131 IF ( .NOT.
allocated(out_axis%attributes) )
THEN
1132 ALLOCATE(out_axis%attributes(max_axis_attributes), stat=istat)
1133 IF ( istat.NE.0 )
THEN
1137 IF ( fms_error_handler(
'diag_util_mod::attribute_init_axis', &
1138 &
'Unable to allocate memory for diag axis attributes', err_msg) )
THEN
1143 out_axis%num_attributes = 0
1151 TYPE(diag_axis_type),
INTENT(inout) :: out_axis
1152 CHARACTER(len=*),
INTENT(in) :: att_name
1153 CHARACTER(len=*),
INTENT(in) :: prepend_value
1154 CHARACTER(len=*),
INTENT(out) ,
OPTIONAL :: err_msg
1156 INTEGER :: length, i, this_attribute
1157 CHARACTER(len=512) :: err_msg_local
1161 IF (
PRESENT(err_msg) ) err_msg =
''
1165 IF ( trim(err_msg_local) .NE.
'' )
THEN
1166 IF ( fms_error_handler(
'diag_util_mod::prepend_attribute_axis', trim(err_msg_local), err_msg) )
THEN
1173 DO i=1, out_axis%num_attributes
1174 IF ( trim(out_axis%attributes(i)%name) .EQ. trim(att_name) )
THEN
1180 IF ( this_attribute > 0 )
THEN
1181 IF ( out_axis%attributes(this_attribute)%type .NE. nf90_char )
THEN
1185 IF ( fms_error_handler(
'diag_util_mod::prepend_attribute_axis',&
1186 &
'Attribute "'//trim(att_name)//
'" is not a character attribute.',&
1194 this_attribute = out_axis%num_attributes + 1
1195 IF ( this_attribute .GT. max_axis_attributes )
THEN
1200 IF ( fms_error_handler(
'diag_util_mod::prepend_attribute_axis',&
1201 &
'Number of attributes exceeds max_axis_attributes for attribute "'&
1202 &//trim(att_name)//
'". Increase diag_manager_nml:max_axis_attributes.',&
1207 out_axis%num_attributes = this_attribute
1209 out_axis%attributes(this_attribute)%name = att_name
1210 out_axis%attributes(this_attribute)%type = nf90_char
1212 out_axis%attributes(this_attribute)%catt =
''
1217 IF ( index(trim(out_axis%attributes(this_attribute)%catt), trim(prepend_value)).EQ.0 )
THEN
1219 length = len_trim(trim(prepend_value)//
" "//trim(out_axis%attributes(this_attribute)%catt))
1220 IF ( length.GT.len(out_axis%attributes(this_attribute)%catt) )
THEN
1224 IF ( fms_error_handler(
'diag_util_mod::prepend_attribute_file',&
1225 &
'Prepend length for attribute "'//trim(att_name)//
'" is longer than allowed.',&
1231 out_axis%attributes(this_attribute)%catt =&
1232 & trim(prepend_value)//
' '//trim(out_axis%attributes(this_attribute)%catt)
1233 out_axis%attributes(this_attribute)%len = length
1241 integer,
intent(in) :: id
1248 if (.not.
allocated(
axes(id)%attributes))
return
1249 do i = 1,
axes(id)%num_attributes
1250 if (trim(
axes(id)%attributes(i)%name)==
'compress')
then
1261 integer,
intent(in) :: id
1262 integer,
intent(out),
allocatable :: r(:)
1264 integer iatt, k, k1, k2, n
1267 character(*),
parameter :: tag =
'get_compressed_axes_ids'
1271 associate(axis=>
axes(id))
1272 if (.not.
allocated(axis%attributes))
call error_mesg(tag, &
1273 'attempt to get compression dimensions from axis "'//trim(axis%name)// &
1274 &
'" which is not compressed (does not have any attributes)', fatal)
1277 do k = 1,axis%num_attributes
1278 if (trim(axis%attributes(k)%name)==
'compress')
then
1283 if (iatt == 0)
call error_mesg(tag, &
1284 'attempt to get compression dimensions from axis "'//trim(axis%name)//&
1285 '" which is not compressed (does not have "compress" attributes).', fatal)
1286 if (axis%attributes(iatt)%type/=nf90_char)
call error_mesg(tag, &
1287 'attempt to get compression dimensions from axis "'//trim(axis%name)//&
1288 '" but the axis attribute "compress" has incorrect type.', fatal)
1293 do k = 1, len(axis%attributes(iatt)%catt)
1294 if (space.and.(axis%attributes(iatt)%catt(k:k)/=
' '))
then
1297 space = (axis%attributes(iatt)%catt(k:k)==
' ')
1306 do k1 = k2+1, len(axis%attributes(iatt)%catt)
1307 if (axis%attributes(iatt)%catt(k1:k1)/=
' ')
exit
1309 do k2 = k1+1, len(axis%attributes(iatt)%catt)
1310 if (axis%attributes(iatt)%catt(k2:k2)==
' ')
exit
1313 if (r(k)<=0)
call error_mesg(tag, &
1314 'compression dimension "'//trim(axis%attributes(iatt)%catt(k1:k2))//&
1315 '" not found among the axes of set "'//trim(
axis_sets(axis%set))//
'".', fatal)
1319 END MODULE diag_axis_mod
subroutine, public get_compressed_axes_ids(id, r)
given an index of compressed-by-gathering axis, return an array of axes used in compression....
integer(i4_kind) function, public axis_compatible_check(id, varname)
Checks if the axes are compatible.
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.
subroutine, public get_diag_axis_cart(id, cart_name)
Return the axis cartesian.
subroutine valid_id_check(id, routine_name)
Check to see if the given axis id is a valid id. If the axis id is invalid, call a FATAL error....
integer function, public get_axis_num(axis_name, set_name)
Returns index into axis table corresponding to a given axis name.
subroutine attribute_init_axis(out_axis, err_msg)
Allocates memory in out_file for the attributes. Will FATAL if err_msg is not included in the subrout...
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.
integer function get_axis_set_num(set_name)
Returns index in axis set table corresponding to a given axis set name.
type(domainug) function, public get_domainug(id)
Retrun the 1D domain for the axis ID given.
subroutine, public get_diag_axis_data(id, axis_data)
Return the axis data.
character(len=128) function, public get_axis_reqfld(id)
Return the required field names for the axis.
subroutine diag_axis_attribute_init(diag_axis_id, name, type, cval, ival, rval)
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.
subroutine prepend_attribute_axis(out_axis, att_name, prepend_value, err_msg)
Prepends the attribute value to an already existing attribute. If the attribute isn't yet defined,...
character(len=128) function, public get_axis_aux(id)
Return the auxiliary name for the axis.
integer(i4_kind), parameter, public diag_axis_2ddomain
For unstructured grid support.
type(diag_axis_type), dimension(:), allocatable, save axes
global storage for all defined axes
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.
logical function, public axis_is_compressed(id)
given an axis, returns TRUE if the axis uses compression-by-gathering: that is, if this is an axis fo...
subroutine, public get_axes_shift(ids, ishift, jshift)
Return the value of the shift for the axis IDs given.
integer, dimension(:), allocatable num_subaxes
counter of number of axes defined
integer(i4_kind), parameter, public diag_axis_ugdomain
For unstructured grid support.
subroutine, public get_diag_axis_domain_name(id, name)
Return the name of the axis' domain.
type(domain1d) function, public get_domain1d(id)
Retrun the 1D domain for the axis ID given.
integer function, public diag_subaxes_init(axis, subdata, start_indx, end_indx, domain_2d)
Create a subaxis on a parent axis.
character(len=128), dimension(:), allocatable, save axis_sets
storage for axis set names
Add an arbitrary attribute and value to the diagnostic axis.
integer max_axis_attributes
Maximum number of user definable attributes per axis.
logical use_modern_diag
Namelist flag to use the modernized diag_manager code.
integer max_axes
Maximum number of independent axes.
Attribute type for diagnostic fields.
Type to hold the diagnostic axis description.
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....
subroutine mpp_get_domain_components(domain, x, y, tile_count)
Retrieve 1D components of 2D decomposition.
character(len=name_length) function mpp_get_domain_name(domain)
Set user stack size.
These routines retrieve the axis specifications associated with the compute domains....
These routines retrieve the axis specifications associated with the global domains....
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.