29 module fms_diag_axis_object_mod
34 use platform_mod,
only: r8_kind, r4_kind, i4_kind, i8_kind
41 use fms2_io_mod,
only: fmsnetcdffile_t, fmsnetcdfdomainfile_t, fmsnetcdfunstructureddomainfile_t, &
67 procedure :: get_ntiles
88 INTEGER ,
private :: axis_id
106 class(fmsDiagAxis_type),
allocatable :: axis
112 CHARACTER(len=:),
ALLOCATABLE ,
private :: subaxis_name
113 INTEGER ,
private :: starting_index
115 INTEGER ,
private :: ending_index
117 INTEGER ,
private :: parent_axis_id
118 INTEGER ,
private :: compute_idx(2)
119 INTEGER,
allocatable,
private :: global_idx(:)
120 real(kind=r4_kind),
allocatable,
private :: zbounds(:)
133 INTEGER ,
private :: ndiurnal_samples
134 CHARACTER(len=:),
ALLOCATABLE,
private :: axis_name
135 CHARACTER(len=:),
ALLOCATABLE,
private :: long_name
136 CHARACTER(len=:),
ALLOCATABLE,
private :: units
137 INTEGER ,
private :: edges_id
138 CHARACTER(len=:),
ALLOCATABLE,
private :: edges_name
139 CLASS(*),
ALLOCATABLE,
private :: diurnal_data(:)
149 CHARACTER(len=:),
ALLOCATABLE,
private :: axis_name
150 CHARACTER(len=:),
ALLOCATABLE,
private :: units
151 CHARACTER(len=:),
ALLOCATABLE,
private :: long_name
152 CHARACTER(len=1) ,
private :: cart_name
153 CLASS(*),
ALLOCATABLE,
private :: axis_data(:)
154 CHARACTER(len=:),
ALLOCATABLE,
private :: type_of_data
156 integer,
ALLOCATABLE,
private :: subaxis(:)
157 integer ,
private :: nsubaxis
159 INTEGER ,
private :: type_of_domain
161 INTEGER ,
private :: length
162 INTEGER ,
private :: direction
163 INTEGER,
ALLOCATABLE,
private :: edges_id
165 CHARACTER(len=:),
ALLOCATABLE,
private :: edges_name
167 CHARACTER(len=:),
ALLOCATABLE,
private :: aux
169 CHARACTER(len=128) ,
private :: req
170 INTEGER ,
private :: tile_count
172 INTEGER ,
private :: num_attributes
173 INTEGER ,
private :: domain_position
174 integer,
allocatable ,
private :: structured_ids(:)
176 CHARACTER(len=:),
ALLOCATABLE,
private :: set_name
206 & set_name, Domain, Domain2, DomainU, aux, req, tile_count, domain_position, axis_length )
208 CHARACTER(len=*),
INTENT(in) :: axis_name
209 class(*),
INTENT(in) :: axis_data(:)
210 CHARACTER(len=*),
INTENT(in) :: units
211 CHARACTER(len=1),
INTENT(in) :: cart_name
212 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: long_name
213 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: set_name
214 INTEGER,
INTENT(in),
OPTIONAL :: direction
215 TYPE(
domain1d),
INTENT(in),
OPTIONAL :: Domain
216 TYPE(
domain2d),
INTENT(in),
OPTIONAL :: Domain2
217 TYPE(
domainug),
INTENT(in),
OPTIONAL :: DomainU
218 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: aux
220 CHARACTER(len=*),
INTENT(in),
OPTIONAL :: req
221 INTEGER,
INTENT(in),
OPTIONAL :: tile_count
222 INTEGER,
INTENT(in),
OPTIONAL :: domain_position
223 integer,
intent(in),
optional :: axis_length
225 this%axis_name = trim(axis_name)
226 this%units = trim(units)
227 this%cart_name = uppercase(cart_name)
230 if (
present(long_name)) this%long_name = trim(long_name)
232 select type (axis_data)
233 type is (real(kind=r8_kind))
234 allocate(real(kind=r8_kind) :: this%axis_data(axis_length))
235 this%axis_data = axis_data
236 this%length = axis_length
237 this%type_of_data =
"double"
238 type is (real(kind=r4_kind))
239 allocate(real(kind=r4_kind) :: this%axis_data(axis_length))
240 this%axis_data = axis_data
241 this%length = axis_length
242 this%type_of_data =
"float"
244 call mpp_error(fatal,
"The axis_data in your diag_axis_init call is not a supported type. &
245 & Currently only r4 and r8 data is supported.")
249 if (
present(domain))
then
250 if (
present(domain2) .or.
present(domainu))
call mpp_error(fatal, &
251 "The presence of Domain with any other domain type is prohibited. "//&
252 "Check you diag_axis_init call for axis_name:"//trim(axis_name))
254 call this%axis_domain%set(domain=domain)
255 else if (
present(domain2))
then
256 if (
present(domainu))
call mpp_error(fatal, &
257 "The presence of Domain2 with any other domain type is prohibited. "//&
258 "Check you diag_axis_init call for axis_name:"//trim(axis_name))
260 call this%axis_domain%set(domain2=domain2)
262 else if (
present(domainu))
then
264 call this%axis_domain%set(domainu=domainu)
269 if (
present(tile_count)) this%tile_count = tile_count
271 this%domain_position = center
272 if (
present(domain_position)) this%domain_position = domain_position
276 if (
present(direction)) this%direction = direction
279 if (
present(aux)) this%aux = trim(aux)
280 if (
present(req)) this%req = trim(req)
282 if (
present(set_name)) this%set_name = trim(set_name)
284 if (max_subaxes .gt. 0)
then
285 allocate(this%subaxis(max_subaxes))
286 this%subaxis = diag_null
290 this%num_attributes = 0
296 character(len=*),
intent(in) :: att_name
297 class(*),
intent(in) :: att_value(:)
301 if (.not.
allocated(this%attributes)) &
304 this%num_attributes = this%num_attributes + 1
306 j = this%num_attributes
307 call this%attributes(j)%add(att_name, att_value)
313 class(fmsnetcdffile_t),
INTENT(INOUT) :: fms2io_fileobj
314 logical,
INTENT(IN) :: edges_in_file
320 character(len=:),
ALLOCATABLE :: axis_edges_name
321 character(len=:),
pointer :: axis_name
322 integer :: axis_length
326 integer :: type_of_domain
327 logical :: is_subaxis
328 logical :: needs_domain_decomposition
330 integer :: domain_decomposition(4)
333 needs_domain_decomposition = .false.
337 axis_name => this%axis_name
338 axis_length = this%length
340 type_of_domain = this%type_of_domain
343 axis_name => this%subaxis_name
344 axis_length = this%ending_index - this%starting_index + 1
345 if (
allocated(this%global_idx))
then
346 needs_domain_decomposition = .true.
347 domain_decomposition(1:2) = this%global_idx
348 domain_decomposition(3) = this%starting_index
349 domain_decomposition(4) = this%ending_index
352 if (
present(parent_axis))
then
353 select type(parent_axis)
355 diag_axis => parent_axis
360 call this%write_diurnal_metadata(fms2io_fileobj)
365 select type (fms2io_fileobj)
368 type is (fmsnetcdffile_t)
371 call register_field(fms2io_fileobj, axis_name, diag_axis%type_of_data, (/axis_name/))
372 if (needs_domain_decomposition)
then
373 call register_variable_attribute(fms2io_fileobj, axis_name,
"domain_decomposition", &
374 domain_decomposition)
376 type is (fmsnetcdfdomainfile_t)
377 select case (type_of_domain)
382 call register_field(fms2io_fileobj, axis_name, diag_axis%type_of_data, (/axis_name/))
385 call register_axis(fms2io_fileobj, axis_name, diag_axis%cart_name, domain_position=diag_axis%domain_position)
386 call register_field(fms2io_fileobj, axis_name, diag_axis%type_of_data, (/axis_name/))
388 type is (fmsnetcdfunstructureddomainfile_t)
389 select case (type_of_domain)
393 call register_field(fms2io_fileobj, axis_name, diag_axis%type_of_data, (/axis_name/))
398 call register_field(fms2io_fileobj, axis_name, diag_axis%type_of_data, (/axis_name/))
403 if(
allocated(diag_axis%long_name)) &
404 call register_variable_attribute(fms2io_fileobj, axis_name,
"long_name", diag_axis%long_name, &
405 str_len=len_trim(diag_axis%long_name))
407 if (diag_axis%cart_name .NE.
"N") &
408 call register_variable_attribute(fms2io_fileobj, axis_name,
"axis", diag_axis%cart_name, str_len=1)
410 if (trim(diag_axis%units) .NE.
"none") &
411 call register_variable_attribute(fms2io_fileobj, axis_name,
"units", diag_axis%units, &
412 str_len=len_trim(diag_axis%units))
414 select case (diag_axis%direction)
416 call register_variable_attribute(fms2io_fileobj, axis_name,
"positive",
"up", str_len=2)
418 call register_variable_attribute(fms2io_fileobj, axis_name,
"positive",
"down", str_len=4)
422 if (.not. edges_in_file .and.
allocated(diag_axis%edges_name) .and. .not. is_subaxis)
then
423 call register_variable_attribute(fms2io_fileobj, axis_name,
"edges", diag_axis%edges_name, &
424 str_len=len_trim(diag_axis%edges_name))
427 if(
allocated(diag_axis%attributes))
then
428 do i = 1, diag_axis%num_attributes
429 select type (att_value => diag_axis%attributes(i)%att_value)
430 type is (
character(len=*))
431 call register_variable_attribute(fms2io_fileobj, axis_name, diag_axis%attributes(i)%att_name, &
432 trim(att_value(1)), str_len=len_trim(att_value(1)))
434 call register_variable_attribute(fms2io_fileobj, axis_name, diag_axis%attributes(i)%att_name, att_value)
444 class(fmsnetcdffile_t),
INTENT(INOUT) :: fms2io_fileobj
449 integer :: global_io_index(2)
452 call this%get_global_io_domain(global_io_index, fms2io_fileobj%is_file_using_netcdf_mpi())
453 call write_data(fms2io_fileobj, this%axis_name, this%axis_data(global_io_index(1):global_io_index(2)))
455 i = this%starting_index
456 j = this%ending_index
458 if (
present(parent_axis))
then
459 select type(parent_axis)
462 select type (vardata => parent_axis%axis_data)
463 type is (real(kind=r8_kind))
464 call write_data(fms2io_fileobj, this%subaxis_name, vardata(i:j))
465 type is (real(kind=r4_kind))
466 call write_data(fms2io_fileobj, this%subaxis_name, vardata(i:j))
471 call write_data(fms2io_fileobj, this%axis_name, this%diurnal_data)
479 integer,
intent(inout) :: naxis
481 integer,
intent(in) :: n_diurnal_samples
483 logical,
intent(in) :: is_edges
486 CHARACTER(32) :: axis_name
487 CHARACTER(32) :: long_name
488 CHARACTER(32) :: edges_name
489 CHARACTER(128) :: units
490 real(kind=r8_kind),
allocatable :: diurnal_data(:)
499 WRITE (axis_name,
'(a,i2.2)')
'time_of_day_edges_', n_diurnal_samples
500 long_name =
"time of day edges"
501 allocate(diurnal_data(n_diurnal_samples + 1))
502 diurnal_data(1) = 0.0
504 do i = 1, n_diurnal_samples
505 diurnal_data(i+1) = 24.0* real(i)/n_diurnal_samples
508 WRITE (axis_name,
'(a,i2.2)')
'time_of_day_', n_diurnal_samples
509 long_name =
"time of day"
510 allocate(diurnal_data(n_diurnal_samples))
512 do i = 1, n_diurnal_samples
513 diurnal_data(i) = 24.0*(real(i)-0.5)/n_diurnal_samples
515 WRITE (edges_name,
'(a,i2.2)')
'time_of_day_edges_', n_diurnal_samples
520 11
FORMAT(a,
' since ',i4.4,
'-',i2.2,
'-',i2.2,
' ',i2.2,
':',i2.2,
':',i2.2)
523 select type (diurnal_axis => diag_axis(naxis)%axis)
525 diurnal_axis%axis_id = naxis
526 diurnal_axis%ndiurnal_samples = n_diurnal_samples
527 diurnal_axis%axis_name = trim(axis_name)
528 diurnal_axis%long_name = trim(long_name)
529 diurnal_axis%units = trim(units)
530 diurnal_axis%diurnal_data = diurnal_data
531 diurnal_axis%edges_id = edges_id
533 WRITE (edges_name,
'(a,i2.2)')
'time_of_day_edges_', n_diurnal_samples
534 diurnal_axis%edges_name = trim(edges_name)
553 integer,
intent(in) :: axis_ids(2)
557 allocate(this%structured_ids(2))
558 this%structured_ids = axis_ids
572 rslt = this%structured_ids
585 if (
allocated(this%edges_id))
get_edges_id = this%edges_id
592 integer,
intent(out) :: global_io_index(2)
593 logical,
intent(in) :: use_collective_writes
595 type(
domain2d),
pointer :: io_domain
597 global_io_index(1) = 1
598 global_io_index(2) = this%length
600 if (
allocated(this%axis_domain))
then
601 select type(domain => this%axis_domain)
603 if (use_collective_writes)
then
604 io_domain => domain%domain2
609 if (this%cart_name .eq.
"X")
then
611 position=this%domain_position)
612 elseif (this%cart_name .eq.
"Y")
then
614 position=this%domain_position)
628 if (
allocated(this%axis_domain))
then
629 axis_length = this%axis_domain%length(this%cart_name, this%domain_position, this%length)
645 if (
allocated(this%aux)) rslt = trim(this%aux) .ne.
""
656 if (
allocated(this%set_name)) rslt = trim(this%set_name) .ne.
""
664 integer,
optional,
intent(inout) :: x_or_y
668 select case (trim(this%cart_name))
677 if (
present(x_or_y)) x_or_y = diag_null
686 integer,
intent(out) :: dim_size
687 integer,
intent(out) :: layout
690 integer :: layout_xy(2)
692 select type (domain => this%axis_domain)
697 if (this%cart_name .eq.
"X")
then
699 layout = layout_xy(1)
700 else if (this%cart_name .eq.
"Y")
then
702 layout = layout_xy(2)
712 character(len=:),
allocatable :: rslt
722 character(len=:),
allocatable :: rslt
730 integer,
intent(in) :: axis_id
732 this%axis_id = axis_id
739 CHARACTER(len=*),
intent(in) :: edges_name
740 integer,
intent(in) :: edges_id
746 this%edges_name = edges_name
747 this%edges_id = edges_id
752 subroutine get_indices(this, compute_idx, corners_indices, starting_index, ending_index, need_to_define_axis)
754 integer,
intent(in) :: compute_idx(:)
755 class(*),
intent(in) :: corners_indices(:)
756 integer,
intent(out) :: starting_index
758 integer,
intent(out) :: ending_index
760 logical,
intent(out) :: need_to_define_axis
763 integer :: subregion_start
764 integer :: subregion_end
769 select type (corners_indices)
770 type is (
integer(kind=i4_kind))
771 subregion_start = minval(corners_indices)
772 subregion_end = maxval(corners_indices)
776 need_to_define_axis = .false.
777 starting_index = diag_null
778 ending_index = diag_null
781 if (compute_idx(1) < subregion_start .and. compute_idx(2) < subregion_start)
return
782 if (compute_idx(1) > subregion_end .and. compute_idx(2) > subregion_end)
return
784 need_to_define_axis = .true.
785 if (compute_idx(1) >= subregion_start .and. compute_idx(2) >= subregion_end)
then
787 starting_index = compute_idx(1)
788 ending_index = subregion_end
789 else if (compute_idx(1) >= subregion_start .and. compute_idx(2) <= subregion_end)
then
791 starting_index = compute_idx(1)
792 ending_index = compute_idx(2)
793 else if (compute_idx(1) <= subregion_start .and. compute_idx(2) <= subregion_end)
then
795 starting_index = subregion_start
796 ending_index = compute_idx(2)
797 else if (compute_idx(1) <= subregion_start .and. compute_idx(2) >= subregion_end)
then
799 starting_index = subregion_start
800 ending_index = subregion_end
803 if (this%domain_position .ne. center)
then
804 if (subregion_end - subregion_start + 1 .eq. 1)
then
806 if (ending_index .eq. compute_idx(2)) need_to_define_axis = .false.
808 if (ending_index - starting_index + 1 .eq. 1)
then
810 if (starting_index .eq. compute_idx(2) .or. ending_index .eq. compute_idx(1)) &
811 need_to_define_axis = .false.
821 integer,
intent(inout) :: compute_idx(:)
822 logical,
intent(out) :: need_to_define_axis
823 integer,
optional,
intent(in) :: tile_number
826 need_to_define_axis = .false.
827 compute_idx = diag_null
829 if (.not.
allocated(this%axis_domain))
then
831 if (this%cart_name .eq.
"X" .or. this%cart_name .eq.
"Y")
then
833 compute_idx(2) =
size(this%axis_data)
834 need_to_define_axis = .true.
839 select type(domain => this%axis_domain)
841 if (
present(tile_number))
then
845 need_to_define_axis = .false.
851 select case (this%cart_name)
854 & position=this%domain_position)
855 need_to_define_axis = .true.
858 & position=this%domain_position)
859 need_to_define_axis = .true.
867 subroutine fill_subaxis(this, starting_index, ending_index, axis_id, parent_id, parent_axis_name, compute_idx, &
868 global_idx, zbounds, nz_subaxis)
870 integer ,
intent(in) :: starting_index
871 integer ,
intent(in) :: ending_index
872 integer ,
intent(in) :: axis_id
873 integer ,
intent(in) :: parent_id
874 character(len=*) ,
intent(in) :: parent_axis_name
875 integer ,
intent(in) :: compute_idx(2)
877 integer,
optional,
intent(in) :: global_idx(2)
879 real(kind=r4_kind),
optional,
intent(in) :: zbounds(2)
880 integer,
optional,
intent(in) :: nz_subaxis
884 character(len=2) :: nsubaxis_char
887 if (
present(nz_subaxis)) nsubaxis = nz_subaxis
889 this%axis_id = axis_id
892 this%starting_index = min(starting_index, ending_index)
893 this%ending_index = max(starting_index, ending_index)
894 this%parent_axis_id = parent_id
895 write(nsubaxis_char,
'(i2.2)') nsubaxis
896 this%subaxis_name = trim(parent_axis_name)//
"_sub"//nsubaxis_char
897 this%compute_idx = compute_idx
899 if (
present(zbounds))
then
901 allocate(this%zbounds(2))
902 this%zbounds = zbounds
905 if (
present(global_idx))
then
907 allocate(this%global_idx(2))
908 this%global_idx = global_idx
919 res = this%ending_index - this%starting_index + 1
927 indx = this%starting_index
935 indx = this%ending_index
943 indx = this%compute_idx
950 real(kind=r4_kind),
intent(in) :: zbounds(2)
953 is_same = zbounds(1) .eq. this%zbounds(1) .and. zbounds(2) .eq. this%zbounds(2)
972 function get_length(this, cart_axis, domain_position, global_length) &
975 character(len=*),
INTENT(IN) :: cart_axis
976 integer,
INTENT(IN) :: domain_position
977 integer,
INTENT(IN) :: global_length
983 if (trim(cart_axis) ==
"X")
call mpp_get_compute_domain(this%Domain2, xsize=length, position=domain_position)
984 if (trim(cart_axis) ==
"Y")
call mpp_get_compute_domain(this%Domain2, ysize=length, position=domain_position)
987 length = global_length
996 TYPE(
domain1d),
INTENT(in),
OPTIONAL :: Domain
997 TYPE(
domain2d),
INTENT(in),
OPTIONAL :: Domain2
998 TYPE(
domainug),
INTENT(in),
OPTIONAL :: DomainU
1002 this%Domain = domain
1004 this%Domain2 = domain2
1006 this%DomainUG = domainu
1015 if (
allocated(axis_array))
call mpp_error(fatal,
"The diag_axis containers is already allocated")
1027 if (
allocated(axis_array))
deallocate(axis_array)
1040 logical,
intent(in),
optional :: is_regional
1042 character(len=:),
allocatable :: axis_name
1046 axis_name = this%axis_name
1047 if (
present(is_regional))
then
1048 if (is_regional)
then
1049 if (this%cart_name .eq.
"X" .or. this%cart_name .eq.
"Y") axis_name = axis_name//
"_sub01"
1053 axis_name = this%subaxis_name
1064 if (this%cart_name .eq.
"Z")
is_z_axis = .true.
1070 character(len=*),
intent(in) :: cart_name
1072 select case (cart_name)
1073 case (
"X",
"Y",
"Z",
"T",
"U",
"N")
1075 call mpp_error(fatal,
"diag_axit_init: Invalid cart_name: "//cart_name//&
1076 "The acceptable values are X, Y, Z, T, U, N.")
1082 integer,
INTENT(IN) :: domain_position
1084 select case (domain_position)
1085 case (center, north, east)
1087 call mpp_error(fatal,
"diag_axit_init: Invalid domain_positon. &
1088 &The acceptable values are NORTH, EAST, CENTER")
1094 integer,
INTENT(IN) :: direction
1096 select case(direction)
1099 call mpp_error(fatal,
"diag_axit_init: Invalid direction. &
1100 &The acceptable values are-1 0 1")
1107 integer,
INTENT(IN) :: axis_id(:)
1108 integer,
INTENT(OUT) :: domain_type
1110 character(len=*),
INTENT(IN) :: var_name
1118 do i = 1,
size(axis_id)
1120 select type (axis => diag_axis(j)%axis)
1123 if (domain_type .ne. axis%type_of_domain)
then
1128 if ((axis%type_of_domain .eq.
two_d_domain .and.
size(axis_id) > 1) &
1129 & .or. axis%type_of_domain .eq.
ug_domain)
then
1130 domain_type = axis%type_of_domain
1131 domain => axis%axis_domain
1134 call mpp_error(fatal,
"The variable:"//trim(var_name)//
" has axis that are not in the same domain")
1145 integer,
intent(inout) :: naxis
1147 integer,
intent(in) :: is_x_or_y
1149 logical,
intent(out) :: write_on_this_pe
1151 integer :: compute_idx(2)
1152 integer :: global_idx(2)
1153 integer :: starting_index
1154 integer :: ending_index
1156 call parent_axis%get_compute_domain(compute_idx, write_on_this_pe, tile_number=subregion%tile)
1157 if (.not. write_on_this_pe)
return
1161 call parent_axis%get_indices(compute_idx, subregion%corners(:,is_x_or_y), starting_index, ending_index, &
1164 if (.not. write_on_this_pe)
return
1166 select type(corners=> subregion%corners)
1167 type is (
integer(kind=i4_kind))
1168 global_idx(1) = minval(corners(:,is_x_or_y))
1169 global_idx(2) = maxval(corners(:,is_x_or_y))
1173 call define_new_axis(diag_axis, parent_axis, naxis, parent_axis%axis_id, &
1174 starting_index, ending_index, compute_idx, global_idx)
1181 integer,
INTENT(in) :: axis_ids(:)
1182 integer,
intent(inout) :: naxis
1184 logical,
intent(in) :: is_cube_sphere
1185 logical,
intent(out) :: write_on_this_pe
1190 integer :: lat_indices(2)
1191 integer :: lon_indices(2)
1192 integer :: compute_idx(2)
1193 integer :: starting_index(2)
1195 integer :: ending_index(2)
1196 logical :: need_to_define_axis(2)
1198 integer :: parent_axis_ids(2)
1199 logical :: is_x_y_axis
1200 integer :: compute_idx_2(2, 2)
1201 integer :: global_idx (2, 2)
1203 write_on_this_pe = .false.
1204 need_to_define_axis = .true.
1205 parent_axis_ids = diag_null
1210 select type (corners => subregion%corners)
1211 type is (real(kind=r4_kind))
1212 lon(1) = minval(corners(:,1))
1213 lon(2) = maxval(corners(:,1))
1214 lat(1) = minval(corners(:,2))
1215 lat(2) = maxval(corners(:,2))
1218 if_is_cube_sphere:
if (is_cube_sphere)
then
1220 call get_local_indices_cubesphere(lat(1), lat(2), lon(1), lon(2),&
1221 & lon_indices(1), lon_indices(2), lat_indices(1), lat_indices(2))
1222 loop_over_axis_ids:
do i = 1,
size(axis_ids)
1223 select_axis_type:
select type (parent_axis => diag_axis(axis_ids(i))%axis)
1226 call parent_axis%get_compute_domain(compute_idx, is_x_y_axis)
1229 if (.not. is_x_y_axis) cycle
1233 if (parent_axis%cart_name .eq.
"X")
then
1234 call parent_axis%get_indices(compute_idx, lon_indices, starting_index(1), ending_index(1), &
1235 need_to_define_axis(1))
1236 parent_axis_ids(1) = axis_ids(i)
1237 compute_idx_2(1,:) = compute_idx
1238 global_idx(1,:) = lon_indices
1239 else if (parent_axis%cart_name .eq.
"Y")
then
1240 call parent_axis%get_indices(compute_idx, lat_indices, starting_index(2), ending_index(2), &
1241 need_to_define_axis(2))
1242 parent_axis_ids(2) = axis_ids(i)
1243 compute_idx_2(2,:) = compute_idx
1244 global_idx(2,:) = lat_indices
1246 end select select_axis_type
1247 enddo loop_over_axis_ids
1248 else if_is_cube_sphere
1249 loop_over_axis_ids2:
do i = 1,
size(axis_ids)
1250 select type (parent_axis => diag_axis(axis_ids(i))%axis)
1253 call parent_axis%get_compute_domain(compute_idx, is_x_y_axis)
1256 if (.not. is_x_y_axis) cycle
1259 if (parent_axis%cart_name .eq.
"X")
then
1260 select type(adata=>parent_axis%axis_data)
1261 type is (real(kind=r8_kind))
1262 lon_indices(1) =
nearest_index(real(lon(1), kind=r8_kind), adata)
1263 lon_indices(2) =
nearest_index(real(lon(2), kind=r8_kind), adata)
1264 type is (real(kind=r4_kind))
1265 lon_indices(1) =
nearest_index(real(lon(1), kind=r4_kind), adata)
1266 lon_indices(2) =
nearest_index(real(lon(2), kind=r4_kind), adata)
1268 call parent_axis%get_indices(compute_idx, lon_indices, starting_index(1), ending_index(1), &
1269 need_to_define_axis(1))
1270 parent_axis_ids(1) = axis_ids(i)
1271 compute_idx_2(1,:) = compute_idx
1272 global_idx(1,:) = lon_indices
1273 else if (parent_axis%cart_name .eq.
"Y")
then
1274 select type(adata=>parent_axis%axis_data)
1275 type is (real(kind=r8_kind))
1276 lat_indices(1) =
nearest_index(real(lat(1), kind=r8_kind), adata)
1277 lat_indices(2) =
nearest_index(real(lat(2), kind=r8_kind), adata)
1278 type is (real(kind=r4_kind))
1279 lat_indices(1) =
nearest_index(real(lat(1), kind=r4_kind), adata)
1280 lat_indices(2) =
nearest_index(real(lat(2), kind=r4_kind), adata)
1282 call parent_axis%get_indices(compute_idx, lat_indices, starting_index(2), ending_index(2), &
1283 need_to_define_axis(2))
1284 parent_axis_ids(2) = axis_ids(i)
1285 compute_idx_2(2,:) = compute_idx
1286 global_idx(2,:) = lat_indices
1289 enddo loop_over_axis_ids2
1290 endif if_is_cube_sphere
1293 if (any(.not. need_to_define_axis ))
return
1296 write_on_this_pe = .true.
1298 do i = 1,
size(parent_axis_ids)
1299 if (parent_axis_ids(i) .eq. diag_null) cycle
1300 select type (parent_axis => diag_axis(parent_axis_ids(i))%axis)
1302 call define_new_axis(diag_axis, parent_axis, naxis, parent_axis_ids(i), &
1303 starting_index(i), ending_index(i), compute_idx_2(i,:), global_idx(i,:))
1311 starting_index, ending_index, compute_idx, global_idx, new_axis_id, zbounds, &
1316 integer,
intent(inout) :: naxis
1318 integer,
intent(in) :: parent_id
1319 integer,
intent(in) :: starting_index
1320 integer,
intent(in) :: ending_index
1321 integer,
intent(in) :: compute_idx(2)
1323 integer,
optional,
intent(in) :: global_idx(2)
1325 integer,
optional,
intent(out) :: new_axis_id
1326 real(kind=r4_kind),
optional,
intent(in) :: zbounds(2)
1327 integer,
optional,
intent(in) :: nz_subaxis
1333 parent_axis%nsubaxis = parent_axis%nsubaxis + 1
1334 parent_axis%subaxis(parent_axis%nsubaxis) = naxis
1338 diag_axis(naxis)%axis%axis_id = naxis
1339 if (
present(new_axis_id)) new_axis_id = naxis
1341 select type (sub_axis => diag_axis(naxis)%axis)
1343 call sub_axis%fill_subaxis(starting_index, ending_index, naxis, parent_id, &
1344 parent_axis%axis_name, compute_idx, global_idx=global_idx, zbounds=zbounds, nz_subaxis=nz_subaxis)
1351 result(parent_axis_id)
1354 integer :: parent_axis_id
1358 parent_axis_id = diag_null
1360 parent_axis_id = this%parent_axis_id
1362 parent_axis_id = diag_null
1373 integer :: sub_axis_id
1375 sub_axis_id = this%axis_id
1378 if (this%cart_name .ne.
"Z") sub_axis_id = this%subaxis(this%nsubaxis)
1387 class(*),
intent(in) :: compress_att(:)
1388 character(len=120) :: axis_names(2)
1392 select type (compress_att)
1393 type is (
character(len=*))
1394 read(compress_att(1),*, iostat=ios) axis_names
1395 if (ios .ne. 0) axis_names =
""
1406 character(len=*),
intent(in) :: axis_name
1407 integer,
intent(in) :: naxis
1408 character(len=*),
intent(in) :: set_name
1415 select type(axis => diag_axis(i)%axis)
1417 if (trim(axis%axis_name) .eq. trim(axis_name))
then
1418 if (trim(axis%set_name) .eq. trim(set_name))
then
1431 result(n_diurnal_samples)
1434 integer :: n_diurnal_samples
1436 n_diurnal_samples = this%ndiurnal_samples
1442 class(fmsnetcdffile_t),
intent(inout) :: fms2io_fileobj
1444 call register_axis(fms2io_fileobj, this%axis_name,
size(this%diurnal_data))
1446 call register_variable_attribute(fms2io_fileobj, this%axis_name,
"units", &
1447 &trim(this%units), str_len=len_trim(this%units))
1448 call register_variable_attribute(fms2io_fileobj, this%axis_name,
"long_name", &
1449 &trim(this%long_name), str_len=len_trim(this%long_name))
1450 if (this%edges_id .ne. diag_null) &
1451 call register_variable_attribute(fms2io_fileobj, this%axis_name,
"edges", &
1452 &trim(this%edges_name), str_len=len_trim(this%edges_name))
1458 real(kind=r4_kind),
intent(in) :: zbounds(2)
1459 integer,
intent(inout) :: var_axis_ids(:)
1461 integer,
intent(inout) :: naxis
1463 integer,
intent(inout) :: file_axis_id(:)
1464 integer,
intent(inout) :: nfile_axis
1466 integer,
intent(inout) :: nz_subaxis
1468 character(len=*),
intent(inout) :: error_mseg
1471 class(*),
pointer :: zaxis_data(:)
1472 integer :: subaxis_indices(2)
1475 integer :: subaxis_id
1476 integer :: parent_axis_id
1477 integer :: zaxis_index
1480 parent_axis_id = diag_null
1481 zaxis_index = diag_null
1484 do i = 1,
size(var_axis_ids)
1485 select type (parent_axis => diag_axis(var_axis_ids(i))%axis)
1487 if (parent_axis%cart_name .eq.
"Z")
then
1488 parent_axis_id = var_axis_ids(i)
1494 if (parent_axis_id .eq. diag_null)
then
1495 call mpp_error(fatal,
"create_new_z_subaxis:: unable to find the zaxis for "//trim(error_mseg))
1499 do i = 1, nfile_axis
1500 select type (axis => diag_axis(file_axis_id(i))%axis)
1502 if (axis%parent_axis_id .ne. parent_axis_id) cycle
1503 if (axis%zbounds(1) .eq. zbounds(1) .and. axis%zbounds(2) .eq. zbounds(2))
then
1504 var_axis_ids(zaxis_index) = file_axis_id(i)
1510 select type (axis => diag_axis(parent_axis_id)%axis)
1512 zaxis_data => axis%axis_data
1516 select type(zaxis_data)
1517 type is (real(kind=r4_kind))
1519 subaxis_indices(1) =
nearest_index(real(zbounds(1)), real(zaxis_data))
1520 subaxis_indices(2) =
nearest_index(real(zbounds(2)), real(zaxis_data))
1521 type is (real(kind=r8_kind))
1522 subaxis_indices(1) =
nearest_index(real(zbounds(1)), real(zaxis_data))
1523 subaxis_indices(2) =
nearest_index(real(zbounds(2)), real(zaxis_data))
1526 nz_subaxis = nz_subaxis + 1
1527 call define_new_axis(diag_axis, parent_axis, naxis, parent_axis%axis_id, &
1528 &subaxis_indices(1), subaxis_indices(2), (/lbound(zaxis_data,1), ubound(zaxis_data,1)/), &
1529 &new_axis_id=subaxis_id, zbounds=zbounds, nz_subaxis=nz_subaxis)
1530 var_axis_ids(zaxis_index) = subaxis_id
1538 integer,
intent(in) :: axis_id
1539 integer,
intent(in) :: parent_axis_id
1545 select type(axis => diag_axis(axis_id)%axis)
1547 if (axis%parent_axis_id .eq. parent_axis_id) rslt = .true.
1554 character(len=*),
intent(inout) :: dim_name
1555 integer,
intent(in) :: parent_axis_id
1556 integer,
intent(in) :: file_axis_id(:)
1563 do i = 1,
size(file_axis_id)
1564 id = file_axis_id(i)
1565 select type (axis_ptr => diag_axis(id)%axis)
1567 if (axis_ptr%parent_axis_id .eq. parent_axis_id)
then
1568 if (axis_ptr%is_same_zbounds(field_yaml%get_var_zbounds()))
then
1569 dim_name = axis_ptr%subaxis_name
1575 call mpp_error(fatal,
"Unable to determine the z subaxis name for field "//&
1576 trim(field_yaml%get_var_varname())//
" in file: "//&
1577 trim(field_yaml%get_var_fname()))
1580 end module fms_diag_axis_object_mod
integer, parameter direction_down
The axis points down if positive.
integer function get_base_minute()
gets the module variable base_minute
integer function get_base_year()
gets the module variable base_year
integer function get_base_hour()
gets the module variable base_hour
integer, parameter no_domain
Use the FmsNetcdfFile_t fileobj.
integer max_axis_attributes
Maximum number of user definable attributes per axis.
character(len=6) pack_size_str
Pack size as a string to be used in fms2_io register call set to "double" or "float".
integer max_axes
Maximum number of independent axes.
integer, parameter is_x_axis
integer indicating that it is a x axis
integer, parameter is_y_axis
integer indicating that it is a y axis
integer function get_base_day()
gets the module variable base_day
integer, parameter ug_domain
Use the FmsNetcdfUnstructuredDomainFile_t fileobj.
integer, parameter direction_up
The axis points up if positive.
integer function get_base_month()
gets the module variable base_month
integer function get_base_second()
gets the module variable base_second
integer, parameter two_d_domain
Use the FmsNetcdfDomainFile_t fileobj.
Attribute type for diagnostic fields.
Type to hold the attributes of the field/axis/file.
subroutine, public get_local_indexes(latStart, latEnd, lonStart, lonEnd, istart, iend, jstart, jend)
Find the local start and local end indexes on the local PE for regional output.
Adds a dimension/axis to a given netcdf file object.
Defines a new field/variable within the given file. After a variable is registered,...
Write data to a registered field within a file Example usage:
subroutine, public define_new_subaxis_latlon(diag_axis, axis_ids, naxis, subRegion, is_cube_sphere, write_on_this_pe)
Fill in the subaxis object for a subRegion defined by lat lon.
subroutine get_dim_size_layout(this, dim_size, layout)
pure character(len=:) function, allocatable get_axis_name(this, is_regional)
integer function get_length(this, cart_axis, domain_position, global_length)
Get the length of a 2D domain.
integer function get_ending_index(this)
Accesses its member ending_index.
logical function, public fms_diag_axis_object_end(axis_array)
subroutine check_if_valid_domain_position(domain_position)
Check if a domain_position is valid and crashes if it isn't.
logical function is_x_or_y_axis(this, x_or_y)
Determine if an axis object is an x or y axis.
pure logical function is_unstructured_grid(this)
subroutine set_axis_id(this, axis_id)
Set the axis_id.
pure logical function is_z_axis(this)
integer function axis_length(this)
Get the axis length of a subaxis.
pure integer function get_diurnal_axis_samples(this)
integer function get_ntiles(this)
Get the ntiles in a domain.
subroutine, public define_new_subaxis_index(parent_axis, subRegion, diag_axis, naxis, is_x_or_y, write_on_this_pe)
Fill in the subaxis object for a subRegion defined by index.
subroutine, public find_z_sub_axis_name(dim_name, parent_axis_id, file_axis_id, field_yaml, diag_axis)
Determine the name of the z subaxis by matching the parent axis id and the zbounds in the diag table ...
pure integer function, public get_axis_id_from_name(axis_name, diag_axis, naxis, set_name)
subroutine get_compute_domain(this, compute_idx, need_to_define_axis, tile_number)
subroutine, public create_new_z_subaxis(zbounds, var_axis_ids, diag_axis, naxis, file_axis_id, nfile_axis, nz_subaxis, error_mseg)
Creates a new z subaxis to use.
subroutine, public define_diurnal_axis(diag_axis, naxis, n_diurnal_samples, is_edges)
Defined a new diurnal axis.
pure integer function, dimension(2) get_structured_axis(this)
pure logical function has_aux(this)
Determine if an axis object has an auxiliary name.
logical function is_same_zbounds(this, zbounds)
Determines if the zbounds passed in are the same as those in the file.
subroutine add_structured_axis_ids(this, axis_ids)
subroutine check_if_valid_cart_name(cart_name)
Check if a cart_name is valid and crashes if it isn't.
subroutine write_axis_metadata(this, fms2io_fileobj, edges_in_file, parent_axis)
Write the axis meta data to an open fileobj.
subroutine fill_subaxis(this, starting_index, ending_index, axis_id, parent_id, parent_axis_name, compute_idx, global_idx, zbounds, nz_subaxis)
Fills in the information needed to define a subaxis.
subroutine get_global_io_domain(this, global_io_index, use_collective_writes)
Get the starting and ending indices of the global io domain of the axis.
logical function, public fms_diag_axis_object_init(axis_array)
pure integer function get_subaxes_id(this)
integer function get_starting_index(this)
Accesses its member starting_index.
subroutine get_indices(this, compute_idx, corners_indices, starting_index, ending_index, need_to_define_axis)
Determine if the subRegion is in the current PE. If it is, determine the starting and ending indices ...
pure integer function get_parent_axis_id(this)
subroutine check_if_valid_direction(direction)
Check if a direction is valid and crashes if it isn't.
subroutine register_diag_axis_obj(this, axis_name, axis_data, units, cart_name, long_name, direction, set_name, Domain, Domain2, DomainU, aux, req, tile_count, domain_position, axis_length)
Initialize the axis.
subroutine write_axis_data(this, fms2io_fileobj, parent_axis)
Write the axis data to an open fms2io_fileobj.
subroutine, public define_new_axis(diag_axis, parent_axis, naxis, parent_id, starting_index, ending_index, compute_idx, global_idx, new_axis_id, zbounds, nz_subaxis)
Creates a new subaxis and fills it will all the information it needs.
integer function get_axis_length(this)
Get the length of the axis.
pure character(len=:) function, allocatable get_set_name(this)
Get the set name of an axis object.
pure character(len=120) function, dimension(2), public parse_compress_att(compress_att)
subroutine set_edges(this, edges_name, edges_id)
Set the name and ids of the edges.
logical function, public is_parent_axis(axis_id, parent_axis_id, diag_axis)
Determine if the diag_axis(parent_axis_id) is the parent of diag_axis(axis_id)
subroutine add_axis_attribute(this, att_name, att_value)
Add an attribute to an axis.
subroutine write_diurnal_metadata(this, fms2io_fileobj)
pure logical function has_set_name(this)
Determine if an axis object has a set_name.
pure integer function get_edges_id(this)
integer function, dimension(2) get_compute_indices(this)
Accesses its member compute_indices.
subroutine, public get_domain_and_domain_type(diag_axis, axis_id, domain_type, domain, var_name)
Loop through a variable's axis_id to determine and return the domain type and domain to use.
subroutine set_axis_domain(this, Domain, Domain2, DomainU)
Set the axis domain.
pure character(len=:) function, allocatable get_aux(this)
Get the auxiliary name of an axis object.
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
integer function mpp_get_ntile_count(domain)
Returns number of tiles in mosaic.
type(domain2d) function, pointer mpp_get_io_domain(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....
Retrieve layout associated with a domain decomposition The 1D version of this call returns the number...
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 stdout()
This function returns the current standard fortran unit numbers for output.
integer function mpp_pe()
Returns processor ID.
Type to hold the 1d domain.
Type to hold the 2d domain.
Type to hold the domain info for an axis This type was created to avoid having to send in "Domain",...
Type to hold the unstructured domain.
Type to hold the diagnostic axis description.
Type to hold the diag_axis (either subaxis or a full axis)
Type to hold the diurnal axis.
Type to hold the diagnostic axis description.
Type to hold the subaxis.
type to hold the info a diag_field
type to hold the sub region information about a file