FMS  2024.03
Flexible Modeling System
fms_diag_input_buffer.F90
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @defgroup fms_diag_input_buffer_mod fms_diag_input_buffer_mod
20 !> @ingroup diag_manager
21 !! @brief
22 !> @addtogroup fms_diag_input_buffer_mod
23 !> @{
24 module fms_diag_input_buffer_mod
25 #ifdef use_yaml
26  use platform_mod, only: r8_kind, r4_kind, i4_kind, i8_kind
27  use fms_diag_axis_object_mod, only: fmsdiagaxiscontainer_type, fmsdiagfullaxis_type
28  use time_manager_mod, only: time_type
29  use mpp_mod, only: mpp_error, fatal
30  implicit NONE
31  private
32 
33  !> @brief Appends the input_data_buffer and the mask (only when the mask is set to .True.)
35  module procedure append_data_buffer_r4, append_data_buffer_r8
36  end interface
37 
38  !> @brief Sums the data in the input_data_buffer
39  interface sum_data_buffer
40  module procedure sum_data_buffer_r4, sum_data_buffer_r8
41  end interface
42 
43  !> @brief Type to hold the information needed for the input buffer
44  !! This is used when set_math_needs_to_be_done = .true. (i.e calling send_data
45  !! from an openmp region with multiple threads)
47  logical :: initialized !< .True. if the input buffer has been initialized
48  class(*), allocatable :: buffer(:,:,:,:) !< Input data passed in send_data
49  integer, allocatable :: counter(:,:,:,:)!< Number of send_data calls for each point
50  real(kind=r8_kind) :: weight !< Weight passed in send_data
51  type(time_type) :: send_data_time !< The time send data was called last
52 
53  contains
54  procedure :: get_buffer
55  procedure :: get_weight
56  procedure :: allocate_input_buffer_object
57  procedure :: init_input_buffer_object
58  procedure :: set_input_buffer_object
59  procedure :: update_input_buffer_object
60  procedure :: prepare_input_buffer_object
61  procedure :: set_send_data_time
62  procedure :: get_send_data_time
63  procedure :: is_initialized
64  end type fmsdiaginputbuffer_t
65 
66  public :: fmsdiaginputbuffer_t
67 
68  contains
69 
70  !> @brief Get the buffer from the input buffer object
71  !! @return a pointer to the buffer
72  function get_buffer(this) &
73  result(buffer)
74  class(fmsdiaginputbuffer_t), target, intent(in) :: this !< input buffer object
75  class(*), pointer :: buffer(:,:,:,:)
76 
77  buffer => this%buffer
78  end function get_buffer
79 
80 
81  !> @brief Get the weight from the input buffer object
82  !! @return a pointer to the weight
83  function get_weight(this) &
84  result(weight)
85  class(fmsdiaginputbuffer_t), target, intent(in) :: this !< input buffer object
86  real(kind=r8_kind), pointer :: weight
87 
88  weight => this%weight
89  end function get_weight
90 
91  !> @brief Initiliazes an input data buffer
92  !! @return Error message if something went wrong
93  function allocate_input_buffer_object(this, input_data, axis_ids, diag_axis) &
94  result(err_msg)
95  class(fmsdiaginputbuffer_t), intent(out) :: this !< input buffer object
96  class(*), intent(in) :: input_data(:,:,:,:) !< input data
97  integer, target, intent(in) :: axis_ids(:) !< axis ids for the field
98  class(fmsdiagaxiscontainer_type), intent(in) :: diag_axis(:) !< Array of diag_axis
99  character(len=128) :: err_msg
100 
101  integer :: naxes !< The number of axes in the field
102  integer, parameter :: ndims = 4 !< Number of dimensions
103  integer :: length(ndims) !< The length of an axis
104  integer :: a !< For looping through axes
105  integer, pointer :: axis_id !< The axis ID
106 
107  err_msg = ""
108 
109  !! Use the axis to get the size
110  !> Initialize the axis lengths to 1. Any dimension that does not have an axis will have a length
111  !! of 1.
112  length = 1
113  naxes = size(axis_ids)
114  axis_loop: do a = 1,naxes
115  axis_id => axis_ids(a)
116  select type (axis => diag_axis(axis_id)%axis)
117  type is (fmsdiagfullaxis_type)
118  length(a) = axis%axis_length()
119  end select
120  enddo axis_loop
121 
122  select type (input_data)
123  type is (real(r4_kind))
124  allocate(real(kind=r4_kind) :: this%buffer(length(1), length(2), length(3), length(4)))
125  this%buffer = 0.0_r4_kind
126  type is (real(r8_kind))
127  allocate(real(kind=r8_kind) :: this%buffer(length(1), length(2), length(3), length(4)))
128  this%buffer = 0.0_r8_kind
129  type is (integer(i4_kind))
130  allocate(integer(kind=i4_kind) :: this%buffer(length(1), length(2), length(3), length(4)))
131  this%buffer = 0_i4_kind
132  type is (integer(i8_kind))
133  allocate(integer(kind=i4_kind) :: this%buffer(length(1), length(2), length(3), length(4)))
134  this%buffer = 0_i8_kind
135  class default
136  err_msg = "The data input is not one of the supported types. &
137  &Only r4, r8, i4, and i8 types are supported."
138  end select
139 
140  this%weight = 1.0_r8_kind
141  this%initialized = .true.
142  allocate(this%counter(length(1), length(2), length(3), length(4)))
143  this%counter = 0
144  end function allocate_input_buffer_object
145 
146  !> @brief Initiliazes an input data buffer and the counter
147  subroutine init_input_buffer_object(this)
148  class(fmsdiaginputbuffer_t), intent(inout) :: this !< input buffer object
149 
150  select type(buffer=>this%buffer)
151  type is (real(kind=r8_kind))
152  buffer = 0.0_r8_kind
153  type is (real(kind=r4_kind))
154  buffer = 0.0_r4_kind
155  end select
156  this%counter = 0
157  end subroutine init_input_buffer_object
158 
159  !> @brief Sets the time send data was called last
160  subroutine set_send_data_time(this, time)
161  class(fmsdiaginputbuffer_t), intent(inout) :: this !< input buffer object
162  type(time_type), intent(in) :: time !< The time send data was called
163 
164  this%send_data_time = time
165  end subroutine set_send_data_time
166 
167  !> @brief Get the time send data was called last
168  !! @result the time send data was called last
169  function get_send_data_time(this) &
170  result(rslt)
171  class(fmsdiaginputbuffer_t), intent(in) :: this !< input buffer object
172  type(time_type) :: rslt
173 
174  rslt = this%send_data_time
175  end function get_send_data_time
176 
177  !> @brief Updates the input data buffer object for the current send_data call
178  !! @return Error message (if an error occurs)
179  function update_input_buffer_object(this, input_data, is, js, ks, ie, je, ke, mask_in, mask_out, &
180  mask_variant, var_is_masked) &
181  result(err_msg)
182 
183  class(fmsdiaginputbuffer_t), intent(inout) :: this !< input buffer object
184  class(*), intent(in) :: input_data(:,:,:,:) !< Field data
185  integer, intent(in) :: is, js, ks !< Starting index for each of the dimension
186  integer, intent(in) :: ie, je, ke !< Ending index for each of the dimensions
187  logical, intent(in) :: mask_in(:,:,:,:)
188  logical, intent(inout) :: mask_out(:,:,:,:)
189  logical, intent(in) :: mask_variant
190  logical, intent(in) :: var_is_masked
191 
192  character(len=128) :: err_msg
193 
194  if (mask_variant) then
195  err_msg = append_data_buffer_wrapper(mask_out(is:ie,js:je,ks:ke,:), mask_in, &
196  this%buffer(is:ie,js:je,ks:ke,:), input_data)
197  else
198  mask_out(is:ie,js:je,ks:ke,:) = mask_in
199  err_msg = sum_data_buffer_wrapper(mask_in, this%buffer(is:ie,js:je,ks:ke,:), input_data, &
200  this%counter(is:ie,js:je,ks:ke,:), &
201  var_is_masked)
202  endif
203 
204  end function update_input_buffer_object
205 
206  !> @brief Prepare the input data buffer to do the reduction methods (i.e divide by the number of times
207  !! send data has been called)
208  subroutine prepare_input_buffer_object(this, field_info)
209  class(fmsdiaginputbuffer_t), intent(inout) :: this !< input buffer object
210  character(len=*), intent(in) :: field_info !< Field info to append to error message
211 
212  select type (input_data => this%buffer)
213  type is (real(kind=r4_kind))
214  input_data = input_data / this%counter(1,1,1,1)
215  type is (real(kind=r8_kind))
216  input_data = input_data / this%counter(1,1,1,1)
217  class default
218  call mpp_error(fatal, "prepare_input_buffer_object::"//trim(field_info)//&
219  " has only been implemented for real variables. Contact developers.")
220  end select
221  end subroutine prepare_input_buffer_object
222 
223  !> @brief Sums the data in the input_data_buffer
224  !! @return Error message (if an error occurs)
225  function sum_data_buffer_wrapper(mask, data_out, data_in, counter, var_is_masked) &
226  result(err_msg)
227 
228  logical, intent(in) :: mask(:,:,:,:) !< Mask passed into send_data
229  class(*), intent(inout) :: data_out(:,:,:,:) !< Data currently saved in the input_data_buffer
230  class(*), intent(in) :: data_in(:,:,:,:) !< Data passed into send_data
231  integer, intent(inout) :: counter(:,:,:,:) !< Number of times data has been summed
232  logical, intent(in) :: var_is_masked !< .True. if the variable is masked
233 
234  character(len=128) :: err_msg
235 
236  err_msg = ""
237  select type(data_out)
238  type is (real(kind=r8_kind))
239  select type (data_in)
240  type is (real(kind=r8_kind))
241  call sum_data_buffer(mask, data_out, data_in, counter, var_is_masked)
242  end select
243  type is (real(kind=r4_kind))
244  select type (data_in)
245  type is (real(kind=r4_kind))
246  call sum_data_buffer(mask, data_out, data_in, counter, var_is_masked)
247  end select
248  class default
249  err_msg = "sum_data_buffer_wrapper:: has only been implemented for real. Contact developers"
250  end select
251  end function sum_data_buffer_wrapper
252 
253  !> @brief Appends the input_data_buffer and the mask (only when the mask is set to .True.)
254  !! @return Error message (if an error occurs)
255  function append_data_buffer_wrapper(mask_out, mask_in, data_out, data_in) &
256  result(err_msg)
257  logical, intent(inout) :: mask_out(:,:,:,:) !< Mask currently in the input_data_buffer
258  logical, intent(in) :: mask_in(:,:,:,:) !< Mask passed in to send_data
259  class(*), intent(inout) :: data_out(:,:,:,:) !< Data currently in the input_data_buffer
260  class(*), intent(in) :: data_in(:,:,:,:) !< Data passed in to send_data
261 
262  character(len=128) :: err_msg
263 
264  err_msg = ""
265  select type(data_out)
266  type is (real(kind=r8_kind))
267  select type (data_in)
268  type is (real(kind=r8_kind))
269  call append_data_buffer(mask_out, mask_in, data_out, data_in)
270  end select
271  type is (real(kind=r4_kind))
272  select type (data_in)
273  type is (real(kind=r4_kind))
274  call append_data_buffer(mask_out, mask_in, data_out, data_in)
275  end select
276  class default
277  err_msg = "append_data_buffer:: has only been implemented for real. Contact developers"
278  end select
279  end function append_data_buffer_wrapper
280 
281  !> @brief Sets the members of the input buffer object
282  !! @return Error message if something went wrong
283  function set_input_buffer_object(this, input_data, weight, is, js, ks, ie, je, ke) &
284  result(err_msg)
285 
286  class(fmsdiaginputbuffer_t), intent(inout) :: this !< input buffer object
287  class(*), intent(in) :: input_data(:,:,:,:) !< Field data
288  real(kind=r8_kind), intent(in) :: weight !< Weight for the field
289  integer, intent(in) :: is, js, ks !< Starting index for each of the dimension
290  integer, intent(in) :: ie, je, ke !< Ending index for each of the dimensions
291 
292  character(len=128) :: err_msg
293  err_msg = ""
294 
295  if (.not. this%initialized) then
296  err_msg = "The data buffer was never initiliazed. This shouldn't happen."
297  return
298  endif
299 
300  this%weight = weight
301 
302  select type (input_data)
303  type is (real(kind=r4_kind))
304  select type (db => this%buffer)
305  type is (real(kind=r4_kind))
306  db(is:ie, js:je, ks:ke, :) = input_data
307  class default
308  err_msg = "The data buffer was not allocated to the correct type (r4_kind). This shouldn't happen"
309  return
310  end select
311  type is (real(kind=r8_kind))
312  select type (db => this%buffer)
313  type is (real(kind=r8_kind))
314  db(is:ie, js:je, ks:ke, :) = input_data
315  class default
316  err_msg = "The data buffer was not allocated to the correct type (r8_kind). This shouldn't happen"
317  return
318  end select
319  type is (integer(kind=i4_kind))
320  select type (db => this%buffer)
321  type is (integer(kind=i4_kind))
322  db(is:ie, js:je, ks:ke, :) = input_data
323  class default
324  err_msg = "The data buffer was not allocated to the correct type (i4_kind). This shouldn't happen"
325  return
326  end select
327  type is (integer(kind=i8_kind))
328  select type (db => this%buffer)
329  type is (integer(kind=i8_kind))
330  db(is:ie, js:je, ks:ke, :) = input_data
331  class default
332  err_msg = "The data buffer was not allocated to the correct type (i8_kind). This shouldn't happen"
333  return
334  end select
335  end select
336  end function set_input_buffer_object
337 
338  !> @brief Determine if an input buffer is initialized
339  !! @return .true. if the input buffer is initialized
340  pure logical function is_initialized(this)
341  class(fmsdiaginputbuffer_t), intent(in) :: this !< input buffer object
342 
343  is_initialized = .false.
344  if (this%initialized) then
345  is_initialized = .true.
346  else
347  if (allocated(this%buffer)) is_initialized = .true.
348  endif
349  end function is_initialized
350 
351 #include "fms_diag_input_buffer_r4.fh"
352 #include "fms_diag_input_buffer_r8.fh"
353 
354 #endif
355 end module fms_diag_input_buffer_mod
356 !> @}
character(len=128) function append_data_buffer_wrapper(mask_out, mask_in, data_out, data_in)
Appends the input_data_buffer and the mask (only when the mask is set to .True.)
subroutine set_send_data_time(this, time)
Sets the time send data was called last.
pure logical function is_initialized(this)
Determine if an input buffer is initialized.
character(len=128) function allocate_input_buffer_object(this, input_data, axis_ids, diag_axis)
Initiliazes an input data buffer.
character(len=128) function update_input_buffer_object(this, input_data, is, js, ks, ie, je, ke, mask_in, mask_out, mask_variant, var_is_masked)
Updates the input data buffer object for the current send_data call.
class(*) function, dimension(:,:,:,:), pointer get_buffer(this)
Get the buffer from the input buffer object.
subroutine init_input_buffer_object(this)
Initiliazes an input data buffer and the counter.
subroutine prepare_input_buffer_object(this, field_info)
Prepare the input data buffer to do the reduction methods (i.e divide by the number of times send dat...
character(len=128) function sum_data_buffer_wrapper(mask, data_out, data_in, counter, var_is_masked)
Sums the data in the input_data_buffer.
character(len=128) function set_input_buffer_object(this, input_data, weight, is, js, ks, ie, je, ke)
Sets the members of the input buffer object.
real(kind=r8_kind) function, pointer get_weight(this)
Get the weight from the input buffer object.
type(time_type) function get_send_data_time(this)
Get the time send data was called last.
Sums the data in the input_data_buffer.
Type to hold the information needed for the input buffer This is used when set_math_needs_to_be_done ...
Error handler.
Definition: mpp.F90:382
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.
Appends the input_data_buffer and the mask (only when the mask is set to .True.)
Type to hold the diag_axis (either subaxis or a full axis)
Type to hold the diagnostic axis description.