diff --git a/diag_manager/fms_diag_bbox.F90 b/diag_manager/fms_diag_bbox.F90
index 956dabd31c..74a715aadb 100644
--- a/diag_manager/fms_diag_bbox.F90
+++ b/diag_manager/fms_diag_bbox.F90
@@ -57,6 +57,9 @@ MODULE fms_diag_bbox_mod
procedure :: get_jmax
procedure :: get_kmin
procedure :: get_kmax
+ procedure :: set_ibounds
+ procedure :: set_jbounds
+ procedure :: set_kbounds
END TYPE fmsDiagIbounds_type
!> @brief Data structure holding starting and ending indices in the I, J, and
@@ -79,6 +82,7 @@ MODULE fms_diag_bbox_mod
procedure :: get_fie
procedure :: get_fjs
procedure :: get_fje
+ procedure :: get_bounds3D
end type fmsDiagBoundsHalos_type
public :: recondition_indices
@@ -128,6 +132,36 @@ pure integer function get_kmax (this) result(rslt)
rslt = this%kmax
end function get_kmax
+ !> @brief Sets bounds in the I dimensions
+ subroutine set_ibounds(this, lower, upper)
+ class(fmsDiagIbounds_type), intent(inout) :: this !< The calling object
+ integer, intent(in) :: lower !< The lower bound
+ integer, intent(in) :: upper !< The upper bound
+
+ this%imin = lower
+ this%imax = upper
+ end subroutine set_ibounds
+
+ !> @brief Sets bounds in the J dimensions
+ subroutine set_jbounds(this, lower, upper)
+ class(fmsDiagIbounds_type), intent(inout) :: this !< The calling object
+ integer, intent(in) :: lower !< The lower bound
+ integer, intent(in) :: upper !< The upper bound
+
+ this%jmin = lower
+ this%jmax = upper
+ end subroutine set_jbounds
+
+ !> @brief Sets bounds in the K dimensions
+ subroutine set_kbounds(this, lower, upper)
+ class(fmsDiagIbounds_type), intent(inout) :: this !< The calling object
+ integer, intent(in) :: lower !< The lower bound
+ integer, intent(in) :: upper !< The upper bound
+
+ this%kmin = lower
+ this%kmax = upper
+ end subroutine set_kbounds
+
!> @brief Gets the halo size of fmsDiagBoundsHalos_type in the I dimension
!! @return copy of integer member hi
pure integer function get_hi (this) result(rslt)
@@ -142,34 +176,42 @@ pure integer function get_hj (this) result(rslt)
rslt = this%hj
end function get_hj
- !> @brief Gets the updated index `fis' of fmsDiagBoundsHalos_type in the I dimension
+ !> @brief Gets the updated starting index `fis' of fmsDiagBoundsHalos_type in the I dimension
!! @return copy of integer member `fis'
pure integer function get_fis (this) result(rslt)
class (fmsDiagBoundsHalos_type), intent(in) :: this !< Calling object
rslt = this%fis
end function get_fis
- !> @brief Gets the updated index `fie' of fmsDiagBoundsHalos_type in the I dimension
+ !> @brief Gets the updated ending index `fie' of fmsDiagBoundsHalos_type in the I dimension
!! @return copy of integer member `fie'
pure integer function get_fie (this) result(rslt)
class (fmsDiagBoundsHalos_type), intent(in) :: this !< Calling object
rslt = this%fie
end function get_fie
- !> @brief Gets the updated index `fjs' of fmsDiagBoundsHalos_type in the I dimension
+ !> @brief Gets the updated starting index `fjs' of fmsDiagBoundsHalos_type in the J dimension
!! @return copy of integer member `fjs'
pure integer function get_fjs (this) result(rslt)
class (fmsDiagBoundsHalos_type), intent(in) :: this !< Calling object
rslt = this%fjs
end function get_fjs
- !> @brief Gets the updated index `fje' of fmsDiagBoundsHalos_type in the I dimension
+ !> @brief Gets the updated ending index `fje' of fmsDiagBoundsHalos_type in the J dimension
!! @return copy of integer member `fje'
pure integer function get_fje (this) result(rslt)
class (fmsDiagBoundsHalos_type), intent(in) :: this !< Calling object
rslt = this%fje
end function get_fje
+ !> @brief Gets a member of fmsDiagIbounds_type, `bounds3D`, of calling fmsDiagBoundsHalos_type object.
+ !! @return Returns a copy of fmsDiagIbounds_type member `bounds3D`
+ pure function get_bounds3D(this) result(bounds_obj)
+ class(fmsDiagBoundsHalos_type), intent(in) :: this !< Calling object
+ type(fmsDiagIbounds_type) :: bounds_obj !< Object copy to return
+ bounds_obj = this%bounds3D
+ end function
+
!> @brief Reset the instance bounding lower and upper bounds to lower_val and upper_val, respectively.
SUBROUTINE reset_bounds (this, lower_val, upper_val)
class (fmsDiagIbounds_type), target, intent(inout) :: this !< ibounds instance
diff --git a/diag_manager/fms_diag_file_object.F90 b/diag_manager/fms_diag_file_object.F90
index 84c3f3980e..de566ec693 100644
--- a/diag_manager/fms_diag_file_object.F90
+++ b/diag_manager/fms_diag_file_object.F90
@@ -129,6 +129,10 @@ module fms_diag_file_object_mod
procedure, public :: get_file_duration_units
procedure, public :: get_file_varlist
procedure, public :: get_file_global_meta
+ procedure, public :: get_last_output
+ procedure, public :: get_next_output
+ procedure, public :: get_next_next_output
+ procedure, public :: get_no_more_data
procedure, public :: has_file_fname
procedure, public :: has_file_frequnit
procedure, public :: has_file_freq
@@ -559,6 +563,38 @@ pure function get_file_global_meta (this) result(res)
res = this%diag_yaml_file%get_file_global_meta()
end function get_file_global_meta
+!> \brief Gets last_output time
+!! \return Copy of last_output time
+pure function get_last_output (this) result(res)
+ class(fmsDiagFile_type), intent(in) :: this !< The file object
+ type(time_type) :: res
+ res = this%last_output
+end function get_last_output
+
+!> \brief Gets next_output time
+!! \return Copy of next_output time
+pure function get_next_output (this) result(res)
+ class(fmsDiagFile_type), intent(in) :: this !< The file object
+ type(time_type) :: res
+ res = this%next_output
+end function get_next_output
+
+!> \brief Gets next_next_output time
+!! \return Copy of next_next_output time
+pure function get_next_next_output (this) result(res)
+ class(fmsDiagFile_type), intent(in) :: this !< The file object
+ type(time_type) :: res
+ res = this%next_next_output
+end function get_next_next_output
+
+!> \brief Gets no_more_data time
+!! \return Copy of no_more_data time
+pure function get_no_more_data (this) result(res)
+ class(fmsDiagFile_type), intent(in) :: this !< The file object
+ type(time_type) :: res
+ res = this%no_more_data
+end function get_no_more_data
+
!> \brief Checks if file_fname is allocated in the yaml object
!! \return true if file_fname is allocated
pure function has_file_fname (this) result(res)
diff --git a/diag_manager/fms_diag_object.F90 b/diag_manager/fms_diag_object.F90
index 208be4b2f4..22f2d7822b 100644
--- a/diag_manager/fms_diag_object.F90
+++ b/diag_manager/fms_diag_object.F90
@@ -20,7 +20,9 @@ module fms_diag_object_mod
use mpp_mod, only: fatal, note, warning, mpp_error, mpp_pe, mpp_root_pe, stdout
use diag_data_mod, only: diag_null, diag_not_found, diag_not_registered, diag_registered_id, &
&DIAG_FIELD_NOT_FOUND, diag_not_registered, max_axes, TWO_D_DOMAIN, &
- &get_base_time, NULL_AXIS_ID, get_var_type, diag_not_registered
+ &get_base_time, NULL_AXIS_ID, get_var_type, diag_not_registered, EVERY_TIME, &
+ time_none, time_average, time_min, time_max, time_rms, time_sum, &
+ time_diurnal, time_power
USE time_manager_mod, ONLY: set_time, set_date, get_time, time_type, OPERATOR(>=), OPERATOR(>),&
& OPERATOR(<), OPERATOR(==), OPERATOR(/=), OPERATOR(/), OPERATOR(+), ASSIGNMENT(=), get_date, &
@@ -38,6 +40,9 @@ module fms_diag_object_mod
use fms_mod, only: fms_error_handler
use fms_diag_reduction_methods_mod, only: check_indices_order, init_mask, set_weight
use constants_mod, only: SECONDS_PER_DAY
+use fms_diag_bbox_mod, only: fmsDiagBoundsHalos_type, recondition_indices, fmsDiagIbounds_type
+use fms_diag_reduction_methods_mod, only: check_indices_order, init_mask_3d, real_copy_set, fms_diag_update_extremum, &
+ fms_diag_time_average
#endif
#if defined(_OPENMP)
use omp_lib
@@ -88,6 +93,7 @@ module fms_diag_object_mod
procedure :: fms_diag_field_add_cell_measures
procedure :: allocate_diag_field_output_buffers
procedure :: fms_diag_compare_window
+ procedure :: fms_diag_do_reduction
#ifdef use_yaml
procedure :: get_diag_buffer
#endif
@@ -517,6 +523,9 @@ logical function fms_diag_accept_data (this, diag_field_id, field_data, mask, rm
!! error message
logical, allocatable, dimension(:,:,:,:) :: oor_mask !< Out of range mask
real(kind=r8_kind) :: field_weight !< Weight to use when averaging (it will be converted
+ real :: weight2 !< Weight to be used in computation of sum, average, etc.
+ logical, allocatable, dimension(:,:,:) :: oor_mask !< Out of range mask
+
!! based on the type of field_data when doing the math)
#ifndef use_yaml
@@ -535,6 +544,30 @@ logical function fms_diag_accept_data (this, diag_field_id, field_data, mask, rm
error_string = check_indices_order(is_in, ie_in, js_in, je_in)
if (trim(error_string) .ne. "") call mpp_error(FATAL, trim(error_string)//". "//trim(field_info))
+ !> Input weight is for time averaging where each time level may have a different weight.
+ !! The input weight is polymorphic in intrinsic real types. If it is present it will be
+ !! assigned to weight2 else weight2 gets val value.
+ call real_copy_set(weight2, weight, 1., err_msg)
+
+ !> oor_mask is only used for checking out of range values.
+ if (present(rmask)) then
+ select type (rmask)
+ type is (real(kind=r4_kind))
+ call init_mask_3d(field_data, oor_mask, 0.5_r4_kind, mask, rmask)
+ type is (real(kind=r8_kind))
+ call init_mask_3d(field_data, oor_mask, 0.5_r8_kind, mask, rmask)
+ class default
+ call mpp_error(FATAL, "fms_diag_object_mod::fms_diag_accept_data unsupported type")
+ end select
+ end if
+
+ !> Check improper combinations of is, ie, js, and je.
+ if (check_indices_order(is_in, ie_in, js_in, je_in, err_msg)) then
+ !if (associated(field_data)) deallocate(field_data)
+ !if (allocated(oor_mask)) deallocate(oor_mask)
+ return
+ end if
+
!< If the field has `mask_variant=.true.`, check that mask OR rmask are present
if (this%FMS_diag_fields(diag_field_id)%is_mask_variant()) then
if (.not. associated(mask) .and. .not. associated(rmask)) call mpp_error(FATAL, &
@@ -1046,6 +1079,7 @@ subroutine allocate_diag_field_output_buffers(this, field_data, field_id)
! Loop over a number of fields/buffers where this variable occurs
do i = 1, size(this%FMS_diag_fields(field_id)%buffer_ids)
+ if (this%FMS_diag_fields(field_id)%buffer_allocated(i)) return !< The buffer is allocated before
buffer_id = this%FMS_diag_fields(field_id)%buffer_ids(i)
ndims = 0
@@ -1118,6 +1152,7 @@ subroutine allocate_diag_field_output_buffers(this, field_data, field_id)
class default
call mpp_error( FATAL, 'allocate_diag_field_output_buffers: invalid buffer type')
end select
+ this%FMS_diag_fields(field_id)%buffer_allocated(i) = .true. !< The buffer is allocated.
if (allocated(axis_ids)) deallocate(axis_ids)
deallocate(axes_length)
@@ -1130,49 +1165,280 @@ subroutine allocate_diag_field_output_buffers(this, field_data, field_id)
#endif
end subroutine allocate_diag_field_output_buffers
-!> @brief Determines if the window defined by the input bounds is a physics window.
-!> @return TRUE if the window size is less then the actual field size else FALSE.
-function fms_diag_compare_window(this, field, field_id, &
- is_in, ie_in, js_in, je_in, ks_in, ke_in) result(is_phys_win)
- class(fmsDiagObject_type), intent(in) :: this !< Diag Object
- class(*), intent(in) :: field(:,:,:,:) !< Field data
- integer, intent(in) :: field_id !< ID of the input field
- integer, intent(in) :: is_in, js_in !< Starting field indices for the first 2 dimensions;
- !< pass reconditioned indices fis and fjs
- !< which are computed elsewhere.
- integer, intent(in) :: ie_in, je_in !< Ending field indices for the first 2 dimensions;
- !< pass reconditioned indices fie and fje
- !< which are computed elsewhere.
- integer, intent(in) :: ks_in, ke_in !< Starting and ending indices of the field in 3rd dimension
- logical :: is_phys_win !< Return flag
+ !> @brief Determines if the window defined by the input bounds is a physics window.
+ !> @return TRUE if the window size is less then the actual field size else FALSE.
+ function fms_diag_compare_window(this, field, field_id, &
+ is_in, ie_in, js_in, je_in, ks_in, ke_in) result(is_phys_win)
+ class(fmsDiagObject_type), intent(in) :: this !< Diag Object
+ class(*), intent(in) :: field(:,:,:,:) !< Field data
+ integer, intent(in) :: field_id !< ID of the input field
+ integer, intent(in) :: is_in, js_in !< Starting field indices for the first 2 dimensions;
+ !< pass reconditioned indices fis and fjs
+ !< which are computed elsewhere.
+ integer, intent(in) :: ie_in, je_in !< Ending field indices for the first 2 dimensions;
+ !< pass reconditioned indices fie and fje
+ !< which are computed elsewhere.
+ integer, intent(in) :: ks_in, ke_in !< Starting and ending indices of the field in 3rd dimension
+ logical :: is_phys_win !< Return flag
#ifdef use_yaml
- integer, pointer :: axis_ids(:)
- integer :: total_elements
- integer :: i !< For do loop
- integer :: field_size
- integer, allocatable :: field_shape(:) !< Shape of the field data
- integer :: window_size
-
- !> Determine shape of the field defined by the input bounds
- field_shape = shape(field(is_in:ie_in, js_in:je_in, ks_in:ke_in, :))
-
- window_size = field_shape(1) * field_shape(2) * field_shape(3)
-
- total_elements = 1
- axis_ids => this%FMS_diag_fields(field_id)%get_axis_id()
- do i=1, size(axis_ids)
- total_elements = total_elements * this%fms_get_axis_length(axis_ids(i))
- enddo
+ integer, pointer :: axis_ids(:)
+ integer :: total_elements
+ integer :: i !< For do loop
+ integer :: field_size
+ integer, allocatable :: field_shape(:) !< Shape of the field data
+ integer :: window_size
+
+ !> Determine shape of the field defined by the input bounds
+ field_shape = shape(field(is_in:ie_in, js_in:je_in, ks_in:ke_in, :))
+
+ window_size = field_shape(1) * field_shape(2) * field_shape(3)
+
+ total_elements = 1
+ axis_ids => this%FMS_diag_fields(field_id)%get_axis_id()
+ do i=1, size(axis_ids)
+ total_elements = total_elements * this%fms_get_axis_length(axis_ids(i))
+ enddo
- if (total_elements > window_size) then
- is_phys_win = .true.
- else
- is_phys_win = .false.
- end if
+ if (total_elements > window_size) then
+ is_phys_win = .true.
+ else
+ is_phys_win = .false.
+ end if
#else
- is_phys_win = .false.
- call mpp_error( FATAL, "fms_diag_compare_window: "//&
- "you can not use the modern diag manager without compiling with -Duse_yaml")
+ call mpp_error( FATAL, "fms_diag_compare_window: "//&
+ "you can not use the modern diag manager without compiling with -Duse_yaml")
+#endif
+ end function fms_diag_compare_window
+
+ !> @brief Computes average, min, max, rms error, etc.
+ !! based on the specified reduction method for the field.
+ !> @return .True. if no error occurs.
+ function fms_diag_do_reduction(this, field_data, diag_field_id, oor_mask, weight, &
+ time, is_in, js_in, ks_in, ie_in, je_in, ke_in, err_msg) result(redn_done)
+ class(fmsDiagObject_type), intent(in), target :: this !< Diag Object
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ integer, intent(in) :: diag_field_id !< ID of the input field
+ logical, intent(in), target, contiguous :: oor_mask(:,:,:) !< Out of range mask
+ real, intent(in) :: weight !< Must be a updated weight
+ type(time_type), intent(in), optional :: time !< Current time
+ integer, intent(in), optional :: is_in, js_in, ks_in !< Starting indices of the variable
+ integer, intent(in), optional :: ie_in, je_in, ke_in !< Ending indices of the variable
+ character(len=*), intent(out), optional :: err_msg !< An error message returned
+ logical :: redn_done !< Return flag: .TRUE. if no error occurs
+#ifdef use_yaml
+ integer :: buffer_id !< Index of a buffer
+ integer :: file_id !< File id where the field/buffer is in
+ integer, allocatable :: freq(:) !< Output frequency
+ integer :: reduction_method !< Integer representing a reduction method: none, average, min, max, ... etc.
+ integer :: pow_val !< Exponent used in calculation of time average
+ logical :: phys_window !< Flag indicating if the field is a physics window
+ logical :: reduced_k_range !< Flag indicating if the field has zbounds
+ logical :: is_regional !< Flag to indicate if the field is regional
+ logical :: this_pe_writes !< Flag to indicate if the data from the current PE need to be written
+ integer, allocatable :: l_start(:) !< local start indices on axes for regional output
+ integer, allocatable :: l_end(:) !< local end indices on axes for regional output
+ integer :: day !< Number of days
+ integer :: second !< Number of seconds
+ integer :: tick !< Number of ticks representing fractional second
+ integer :: sample !< Index along the diurnal time axis
+ class(diagYamlFilesVar_type), pointer :: ptr_diag_field_yaml !< Pointer to a field from yaml fields
+ class(fmsDiagOutputBuffer_class), pointer :: ptr_diag_buffer_obj !< Pointer to the buffer class
+ character(len=128) :: error_string !< Store error text
+ integer :: updated_bounds(12) !< Adjusted starting and ending indices in the I, J, and K dimensions &
+ !! and halo sizes
+ logical :: has_diurnal_axis !< Flag to indicate if the field/buffer has a diurnal axis
+ character(len=128) :: field_name !< Field name for error reporting
+ type(fmsDiagBoundsHalos_type) :: bounds_with_halos !< Data structure that holds 3D bounds
+ !! in the I, J, and K dimensions and halo sizes
+ !! in the I, and J dimensions
+ integer :: id, ax !< For looping
+ integer :: n_axis !< Number of axes
+ integer :: axis_id !< Axis id
+ class(fmsDiagAxis_type), pointer :: ptr_axis !< Pointer of type diag_axis%axis
+ logical :: ierr !< Error flag
+ logical, pointer :: oor_mask_4d(:,:,:,:) !< Remapped out-of-range mask oor_mask
+ type(fmsDiagIbounds_type) :: IJKBounds !< Bounding object for the I, J, and K indices
+
+ redn_done = .FALSE.
+
+ !> Recondition the input indices
+ ierr = recondition_indices(bounds_with_halos, field_data, is_in, js_in, ks_in, &
+ ie_in, je_in, ke_in, err_msg)
+ if (ierr) return
+
+ !> Get the `bounds3D` member of the `recon_bounds`
+ IJKBounds = bounds_with_halos%get_bounds3D() !< Assignment of data structure with intrinsic type members may work!!!
+
+ !> Remap oor_mask to 4D array
+ oor_mask_4d => null()
+ oor_mask_4d(1:size(oor_mask,1), 1:size(oor_mask,2), 1:size(oor_mask,3), 1:1) => oor_mask
+
+ loop_over_buffer_id: do id = 1, size(this%FMS_diag_fields(diag_field_id)%buffer_ids)
+ file_id = this%FMS_diag_fields(diag_field_id)%file_ids(id)
+ !> Is this field output on a local domain only?
+ this_pe_writes = this%FMS_diag_files(file_id)%writing_on_this_pe()
+
+ !> If local_output, does the current PE take part in send_data?
+ is_regional = this%FMS_diag_files(file_id)%is_regional()
+
+ !> Skip all PEs not participating in outputting this field
+ if (.not.this_pe_writes) cycle
+
+ !> Store buffer ID of the i-th element of the buffer_ids(:)
+ buffer_id = this%FMS_diag_fields(diag_field_id)%buffer_ids(id)
+
+ !> Make local copies of field information
+ freq = this%FMS_diag_fields(diag_field_id)%get_frequency()
+ reduction_method = this%FMS_diag_fields(diag_field_id)%diag_field(id)%get_var_reduction()
+ has_diurnal_axis = this%FMS_diag_fields(diag_field_id)%diag_field(id)%has_n_diurnal()
+ field_name = this%FMS_diag_fields(diag_field_id)%diag_field(id)%get_var_fname()
+ reduced_k_range = this%FMS_diag_fields(diag_field_id)%diag_field(id)%has_var_zbounds()
+ if (this%FMS_diag_fields(diag_field_id)%diag_field(id)%has_pow_value()) THEN
+ pow_val = this%FMS_diag_fields(diag_field_id)%diag_field(id)%get_pow_value()
+ else
+ pow_val = 1 !< Default value, if not explicitly set, that guarantees simple weighted arithmetic mean
+ end if
+
+ !> Check if the field is a physics window
+ !! Pass fis, fie, fjs, fje, ks, and ke indices obtained from call to
+ !! recondition_indices() above as components of an array of indices output.
+ phys_window = this%fms_diag_compare_window(field_data, diag_field_id, &
+ bounds_with_halos%get_fis(), &
+ bounds_with_halos%get_fie(), &
+ bounds_with_halos%get_fjs(), &
+ bounds_with_halos%get_fje(), &
+ IJKBounds%get_kmin(), &
+ IJKBounds%get_kmax())
+
+ !> If sub regional output, get starting and ending indices
+ if (is_regional) then
+ if (allocated(this%FMS_diag_output_buffers(buffer_id)%axis_ids)) then
+ n_axis = size(this%FMS_diag_output_buffers(buffer_id)%axis_ids)
+ allocate(l_start(n_axis))
+ allocate(l_end(n_axis))
+ l_start = 1
+ l_end = 1
+ do ax = 1, n_axis
+ ptr_axis => this%diag_axis(this%FMS_diag_output_buffers(buffer_id)%axis_ids(ax))%axis
+ select type (ptr_axis)
+ type is (fmsDiagSubAxis_type)
+ l_start(ax) = ptr_axis%get_starting_index()
+ l_end(ax) = ptr_axis%get_ending_index()
+ type is (fmsDiagFullAxis_type)
+ l_start(ax) = 1
+ l_end(ax) = ptr_axis%axis_length()
+ class default
+ call mpp_error(FATAL, 'fms_diag_object_mod::fms_diag_do_reduction non fmsDiagSubAxis_type axis')
+ end select
+ end do
+ else
+ call mpp_error(FATAL, 'fms_diag_object_mod::fms_diag_do_reduction '//&
+ 'member axis_ids of the current buffer is not allocated')
+ end if
+ end if
+
+ !> Get the vertical layer starting and ending indices
+ if (reduced_k_range) then
+ if (.not.allocated(l_start)) then
+ allocate(l_start(3))
+ l_start = 1
+ endif
+ if (.not.allocated(l_end)) then
+ allocate(l_end(3))
+ l_end = 1
+ endif
+ ptr_axis => this%diag_axis(this%FMS_diag_output_buffers(buffer_id)%axis_ids(2))%axis !< Axis in the J dimension
+ select type (ptr_axis)
+ type is (fmsDiagSubAxis_type)
+ if (ptr_axis%is_unstructured_grid()) then
+ call IJKBounds%set_jbounds(ptr_axis%get_starting_index(), &
+ ptr_axis%get_ending_index())
+ end if
+ l_start(3) = ptr_axis%get_starting_index()
+ l_end(3) = ptr_axis%get_ending_index()
+ class default
+ call mpp_error(FATAL, 'fms_diag_object_mod::fms_diag_do_reduction Not a fmsDiagSubAxis_type axis')
+ end select
+
+ ptr_axis => this%diag_axis(this%FMS_diag_output_buffers(buffer_id)%axis_ids(3))%axis !< Axis in the K dimension
+ select type (ptr_axis)
+ type is (fmsDiagSubAxis_type)
+ l_start(3) = ptr_axis%get_starting_index()
+ l_end(3) = ptr_axis%get_ending_index()
+ class default
+ call mpp_error(FATAL, 'fms_diag_object_mod::fms_diag_do_reduction Not a fmsDiagSubAxis_type axis')
+ end select
+ end if
+
+ ! Compute the diurnal index
+ sample = 1
+ if (present(time)) then
+ call get_time(time, second, day, tick) !< Current time in days and seconds
+ ptr_diag_field_yaml => diag_yaml%get_diag_field_from_id(buffer_id)
+ sample = floor((second + real(tick) / get_ticks_per_second()) &
+ & * ptr_diag_field_yaml%get_n_diurnal() / SECONDS_PER_DAY) + 1
+ end if
+
+ ! Check if time is not present for fields output every time step
+ if (all(freq(:) == EVERY_TIME) .and. .not.this%FMS_diag_fields(diag_field_id)%is_static()) then
+ if (this%FMS_diag_files(file_id)%FMS_diag_file%get_next_output() == &
+ this%FMS_diag_files(file_id)%FMS_diag_file%get_last_output()) then
+ if (.not.present(time)) then
+ write (error_string,'(a,"/",a)') trim(this%FMS_diag_fields(diag_field_id)%get_modname()),&
+ trim(this%FMS_diag_fields(diag_field_id)%diag_field(id)%get_var_outname())
+ if (fms_error_handler('fms_diag_object_mod::fms_diag_accept_data', 'module/output_name: '&
+ &//trim(error_string)//', time must be present when output frequency = EVERY_TIME', err_msg)) then
+ return
+ end if
+ end if
+ end if
+ end if
+
+ ! Check if time should be present for this field
+ if (.not.this%FMS_diag_fields(diag_field_id)%is_static() .and. .not.present(time)) then
+ write(error_string, '(a,"/",a)') trim(this%FMS_diag_fields(diag_field_id)%get_modname()),&
+ & trim(this%FMS_diag_fields(diag_field_id)%diag_field(id)%get_var_outname())
+ if (fms_error_handler('fms_diag_object_mod::fms_diag_accept_data', 'module/output_name: '&
+ &//trim(error_string)//', time must be present for nonstatic field', err_msg)) then
+ return
+ end if
+ end if
+
+ !!TODO: Is check to bounds of current field necessary?
+
+ ptr_diag_buffer_obj => this%FMS_diag_output_buffers(buffer_id)%diag_buffer_obj
+
+ !!TODO: Take care of submitted field data
+ Reduction: select case (reduction_method)
+ case (time_none)
+ !! TODO: just copy field data to buffer
+ case (time_average)
+ call fms_diag_time_average(time_average, this%FMS_diag_fields(diag_field_id), ptr_diag_buffer_obj, &
+ field_data, bounds_with_halos, l_start, l_end, is_regional, reduced_k_range, sample, &
+ oor_mask_4d, field_name, has_diurnal_axis, phys_window, weight, pow_val, err_msg)
+ case (time_rms)
+ !! TODO: root-mean-square error
+ case (time_max)
+ call fms_diag_update_extremum(time_max, ptr_diag_buffer_obj, field_data, bounds_with_halos, l_start, &
+ l_end, is_regional, reduced_k_range, sample, oor_mask_4d, field_name, has_diurnal_axis, err_msg)
+ case (time_min)
+ call fms_diag_update_extremum(time_min, ptr_diag_buffer_obj, field_data, bounds_with_halos, l_start, &
+ l_end, is_regional, reduced_k_range, sample, oor_mask_4d, field_name, has_diurnal_axis, err_msg)
+ case (time_sum)
+ !! TODO: sum for the interval
+ !! call fms_diag_sum(time_sum, .......)
+ case (time_diurnal)
+ !! TODO: diurnal calculation
+ case (time_power)
+ !! TODO: reduction is power
+ case default
+ call mpp_error(FATAL, "fms_diag_object_mod::fms_diag_accept_data unsupported reduction method!")
+ end select Reduction
+ enddo loop_over_buffer_id
+ redn_done = .TRUE.
+#else
+ call mpp_error( FATAL, "fms_diag_object_mod::fms_diag_do_reduction "//&
+ "you can not use the modern diag manager without compiling with -Duse_yaml")
#endif
-end function fms_diag_compare_window
+ end function fms_diag_do_reduction
end module fms_diag_object_mod
diff --git a/diag_manager/fms_diag_reduction_methods.F90 b/diag_manager/fms_diag_reduction_methods.F90
index 8962638c04..8a8efd1011 100644
--- a/diag_manager/fms_diag_reduction_methods.F90
+++ b/diag_manager/fms_diag_reduction_methods.F90
@@ -1,43 +1,73 @@
-!***********************************************************************
-!* GNU Lesser General Public License
-!*
-!* This file is part of the GFDL Flexible Modeling System (FMS).
-!*
-!* FMS is free software: you can redistribute it and/or modify it under
-!* the terms of the GNU Lesser General Public License as published by
-!* the Free Software Foundation, either version 3 of the License, or (at
-!* your option) any later version.
-!*
-!* FMS is distributed in the hope that it will be useful, but WITHOUT
-!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-!* for more details.
-!*
-!* You should have received a copy of the GNU Lesser General Public
-!* License along with FMS. If not, see .
-!***********************************************************************
-
-!> @defgroup fms_diag_reduction_methods_mod fms_diag_reduction_methods_mod
-!> @ingroup diag_manager
-!! @brief fms_diag_reduction_methods_mod contains routines that are meant to be used for
-!! error checking and setting up to do the reduction methods
-
-!> @file
-!> @brief File for @ref fms_diag_reduction_methods_mod
-
-!> @addtogroup fms_diag_reduction_methods_mod
-!> @{
+!> \author Ganga Purja Pun
+!> \email GFDL.Climate.Model.Info@noaa.gov
+!! \brief Contains routines for the modern diag manager
+!! These routines are meant to be used for checks and in reduction methods.
+
module fms_diag_reduction_methods_mod
- use platform_mod, only: r8_kind, r4_kind
+ use platform_mod
+ use mpp_mod, only: mpp_error
+ use fms_mod, only: fms_error_handler
+ use fms_diag_bbox_mod
+ use fms_diag_output_buffer_mod
+ use diag_data_mod, only: debug_diag_manager, time_max, time_min, time_average, time_sum
+ use fms_diag_field_object_mod, only: fmsDiagField_type
+
implicit none
private
- public :: check_indices_order, init_mask, set_weight
-
+#ifdef use_yaml
+ public :: compare_two_sets_of_bounds, real_copy_set, check_indices_order, init_mask_3d
+ public :: fms_diag_update_extremum, update_scalar_extremum, update_array_extremum
+ public :: fms_diag_time_average, fms_diag_mask_variant_do_sum, sum_scalar_field_data
+ public :: fms_diag_no_mask_variant_do_sum, update_buffer_obj_num_elements, set_buffer_obj_count_0d
+ public :: update_buffer_obj_count_0d
contains
+ !> @brief Compares the corresponding bounding indices of the first set with the second set.
+ !> @return .TRUE. if any comparison returns true; i.e. the box bounded by the indices of the first set
+ !! is out side the box bounded by the indices of the second set.
+ LOGICAL FUNCTION compare_two_sets_of_bounds(bounds_a, bounds_b, error_str)
+ integer, intent(in) :: bounds_a(:) !< First array with order: (/imin, imax, jmin, jmax, kmin, kmax/)
+ integer, intent(in) :: bounds_b(:) !< Second array with the same order as the first
+ character(*), intent(out) :: error_str !< Error message to report back
+
+ compare_two_sets_of_bounds = .FALSE.
+
+ if (size(bounds_a) .ne. size(bounds_b)) then
+ compare_two_sets_of_bounds = .TRUE.
+ error_str = 'fms_diag_reduction_methods_mod::compare_two_sets_of_bounds Error: sizes of sets do not match'
+ else
+ if ((size(bounds_a) .ne. 6) .and. (size(bounds_b) .ne. 6)) then
+ compare_two_sets_of_bounds = .TRUE.
+ error_str = 'fms_diag_reduction_methods_mod::compare_two_sets_of_bounds Error: sizes of sets must be 6'
+ end if
+ end if
+
+ IF (bounds_a(1) .lt. bounds_b(1) .OR. bounds_a(2) .gt. bounds_b(2) .OR. &
+ bounds_a(3) .lt. bounds_b(3) .OR. bounds_a(4) .gt. bounds_b(4) .OR. &
+ bounds_a(5) .lt. bounds_b(5) .OR. bounds_a(6) .gt. bounds_b(6)) THEN
+ compare_two_sets_of_bounds = .TRUE.
+ error_str ='First set of bounds= : , : , : Second set of bounds= : , : , : '
+ WRITE(error_str(21:23),'(i3)') bounds_a(1)
+ WRITE(error_str(25:27),'(i3)') bounds_a(2)
+ WRITE(error_str(29:31),'(i3)') bounds_a(3)
+ WRITE(error_str(33:35),'(i3)') bounds_a(4)
+ WRITE(error_str(37:39),'(i3)') bounds_a(5)
+ WRITE(error_str(41:43),'(i3)') bounds_a(6)
+ WRITE(error_str(68:70),'(i3)') bounds_b(1)
+ WRITE(error_str(72:74),'(i3)') bounds_b(2)
+ WRITE(error_str(76:78),'(i3)') bounds_b(3)
+ WRITE(error_str(80:82),'(i3)') bounds_b(4)
+ WRITE(error_str(84:86),'(i3)') bounds_b(5)
+ WRITE(error_str(88:90),'(i3)') bounds_b(6)
+ ELSE
+ compare_two_sets_of_bounds = .FALSE.
+ error_str = ''
+ END IF
+ END FUNCTION compare_two_sets_of_bounds
+
!> @brief Checks improper combinations of is, ie, js, and je.
- !! @return The error message, empty string if no errors were found
+ !> @return Returns .false. if there is no error else .true.
!> @note accept_data works in either one or another of two modes.
!! 1. Input field is a window (e.g. FMS physics)
!! 2. Input field includes halo data
@@ -49,81 +79,2051 @@ module fms_diag_reduction_methods_mod
!> @par
!! There are a number of ways a user could mess up this logic, depending on the combination
!! of presence/absence of is,ie,js,je. The checks below should catch improper combinations.
- pure function check_indices_order(is_in, ie_in, js_in, je_in) &
- result(error_msg)
+ function check_indices_order(is_in, ie_in, js_in, je_in, error_msg) result(rslt)
integer, intent(in), optional :: is_in, ie_in, js_in, je_in !< Indices passed to fms_diag_accept_data()
- character(len=128) :: error_msg !< An error message used only for testing purpose!!!
+ character(len=*), intent(inout), optional :: error_msg !< An error message used only for testing purpose!!!
+
+ character(len=52) :: err_module_name !< Stores the module name to be used in error calls
+ logical :: rslt !< Return value
+
+ rslt = .false. !< If no error occurs.
+
+ err_module_name = 'fms_diag_reduction_methods_mod::check_indices_order'
- error_msg = ""
IF ( PRESENT(ie_in) ) THEN
IF ( .NOT.PRESENT(is_in) ) THEN
- error_msg = 'ie_in present without is_in'
- return
+ rslt = fms_error_handler(trim(err_module_name), 'ie_in present without is_in', error_msg)
+ IF (rslt) return
END IF
IF ( PRESENT(js_in) .AND. .NOT.PRESENT(je_in) ) THEN
- error_msg = 'is_in and ie_in present, but js_in present without je_in'
- return
+ rslt = fms_error_handler(trim(err_module_name),&
+ & 'is_in and ie_in present, but js_in present without je_in', error_msg)
+ IF (rslt) return
END IF
END IF
IF ( PRESENT(je_in) ) THEN
IF ( .NOT.PRESENT(js_in) ) THEN
- error_msg = 'je_in present without js_in'
- return
+ rslt = fms_error_handler(trim(err_module_name), 'je_in present without js_in', error_msg)
+ IF (rslt) return
END IF
IF ( PRESENT(is_in) .AND. .NOT.PRESENT(ie_in) ) THEN
- error_msg = 'js_in and je_in present, but is_in present without ie_in'
- return
+ rslt = fms_error_handler(trim(err_module_name),&
+ & 'js_in and je_in present, but is_in present without ie_in', error_msg)
+ IF (rslt) return
END IF
END IF
end function check_indices_order
- !> @brief Sets the logical mask based on mask or rmask
- !> @return logical mask
- function init_mask(rmask, mask, field) &
- result(oor_mask)
- LOGICAL, DIMENSION(:,:,:,:), pointer, INTENT(in) :: mask !< The location of the mask
- CLASS(*), DIMENSION(:,:,:,:), pointer, INTENT(in) :: rmask !< The masking values
- CLASS(*), DIMENSION(:,:,:,:), intent(in) :: field !< Field_data
+ !> @brief Copies input data to output data with specific type and precision
+ !! if the input data is present else sets the output data to a given value val if it is present.
+ !! If the value val and the input data are not present, the output data is untouched.
+ subroutine real_copy_set(out_data, in_data, val, err_msg)
+ real, intent(out) :: out_data !< Proper type copy of in_data
+ class(*), intent(in), optional :: in_data !< Data to copy to out_data
+ real, intent(in), optional :: val !< Default value to assign to out_data if in_data is absent
+ character(len=*), intent(out), optional :: err_msg !< Error message to pass back to caller
+
+ IF ( PRESENT(err_msg) ) err_msg = ''
+
+ IF ( PRESENT(in_data) ) THEN
+ SELECT TYPE (in_data)
+ TYPE IS (real(kind=r4_kind))
+ out_data = in_data
+ TYPE IS (real(kind=r8_kind))
+ out_data = real(in_data)
+ CLASS DEFAULT
+ if (fms_error_handler('fms_diag_reduction_methods_mod::real_copy_set',&
+ & 'The in_data is not one of the supported types of real(kind=4) or real(kind=8)', err_msg)) THEN
+ return
+ end if
+ END SELECT
+ ELSE
+ if (present(val)) then
+ out_data = val
+ else
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::real_copy_set both in_data and val can be absent')
+ end if
+ END IF
+ end subroutine real_copy_set
+
+ !> @brief Allocates `outmask'(second argument) with sizes of the first three dimensions of
+ !! the field(first argument).
+ !! Initializes the `outmask' depending on presence/absence of `inmask' and `rmask'.
+ !! Uses `rmask_threshold' to set the `outmask'.
+ subroutine init_mask_3d(field, outmask, rmask_threshold, inmask, rmask, err_msg)
+ class(*), intent(in) :: field(:,:,:,:) !< Dummy variable whose sizes only in the first three
+ !! dimensions are important
+ logical, allocatable, intent(inout) :: outmask(:,:,:) !< Output logical mask
+ class(*), intent(in) :: rmask_threshold !< Holds the values 0.5_r4_kind or 0.5_r8_kind, or related threhold values
+ !! needed to be passed to the math/buffer update functions.
+ logical, intent(in), optional :: inmask(:,:,:) !< Input logical mask
+ class(*), intent(in), optional :: rmask(:,:,:) !< Floating point input mask value
+ character(len=*), intent(out), optional :: err_msg !< Error message to relay back to caller
+
+ character(len=256) :: err_msg_local !< Stores locally generated error message
+ integer :: status !< Stores status of memory allocation call
+
+ ! Initialize character strings
+ err_msg_local = ''
+ if (present(err_msg)) err_msg = ''
+
+ ! Check if outmask is allocated
+ if (allocated(outmask)) deallocate(outmask)
+ ALLOCATE(outmask(SIZE(field, 1), SIZE(field, 2), SIZE(field, 3)), STAT=status)
+ IF ( status .NE. 0 ) THEN
+ WRITE (err_msg_local, FMT='("Unable to allocate outmask(",I5,",",I5,",",I5,"). (STAT: ",I5,")")')&
+ & SIZE(field, 1), SIZE(field, 2), SIZE(field, 3), status
+ if (fms_error_handler('fms_diag_reduction_methods_mod::init_mask_3d', trim(err_msg_local), err_msg)) then
+ return
+ end if
+ END IF
+
+ IF ( PRESENT(inmask) ) THEN
+ outmask = inmask
+ ELSE
+ outmask = .TRUE.
+ END IF
+
+ IF ( PRESENT(rmask) ) THEN
+ SELECT TYPE (rmask)
+ TYPE IS (real(kind=r4_kind))
+ select type (rmask_threshold)
+ type is (real(kind=r4_kind))
+ WHERE (rmask < rmask_threshold) outmask = .FALSE.
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::init_mask_3d'//&
+ ' types of rmask and rmask_threshold do not match')
+ end select
+ TYPE IS (real(kind=r8_kind))
+ select type (rmask_threshold)
+ type is (real(kind=r8_kind))
+ WHERE (rmask < rmask_threshold) outmask = .FALSE.
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::init_mask_3d'//&
+ ' types of rmask and rmask_threshold do not match')
+ end select
+ CLASS DEFAULT
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::init_mask_3d'//&
+ & ' The rmask is not one of the supported types of real(kind=4) or real(kind=8)')
+ END SELECT
+ END IF
+ end subroutine init_mask_3d
+
+ !> @brief Updates the buffer with the field data based on the value of the flag passed:
+ !! time_min for minimum; time_max for maximum.
+ subroutine fms_diag_update_extremum(flag, buffer_obj, field_data, recon_bounds, l_start, &
+ l_end, is_regional, reduced_k_range, sample, mask, fieldName, hasDiurnalAxis, err_msg)
+ integer, intent(in) :: flag !< Flag to indicate what to update: time_min for minimum; time_max for maximum
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ type(fmsDiagBoundsHalos_type), intent(inout) :: recon_bounds !< Indices of bounds in the first three dimension
+ !! of the field data
+ integer, intent(in) :: l_start(:) !< Local starting indices for the first three dimensions
+ integer, intent(in) :: l_end(:) !< Local ending indices for the first three dimensions
+ logical, intent(in) :: is_regional !< Flag indicating if the current PE takes part in send_data
+ logical, intent(in) :: reduced_k_range !< Flag indicating if the field has zbounds
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+ logical, intent(in) :: mask(:,:,:,:) !< Must be out of range mask
+ character(len=*), intent(in) :: fieldName !< Field name for error reporting
+ logical, intent(in) :: hasDiurnalAxis !< Flag to indicate if the buffer has a diurnal axis
+ character(len=*), intent(inout), optional :: err_msg !< Error mesage to report back
+
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+ integer :: f1, f2 !< Updated starting and ending indices in the I dimension
+ integer :: f3, f4 !< Updated starting and ending indices in the J dimension
+ integer :: ksr, ker !< Reduced indices in the K dimension
+ integer :: i, j, k !< For loops
+ integer :: i1, j1, k1 !< Intermediate computed indices
+ character(len=128) :: err_msg_local !< Stores local error message
+ class(*), pointer :: ptr_buffer(:,:,:,:,:) !< Pointer to 5D buffer for remapping
+ type(fmsDiagIbounds_type) :: IJKBounds !< Bounding object for the I, J, and K indices
+
+ !> Get the `bounds3D` member of the `recon_bounds`
+ IJKBounds = recon_bounds%get_bounds3D() !< Assignment of data structure with intrinsic type members may work!!!
+
+ !> Unpack recon_bounds
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ f1 = recon_bounds%get_fis()
+ f2 = recon_bounds%get_fie()
+ hj = recon_bounds%get_hj()
+ f3 = recon_bounds%get_fjs()
+ f4 = recon_bounds%get_fje()
- logical, allocatable, dimension(:,:,:,:) :: oor_mask !< mask
+ if (flag .ne. 3 .and. flag .ne. 4) then
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::fms_diag_update_extremum: flag must be either 3 or 4.")
+ end if
- ALLOCATE(oor_mask(SIZE(field, 1), SIZE(field, 2), SIZE(field, 3), SIZE(field, 4)))
- oor_mask = .true.
+ !! TODO: remap buffer before passing to subroutines update_scalar_extremum and update_array_extremum
+ ptr_buffer => buffer_obj%remap_buffer(fieldName, hasDiurnalAxis)
- if (associated(mask)) then
- oor_mask = mask
- elseif (associated(rmask)) then
- select type (rmask)
+ ! Update buffer
+ regional_if: IF (is_regional) THEN
+ DO k = l_start(3), l_end(3)
+ k1 = k - l_start(3) + 1
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ type is (outputBuffer1d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ type is (outputBuffer2d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ type is (outputBuffer3d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ type is (outputBuffer4d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ type is (outputBuffer5d_type)
+ call update_scalar_extremum(flag, field_data, ptr_buffer, mask, sample, &
+ recon_bounds, (/i,j,k/), (/i1,j1,k1/))
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' regional buffer_obj is not one of the support buffer types: outputBuffer0d_type'//&
+ ' outputBuffer1d_type outputBuffer2d_type outputBuffer3d_type'//&
+ ' outputBuffer4d_type outputBuffer5d_type')
+ end select
+ end if
+ END DO
+ END DO
+ END DO
+ ELSE !< if not regional
+ reduced_k_range_if: IF (reduced_k_range) THEN
+ call IJKBounds%set_kbounds(l_start(3), l_end(3))
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer1d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer2d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer3d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer4d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer5d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum in reduced_k_range_if'//&
+ ' regional buffer_obj is not one of the support buffer types: outputBuffer0d_type'//&
+ ' outputBuffer1d_type outputBuffer2d_type outputBuffer3d_type'//&
+ ' outputBuffer4d_type outputBuffer5d_type')
+ end select
+ ELSE !< does not have reduced_k_range
+ debug_diag_if: IF ( debug_diag_manager ) THEN
+ ! Compare bounds {is-hi, ie-hi, js-hj, je-hj, ks, ke} with the bounds of first three dimensions of the buffer
+ if (compare_two_sets_of_bounds((/is-hi, ie-hi, js-hj, je-hj, ks, ke/), &
+ (/LBOUND(ptr_buffer,1), UBOUND(ptr_buffer,1), LBOUND(ptr_buffer,2), UBOUND(ptr_buffer,2), &
+ LBOUND(ptr_buffer,3), UBOUND(ptr_buffer,3)/), err_msg_local)) THEN
+ IF ( fms_error_handler('fms_diag_object_mod::fms_diag_update_extremum', err_msg_local, err_msg) ) THEN
+ RETURN
+ END IF
+ END IF
+ END IF debug_diag_if
+
+ !> If no error above, do update the buffer
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer1d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer2d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer3d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer4d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ type is (outputBuffer5d_type)
+ call update_array_extremum(flag, field_data, ptr_buffer, mask, sample, recon_bounds, reduced_k_range)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' regional buffer_obj is not one of the support buffer types: outputBuffer0d_type'//&
+ ' outputBuffer1d_type outputBuffer2d_type outputBuffer3d_type'//&
+ ' outputBuffer4d_type outputBuffer5d_type')
+ end select
+ END IF reduced_k_range_if
+ end if regional_if
+
+ ! Reset counter count_0d of the buffer object
+ call set_buffer_obj_count_0d(buffer_obj, 1.0)
+ end subroutine fms_diag_update_extremum
+
+ !> @brief Sets the counter `count_0d` of a buffer object to a given value
+ subroutine set_buffer_obj_count_0d(buffer_obj, val)
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ class(*) intent(in) :: val !< Reset value
+
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer1d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer2d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer3d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer4d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer5d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum unsupported buffer type')
+ end select
+ end subroutine set_buffer_obj_count_0d
+
+ !> @brief Increments the counter `count_0d` of a buffer object by a given value
+ subroutine update_buffer_obj_count_0d(buffer_obj, val)
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ class(*) intent(in) :: val !< Increment value
+
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer1d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer2d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
type is (real(kind=r8_kind))
- WHERE (rmask < 0.5_r8_kind) oor_mask = .FALSE.
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer3d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer4d_type)
+ select type (real_counter => buffer_obj%count_0d)
type is (real(kind=r4_kind))
- WHERE (rmask < 0.5_r4_kind) oor_mask = .FALSE.
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
+ end select
+ type is (outputBuffer5d_type)
+ select type (real_counter => buffer_obj%count_0d)
+ type is (real(kind=r4_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r4_kind)
+ type is (real(kind=r8_kind))
+ real_counter(sample) = real_counter(sample) + real(val, kind=r8_kind)
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum'//&
+ ' Unsupported type of buffer_obj%count_0d')
end select
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::fms_diag_update_extremum unsupported buffer type')
+ end select
+ end subroutine update_buffer_obj_count_0d
+
+ !> @brief Updates individual element of the buffer associated with indices in running_indx1 and running_indx2
+ subroutine update_scalar_extremum(flag, field_data, buffer, mask, sample, recon_bounds, &
+ running_indx1, running_indx2)
+ integer, intent(in) :: flag !< Flag indicating maximum(time_max) or minimum(time_min)
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ class(*), intent(inout) :: buffer(:,:,:,:,:) !< Remapped output buffer
+ logical, intent(in) :: mask(:,:,:,:) !< Update mask
+ integer, intent(in) :: sample !< diurnal sample index
+ type(fmsDiagBoundsHalos_type), intent(in) :: recon_bounds !< Holds starting and ending indices in the
+ !! I, J, and K dimensions and
+ !! halo sizes in the I, and J dimensions
+ integer, intent(in) :: running_indx1(3) !< Holds indices i, j, and k
+ integer, intent(in) :: running_indx2(3) !< Holds indices i1, j1, and k1
+
+ type(fmsDiagIbounds_type) :: IJKBounds !< Bounding object for the I, J, and K indices
+ integer :: i, j, k !< Unpack running_indx1 to
+ integer :: i1, j1, k1 !< Unpack running_indx2 to
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensiions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+
+ !> Check flag for unsupported operation
+ if (flag .ne. time_max .and. flag .ne. time_min) then
+ call mpp_error(FATAL, "fms_diag_reduction_methods_mod::fms_diag_scalar_extremum &
+ unsupported reduction method")
endif
- end function init_mask
+ ! Initialize i, j, and k
+ i = running_indx1(1)
+ j = running_indx1(2)
+ k = running_indx1(3)
- !> @brief Sets the weight based on the weight passed into send_data (1.0_r8_kind if the weight is not passed in)
- !! The weight will be saved as an r8 and converted to r4 as needed
- !! @return weight to use when averaging
- pure function set_weight(weight) &
- result(out_weight)
- CLASS(*), INTENT(in), OPTIONAL :: weight !< The weight use when averaging
+ ! Initialize i1, j1, and k1
+ i1 = running_indx2(1)
+ j1 = running_indx2(2)
+ k1 = running_indx2(3)
- real(kind=r8_kind) :: out_weight
+ !> Get the `bounds3D` member of the `recon_bounds`
+ IJKBounds = recon_bounds%get_bounds3D() !< Assignment of data structure with intrinsic type members may work!!!
- out_weight = 1.0_r8_kind
- if (present(weight)) then
- select type(weight)
+ !> Unpack index bounds
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ hj = recon_bounds%get_hj()
+
+ ! Select proper type and update the buffer
+ select type (field_data)
+ type is (real(kind=r4_kind))
+ select type (buffer)
+ type is (real(kind=r4_kind))
+ minimum_if: if (flag .eq. time_min) then
+ !> Update the buffer with the current minimum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) <&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ else !< if not minimum, check for maximum
+ !> Update the buffer with the current maximum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) >&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_scalar_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ type is (real(kind=r8_kind))
+ select type (buffer)
type is (real(kind=r8_kind))
- out_weight = real(weight, kind = r8_kind)
+ minimum_if: if (flag .eq. time_min) then
+ ! Update the buffer with the current minimum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) <&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ else
+ ! Update the buffer with the current maximum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) >&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ endif minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_scalar_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ type is (integer(kind=i4_kind))
+ select type (buffer)
+ type is (integer(kind=i4_kind))
+ minimum_if: if (flag .eq. time_min) then
+ ! Update the buffer with the current minimum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) <&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ else
+ ! Update the buffer with the current maximum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) >&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ endif minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_scalar_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ type is (integer(kind=i8_kind))
+ select type (buffer)
+ type is (integer(kind=i8_kind))
+ minimum_if: if (flag .eq. time_min) then
+ ! Update the buffer with the current minimum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) <&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ else
+ ! Update the buffer with the current maximum
+ where (mask(i-is+1+hi,j-js+1+hj,k,:) .AND. field_data(i-is+1+hi,j-js+1+hj,k,:) >&
+ buffer(i1,j1,k1,:,sample))
+ buffer(i1,j1,k1,:,sample) = field_data(i-is+1+hi,j-js+1+hj,k,:)
+ end where
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_scalar_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_scalar_extremum unsupported field data type")
+ end select
+ end subroutine update_scalar_extremum
+
+ !> @brief Updates a chunk of the buffer defined by the bounds in recon_bounds
+ subroutine update_array_extremum(flag, field_data, buffer, mask, sample, recon_bounds, reduced_k_range)
+ integer :: flag !< Flag indicating maximum(time_max) or minimum(time_min)
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ class(*), intent(inout) :: buffer(:,:,:,:,:) !< Remapped output buffer
+ logical, intent(in) :: mask(:,:,:,:) !< Updated mask
+ integer, intent(in) :: sample !< diurnal sample index
+ type(fmsDiagBoundsHalos_type), intent(in) :: recon_bounds !< Object to hold starting and ending indices
+ !! in the I, J, and K dimensions; also holds
+ !! halo sizes in the I, and J dimensions
+ logical, intent(in) :: reduced_k_range !< Flag indicating if the range in the K dimension is present
+
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+ integer :: f1, f2 !< Updated starting and ending indices in the I dimension
+ integer :: f3, f4 !< Updated starting and ending indices in the J dimension
+ type(fmsDiagIbounds_type) :: IJKBounds !< Bounding object for the I, J, and K indices
+
+ !> Check flag for unsupported operation
+ if (flag .ne. time_max .and. flag .ne. time_min) then
+ call mpp_error(FATAL, "fms_diag_reduction_methods_mod::fms_diag_scalar_extremum &
+ unsupported reduction method")
+ endif
+
+ !> Get the `bounds3D` member of the `recon_bounds`
+ IJKBounds = recon_bounds%get_bounds3D() !< Assignment of data structure with intrinsic type members may work!!!
+
+ !> Unpack bounds (/is, js, ks, ie, je, ke, hi, f1, f2, hj, f3, f4/)
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ f1 = recon_bounds%get_fis()
+ f2 = recon_bounds%get_fie()
+ hj = recon_bounds%get_hj()
+ f3 = recon_bounds%get_fjs()
+ f4 = recon_bounds%get_fje()
+
+ ! Select proper type and update the buffer
+ select type (field_data)
+ type is (real(kind=r4_kind))
+ select type (buffer)
type is (real(kind=r4_kind))
- out_Weight = real(weight, kind = r8_kind)
+ minimum_if: if (flag .eq. time_min) then
+ !> Update the buffer with the current minimum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ else
+ !> Update the buffer with the current maximum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:)>&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_array_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ type is (real(kind=r8_kind))
+ select type (buffer)
+ type is (real(kind=r8_kind))
+ minimum_if: if (flag .eq. time_min) then
+ !> Update the buffer with the current minimum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ else
+ !> Update the buffer with the current maximum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:)>&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_array_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ type is (integer(kind=i4_kind))
+ select type (buffer)
+ type is (integer(kind=i4_kind))
+ minimum_if: if (flag .eq. time_min) then
+ !> Update the buffer with the current minimum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ else
+ !> Update the buffer with the current maximum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:)>&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_array_extremum"//&
+ " buffer type does not match with field_data type.")
end select
+ type is (integer(kind=i8_kind))
+ select type (buffer)
+ type is (integer(kind=i8_kind))
+ minimum_if: if (flag .eq. time_min) then
+ !> Update the buffer with the current minimum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ else
+ !> Update the buffer with the current maximum
+ if (reduced_k_range) then
+ ! recon_bounds must have ks = ksr and ke = ker
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:) <&
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,:,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ else
+ WHERE (mask(f1:f2,f3:f4,ks:ke,:) .AND. field_data(f1:f2,f3:f4,ks:ke,:)>&
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample)) &
+ buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,:,sample) = field_data(f1:f2,f3:f4,ks:ke,:)
+ end if
+ end if minimum_if
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_array_extremum"//&
+ " buffer type does not match with field_data type.")
+ end select
+ class default
+ call mpp_error( FATAL, "fms_diag_reduction_methods_mod::update_array_extremum unsupported field data type")
+ end select
+ end subroutine update_array_extremum
+
+ !> @brief Performs actual computation for sum or average for mask variant field depending
+ !! on the flag value passed: time_sum for sum; time_average for average
+ subroutine fms_diag_mask_variant_do_sum(flag, field_data, buffer_obj, recon_bounds, kr_start, kr_end, &
+ reduced_k_range, pow_val, mask, weight, hasDiurnalAxis, field_name, sample)
+ integer, intent(in) :: flag !< Flag indicating a reduction method: sum(time_sum) or average(time_average)
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ type(fmsDiagBoundsHalos_type), intent(inout) :: recon_bounds !< Indices of bounds in the first three dimensions
+ !! of the field data
+ integer, intent(in) :: kr_start(:) !< Local starting indices for the first three dimensions
+ integer, intent(in) :: kr_end(:) !< Local ending indices for the first three dimensions
+ logical, intent(in) :: reduced_k_range !< Flag indicating if the field has zbounds
+ integer, intent(in) :: pow_val !< Power value as an exponent
+ logical, intent(in) :: mask(:,:,:,:) !< Must be out of range mask
+ real, intent(in) :: weight !< Must be a updated weight
+ logical, intent(in) :: hasDiurnalAxis !< Flag to indicate if the buffer has a diurnal axis
+ character(len=*), intent(in) :: field_name !< Field name for error reporting
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+ integer :: f1, f2 !< Updated starting and ending indices in the I dimension
+ integer :: f3, f4 !< Updated starting and ending indices in the J dimension
+ integer :: ksr, ker !< Reduced indices in the K dimension
+ integer :: i, j, k !< Running indices for looping
+ integer :: k1 !< Secondary running index
+ class(*), pointer :: ptr_buffer(:,:,:,:,:) !< Pointer to 5D buffer for remapping
+ character(len=52) :: code_module_name !< String to hold module and routine names
+ type(fmsDiagIbounds_type) :: IJKBounds !< Index bounds in the I, J, and K dimensions
+
+ !> Check flag for time_sum and time_average
+ if (flag /= time_sum .and. flag /= time_average) then
+ call mpp_error( FATAL, TRIM(str_modname)//" flag must be a parameter either time_sum or time_average.")
endif
- end function set_weight
+ !> Initialize code_module_name
+ code_module_name = "fms_diag_reduction_methods_mod::fms_diag_mask_do_sum"
+
+ !> Remap buffer
+ ptr_buffer => buffer_obj%remap_buffer(fieldName, hasDiurnalAxis)
+
+ !> Unpack bounds to individual indices
+ IJKBounds = recon_bounds%get_bounds3D()
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ hj = recon_bounds%get_hj()
+
+ if (reduced_k_range) then
+ ksr = kr_start(3)
+ ker = kr_end(3)
+ else
+ ksr = ks
+ ker = ke
+ end if
+
+ DO k= ksr, ker
+ if (reduced_k_range) then
+ k1= k - ksr + 1
+ else
+ k1 = k
+ end if
+ DO j=js, je
+ DO i=is, ie
+ IF (mask(i-is+1+hi, j-js+1+hj, k, :)) THEN
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ type is (outputBuffer1d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ type is (outputBuffer2d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ type is (outputBuffer3d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ type is (outputBuffer4d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ type is (outputBuffer5d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i-hi, j-hj, k1, 1/), weight, pow_val, sample)
+ if (flag == time_average) then
+ select type (counter_type => buffer_obj%counter)
+ type is (real(kind=r4_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ type is (real(kind=r8_kind))
+ counter_type(i-hi, j-hj, k1, :, sample) = counter_type(i-hi, j-hj, k1, :, sample) + weight
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported type and must be either &
+ r4 or r8 type')
+ end select
+ endif
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported dimensional buffer type')
+ end select
+ END IF
+ END DO
+ END DO
+ END DO
+ end subroutine fms_diag_mask_variant_do_sum
+
+ !> @brief Updates the counter `num_elements` of buffer object
+ !! which is polymorphic in dimensionality
+ subroutine update_buffer_obj_num_elements(buffer_obj, incr, sample)
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ integer, intent(in) :: incr !< Value to increment by
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ type is (outputBuffer1d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ type is (outputBuffer2d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ type is (outputBuffer3d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ type is (outputBuffer4d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ type is (outputBuffer5d_type)
+ buffer_obj%num_elements(sample) = buffer_obj%num_elements(sample) + incr
+ class default
+ call mpp_error(FATAL, 'fms_diag_reduction_methods_mod::update_buffer_num_elemets &
+ Unsupported dimensional buffer type')
+ end select
+ end subroutine update_buffer_obj_num_elements
+
+ !> @brief Computes sum for the non mask variant case in time averaging.
+ subroutine fms_diag_no_mask_variant_do_sum(field_data, buffer_obj, recon_bounds, l_start, l_end, &
+ pow_val, mask, weight, field_name, hasDiurnalAxis, sample, missing_value)
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ type(fmsDiagBoundsHalos_type), intent(inout) :: recon_bounds !< Indices of bounds in the first three dimensions
+ !! of the field data
+ integer, intent(in) :: l_start(:) !< Local starting indices for the first three dimensions
+ integer, intent(in) :: l_end(:) !< Local ending indices for the first three dimensions
+ integer, intent(in) :: pow_val !< Power value as an exponent
+ logical, intent(in) :: mask(:,:,:,:) !< Must be out of range mask
+ real, intent(in) :: weight !< Must be a updated weight
+ character(len=*), intent(in) :: field_name !< Field name for error reporting
+ logical, intent(in) :: hasDiurnalAxis !< Flag to indicate if the buffer has a diurnal axis
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+ class(*), intent(in) :: missing_value !< Missing value of the field data
+
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+ integer :: f1, f2 !< Updated starting and ending indices in the I dimension
+ integer :: f3, f4 !< Updated starting and ending indices in the J dimension
+ integer :: ksr, ker !< Reduced indices in the K dimension
+ integer :: i, j, k !< Running indices for looping
+ integer :: i1, j1, k1 !< Secondary running indices
+ class(*), pointer :: ptr_buffer(:,:,:,:,:) !< Pointer to 5D buffer for remapping
+ type(fmsDiagIbounds_type) :: IJKBounds !< Index bounds in the I, J, and K dimensions
+ character(len=64) :: code_module_name !< Holds module and routine names for error reporting
+
+ code_module_name = "fms_diag_reduction_methods_mod::fms_diag_no_mask_variant_do_sum"
+
+ !> Remap buffer
+ ptr_buffer => buffer_obj%remap_buffer(field_name, hasDiurnalAxis)
+
+ !> Unpack bounds to individual indices
+ IJKBounds = recon_bounds%get_bounds3D()
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ hj = recon_bounds%get_hj()
+
+ DO k = l_start(3), l_end(3)
+ k1 = k-l_start(3)+1
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ IF ( mask(i-is+1+hi, j-js+1+hj, k) ) THEN
+ select type (buffer_obj)
+ type is (outputBuffer0d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ type is (outputBuffer1d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ type is (outputBuffer2d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ type is (outputBuffer3d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ type is (outputBuffer4d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ type is (outputBuffer5d_type)
+ call sum_scalar_field_data(field_data, (/i-is+1+hi, j-js+1+hj, k, 1/), &
+ ptr_buffer, (/i1, j1, k1, 1/), weight, pow_val, sample)
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//' Unsupported dimensional buffer type')
+ end select
+ ELSE
+ select type (buffer_obj) !< Select dimensional buffer type
+ type is (outputBuffer0d_type) !< Scalar buffer
+ select type (ptr_buffer) !< Select type of scalar buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of scalar buffer type
+ type is (outputBuffer1d_type) !< 1D buffer
+ select type (ptr_buffer) !< Select type of 1D buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of 1D buffer type
+ type is (outputBuffer2d_type) !< 2D buffer
+ select type (ptr_buffer) !< Select type of 2D buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of 2D buffer type
+ type is (outputBuffer3d_type) !< 3D buffer
+ select type (ptr_buffer) !< Select type of 3D buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of 3D buffer type
+ type is (outputBuffer4d_type) !< 4D buffer
+ select type (ptr_buffer) !< Select type of 4D buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of 4D buffer type
+ type is (outputBuffer5d_type) !< 5D buffer
+ select type (ptr_buffer) !< Select type of 5D buffer
+ type is (real(kind=r4_kind))
+ select type (missing_value)
+ type is (real(kind=r4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r4')
+ end select
+ type is (real(kind=r8_kind))
+ select type (missing_value)
+ type is (real(kind=r8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be r8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (missing_value)
+ type is (integer(kind=i4_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i4')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (missing_value)
+ type is (integer(kind=i8_kind))
+ ptr_buffer(i1, j1, k1, 1, sample) = missing_value
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported type in missing value; must be i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported buffer type; must be either i4, i8, r4 or r8')
+ end select !< End of selection of 5D buffer type
+ class default
+ call mpp_error(FATAL, TRIM(code_module_name)//&
+ ' Unsupported dimensional buffer type')
+ end select !< End of selection of dimensional buffer
+ END IF
+ END IF
+ END DO
+ END DO
+ END DO
+ end subroutine
+
+ !> @brief Adds single field data to output buffer element.
+ !! Order of indices in field_indices and buf_indices must be in (/i, j, k, l/)
+ !! The argument `weight` is not involved in any calculations related to buffer type i4 or i8
+ subroutine sum_scalar_field_data(field_data, field_indices, buffer, buf_indices, weight, power_val, sample)
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ integer, intent(in) :: field_indices(4) !< Indices of field data
+ class(*), intent(inout) :: buffer(:,:,:,:,:) !< Remapped output buffer
+ integer, intent(in) :: buf_indices(4) !< Indices of buffer data
+ real, intent(in) :: weight !< Must be a updated weight
+ integer, intent(in) :: power_val !< Power value as an exponent
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+
+ character(len=48) :: mod_info !< Holds code module information
+
+ mod_info = 'fms_diag_reduction_methods_mod::sum_scalar_field_data'
+
+ !> Add field data to buffer; if `weight` is not equal to 1.0, it is a weighted sum/average.
+ select type (field_data)
+ type is (real(kind=r4_kind))
+ select type (buffer)
+ type is (real(kind=r4_kind))
+ select case (power_val)
+ case (1)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight
+ case (2)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight *&
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight
+ case default
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ (field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight)**(power_val)
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(mod_info)//' Buffer type not supported and must be either r4, r8, i4 or i8')
+ end select
+ type is (real(kind=r8_kind))
+ select type (buffer)
+ type is (real(kind=r8_kind))
+ select case (power_val)
+ case (1)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight
+ case (2)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight *&
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight
+ case default
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ (field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) * weight)**(power_val)
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(mod_info)//' Buffer type not supported and must be either r4, r8, i4 or i8')
+ end select
+ type is (integer(kind=i4_kind))
+ select type (buffer)
+ type is (integer(kind=i4_kind))
+ select case (power_val)
+ case (1)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4))
+ case (2)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) *&
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4))
+ case default
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ (field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)))**(power_val)
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(mod_info)//' Buffer type not supported and must be either r4, r8, i4 or i8')
+ end select
+ type is (integer(kind=i8_kind))
+ select type (buffer)
+ type is (integer(kind=i8_kind))
+ select case (power_val)
+ case (1)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4))
+ case (2)
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)) *&
+ field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4))
+ case default
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) = &
+ buffer(buf_indices(1), buf_indices(2), buf_indices(3), buf_indices(4), sample) + &
+ (field_data(field_indices(1), field_indices(2), field_indices(3), field_indices(4)))**(power_val)
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(mod_info)//' Buffer type not supported and must be either r4, r8, i4 or i8')
+ end select
+ class default
+ call mpp_error(FATAL, TRIM(mod_info)//' Unsupported field data type and must be either r4, r8, i4 or i8')
+ end select
+ end subroutine sum_scalar_field_data
+
+ !> @brief A wrapper to perform time average or sum of the input field data
+ !! depending on the flag value passed: time_sum for sum; time_average for average
+ subroutine fms_diag_time_average(flag, field, buffer_obj, field_data, recon_bounds, l_start, &
+ l_end, is_regional, reduced_k_range, sample, mask, fieldName, has_diurnal_axis, phys_win, &
+ weight, pow_val, err_msg)
+ integer, intent(in) :: flag !< Flag indicating reduction method: sum(time_sum) or average(time_average)
+ type(fmsDiagField_type), intent(in) :: field !< Field object
+ class(fmsDiagOutputBuffer_class), intent(inout) :: buffer_obj !< Buffer object
+ class(*), intent(in) :: field_data(:,:,:,:) !< Field data
+ type(fmsDiagBoundsHalos_type), intent(inout) :: recon_bounds !< Holds indices of bounds in the I, J, and K
+ !! dimensions and halo sizes in the I and
+ !! J dimensions
+ integer, intent(in) :: l_start(:) !< Local starting indices for the first three dimensions
+ integer, intent(in) :: l_end(:) !< Local ending indices for the first three dimensions
+ logical, intent(in) :: is_regional !< Flag indicating if the current PE takes part in send_data
+ logical, intent(in) :: reduced_k_range !< Flag indicating if the field has zbounds
+ integer, intent(in) :: sample !< Index along the diurnal time axis
+ logical, intent(in) :: mask(:,:,:,:) !< Must be out of range mask
+ character(len=*), intent(in) :: fieldName !< Field name for error reporting
+ logical, intent(in) :: has_diurnal_axis !< Flag to indicate if the buffer has a diurnal axis
+ logical, intent(in) :: phys_win !< Flag indicating if the field is a physics window
+ real, intent(in) :: weight !< Must be a updated weight
+ integer, intent(in) :: pow_val !< Power value as an exponent
+ character(len=*), intent(inout), optional :: err_msg !< Error message
+
+ integer :: is, js, ks !< Starting indices in the I, J, and K dimensions
+ integer :: ie, je, ke !< Ending indices in the I, J, and K dimensions
+ integer :: hi, hj !< Halo sizes in the I, and J dimensions
+ integer :: f1, f2 !< Updated starting and ending indices in the I dimension
+ integer :: f3, f4 !< Updated starting and ending indices in the J dimension
+ integer :: ksr, ker !< Reduced indices in the K dimension
+ integer :: i, j, k, i1, j1, k1 !< For loops
+ class(*), pointer :: ptr_buffer(:,:,:,:,:) !< Pointer to 5D buffer for remapping
+ character(len=128) :: err_msg_local !< Stores local error message
+ character(len=128) :: error_string !< Holds partial error text
+ character(len=52) :: str_modname !< Holds names of this subroutine and the module it is in
+ type(fmsDiagIbounds_type) :: IJKBounds !< Index bounds in the I, J, and K dimensions
+
+ !> Initialize the local error reporting strings
+ error_string = ''
+ str_modname = "fms_diag_reduction_methods_mod::fms_diag_update_sum"
+
+ !> Unpack recon_bounds to respective indices
+ IJKBounds = recon_bounds%get_bounds3D()
+ is = IJKBounds%get_imin()
+ js = IJKBounds%get_jmin()
+ ks = IJKBounds%get_kmin()
+ ie = IJKBounds%get_imax()
+ je = IJKBounds%get_jmax()
+ ke = IJKBounds%get_kmax()
+ hi = recon_bounds%get_hi()
+ f1 = recon_bounds%get_fis()
+ f2 = recon_bounds%get_fie()
+ hj = recon_bounds%get_hj()
+ f3 = recon_bounds%get_fjs()
+ f4 = recon_bounds%get_fje()
+
+ if (flag /= time_average .and. flag /= time_sum) then
+ call mpp_error( FATAL, TRIM(str_modname)//" flag must be a parameter either time_sum or time_average.")
+ end if
+
+ IF (field%is_mask_variant()) THEN
+ IF (is_regional) THEN
+ WRITE (error_string,'(a,"/",a)') &
+ & TRIM(field%get_modname()), &
+ & TRIM(fieldName)
+ IF (fms_error_handler(TRIM(str_modname), 'module/field_name '//TRIM(error_string)//&
+ & ', regional output NOT supported with mask_variant', err_msg)) THEN
+ RETURN
+ END IF
+ END IF
+
+ ! Should reduced_k_range data be supported with the mask_variant option ?????
+ ! If not, error message should be produced and the reduced_k_range loop below eliminated
+ IF (PRESENT(mask)) THEN
+ IF (field%has_missing_value()) THEN
+ IF (debug_diag_manager) THEN
+ ! Compare bounds {is-hi, ie-hi, js-hj, je-hj, ks, ke} with the bounds of first three dimensions of the buffer
+ if (compare_two_sets_of_bounds((/is-hi, ie-hi, js-hj, je-hj, ks, ke/), &
+ (/LBOUND(ptr_buffer,1), UBOUND(ptr_buffer,1), LBOUND(ptr_buffer,2), UBOUND(ptr_buffer,2), &
+ LBOUND(ptr_buffer,3), UBOUND(ptr_buffer,3)/), err_msg_local)) THEN
+ IF (fms_error_handler(TRIM(str_modname), err_msg_local, err_msg)) THEN
+ RETURN
+ END IF
+ END IF
+ END IF
+ IF(phys_win) then
+ call fms_diag_mask_variant_do_sum(flag, field_data, buffer_obj, recon_bounds, l_start, l_end, &
+ reduced_k_range, pow_val, mask, weight, has_diurnal_axis, fieldName, sample)
+ ELSE
+ call fms_diag_mask_variant_do_sum(flag, field_data, buffer_obj, recon_bounds, l_start, l_end, &
+ reduced_k_range, pow_val, mask, weight, has_diurnal_axis, fieldName, sample)
+ END IF
+ ELSE
+ WRITE (error_string,'(a,"/",a)')&
+ & TRIM(field%get_modname()), &
+ & TRIM(fieldName)
+ IF(fms_error_handler(TRIM(str_modname), 'module/field_name '//TRIM(error_string)//&
+ & ', variable mask but no missing value defined', err_msg)) THEN
+ RETURN
+ END IF
+ END IF
+ ELSE ! no mask present
+ WRITE (error_string,'(a,"/",a)')&
+ & TRIM(field%get_modname()), &
+ & TRIM(fieldName)
+ IF(fms_error_handler(TRIM(str_modname),'module/field_name'//TRIM(error_string)//&
+ & ', variable mask but no mask given', err_msg)) THEN
+ RETURN
+ END IF
+ END IF
+ ELSE ! mask_variant=false
+ IF ( PRESENT(mask) ) THEN
+ IF (field%has_missing_value()) THEN
+ IF (is_regional) THEN
+ IF (phys_window) then
+ call fms_diag_no_mask_variant_do_sum(field_data, buffer_obj, recon_bounds, &
+ l_start, l_end, pow_val, mask, weight, fieldName, has_diurnal_axis, &
+ sample, field%get_missing_value())
+ ELSE
+ call fms_diag_no_mask_variant_do_sum(field_data, buffer_obj, recon_bounds, &
+ l_start, l_end, pow_val, mask, weight, fieldName, has_diurnal_axis, &
+ sample, field%get_missing_value())
+ ENDIF
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ call update_buffer_obj_num_elements(buffer_obj, (l_end(3)-l_start(3)+1), sample)
+ END IF
+ END DO
+ END DO
+!======================================================================================================
+ !!TODO: everything below has not been refactored/updated
+ ELSE IF ( reduced_k_range ) THEN
+ IF (numthreads>1 .AND. phys_window) then
+ DO k=ksr, ker
+ k1 = k - ksr + 1
+ DO j=js, je
+ DO i=is, ie
+ IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ ELSE
+ DO k=ksr, ker
+ k1 = k - ksr + 1
+ DO j=js, je
+ DO i=is, ie
+ IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample)= missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ END IF
+ ELSE
+ IF ( debug_diag_manager ) THEN
+ CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
+ CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
+ IF ( err_msg_local /= '' ) THEN
+ IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
+ DEALLOCATE(field_out)
+ DEALLOCATE(oor_mask)
+ RETURN
+ END IF
+ END IF
+ END IF
+ IF (numthreads>1 .AND. phys_window) then
+ DO k=ks, ke
+ DO j=js, je
+ DO i=is, ie
+ IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ ELSE
+ DO k=ks, ke
+ DO j=js, je
+ DO i=is, ie
+ IF ( mask(i-is+1+hi,j-js+1+hj,k) ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample)= missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ END IF
+ END IF
+ IF ( need_compute .AND. .NOT.phys_window ) THEN
+ IF ( ANY(mask(l_start(1)+hi:l_end(1)+hi,l_start(2)+hj:l_end(2)+hj,l_start(3):l_end(3))) ) &
+ & output_fields(out_num)%count_0d(sample) =&
+ & output_fields(out_num)%count_0d(sample) + weight1
+ ELSE
+ IF ( ANY(mask(f1:f2,f3:f4,ks:ke)) ) output_fields(out_num)%count_0d(sample) =&
+ & output_fields(out_num)%count_0d(sample)+weight1
+ END IF
+ ELSE ! missing value NOT present
+ IF ( (.NOT.ALL(mask(f1:f2,f3:f4,ks:ke)) .AND. mpp_pe() .EQ. mpp_root_pe()).AND.&
+ & .NOT.input_fields(diag_field_id)%issued_mask_ignore_warning ) THEN
+ !
+ ! Mask will be ignored since missing values were not specified for field
+ ! in module
+ !
+ CALL error_mesg('diag_manager_mod::send_data_3d',&
+ & 'Mask will be ignored since missing values were not specified for field '//&
+ & trim(input_fields(diag_field_id)%field_name)//' in module '//&
+ & trim(input_fields(diag_field_id)%module_name), WARNING)
+ input_fields(diag_field_id)%issued_mask_ignore_warning = .TRUE.
+ END IF
+ IF ( need_compute ) THEN
+ IF (numthreads>1 .AND. phys_window) then
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1 = j-l_start(2)-hj+1
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
+ & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
+ & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
+ END IF
+ END IF
+ END DO
+ END DO
+ ELSE
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1 = j-l_start(2)-hj+1
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
+ & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample)+ &
+ & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
+ END IF
+ END IF
+ END DO
+ END DO
+ END IF
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ output_fields(out_num)%num_elements(sample)=&
+ & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
+
+ END IF
+ END DO
+ END DO
+ ELSE IF ( reduced_k_range ) THEN
+ IF (numthreads>1 .AND. phys_window) then
+ ksr= l_start(3)
+ ker= l_end(3)
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
+ & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
+ & field_out(f1:f2,f3:f4,ksr:ker)*weight1
+ END IF
+ ELSE
+ ksr= l_start(3)
+ ker= l_end(3)
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
+ & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) +&
+ & field_out(f1:f2,f3:f4,ksr:ker)*weight1
+ END IF
+ END IF
+ ELSE
+ IF ( debug_diag_manager ) THEN
+ CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
+ CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
+ IF ( err_msg_local /= '') THEN
+ IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
+ DEALLOCATE(field_out)
+ DEALLOCATE(oor_mask)
+ RETURN
+ END IF
+ END IF
+ END IF
+ IF (numthreads>1 .AND. phys_window) then
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & field_out(f1:f2,f3:f4,ks:ke)*weight1
+ END IF
+ ELSE
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & field_out(f1:f2,f3:f4,ks:ke)*weight1
+ END IF
+ END IF
+ END IF
+ IF ( .NOT.phys_window ) output_fields(out_num)%count_0d(sample) =&
+ & output_fields(out_num)%count_0d(sample) + weight1
+ END IF
+ ELSE ! mask NOT present
+ IF ( missvalue_present ) THEN
+ IF ( need_compute ) THEN
+ if( numthreads>1 .AND. phys_window ) then
+ DO k = l_start(3), l_end(3)
+ k1 = k - l_start(3) + 1
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,k1,sample) =&
+ & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,k1,sample) =&
+ & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
+ END IF
+ END IF
+ END DO
+ END DO
+ END DO
+ ELSE
+ DO k = l_start(3), l_end(3)
+ k1 = k - l_start(3) + 1
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,k1,sample) =&
+ & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,k1,sample) =&
+ & output_fields(out_num)%buffer(i1,j1,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,k1,sample) = missvalue
+ END IF
+ END IF
+ END DO
+ END DO
+ END DO
+ END IF
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj) THEN
+ output_fields(out_num)%num_elements(sample) =&
+ & output_fields(out_num)%num_elements(sample) + l_end(3) - l_start(3) + 1
+ END IF
+ END DO
+ END DO
+ IF ( .NOT.phys_window ) THEN
+ outer0: DO k = l_start(3), l_end(3)
+ DO j=l_start(2)+hj, l_end(2)+hj
+ DO i=l_start(1)+hi, l_end(1)+hi
+ IF ( field_out(i,j,k) /= missvalue ) THEN
+ output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample)&
+ & + weight1
+ EXIT outer0
+ END IF
+ END DO
+ END DO
+ END DO outer0
+ END IF
+ ELSE IF ( reduced_k_range ) THEN
+ if( numthreads>1 .AND. phys_window ) then
+ ksr= l_start(3)
+ ker= l_end(3)
+ DO k = ksr, ker
+ k1 = k - ksr + 1
+ DO j=js, je
+ DO i=is, ie
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ else
+ ksr= l_start(3)
+ ker= l_end(3)
+ DO k = ksr, ker
+ k1 = k - ksr + 1
+ DO j=js, je
+ DO i=is, ie
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k1,sample) = missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ END IF
+ outer3: DO k = ksr, ker
+ k1=k-ksr+1
+ DO j=f3, f4
+ DO i=f1, f2
+ IF ( field_out(i,j,k) /= missvalue ) THEN
+ output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) &
+ & + weight1
+ EXIT outer3
+ END IF
+ END DO
+ END DO
+ END DO outer3
+ ELSE
+ IF ( debug_diag_manager ) THEN
+ CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
+ CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
+ IF ( err_msg_local /= '' ) THEN
+ IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
+ DEALLOCATE(field_out)
+ DEALLOCATE(oor_mask)
+ RETURN
+ END IF
+ END IF
+ END IF
+ IF( numthreads > 1 .AND. phys_window ) then
+ DO k=ks, ke
+ DO j=js, je
+ DO i=is, ie
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ ELSE
+ DO k=ks, ke
+ DO j=js, je
+ DO i=is, ie
+ IF ( field_out(i-is+1+hi,j-js+1+hj,k) /= missvalue ) THEN
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,k) * weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) =&
+ & output_fields(out_num)%buffer(i-hi,j-hj,k,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,k) * weight1
+ END IF
+ ELSE
+ output_fields(out_num)%buffer(i-hi,j-hj,k,sample) = missvalue
+ END IF
+ END DO
+ END DO
+ END DO
+ END IF
+ outer1: DO k=ks, ke
+ DO j=f3, f4
+ DO i=f1, f2
+ IF ( field_out(i,j,k) /= missvalue ) THEN
+ output_fields(out_num)%count_0d(sample) = output_fields(out_num)%count_0d(sample) &
+ & + weight1
+ EXIT outer1
+ END IF
+ END DO
+ END DO
+ END DO outer1
+ END IF
+ ELSE ! no missing value defined, No mask
+ IF ( need_compute ) THEN
+ IF( numthreads > 1 .AND. phys_window ) then
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
+ END IF
+ END IF
+ END DO
+ END DO
+ ELSE
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ i1 = i-l_start(1)-hi+1
+ j1= j-l_start(2)-hj+1
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample) +&
+ & (field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(i1,j1,:,sample)= &
+ & output_fields(out_num)%buffer(i1,j1,:,sample) +&
+ & field_out(i-is+1+hi,j-js+1+hj,l_start(3):l_end(3))*weight1
+ END IF
+ END IF
+ END DO
+ END DO
+ END IF
+
+ DO j = js, je
+ DO i = is, ie
+ IF ( l_start(1)+hi <= i .AND. i <= l_end(1)+hi .AND. l_start(2)+hj <= j .AND. &
+ & j <= l_end(2)+hj ) THEN
+ output_fields(out_num)%num_elements(sample) =&
+ & output_fields(out_num)%num_elements(sample)+l_end(3)-l_start(3)+1
+ END IF
+ END DO
+ END DO
+ ! Accumulate time average
+ ELSE IF ( reduced_k_range ) THEN
+ ksr= l_start(3)
+ ker= l_end(3)
+ IF( numthreads > 1 .AND. phys_window ) then
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
+ & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
+ & field_out(f1:f2,f3:f4,ksr:ker)*weight1
+ END IF
+ ELSE
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
+ & (field_out(f1:f2,f3:f4,ksr:ker)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,:,sample) + &
+ & field_out(f1:f2,f3:f4,ksr:ker)*weight1
+ END IF
+ END IF
+ ELSE
+ IF ( debug_diag_manager ) THEN
+ CALL update_bounds(out_num, is-hi, ie-hi, js-hj, je-hj, ks, ke)
+ CALL check_out_of_bounds(out_num, diag_field_id, err_msg=err_msg_local)
+ IF ( err_msg_local /= '' ) THEN
+ IF ( fms_error_handler('diag_manager_mod::send_data_3d', err_msg_local, err_msg) ) THEN
+ DEALLOCATE(field_out)
+ DEALLOCATE(oor_mask)
+ RETURN
+ END IF
+ END IF
+ END IF
+ IF( numthreads > 1 .AND. phys_window ) then
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & field_out(f1:f2,f3:f4,ks:ke)*weight1
+ END IF
+ ELSE
+ IF ( pow_value /= 1 ) THEN
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & (field_out(f1:f2,f3:f4,ks:ke)*weight1)**(pow_value)
+ ELSE
+ output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) =&
+ & output_fields(out_num)%buffer(is-hi:ie-hi,js-hj:je-hj,ks:ke,sample) +&
+ & field_out(f1:f2,f3:f4,ks:ke)*weight1
+ END IF
+ END IF
+ END IF
+ IF ( .NOT.phys_win ) call update_buffer_obj_count_0d(buffer_obj, weight)
+ END IF
+ END IF ! if mask present
+ END IF !if mask_variant
+ IF ( .NOT.is_regional .AND. .NOT.reduced_k_range )&
+ call update_buffer_obj_num_elements(buffer_obj, (ie-is+1)*(je-js+1)*(ke-ks+1), sample)
+ IF ( reduced_k_range ) &
+ call update_buffer_obj_num_elements(buffer_obj, (ie-is+1)*(je-js+1)*(ker-ksr+1), sample)
+
+
+ end subroutine fms_diag_time_average
+#endif
end module fms_diag_reduction_methods_mod
-!> @}
-! close documentation grouping
\ No newline at end of file