1 !***********************************************************************
2 !* GNU Lesser General Public License
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
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.
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
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 !***********************************************************************
20 !> @brief Checks the output file after running test_reduction_methods using the "time_avg" reduction method
21 program check_time_avg
22 use fms_mod, only: fms_init, fms_end, string
23 use fms2_io_mod, only: FmsNetcdfFile_t, read_data, close_file, open_file
24 use mpp_mod, only: mpp_npes, mpp_error, FATAL, mpp_pe, input_nml_file
25 use platform_mod, only: r4_kind, r8_kind
26 use testing_utils, only: allocate_buffer, test_normal, test_openmp, test_halos, no_mask, logical_mask, real_mask
30 type(FmsNetcdfFile_t) :: fileobj !< FMS2 fileobj
31 type(FmsNetcdfFile_t) :: fileobj1 !< FMS2 fileobj for subregional file 1
32 type(FmsNetcdfFile_t) :: fileobj2 !< FMS2 fileobj for subregional file 2
33 real(kind=r4_kind), allocatable :: cdata_out(:,:,:,:) !< Data in the compute domain
34 integer :: nx !< Number of points in the x direction
35 integer :: ny !< Number of points in the y direction
36 integer :: nz !< Number of points in the z direction
37 integer :: nw !< Number of points in the 4th dimension
38 integer :: ti !< For looping through time levels
39 integer :: io_status !< Io status after reading the namelist
40 logical :: use_mask !< .true. if using masks
41 integer, parameter :: file_freq = 6 !< file frequency as set in diag_table.yaml
43 integer :: test_case = test_normal !< Indicates which test case to run
44 integer :: mask_case = no_mask !< Indicates which masking option to run
45 integer, parameter :: kindl = KIND(0.0) !< compile-time default kind size
47 namelist / test_reduction_methods_nml / test_case, mask_case
51 read (input_nml_file, test_reduction_methods_nml, iostat=io_status)
53 select case(mask_case)
56 case (logical_mask, real_mask)
64 if (.not. open_file(fileobj, "test_avg.nc", "read")) &
65 call mpp_error(FATAL, "unable to open test_avg.nc")
67 if (.not. open_file(fileobj1, "test_avg_regional.nc.0004", "read")) &
68 call mpp_error(FATAL, "unable to open test_avg_regional.nc.0004")
70 if (.not. open_file(fileobj2, "test_avg_regional.nc.0005", "read")) &
71 call mpp_error(FATAL, "unable to open test_avg_regional.nc.0005")
73 cdata_out = allocate_buffer(1, nx, 1, ny, nz, nw)
76 cdata_out = -999_r4_kind
77 print *, "Checking answers for var0_avg - time_level:", string(ti)
78 call read_data(fileobj, "var0_avg", cdata_out(1,1,1,1), unlim_dim_level=ti)
79 call check_data_0d(cdata_out(1,1,1,1), ti)
81 cdata_out = -999_r4_kind
82 print *, "Checking answers for IOnASphere - time_level:", string(ti)
83 call read_data(fileobj, "IOnASphere", cdata_out(1,1,1,1), unlim_dim_level=ti)
84 if (cdata_out(1,1,1,1) .ne. -666._r4_kind) &
85 call mpp_error(FATAL, "IOnASphere is not set to the expected value (_FillVal)")
87 cdata_out = -999_r4_kind
88 print *, "Checking answers for var1_avg - time_level:", string(ti)
89 call read_data(fileobj, "var1_avg", cdata_out(:,1,1,1), unlim_dim_level=ti)
90 call check_data_1d(cdata_out(:,1,1,1), ti)
92 cdata_out = -999_r4_kind
93 print *, "Checking answers for var2_avg - time_level:", string(ti)
94 call read_data(fileobj, "var2_avg", cdata_out(:,:,1,1), unlim_dim_level=ti)
95 call check_data_2d(cdata_out(:,:,1,1), ti)
97 cdata_out = -999_r4_kind
98 print *, "Checking answers for var3_avg - time_level:", string(ti)
99 call read_data(fileobj, "var3_avg", cdata_out(:,:,:,1), unlim_dim_level=ti)
100 call check_data_3d(cdata_out(:,:,:,1), ti, .false.)
102 cdata_out = -999_r4_kind
103 print *, "Checking answers for var4_avg - time_level:", string(ti)
104 call read_data(fileobj, "var4_avg", cdata_out(:,:,:,:), unlim_dim_level=ti)
105 call check_data_3d(cdata_out(:,:,:,1), ti, .false.)
106 call check_data_3d(cdata_out(:,:,:,2), ti, .false.)
108 cdata_out = -999_r4_kind
109 print *, "Checking answers for var3_Z - time_level:", string(ti)
110 call read_data(fileobj, "var3_Z", cdata_out(:,:,1:2,1), unlim_dim_level=ti)
111 call check_data_3d(cdata_out(:,:,1:2,1), ti, .true., nz_offset=1)
113 cdata_out = -999_r4_kind
114 print *, "Checking answers for var3_avg in the first regional file- time_level:", string(ti)
115 call read_data(fileobj1, "var3_avg", cdata_out(1:4,1:3,1:2,1), unlim_dim_level=ti)
116 call check_data_3d(cdata_out(1:4,1:3,1:2,1), ti, .true., nx_offset=77, ny_offset=77, nz_offset=1)
118 cdata_out = -999_r4_kind
119 print *, "Checking answers for var3_avg in the second regional file- time_level:", string(ti)
120 call read_data(fileobj2, "var3_avg", cdata_out(1:4,1:1,1:2,1), unlim_dim_level=ti)
121 call check_data_3d(cdata_out(1:4,1:1,1:2,1), ti, .true., nx_offset=77, ny_offset=80, nz_offset=1)
129 ! buffer(ii-is+1+nhalo, j-js+1+nhalo, k, l) = real(ii, kind=r8_kind)* 1000_r8_kind + &
130 ! real(j, kind=r8_kind)* 10_r8_kind + &
131 ! real(k, kind=r8_kind)
133 !> @brief Check that the 0d data read in is correct
134 subroutine check_data_0d(buffer, time_level)
135 real(kind=r4_kind), intent(inout) :: buffer !< Buffer read from the table
136 integer, intent(in) :: time_level !< Time level read in
138 real(kind=r4_kind) :: buffer_exp !< Expected result
139 integer :: i, step_avg = 0 !< avg of time step increments to use in generating reference data
141 ! avgs integers for decimal part of field input
142 ! ie. level 1 = 1+2+..+6
145 do i=(time_level-1)*file_freq+1, time_level*file_freq
146 step_avg = step_avg + i
150 ! (1011 * frequency avg'd over )
151 ! + ( 1/100 * avg of time step increments )
152 buffer_exp = real((1000.0_r8_kind+10.0_r8_kind+1.0_r8_kind) * file_freq + &
153 real(step_avg,r8_kind)/100.0_r8_kind, kind=r4_kind)
154 buffer_exp = buffer_exp / file_freq
156 if (abs(buffer - buffer_exp) > 0.0) print *, "answer not exact for 0d, time:", time_level, &
157 " diff:", abs(buffer-buffer_exp)
159 if (abs(buffer - buffer_exp) > 1.0e-4) then
160 print *, "time_level", time_level, "expected", buffer_exp, "read", buffer
161 call mpp_error(FATAL, "Check_time_avg::check_data_0d:: Data is not correct")
163 end subroutine check_data_0d
165 !> @brief Check that the 1d data read in is correct
166 subroutine check_data_1d(buffer, time_level)
167 real(kind=r4_kind), intent(in) :: buffer(:) !< Buffer read from the table
168 integer, intent(in) :: time_level !< Time level read in
169 real(kind=r4_kind) :: buffer_exp !< Expected result
170 integer :: step_sum !< avg of time step increments to use in generating reference data
171 integer :: ii, i, j, k, l !< For looping
175 do i=(time_level-1)*file_freq+1, time_level*file_freq
176 step_sum = step_sum + i
180 ! (((i * 1000 + 11) * frequency) + (sum of time steps)) / frequency
182 ! => (i * 1000 + 11) + (sum of time_steps/frequency/100)
183 do ii = 1, size(buffer, 1)
185 (real(ii, kind=r8_kind)*1000.0_r8_kind +11.0_r8_kind) + &
186 (real(step_sum, kind=r8_kind)/file_freq/100.0_r8_kind) &
189 if (use_mask .and. ii .eq. 1) buffer_exp = -666_r4_kind
190 if (abs(buffer(ii) - buffer_exp) > 0.0) then
191 print *, "i:", ii, "read in:", buffer(ii), "expected:", buffer_exp, "time level:", time_level
192 print *, "diff:", abs(buffer(ii) - buffer_exp)
193 call mpp_error(FATAL, "Check_time_avg::check_data_1d:: Data is not correct")
196 end subroutine check_data_1d
198 !> @brief Check that the 2d data read in is correct
199 subroutine check_data_2d(buffer, time_level)
200 real(kind=r4_kind), intent(in) :: buffer(:,:) !< Buffer read from the table
201 integer, intent(in) :: time_level !< Time level read in
202 real(kind=r4_kind) :: buffer_exp !< Expected result
204 integer :: ii,i, j, k, l !< For looping
205 integer :: step_avg !< avg of time step increments to use in generating reference data
208 do i=(time_level-1)*file_freq+1, time_level*file_freq
209 step_avg = step_avg + i
213 ! ((i * 1000 + j * 10 + 1) * frequency) + (avg of time steps)
214 do ii = 1, size(buffer, 1)
215 do j = 1, size(buffer, 2)
216 buffer_exp = real(real(ii, kind=r8_kind)* 1000.0_kindl+ &
217 10.0_kindl*real(j, kind=r8_kind)+1.0_kindl + &
218 real(step_avg, kind=r8_kind)/file_freq/100.0_r8_kind, kind=r4_kind)
219 if (use_mask .and. ii .eq. 1 .and. j .eq. 1) buffer_exp = -666_r4_kind
220 if (abs(buffer(ii, j) - buffer_exp) > 0.0) then
221 print *, "indices:", ii, j, "expected:", buffer_exp, "read in:",buffer(ii, j)
222 call mpp_error(FATAL, "Check_time_avg::check_data_2d:: Data is not correct")
226 end subroutine check_data_2d
228 !> @brief Check that the 3d data read in is correct
229 subroutine check_data_3d(buffer, time_level, is_regional, nx_offset, ny_offset, nz_offset)
230 real(kind=r4_kind), intent(in) :: buffer(:,:,:) !< Buffer read from the table
231 integer, intent(in) :: time_level !< Time level read in
232 logical, intent(in) :: is_regional !< .True. if the variable is subregional
233 real(kind=r4_kind) :: buffer_exp !< Expected result
234 integer, optional, intent(in) :: nx_offset !< Offset in the x direction
235 integer, optional, intent(in) :: ny_offset !< Offset in the y direction
236 integer, optional, intent(in) :: nz_offset !< Offset in the z direction
238 integer :: ii, i, j, k, l !< For looping
239 integer :: nx_oset !< Offset in the x direction (local variable)
240 integer :: ny_oset !< Offset in the y direction (local variable)
241 integer :: nz_oset !< Offset in the z direction (local variable)
242 integer :: step_avg!< avg of time step increments to use in generating reference data
245 do i=(time_level-1)*file_freq+1, time_level*file_freq
246 step_avg = step_avg + i
250 if (present(nx_offset)) nx_oset = nx_offset
253 if (present(ny_offset)) ny_oset = ny_offset
256 if (present(nz_offset)) nz_oset = nz_offset
259 ! ((i * 1000 + j * 10 + k) * frequency) + (avg of time steps)
260 do ii = 1, size(buffer, 1)
261 do j = 1, size(buffer, 2)
262 do k = 1, size(buffer, 3)
263 buffer_exp = real(real(ii+nx_oset, kind=r8_kind)* 1000.0_kindl + &
264 10.0_kindl*real(j+ny_oset, kind=r8_kind) + &
265 1.0_kindl*real(k+nz_oset, kind=r8_kind) + &
266 real(step_avg, kind=r8_kind)/file_freq/100.0_kindl, kind=r4_kind)
267 if (use_mask .and. ii .eq. 1 .and. j .eq. 1 .and. k .eq. 1 .and. .not. is_regional) buffer_exp = -666_r4_kind
268 if (abs(buffer(ii, j, k) - buffer_exp) > 0.0) then
269 print *, mpp_pe(),'indices:',ii, j, k, "read in:", buffer(ii, j, k), "expected:",buffer_exp
270 call mpp_error(FATAL, "Check_time_avg::check_data_3d:: Data is not correct")
275 end subroutine check_data_3d