7 use iso_fortran_env
, only : stdout=>output_unit, stderr=>error_unit
9 implicit none ;
private 11 public diag_vkernels_unit_tests
12 public interpolate_column
13 public reintegrate_column
18 subroutine interpolate_column(nsrc, h_src, u_src, ndest, h_dest, missing_value, u_dest)
19 integer,
intent(in) :: nsrc
20 real,
dimension(nsrc),
intent(in) :: h_src
21 real,
dimension(nsrc+1),
intent(in) :: u_src
22 integer,
intent(in) :: ndest
23 real,
dimension(ndest),
intent(in) :: h_dest
24 real,
intent(in) :: missing_value
25 real,
dimension(ndest+1),
intent(inout) :: u_dest
30 real :: weight_a, weight_b
31 integer :: k_src, k_dest
32 logical :: still_vanished
35 still_vanished = .true.
43 do while (dh<=x_dest .and. k_src<nsrc)
55 weight_a = max(0., ( dh - x_dest ) / dh)
56 weight_b = min(1., x_dest / dh)
57 u_dest(k_dest) = weight_a * u1 + weight_b * u2
59 u_dest(k_dest) = 0.5 * ( u1 + u2 )
65 if (k_dest<=ndest)
then 66 x_dest = x_dest + h_dest(k_dest)
67 if (still_vanished .and. h_dest(k_dest)==0.)
then 70 u_dest(k_dest) = missing_value
72 still_vanished = .false.
79 still_vanished = .true.
80 do k_dest=ndest, 1, -1
81 if (still_vanished .and. h_dest(k_dest)==0.)
then 84 u_dest(k_dest+1) = missing_value
90 end subroutine interpolate_column
93 subroutine reintegrate_column(nsrc, h_src, uh_src, ndest, h_dest, missing_value, uh_dest)
94 integer,
intent(in) :: nsrc
95 real,
dimension(nsrc),
intent(in) :: h_src
96 real,
dimension(nsrc),
intent(in) :: uh_src
97 integer,
intent(in) :: ndest
98 real,
dimension(ndest),
intent(in) :: h_dest
99 real,
intent(in) :: missing_value
100 real,
dimension(ndest),
intent(inout) :: uh_dest
103 real :: h_src_rem, h_dest_rem, dh
104 real :: uh_src_rem, uh_dest_rem, duh
105 integer :: k_src, k_dest
107 logical :: src_ran_out, src_exists
109 uh_dest(:) = missing_value
115 src_ran_out = .false.
119 if (h_src_rem==0. .and. k_src<nsrc)
then 122 h_src_rem = h_src(k_src)
123 uh_src_rem = uh_src(k_src)
124 if (h_src_rem==0.) cycle
127 if (h_dest_rem==0. .and. k_dest<ndest)
then 130 h_dest_rem = h_dest(k_dest)
132 if (h_dest_rem==0.) cycle
134 if (k_src==nsrc .and. h_src_rem==0.)
then 135 if (src_ran_out)
exit 140 if (h_src_rem<h_dest_rem)
then 143 if (dh>0.) duh = uh_src_rem
146 h_dest_rem = max(0., h_dest_rem - dh)
147 elseif (h_src_rem>h_dest_rem)
then 150 duh = (dh / h_src_rem) * uh_src_rem
151 h_src_rem = max(0., h_src_rem - dh)
152 uh_src_rem = uh_src_rem - duh
161 uh_dest(k_dest) = uh_dest(k_dest) + duh
162 if (k_dest==ndest .and. (k_src==nsrc .or. h_dest_rem==0.))
exit 165 if (.not. src_exists) uh_dest(1:ndest) = missing_value
167 end subroutine reintegrate_column
170 logical function diag_vkernels_unit_tests(verbose)
171 logical,
intent(in) :: verbose
173 real,
parameter :: mv=-9.999999999e9
178 write(stdout,*)
'==== MOM_diag_kernels: diag_vkernels_unit_tests ==========' 179 if (v)
write(stdout,*)
'- - - - - - - - - - interpolation tests - - - - - - - - -' 181 fail = test_interp(v,mv,
'Identity: 3 layer', &
182 3, (/1.,2.,3./), (/1.,2.,3.,4./), &
183 3, (/1.,2.,3./), (/1.,2.,3.,4./) )
184 diag_vkernels_unit_tests = fail
186 fail = test_interp(v,mv,
'A: 3 layer to 2', &
187 3, (/1.,1.,1./), (/1.,2.,3.,4./), &
188 2, (/1.5,1.5/), (/1.,2.5,4./) )
189 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
191 fail = test_interp(v,mv,
'B: 2 layer to 3', &
192 2, (/1.5,1.5/), (/1.,4.,7./), &
193 3, (/1.,1.,1./), (/1.,3.,5.,7./) )
194 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
196 fail = test_interp(v,mv,
'C: 3 layer (vanished middle) to 2', &
197 3, (/1.,0.,2./), (/1.,2.,2.,3./), &
198 2, (/1.,2./), (/1.,2.,3./) )
199 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
201 fail = test_interp(v,mv,
'D: 3 layer (deep) to 3', &
202 3, (/1.,2.,3./), (/1.,2.,4.,7./), &
203 2, (/2.,2./), (/1.,3.,5./) )
204 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
206 fail = test_interp(v,mv,
'E: 3 layer to 3 (deep)', &
207 3, (/1.,2.,4./), (/1.,2.,4.,8./), &
208 3, (/2.,3.,4./), (/1.,3.,6.,8./) )
209 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
211 fail = test_interp(v,mv,
'F: 3 layer to 4 with vanished top/botton', &
212 3, (/1.,2.,4./), (/1.,2.,4.,8./), &
213 4, (/0.,2.,5.,0./), (/mv,1.,3.,8.,mv/) )
214 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
216 fail = test_interp(v,mv,
'Fs: 3 layer to 4 with vanished top/botton (shallow)', &
217 3, (/1.,2.,4./), (/1.,2.,4.,8./), &
218 4, (/0.,2.,4.,0./), (/mv,1.,3.,7.,mv/) )
219 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
221 fail = test_interp(v,mv,
'Fd: 3 layer to 4 with vanished top/botton (deep)', &
222 3, (/1.,2.,4./), (/1.,2.,4.,8./), &
223 4, (/0.,2.,6.,0./), (/mv,1.,3.,8.,mv/) )
224 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
226 if (v)
write(stdout,*)
'- - - - - - - - - - reintegration tests - - - - - - - - -' 228 fail = test_reintegrate(v,mv,
'Identity: 3 layer', &
229 3, (/1.,2.,3./), (/-5.,2.,1./), &
230 3, (/1.,2.,3./), (/-5.,2.,1./) )
231 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
233 fail = test_reintegrate(v,mv,
'A: 3 layer to 2', &
234 3, (/2.,2.,2./), (/-5.,2.,1./), &
235 2, (/3.,3./), (/-4.,2./) )
236 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
238 fail = test_reintegrate(v,mv,
'A: 3 layer to 2 (deep)', &
239 3, (/2.,2.,2./), (/-5.,2.,1./), &
240 2, (/3.,4./), (/-4.,2./) )
241 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
243 fail = test_reintegrate(v,mv,
'A: 3 layer to 2 (shallow)', &
244 3, (/2.,2.,2./), (/-5.,2.,1./), &
245 2, (/3.,2./), (/-4.,1.5/) )
246 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
248 fail = test_reintegrate(v,mv,
'B: 3 layer to 4 with vanished top/bottom', &
249 3, (/2.,2.,2./), (/-5.,2.,1./), &
250 4, (/0.,3.,3.,0./), (/0.,-4.,2.,0./) )
251 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
253 fail = test_reintegrate(v,mv,
'C: 3 layer to 4 with vanished top//middle/bottom', &
254 3, (/2.,2.,2./), (/-5.,2.,1./), &
255 5, (/0.,3.,0.,3.,0./), (/0.,-4.,0.,2.,0./) )
256 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
258 fail = test_reintegrate(v,mv,
'D: 3 layer to 3 (vanished)', &
259 3, (/2.,2.,2./), (/-5.,2.,1./), &
260 3, (/0.,0.,0./), (/0.,0.,0./) )
261 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
263 fail = test_reintegrate(v,mv,
'D: 3 layer (vanished) to 3', &
264 3, (/0.,0.,0./), (/-5.,2.,1./), &
265 3, (/2.,2.,2./), (/mv, mv, mv/) )
266 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
268 fail = test_reintegrate(v,mv,
'D: 3 layer (vanished) to 3 (vanished)', &
269 3, (/0.,0.,0./), (/-5.,2.,1./), &
270 3, (/0.,0.,0./), (/mv, mv, mv/) )
271 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
273 fail = test_reintegrate(v,mv,
'D: 3 layer (vanished) to 3 (vanished)', &
274 3, (/0.,0.,0./), (/0.,0.,0./), &
275 3, (/0.,0.,0./), (/mv, mv, mv/) )
276 diag_vkernels_unit_tests = diag_vkernels_unit_tests .or. fail
278 if (.not. fail)
write(stdout,*)
'Pass' 280 end function diag_vkernels_unit_tests
283 logical function test_interp(verbose, missing_value, msg, nsrc, h_src, u_src, ndest, h_dest, u_true)
284 logical,
intent(in) :: verbose
285 real,
intent(in) :: missing_value
286 character(len=*),
intent(in) :: msg
287 integer,
intent(in) :: nsrc
288 real,
dimension(nsrc),
intent(in) :: h_src
289 real,
dimension(nsrc+1),
intent(in) :: u_src
290 integer,
intent(in) :: ndest
291 real,
dimension(ndest),
intent(in) :: h_dest
292 real,
dimension(ndest+1),
intent(in) :: u_true
294 real,
dimension(ndest+1) :: u_dest
297 logical :: print_results
300 call interpolate_column(nsrc, h_src, u_src, ndest, h_dest, missing_value, u_dest)
302 test_interp = .false.
304 if (u_dest(k)/=u_true(k)) test_interp = .true.
306 if (verbose .or. test_interp)
then 307 write(stdout,
'(2a)')
' Test: ',msg
308 write(stdout,
'(a3,3(a24))')
'k',
'u_result',
'u_true',
'error' 310 error = u_dest(k)-u_true(k)
312 write(stdout,
'(i3,3(1pe24.16))') k,u_dest(k),u_true(k),u_dest(k)-u_true(k)
314 write(stdout,
'(i3,3(1pe24.16),x,a)') k,u_dest(k),u_true(k),u_dest(k)-u_true(k),
'<--- WRONG!' 315 write(stderr,
'(i3,3(1pe24.16),x,a)') k,u_dest(k),u_true(k),u_dest(k)-u_true(k),
'<--- WRONG!' 319 end function test_interp
322 logical function test_reintegrate(verbose, missing_value, msg, nsrc, h_src, uh_src, ndest, h_dest, uh_true)
323 logical,
intent(in) :: verbose
324 real,
intent(in) :: missing_value
325 character(len=*),
intent(in) :: msg
326 integer,
intent(in) :: nsrc
327 real,
dimension(nsrc),
intent(in) :: h_src
328 real,
dimension(nsrc),
intent(in) :: uh_src
329 integer,
intent(in) :: ndest
330 real,
dimension(ndest),
intent(in) :: h_dest
331 real,
dimension(ndest),
intent(in) :: uh_true
333 real,
dimension(ndest) :: uh_dest
336 logical :: print_results
339 call reintegrate_column(nsrc, h_src, uh_src, ndest, h_dest, missing_value, uh_dest)
341 test_reintegrate = .false.
343 if (uh_dest(k)/=uh_true(k)) test_reintegrate = .true.
345 if (verbose .or. test_reintegrate)
then 346 write(stdout,
'(2a)')
' Test: ',msg
347 write(stdout,
'(a3,3(a24))')
'k',
'uh_result',
'uh_true',
'error' 349 error = uh_dest(k)-uh_true(k)
351 write(stdout,
'(i3,3(1pe24.16))') k,uh_dest(k),uh_true(k),uh_dest(k)-uh_true(k)
353 write(stdout,
'(i3,3(1pe24.16),x,a)') k,uh_dest(k),uh_true(k),uh_dest(k)-uh_true(k),
'<--- WRONG!' 354 write(stderr,
'(i3,3(1pe24.16),x,a)') k,uh_dest(k),uh_true(k),uh_dest(k)-uh_true(k),
'<--- WRONG!' 358 end function test_reintegrate
Provides kernels for single-column interpolation, re-integration (re-mapping of integrated quantities...