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_pow" reduction method
21 !! Pow reductions are run with a different dataset to simplify checking
22 !! Each element in sent arrays is just the sum of its indices
23 program check_time_pow
24 use fms_mod, only: fms_init, fms_end, string
25 use fms2_io_mod, only: FmsNetcdfFile_t, read_data, close_file, open_file
26 use mpp_mod, only: mpp_npes, mpp_error, FATAL, mpp_pe, input_nml_file, NOTE
27 use platform_mod, only: r4_kind, r8_kind
28 use testing_utils, only: allocate_buffer, test_normal, test_openmp, test_halos, no_mask, logical_mask, real_mask
32 type(FmsNetcdfFile_t) :: fileobj !< FMS2 fileobj
33 type(FmsNetcdfFile_t) :: fileobj1 !< FMS2 fileobj for subregional file 1
34 type(FmsNetcdfFile_t) :: fileobj2 !< FMS2 fileobj for subregional file 2
35 real(kind=r4_kind), allocatable :: cdata_out(:,:,:,:) !< Data in the compute domain
36 integer :: nx !< Number of points in the x direction
37 integer :: ny !< Number of points in the y direction
38 integer :: nz !< Number of points in the z direction
39 integer :: nw !< Number of points in the 4th dimension
40 integer :: ti !< For looping through time levels
41 integer :: io_status !< Io status after reading the namelist
42 logical :: use_mask !< .true. if using masks
43 integer, parameter :: file_freq = 6 !< file frequency as set in diag_table.yaml
44 integer, parameter :: pow_value = 2 !< pow value as set in reduction method (ie. pow2)
46 integer :: test_case = test_normal !< Indicates which test case to run
47 integer :: mask_case = no_mask !< Indicates which masking option to run
48 integer, parameter :: kindl = KIND(0.0) !< compile-time default kind size
50 namelist / test_reduction_methods_nml / test_case, mask_case
54 read (input_nml_file, test_reduction_methods_nml, iostat=io_status)
56 select case(mask_case)
59 case (logical_mask, real_mask)
67 if (.not. open_file(fileobj, "test_pow.nc", "read")) &
68 call mpp_error(FATAL, "unable to open test_pow.nc")
70 if (.not. open_file(fileobj1, "test_pow_regional.nc.0004", "read")) &
71 call mpp_error(FATAL, "unable to open test_pow_regional.nc.0004")
73 if (.not. open_file(fileobj2, "test_pow_regional.nc.0005", "read")) &
74 call mpp_error(FATAL, "unable to open test_pow_regional.nc.0005")
76 cdata_out = allocate_buffer(1, nx, 1, ny, nz, nw)
79 cdata_out = -999_r4_kind
80 print *, "Checking answers for var0_pow - time_level:", string(ti)
81 call read_data(fileobj, "var0_pow", cdata_out(1,1,1,1), unlim_dim_level=ti)
82 call check_data_0d(cdata_out(1,1,1,1), ti)
84 cdata_out = -999_r4_kind
85 print *, "Checking answers for var1_pow - time_level:", string(ti)
86 call read_data(fileobj, "var1_pow", cdata_out(:,1,1,1), unlim_dim_level=ti)
87 call check_data_1d(cdata_out(:,1,1,1), ti)
89 cdata_out = -999_r4_kind
90 print *, "Checking answers for var2_pow - time_level:", string(ti)
91 call read_data(fileobj, "var2_pow", cdata_out(:,:,1,1), unlim_dim_level=ti)
92 call check_data_2d(cdata_out(:,:,1,1), ti)
94 cdata_out = -999_r4_kind
95 print *, "Checking answers for var3_pow - time_level:", string(ti)
96 call read_data(fileobj, "var3_pow", cdata_out(:,:,:,1), unlim_dim_level=ti)
97 call check_data_3d(cdata_out(:,:,:,1), ti, .false.)
99 cdata_out = -999_r4_kind
100 print *, "Checking answers for var3_Z - time_level:", string(ti)
101 call read_data(fileobj, "var3_Z", cdata_out(:,:,1:2,1), unlim_dim_level=ti)
102 call check_data_3d(cdata_out(:,:,1:2,1), ti, .true., nz_offset=1)
104 cdata_out = -999_r4_kind
105 print *, "Checking answers for var3_pow in the first regional file- time_level:", string(ti)
106 call read_data(fileobj1, "var3_pow", cdata_out(1:4,1:3,1:2,1), unlim_dim_level=ti)
107 call check_data_3d(cdata_out(1:4,1:3,1:2,1), ti, .true., nx_offset=77, ny_offset=77, nz_offset=1)
109 cdata_out = -999_r4_kind
110 print *, "Checking answers for var3_pow in the second regional file- time_level:", string(ti)
111 call read_data(fileobj2, "var3_pow", cdata_out(1:4,1:1,1:2,1), unlim_dim_level=ti)
112 call check_data_3d(cdata_out(1:4,1:1,1:2,1), ti, .true., nx_offset=77, ny_offset=80, nz_offset=1)
120 ! buffer(ii-is+1+nhalo, j-js+1+nhalo, k, l) = i + j + k + l
122 ! sum of squares for 1..n can be calculated with:
123 ! P(n) = (n^3 / 3) + (n^2 / 2) + (n/6)
124 !> @brief Check that the 0d data read in is correct
125 subroutine check_data_0d(buffer, time_level)
126 real(kind=r4_kind), intent(inout) :: buffer !< Buffer read from the table
127 integer, intent(in) :: time_level !< Time level read in
129 real(kind=r4_kind) :: buffer_exp !< Expected result
130 integer :: i, step_pow = 0 !< pow of time step increments to use in generating reference data
132 ! only one index(1,1,1,1) = sums to 4
133 buffer_exp = get_answer_from_index(4)
135 if (abs(buffer - buffer_exp) > 0.0) then
136 print *, "time_level", time_level, "expected", buffer_exp, "read", buffer
137 call mpp_error(FATAL, "Check_time_pow::check_data_0d:: Data is not correct")
139 end subroutine check_data_0d
141 !> @brief Check that the 1d data read in is correct
142 subroutine check_data_1d(buffer, time_level)
143 real(kind=r4_kind), intent(in) :: buffer(:) !< Buffer read from the table
144 integer, intent(in) :: time_level !< Time level read in
145 real(kind=r4_kind) :: buffer_exp !< Expected result
146 integer :: step_sum !< pow of time step increments to use in generating reference data
147 integer :: ii, i, j, k, l !< For looping
151 ! (((i * 1000 + 11) * frequency) + (sum of time steps)) / frequency
153 ! => (i * 1000 + 11) + (sum of time_steps/frequency/100)
154 do ii = 1, size(buffer, 1)
155 buffer_exp = get_answer_from_index(ii + 3)
157 if (use_mask .and. ii .eq. 1) buffer_exp = -666_r4_kind
158 if (abs(buffer(ii) - buffer_exp) > 0.0) then
159 print *, "i:", ii, "read in:", buffer(ii), "expected:", buffer_exp, "time level:", time_level
160 print *, "diff:", abs(buffer(ii) - buffer_exp)
161 call mpp_error(FATAL, "Check_time_pow::check_data_1d:: Data is not exact")
164 end subroutine check_data_1d
166 !> @brief Check that the 2d data read in is correct
167 subroutine check_data_2d(buffer, time_level)
168 real(kind=r4_kind), intent(in) :: buffer(:,:) !< Buffer read from the table
169 integer, intent(in) :: time_level !< Time level read in
170 real(kind=r4_kind) :: buffer_exp !< Expected result
172 integer :: ii,i, j, k, l !< For looping
173 integer :: step_pow !< pow of time step increments to use in generating reference data
175 do ii = 1, size(buffer, 1)
176 do j = 1, size(buffer, 2)
177 buffer_exp = get_answer_from_index(ii + j + 2)
178 if (use_mask .and. ii .eq. 1 .and. j .eq. 1) buffer_exp = -666_r4_kind
179 if (abs(buffer(ii, j) - buffer_exp) > 0.0) then
180 print *, "indices:", ii, j, "expected:", buffer_exp, "read in:",buffer(ii, j)
181 call mpp_error(FATAL, "Check_time_pow::check_data_2d:: Data is not correct")
185 end subroutine check_data_2d
187 !> @brief Check that the 3d data read in is correct
188 subroutine check_data_3d(buffer, time_level, is_regional, nx_offset, ny_offset, nz_offset)
189 real(kind=r4_kind), intent(in) :: buffer(:,:,:) !< Buffer read from the table
190 integer, intent(in) :: time_level !< Time level read in
191 logical, intent(in) :: is_regional !< .True. if the variable is subregional
192 real(kind=r4_kind) :: buffer_exp !< Expected result
193 integer, optional, intent(in) :: nx_offset !< Offset in the x direction
194 integer, optional, intent(in) :: ny_offset !< Offset in the y direction
195 integer, optional, intent(in) :: nz_offset !< Offset in the z direction
197 integer :: ii, i, j, k, l !< For looping
198 integer :: nx_oset !< Offset in the x direction (local variable)
199 integer :: ny_oset !< Offset in the y direction (local variable)
200 integer :: nz_oset !< Offset in the z direction (local variable)
201 integer :: step_pow!< pow of time step increments to use in generating reference data
204 do i=(time_level-1)*file_freq+1, time_level*file_freq
205 step_pow = step_pow + i
209 if (present(nx_offset)) nx_oset = nx_offset
212 if (present(ny_offset)) ny_oset = ny_offset
215 if (present(nz_offset)) nz_oset = nz_offset
218 ! ((i * 1000 + j * 10 + k) * frequency) + (pow of time steps)
219 do ii = 1, size(buffer, 1)
220 do j = 1, size(buffer, 2)
221 do k = 1, size(buffer, 3)
222 buffer_exp = get_answer_from_index(ii + j + k + 1 + ny_oset + nx_oset + nz_oset)
223 if (use_mask .and. ii .eq. 1 .and. j .eq. 1 .and. k .eq. 1 .and. .not. is_regional) buffer_exp = -666_r4_kind
224 if (abs(buffer(ii, j, k) - buffer_exp) > 0.0) then
225 print *, mpp_pe(),'indices:',ii, j, k, "read in:", buffer(ii, j, k), "expected:",buffer_exp
226 call mpp_error(FATAL, "Check_time_pow::check_data_3d:: Data is not correct")
231 end subroutine check_data_3d
233 function get_answer_from_index(index_sum) &
235 integer, intent(in) :: index_sum !< sum of indices
236 real(r4_kind) :: answ
240 answ = answ + real(index_sum, r4_kind) ** 2.0
242 answ = answ / file_freq