FMS 2025.01.02-dev
Flexible Modeling System
Loading...
Searching...
No Matches
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!> @{
24module 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
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
61 procedure :: set_send_data_time
62 procedure :: get_send_data_time
63 procedure :: is_initialized
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
145
146 !> @brief Initiliazes an input data buffer and the counter
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
355end module fms_diag_input_buffer_mod
356!> @}
subroutine set_send_data_time(this, time)
Sets the time send data was called last.
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.)
class(*) function, dimension(:,:,:,:), pointer get_buffer(this)
Get the buffer from the input buffer object.
real(kind=r8_kind) function, pointer get_weight(this)
Get the weight from the input buffer object.
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.
subroutine init_input_buffer_object(this)
Initiliazes an input data buffer and the counter.
type(time_type) function get_send_data_time(this)
Get the time send data was called last.
pure logical function is_initialized(this)
Determine if an input buffer is initialized.
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 set_input_buffer_object(this, input_data, weight, is, js, ks, ie, je, ke)
Sets the members of the input buffer object.
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 allocate_input_buffer_object(this, input_data, axis_ids, diag_axis)
Initiliazes an input data buffer.
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.