← back to index

src/diagnostics/MOM_debugging.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Provides checksumming functions for debugging
6!!
7!! This module contains subroutines that perform various error checking and
8!! debugging functions for MOM6. This routine is similar to it counterpart in
9!! the SIS2 code, except for the use of the ocean_grid_type and by keeping them
10!! separate we retain the ability to set up MOM6 and SIS2 debugging separately.
11module MOM_debugging
12
13use MOM_checksums, only : hchksum, Bchksum, qchksum, uvchksum, hchksum_pair
14use MOM_checksums, only : is_NaN, chksum, MOM_checksums_init
15use MOM_coms, only : PE_here, root_PE, num_PEs
16use MOM_coms, only : min_across_PEs, max_across_PEs, reproducing_sum
17use MOM_domains, only : pass_vector, pass_var, pe_here
18use MOM_domains, only : BGRID_NE, AGRID, To_All, Scalar_Pair
19use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe
20use MOM_file_parser, only : log_version, param_file_type, get_param
21use MOM_grid, only : ocean_grid_type
22use MOM_hor_index, only : hor_index_type
23use MOM_io, only : stdout
24use MOM_unit_scaling, only : unit_scale_type
25
26implicit none ; private
27
28public :: check_redundant_C, check_redundant_B, check_redundant_T, check_redundant
29public :: vec_chksum, vec_chksum_C, vec_chksum_B, vec_chksum_A
30public :: MOM_debugging_init, totalStuff, totalTandS
31public :: check_column_integral, check_column_integrals
32public :: query_debugging_checks
33
34! These interfaces come from MOM_checksums.
35public :: hchksum, Bchksum, qchksum, is_NaN, chksum, uvchksum, hchksum_pair
36
37!> Check for consistency between the duplicated points of a C-grid vector
38interface check_redundant
39 module procedure check_redundant_vC3d, check_redundant_vC2d
40end interface check_redundant
41!> Check for consistency between the duplicated points of a C-grid vector
42interface check_redundant_C
43 module procedure check_redundant_vC3d, check_redundant_vC2d
44end interface check_redundant_C
45!> Check for consistency between the duplicated points of a B-grid vector or scalar
46interface check_redundant_B
47 module procedure check_redundant_vB3d, check_redundant_vB2d
48 module procedure check_redundant_sB3d, check_redundant_sB2d
49end interface check_redundant_B
50!> Check for consistency between the duplicated points of an A-grid vector or scalar
51interface check_redundant_T
52 module procedure check_redundant_sT3d, check_redundant_sT2d
53 module procedure check_redundant_vT3d, check_redundant_vT2d
54end interface check_redundant_T
55
56!> Do checksums on the components of a C-grid vector
57interface vec_chksum
58 module procedure chksum_vec_C3d, chksum_vec_C2d
59end interface vec_chksum
60!> Do checksums on the components of a C-grid vector
61interface vec_chksum_C
62 module procedure chksum_vec_C3d, chksum_vec_C2d
63end interface vec_chksum_C
64!> Do checksums on the components of a B-grid vector
65interface vec_chksum_B
66 module procedure chksum_vec_B3d, chksum_vec_B2d
67end interface vec_chksum_B
68!> Do checksums on the components of an A-grid vector
69interface vec_chksum_A
70 module procedure chksum_vec_A3d, chksum_vec_A2d
71end interface vec_chksum_A
72
73! Note: these parameters are module data but ONLY used when debugging and
74! so can violate the thread-safe requirement of no module/global data.
75integer :: max_redundant_prints = 100 !< Maximum number of times to write redundant messages
76integer :: redundant_prints(3) = 0 !< Counters for controlling redundant printing
77logical :: debug = .false. !< Write out verbose debugging data
78logical :: debug_chksums = .true. !< Perform checksums on arrays
79logical :: debug_redundant = .true. !< Check redundant values on PE boundaries
80
81contains
82
83!> MOM_debugging_init initializes the MOM_debugging module, and sets
84!! the parameters that control which checks are active for MOM6.
851subroutine MOM_debugging_init(param_file)
86 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
87 ! This include declares and sets the variable "version".
88# include "version_variable.h"
89 character(len=40) :: mdl = "MOM_debugging" ! This module's name.
90
911 call log_version(param_file, mdl, version, debugging=.true.)
92 call get_param(param_file, mdl, "DEBUG", debug, &
93 "If true, write out verbose debugging data.", &
941 default=.false., debuggingParam=.true.)
95 call get_param(param_file, mdl, "DEBUG_CHKSUMS", debug_chksums, &
96 "If true, checksums are performed on arrays in the "//&
97 "various vec_chksum routines.", default=debug, &
981 debuggingParam=.true.)
99 call get_param(param_file, mdl, "DEBUG_REDUNDANT", debug_redundant, &
100 "If true, debug redundant data points during calls to "//&
101 "the various vec_chksum routines.", default=debug, &
1021 debuggingParam=.true.)
103
1041 call MOM_checksums_init(param_file)
105
1061end subroutine MOM_debugging_init
107
108!> Returns logicals indicating which debugging checks should be performed.
1090subroutine query_debugging_checks(do_debug, do_chksums, do_redundant)
110 logical, optional, intent(out) :: do_debug !< True if verbose debugging is to be output
111 logical, optional, intent(out) :: do_chksums !< True if checksums are to be output
112 logical, optional, intent(out) :: do_redundant !< True if redundant points are to be checked
113
1140 if (present(do_debug)) do_debug = debug
1150 if (present(do_chksums)) do_chksums = debug_chksums
1160 if (present(do_redundant)) do_redundant = debug_redundant
117
1180end subroutine query_debugging_checks
119
120!> Check for consistency between the duplicated points of a 3-D C-grid vector
1210subroutine check_redundant_vC3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
122 direction, unscale)
123 character(len=*), intent(in) :: mesg !< An identifying message
124 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
125 real, dimension(G%IsdB:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector to be
126 !! checked for consistency in arbitrary,
127 !! possibly rescaled units [A ~> a]
128 real, dimension(G%isd:,G%JsdB:,:), intent(in) :: v_comp !< The u-component of the vector to be
129 !! checked for consistency in arbitrary,
130 !! possibly rescaled units [A ~> a]
131 integer, optional, intent(in) :: is !< The starting i-index to check
132 integer, optional, intent(in) :: ie !< The ending i-index to check
133 integer, optional, intent(in) :: js !< The starting j-index to check
134 integer, optional, intent(in) :: je !< The ending j-index to check
135 integer, optional, intent(in) :: direction !< the direction flag to be
136 !! passed to pass_vector
137 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
138 !! arrays to give consistent output [a A-1 ~> 1]
139
140 ! Local variables
141 character(len=24) :: mesg_k
142 integer :: k
143
1440 do k=1,size(u_comp,3)
1450 write(mesg_k,'(" Layer ",i0," ")') k
146 call check_redundant_vC2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
1470 v_comp(:,:,k), G, is, ie, js, je, direction, unscale)
148 enddo
1490end subroutine check_redundant_vC3d
150
151!> Check for consistency between the duplicated points of a 2-D C-grid vector
1520subroutine check_redundant_vC2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
153 direction, unscale)
154 character(len=*), intent(in) :: mesg !< An identifying message
155 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
156 real, dimension(G%IsdB:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector to be
157 !! checked for consistency in arbitrary,
158 !! possibly rescaled units [A ~> a]
159 real, dimension(G%isd:,G%JsdB:), intent(in) :: v_comp !< The u-component of the vector to be
160 !! checked for consistency in arbitrary,
161 !! possibly rescaled units [A ~> a]
162 integer, optional, intent(in) :: is !< The starting i-index to check
163 integer, optional, intent(in) :: ie !< The ending i-index to check
164 integer, optional, intent(in) :: js !< The starting j-index to check
165 integer, optional, intent(in) :: je !< The ending j-index to check
166 integer, optional, intent(in) :: direction !< the direction flag to be
167 !! passed to pass_vector
168 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
169 !! arrays to give consistent output [a A-1 ~> 1]
170 ! Local variables
171 ! In the following comments, [A] is used to indicate the arbitrary, possibly rescaled units
172 ! of the input vector while [a] indicates the unscaled (e.g., mks) units to used for output.
1730 real :: u_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A nonsymmetric version of u_comp [A ~> a]
1740 real :: v_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A nonsymmetric version of v_comp [A ~> a]
1750 real :: u_resym(G%IsdB:G%IedB,G%jsd:G%jed) ! A reconstructed symmetric version of u_comp [A ~> a]
1760 real :: v_resym(G%isd:G%ied,G%JsdB:G%JedB) ! A reconstructed symmetric version of v_comp [A ~> a]
177 real :: sc ! A factor that undoes the scaling for the arrays to give consistent output [a A-1 ~> 1]
178 character(len=128) :: mesg2
179 integer :: i, j, is_ch, ie_ch, js_ch, je_ch
180 integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
181
1820 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
1830 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
1840 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
185
1860 if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
187 ! This only works with symmetric memory, so otherwise return.
1880 if ((isd == IsdB) .and. (jsd == JsdB)) return
189 endif
190
1910 sc = 1.0 ; if (present(unscale)) sc = unscale
192
1930 do i=isd,ied ; do j=jsd,jed
1940 u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
195 enddo ; enddo
196
1970 if (.not.associated(G%Domain_aux)) call MOM_error(FATAL, &
1980 " check_redundant called with a non-associated auxiliary domain the grid type.")
1990 call pass_vector(u_nonsym, v_nonsym, G%Domain_aux, direction)
200
2010 do I=IsdB,IedB ; do j=jsd,jed ; u_resym(I,j) = u_comp(I,j) ; enddo ; enddo
2020 do i=isd,ied ; do J=JsdB,JedB ; v_resym(i,J) = v_comp(i,J) ; enddo ; enddo
2030 do i=isd,ied ; do j=jsd,jed
2040 u_resym(i,j) = u_nonsym(i,j) ; v_resym(i,j) = v_nonsym(i,j)
205 enddo ; enddo
2060 call pass_vector(u_resym, v_resym, G%Domain, direction)
207
2080 is_ch = Isq ; ie_ch = Ieq ; js_ch = Jsq ; je_ch = Jeq
2090 if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
2100 if (present(js)) js_ch = js ; if (present(js)) je_ch = je
211
2120 do i=is_ch,ie_ch ; do j=js_ch+1,je_ch
2130 if (u_resym(i,j) /= u_comp(i,j) .and. &
2140 redundant_prints(3) < max_redundant_prints) then
215 write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
216 & 1pe12.4," at i,j = ",I0,",",I0," on pe ",I0)') &
2170 sc*u_comp(i,j), sc*u_resym(i,j), sc*(u_comp(i,j)-u_resym(i,j)), i, j, pe_here()
2180 write(0,'(A130)') trim(mesg)//trim(mesg2)
2190 redundant_prints(3) = redundant_prints(3) + 1
220 endif
221 enddo ; enddo
2220 do i=is_ch+1,ie_ch ; do j=js_ch,je_ch
2230 if (v_resym(i,j) /= v_comp(i,j) .and. &
2240 redundant_prints(3) < max_redundant_prints) then
225 write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
226 & 1pe12.4," at i,j = ",I0,",",I0," x,y = ",2(1pe12.4)," on pe ",I0)') &
2270 sc*v_comp(i,j), sc*v_resym(i,j), sc*(v_comp(i,j)-v_resym(i,j)), i, j, &
2280 G%geoLonBu(i,j), G%geoLatBu(i,j), pe_here()
2290 write(0,'(A155)') trim(mesg)//trim(mesg2)
2300 redundant_prints(3) = redundant_prints(3) + 1
231 endif
232 enddo ; enddo
233
2340end subroutine check_redundant_vC2d
235
236!> Check for consistency between the duplicated points of a 3-D scalar at corner points
2370subroutine check_redundant_sB3d(mesg, array, G, is, ie, js, je, unscale)
238 character(len=*), intent(in) :: mesg !< An identifying message
239 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
240 real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: array !< The array to be checked for consistency in
241 !! arbitrary, possibly rescaled units [A ~> a]
242 integer, optional, intent(in) :: is !< The starting i-index to check
243 integer, optional, intent(in) :: ie !< The ending i-index to check
244 integer, optional, intent(in) :: js !< The starting j-index to check
245 integer, optional, intent(in) :: je !< The ending j-index to check
246 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
247 !! arrays to give consistent output [a A-1 ~> 1]
248
249 ! Local variables
250 character(len=24) :: mesg_k
251 integer :: k
252
2530 do k=1,size(array,3)
2540 write(mesg_k,'(" Layer ",i0," ")') k
255 call check_redundant_sB2d(trim(mesg)//trim(mesg_k), array(:,:,k), &
2560 G, is, ie, js, je, unscale)
257 enddo
2580end subroutine check_redundant_sB3d
259
260!> Check for consistency between the duplicated points of a 2-D scalar at corner points
2610subroutine check_redundant_sB2d(mesg, array, G, is, ie, js, je, unscale)
262 character(len=*), intent(in) :: mesg !< An identifying message
263 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
264 real, dimension(G%IsdB:,G%JsdB:), intent(in) :: array !< The array to be checked for consistency in
265 !! arbitrary, possibly rescaled units [A ~> a]
266 integer, optional, intent(in) :: is !< The starting i-index to check
267 integer, optional, intent(in) :: ie !< The ending i-index to check
268 integer, optional, intent(in) :: js !< The starting j-index to check
269 integer, optional, intent(in) :: je !< The ending j-index to check
270 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
271 !! arrays to give consistent output [a A-1 ~> 1]
272 ! Local variables
273 ! In the following comments, [A] is used to indicate the arbitrary, possibly rescaled units
274 ! of the input array while [a] indicates the unscaled (e.g., mks) units to used for output.
2750 real :: a_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A nonsymmetric version of array [A ~> a]
2760 real :: a_resym(G%IsdB:G%IedB,G%JsdB:G%JedB) ! A reconstructed symmetric version of array [A ~> a]
277 real :: sc ! A factor that undoes the scaling for the arrays to give consistent output [a A-1 ~> 1]
278 character(len=128) :: mesg2
279 integer :: i, j, is_ch, ie_ch, js_ch, je_ch
280 integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
281
2820 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
2830 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
2840 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
285
2860 if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
287 ! This only works with symmetric memory, so otherwise return.
2880 if ((isd == IsdB) .and. (jsd == JsdB)) return
289 endif
290
2910 sc = 1.0 ; if (present(unscale)) sc = unscale
292
2930 do i=isd,ied ; do j=jsd,jed
2940 a_nonsym(i,j) = array(i,j)
295 enddo ; enddo
296
2970 if (.not.associated(G%Domain_aux)) call MOM_error(FATAL, &
2980 " check_redundant called with a non-associated auxiliary domain the grid type.")
299 call pass_vector(a_nonsym, a_nonsym, G%Domain_aux, &
3000 direction=To_All+Scalar_Pair, stagger=BGRID_NE)
301
3020 do I=IsdB,IedB ; do J=JsdB,JedB ; a_resym(I,J) = array(I,J) ; enddo ; enddo
3030 do i=isd,ied ; do j=jsd,jed
3040 a_resym(i,j) = a_nonsym(i,j)
305 enddo ; enddo
306 call pass_vector(a_resym, a_resym, G%Domain, direction=To_All+Scalar_Pair, &
3070 stagger=BGRID_NE)
308
3090 is_ch = Isq ; ie_ch = Ieq ; js_ch = Jsq ; je_ch = Jeq
3100 if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
3110 if (present(js)) js_ch = js ; if (present(js)) je_ch = je
312
3130 do i=is_ch,ie_ch ; do j=js_ch,je_ch
3140 if (a_resym(i,j) /= array(i,j) .and. &
3150 redundant_prints(2) < max_redundant_prints) then
316 write(mesg2,'(" Redundant points",2(1pe12.4)," differ by ", &
317 & 1pe12.4," at i,j = ",I0,",",I0," on pe ",I0)') &
3180 sc*array(i,j), sc*a_resym(i,j), sc*(array(i,j)-a_resym(i,j)), i, j, pe_here()
3190 write(0,'(A130)') trim(mesg)//trim(mesg2)
3200 redundant_prints(2) = redundant_prints(2) + 1
321 endif
322 enddo ; enddo
323
3240end subroutine check_redundant_sB2d
325
326!> Check for consistency between the duplicated points of a 3-D B-grid vector
3270subroutine check_redundant_vB3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
328 direction, unscale)
329 character(len=*), intent(in) :: mesg !< An identifying message
330 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
331 real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: u_comp !< The u-component of the vector to be
332 !! checked for consistency in arbitrary,
333 !! possibly rescaled units [A ~> a]
334 real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: v_comp !< The v-component of the vector to be
335 !! checked for consistency in arbitrary,
336 !! possibly rescaled units [A ~> a]
337 integer, optional, intent(in) :: is !< The starting i-index to check
338 integer, optional, intent(in) :: ie !< The ending i-index to check
339 integer, optional, intent(in) :: js !< The starting j-index to check
340 integer, optional, intent(in) :: je !< The ending j-index to check
341 integer, optional, intent(in) :: direction !< the direction flag to be
342 !! passed to pass_vector
343 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
344 !! arrays to give consistent output [a A-1 ~> 1]
345 ! Local variables
346 character(len=24) :: mesg_k
347 integer :: k
348
3490 do k=1,size(u_comp,3)
3500 write(mesg_k,'(" Layer ",i0," ")') k
351 call check_redundant_vB2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
3520 v_comp(:,:,k), G, is, ie, js, je, direction, unscale)
353 enddo
3540end subroutine check_redundant_vB3d
355
356!> Check for consistency between the duplicated points of a 2-D B-grid vector
3570subroutine check_redundant_vB2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
358 direction, unscale)
359 character(len=*), intent(in) :: mesg !< An identifying message
360 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
361 real, dimension(G%IsdB:,G%JsdB:), intent(in) :: u_comp !< The u-component of the vector to be
362 !! checked for consistency in arbitrary,
363 !! possibly rescaled units [A ~> a]
364 real, dimension(G%IsdB:,G%JsdB:), intent(in) :: v_comp !< The v-component of the vector to be
365 !! checked for consistency in arbitrary,
366 !! possibly rescaled units [A ~> a]
367 integer, optional, intent(in) :: is !< The starting i-index to check
368 integer, optional, intent(in) :: ie !< The ending i-index to check
369 integer, optional, intent(in) :: js !< The starting j-index to check
370 integer, optional, intent(in) :: je !< The ending j-index to check
371 integer, optional, intent(in) :: direction !< the direction flag to be
372 !! passed to pass_vector
373 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
374 !! arrays to give consistent output [a A-1 ~> 1]
375 ! Local variables
376 ! In the following comments, [A] is used to indicate the arbitrary, possibly rescaled units
377 ! of the input vector while [a] indicates the unscaled (e.g., mks) units to used for output.
3780 real :: u_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A nonsymmetric version of u_comp [A ~> a]
3790 real :: v_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A nonsymmetric version of v_comp [A ~> a]
3800 real :: u_resym(G%IsdB:G%IedB,G%JsdB:G%JedB) ! A reconstructed symmetric version of u_comp [A ~> a]
3810 real :: v_resym(G%IsdB:G%IedB,G%JsdB:G%JedB) ! A reconstructed symmetric version of v_comp [A ~> a]
382 real :: sc ! A factor that undoes the scaling for the arrays to give consistent output [a A-1 ~> 1]
383 character(len=128) :: mesg2
384 integer :: i, j, is_ch, ie_ch, js_ch, je_ch
385 integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
386
3870 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
3880 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
3890 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
390
3910 if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
392 ! This only works with symmetric memory, so otherwise return.
3930 if ((isd == IsdB) .and. (jsd == JsdB)) return
394 endif
395
3960 sc = 1.0 ; if (present(unscale)) sc = unscale
397
3980 do i=isd,ied ; do j=jsd,jed
3990 u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
400 enddo ; enddo
401
4020 if (.not.associated(G%Domain_aux)) call MOM_error(FATAL, &
4030 " check_redundant called with a non-associated auxiliary domain the grid type.")
4040 call pass_vector(u_nonsym, v_nonsym, G%Domain_aux, direction, stagger=BGRID_NE)
405
4060 do I=IsdB,IedB ; do J=JsdB,JedB
4070 u_resym(I,J) = u_comp(I,J) ; v_resym(I,J) = v_comp(I,J)
408 enddo ; enddo
4090 do i=isd,ied ; do j=jsd,jed
4100 u_resym(i,j) = u_nonsym(i,j) ; v_resym(i,j) = v_nonsym(i,j)
411 enddo ; enddo
4120 call pass_vector(u_resym, v_resym, G%Domain, direction, stagger=BGRID_NE)
413
4140 is_ch = Isq ; ie_ch = Ieq ; js_ch = Jsq ; je_ch = Jeq
4150 if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
4160 if (present(js)) js_ch = js ; if (present(js)) je_ch = je
417
4180 do i=is_ch,ie_ch ; do j=js_ch,je_ch
4190 if (u_resym(i,j) /= u_comp(i,j) .and. &
4200 redundant_prints(2) < max_redundant_prints) then
421 write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
422 & 1pe12.4," at i,j = ",I0,",",I0," on pe ",I0)') &
4230 sc*u_comp(i,j), sc*u_resym(i,j), sc*(u_comp(i,j)-u_resym(i,j)), i, j, pe_here()
4240 write(0,'(A130)') trim(mesg)//trim(mesg2)
4250 redundant_prints(2) = redundant_prints(2) + 1
426 endif
427 enddo ; enddo
4280 do i=is_ch,ie_ch ; do j=js_ch,je_ch
4290 if (v_resym(i,j) /= v_comp(i,j) .and. &
4300 redundant_prints(2) < max_redundant_prints) then
431 write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
432 & 1pe12.4," at i,j = ",I0,",",I0," x,y = ",2(1pe12.4)," on pe ",I0)') &
4330 sc*v_comp(i,j), sc*v_resym(i,j), sc*(v_comp(i,j)-v_resym(i,j)), i, j, &
4340 G%geoLonBu(i,j), G%geoLatBu(i,j), pe_here()
4350 write(0,'(A155)') trim(mesg)//trim(mesg2)
4360 redundant_prints(2) = redundant_prints(2) + 1
437 endif
438 enddo ; enddo
439
4400end subroutine check_redundant_vB2d
441
442!> Check for consistency between the duplicated points of a 3-D scalar at tracer points
4430subroutine check_redundant_sT3d(mesg, array, G, is, ie, js, je, unscale)
444 character(len=*), intent(in) :: mesg !< An identifying message
445 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
446 real, dimension(G%isd:,G%jsd:,:), intent(in) :: array !< The array to be checked for consistency in
447 !! arbitrary, possibly rescaled units [A ~> a]
448 integer, optional, intent(in) :: is !< The starting i-index to check
449 integer, optional, intent(in) :: ie !< The ending i-index to check
450 integer, optional, intent(in) :: js !< The starting j-index to check
451 integer, optional, intent(in) :: je !< The ending j-index to check
452 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
453 !! arrays to give consistent output [a A-1 ~> 1]
454 ! Local variables
455 character(len=24) :: mesg_k
456 integer :: k
457
4580 do k=1,size(array,3)
4590 write(mesg_k,'(" Layer ",i0," ")') k
460 call check_redundant_sT2d(trim(mesg)//trim(mesg_k), array(:,:,k), &
4610 G, is, ie, js, je, unscale)
462 enddo
4630end subroutine check_redundant_sT3d
464
465
466!> Check for consistency between the duplicated points of a 2-D scalar at tracer points
4670subroutine check_redundant_sT2d(mesg, array, G, is, ie, js, je, unscale)
468 character(len=*), intent(in) :: mesg !< An identifying message
469 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
470 real, dimension(G%isd:,G%jsd:), intent(in) :: array !< The array to be checked for consistency in
471 !! arbitrary, possibly rescaled units [A ~> a]
472 integer, optional, intent(in) :: is !< The starting i-index to check
473 integer, optional, intent(in) :: ie !< The ending i-index to check
474 integer, optional, intent(in) :: js !< The starting j-index to check
475 integer, optional, intent(in) :: je !< The ending j-index to check
476 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
477 !! arrays to give consistent output [a A-1 ~> 1]
478 ! Local variables
479 ! In the following comments, [A] is used to indicate the arbitrary, possibly rescaled units
480 ! of the input array while [a] indicates the unscaled (e.g., mks) units to used for output.
4810 real :: a_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A version of array with halo points updated by message passing [A ~> a]
482 real :: sc ! A factor that undoes the scaling for the arrays to give consistent output [a A-1 ~> 1]
483 character(len=128) :: mesg2
484
485 integer :: i, j, is_ch, ie_ch, js_ch, je_ch
486 integer :: isd, ied, jsd, jed
4870 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
488
4890 is_ch = G%isc ; ie_ch = G%iec ; js_ch = G%jsc ; je_ch = G%jec
4900 if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
4910 if (present(js)) js_ch = js ; if (present(js)) je_ch = je
492
4930 sc = 1.0 ; if (present(unscale)) sc = unscale
494
495 ! This only works on points outside of the standard computational domain.
496 if ((is_ch == G%isc) .and. (ie_ch == G%iec) .and. &
4970 (js_ch == G%jsc) .and. (je_ch == G%jec)) return
498
4990 do i=isd,ied ; do j=jsd,jed
5000 a_nonsym(i,j) = array(i,j)
501 enddo ; enddo
502
5030 call pass_var(a_nonsym, G%Domain)
504
5050 do i=is_ch,ie_ch ; do j=js_ch,je_ch
5060 if (a_nonsym(i,j) /= array(i,j) .and. &
5070 redundant_prints(1) < max_redundant_prints) then
508 write(mesg2,'(" Redundant points",2(1pe12.4)," differ by ", &
509 & 1pe12.4," at i,j = ",I0,",",I0," on pe ",I0)') &
5100 sc*array(i,j), sc*a_nonsym(i,j), sc*(array(i,j)-a_nonsym(i,j)), i, j, pe_here()
5110 write(0,'(A130)') trim(mesg)//trim(mesg2)
5120 redundant_prints(1) = redundant_prints(1) + 1
513 endif
514 enddo ; enddo
515
5160end subroutine check_redundant_sT2d
517
518!> Check for consistency between the duplicated points of a 3-D A-grid vector
5190subroutine check_redundant_vT3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
520 direction, unscale)
521 character(len=*), intent(in) :: mesg !< An identifying message
522 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
523 real, dimension(G%isd:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector to be
524 !! checked for consistency in arbitrary,
525 !! possibly rescaled units [A ~> a]
526 real, dimension(G%isd:,G%jsd:,:), intent(in) :: v_comp !< The v-component of the vector to be
527 !! checked for consistency in arbitrary,
528 !! possibly rescaled units [A ~> a]
529 integer, optional, intent(in) :: is !< The starting i-index to check
530 integer, optional, intent(in) :: ie !< The ending i-index to check
531 integer, optional, intent(in) :: js !< The starting j-index to check
532 integer, optional, intent(in) :: je !< The ending j-index to check
533 integer, optional, intent(in) :: direction !< the direction flag to be
534 !! passed to pass_vector
535 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
536 !! arrays to give consistent output [a A-1 ~> 1]
537 ! Local variables
538 character(len=24) :: mesg_k
539 integer :: k
540
5410 do k=1,size(u_comp,3)
5420 write(mesg_k,'(" Layer ",i0," ")') k
543 call check_redundant_vT2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
5440 v_comp(:,:,k), G, is, ie, js, je, direction, unscale)
545 enddo
5460end subroutine check_redundant_vT3d
547
548!> Check for consistency between the duplicated points of a 2-D A-grid vector
5490subroutine check_redundant_vT2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
550 direction, unscale)
551 character(len=*), intent(in) :: mesg !< An identifying message
552 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
553 real, dimension(G%isd:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector to be
554 !! checked for consistency in arbitrary,
555 !! possibly rescaled units [A ~> a]
556 real, dimension(G%isd:,G%jsd:), intent(in) :: v_comp !< The v-component of the vector to be
557 !! checked for consistency in arbitrary,
558 !! possibly rescaled units [A ~> a]
559 integer, optional, intent(in) :: is !< The starting i-index to check
560 integer, optional, intent(in) :: ie !< The ending i-index to check
561 integer, optional, intent(in) :: js !< The starting j-index to check
562 integer, optional, intent(in) :: je !< The ending j-index to check
563 integer, optional, intent(in) :: direction !< the direction flag to be
564 !! passed to pass_vector
565 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
566 !! arrays to give consistent output [a A-1 ~> 1]
567 ! Local variables
568 ! In the following comments, [A] is used to indicate the arbitrary, possibly rescaled units
569 ! of the input vector while [a] indicates the unscaled (e.g., mks) units to used for output.
5700 real :: u_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A version of u_comp with halo points updated by message passing [A ~> a]
5710 real :: v_nonsym(G%isd:G%ied,G%jsd:G%jed) ! A version of v_comp with halo points updated by message passing [A ~> a]
572 real :: sc ! A factor that undoes the scaling for the arrays to give consistent output [a A-1 ~> 1]
573 character(len=128) :: mesg2
574
575 integer :: i, j, is_ch, ie_ch, js_ch, je_ch
576 integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
5770 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
5780 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
5790 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
580
5810 is_ch = G%isc ; ie_ch = G%iec ; js_ch = G%jsc ; je_ch = G%jec
5820 if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
5830 if (present(js)) js_ch = js ; if (present(js)) je_ch = je
584
5850 sc = 1.0 ; if (present(unscale)) sc = unscale
586
587 ! This only works on points outside of the standard computational domain.
588 if ((is_ch == G%isc) .and. (ie_ch == G%iec) .and. &
5890 (js_ch == G%jsc) .and. (je_ch == G%jec)) return
590
5910 do i=isd,ied ; do j=jsd,jed
5920 u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
593 enddo ; enddo
594
5950 call pass_vector(u_nonsym, v_nonsym, G%Domain, direction, stagger=AGRID)
596
5970 do i=is_ch,ie_ch ; do j=js_ch+1,je_ch
5980 if (u_nonsym(i,j) /= u_comp(i,j) .and. &
5990 redundant_prints(1) < max_redundant_prints) then
600 write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
601 & 1pe12.4," at i,j = ",I0,",",I0," on pe ",I0)') &
6020 sc*u_comp(i,j), sc*u_nonsym(i,j), sc*(u_comp(i,j)-u_nonsym(i,j)), i, j, pe_here()
6030 write(0,'(A130)') trim(mesg)//trim(mesg2)
6040 redundant_prints(1) = redundant_prints(1) + 1
605 endif
606 enddo ; enddo
6070 do i=is_ch+1,ie_ch ; do j=js_ch,je_ch
6080 if (v_nonsym(i,j) /= v_comp(i,j) .and. &
6090 redundant_prints(1) < max_redundant_prints) then
610 write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
611 & 1pe12.4," at i,j = ",I0,",",I0," x,y = ",2(1pe12.4)," on pe ",I0)') &
6120 sc*v_comp(i,j), sc*v_nonsym(i,j), sc*(v_comp(i,j)-v_nonsym(i,j)), i, j, &
6130 G%geoLonBu(i,j), G%geoLatBu(i,j), pe_here()
6140 write(0,'(A155)') trim(mesg)//trim(mesg2)
6150 redundant_prints(1) = redundant_prints(1) + 1
616 endif
617 enddo ; enddo
618
6190end subroutine check_redundant_vT2d
620
621
622! It appears that none of the other routines in this file are ever called.
623
624!> Do a checksum and redundant point check on a 3d C-grid vector.
6250subroutine chksum_vec_C3d(mesg, u_comp, v_comp, G, halos, scalars, unscale)
626 character(len=*), intent(in) :: mesg !< An identifying message
627 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
628 real, dimension(G%IsdB:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector to be
629 !! checked for consistency in arbitrary,
630 !! possibly rescaled units [A ~> a]
631 real, dimension(G%isd:,G%JsdB:,:), intent(in) :: v_comp !< The v-component of the vector to be
632 !! checked for consistency in arbitrary,
633 !! possibly rescaled units [A ~> a]
634 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
635 logical, optional, intent(in) :: scalars !< If true this is a pair of
636 !! scalars that are being checked.
637 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
638 !! arrays to give consistent output [a A-1 ~> 1]
639 ! Local variables
640 logical :: are_scalars
6410 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
642
6430 if (debug_chksums) then
6440 call uvchksum(mesg, u_comp, v_comp, G%HI, halos, unscale=unscale)
645 endif
6460 if (debug_redundant) then
6470 if (are_scalars) then
6480 call check_redundant_C(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
649 else
6500 call check_redundant_C(mesg, u_comp, v_comp, G, unscale=unscale)
651 endif
652 endif
653
6540end subroutine chksum_vec_C3d
655
656!> Do a checksum and redundant point check on a 2d C-grid vector.
6570subroutine chksum_vec_C2d(mesg, u_comp, v_comp, G, halos, scalars, unscale)
658 character(len=*), intent(in) :: mesg !< An identifying message
659 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
660 real, dimension(G%IsdB:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector to be
661 !! checked for consistency in arbitrary,
662 !! possibly rescaled units [A ~> a]
663 real, dimension(G%isd:,G%JsdB:), intent(in) :: v_comp !< The v-component of the vector to be
664 !! checked for consistency in arbitrary,
665 !! possibly rescaled units [A ~> a]
666 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
667 logical, optional, intent(in) :: scalars !< If true this is a pair of
668 !! scalars that are being checked.
669 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
670 !! arrays to give consistent output [a A-1 ~> 1]
671 ! Local variables
672 logical :: are_scalars
6730 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
674
6750 if (debug_chksums) then
6760 call uvchksum(mesg, u_comp, v_comp, G%HI, halos, unscale=unscale)
677 endif
6780 if (debug_redundant) then
6790 if (are_scalars) then
6800 call check_redundant_C(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
681 else
6820 call check_redundant_C(mesg, u_comp, v_comp, G, unscale=unscale)
683 endif
684 endif
685
6860end subroutine chksum_vec_C2d
687
688!> Do a checksum and redundant point check on a 3d B-grid vector.
6890subroutine chksum_vec_B3d(mesg, u_comp, v_comp, G, halos, scalars, unscale)
690 character(len=*), intent(in) :: mesg !< An identifying message
691 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
692 real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: u_comp !< The u-component of the vector to be
693 !! checked for consistency in arbitrary,
694 !! possibly rescaled units [A ~> a]
695 real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: v_comp !< The v-component of the vector to be
696 !! checked for consistency in arbitrary,
697 !! possibly rescaled units [A ~> a]
698 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
699 logical, optional, intent(in) :: scalars !< If true this is a pair of
700 !! scalars that are being checked.
701 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
702 !! arrays to give consistent output [a A-1 ~> 1]
703 ! Local variables
704 logical :: are_scalars
7050 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
706
7070 if (debug_chksums) then
7080 call Bchksum(u_comp, mesg//"(u)", G%HI, halos, unscale=unscale)
7090 call Bchksum(v_comp, mesg//"(v)", G%HI, halos, unscale=unscale)
710 endif
7110 if (debug_redundant) then
7120 if (are_scalars) then
7130 call check_redundant_B(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
714 else
7150 call check_redundant_B(mesg, u_comp, v_comp, G, unscale=unscale)
716 endif
717 endif
718
7190end subroutine chksum_vec_B3d
720
721! Do a checksum and redundant point check on a 2d B-grid vector.
7220subroutine chksum_vec_B2d(mesg, u_comp, v_comp, G, halos, scalars, symmetric, unscale)
723 character(len=*), intent(in) :: mesg !< An identifying message
724 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
725 real, dimension(G%IsdB:,G%JsdB:), intent(in) :: u_comp !< The u-component of the vector to be
726 !! checked for consistency in arbitrary,
727 !! possibly rescaled units [A ~> a]
728 real, dimension(G%IsdB:,G%JsdB:), intent(in) :: v_comp !< The v-component of the vector to be
729 !! checked for consistency in arbitrary,
730 !! possibly rescaled units [A ~> a]
731 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
732 logical, optional, intent(in) :: scalars !< If true this is a pair of
733 !! scalars that are being checked.
734 logical, optional, intent(in) :: symmetric !< If true, do the checksums on the
735 !! full symmetric computational domain.
736 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
737 !! arrays to give consistent output [a A-1 ~> 1]
738 ! Local variables
739 logical :: are_scalars
7400 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
741
7420 if (debug_chksums) then
7430 call Bchksum(u_comp, mesg//"(u)", G%HI, halos, symmetric=symmetric, unscale=unscale)
7440 call Bchksum(v_comp, mesg//"(v)", G%HI, halos, symmetric=symmetric, unscale=unscale)
745 endif
7460 if (debug_redundant) then
7470 if (are_scalars) then
7480 call check_redundant_B(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
749 else
7500 call check_redundant_B(mesg, u_comp, v_comp, G, unscale=unscale)
751 endif
752 endif
753
7540end subroutine chksum_vec_B2d
755
756!> Do a checksum and redundant point check on a 3d C-grid vector.
7570subroutine chksum_vec_A3d(mesg, u_comp, v_comp, G, halos, scalars, unscale)
758 character(len=*), intent(in) :: mesg !< An identifying message
759 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
760 real, dimension(G%isd:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector to be
761 !! checked for consistency in arbitrary,
762 !! possibly rescaled units [A ~> a]
763 real, dimension(G%isd:,G%jsd:,:), intent(in) :: v_comp !< The v-component of the vector to be
764 !! checked for consistency in arbitrary,
765 !! possibly rescaled units [A ~> a]
766 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
767 logical, optional, intent(in) :: scalars !< If true this is a pair of
768 !! scalars that are being checked.
769 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
770 !! arrays to give consistent output [a A-1 ~> 1]
771 ! Local variables
772 logical :: are_scalars
7730 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
774
7750 if (debug_chksums) then
7760 call hchksum(u_comp, mesg//"(u)", G%HI, halos, unscale=unscale)
7770 call hchksum(v_comp, mesg//"(v)", G%HI, halos, unscale=unscale)
778 endif
7790 if (debug_redundant) then
7800 if (are_scalars) then
7810 call check_redundant_T(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
782 else
7830 call check_redundant_T(mesg, u_comp, v_comp, G, unscale=unscale)
784 endif
785 endif
786
7870end subroutine chksum_vec_A3d
788
789!> Do a checksum and redundant point check on a 2d C-grid vector.
7900subroutine chksum_vec_A2d(mesg, u_comp, v_comp, G, halos, scalars, unscale)
791 character(len=*), intent(in) :: mesg !< An identifying message
792 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
793 real, dimension(G%isd:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector to be
794 !! checked for consistency in arbitrary,
795 !! possibly rescaled units [A ~> a]
796 real, dimension(G%isd:,G%jsd:), intent(in) :: v_comp !< The v-component of the vector to be
797 !! checked for consistency in arbitrary,
798 !! possibly rescaled units [A ~> a]
799 integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
800 logical, optional, intent(in) :: scalars !< If true this is a pair of
801 !! scalars that are being checked.
802 real, optional, intent(in) :: unscale !< A factor that undoes the scaling for the
803 !! arrays to give consistent output [a A-1 ~> 1]
804 ! Local variables
805 logical :: are_scalars
8060 are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
807
8080 if (debug_chksums) then
8090 call hchksum(u_comp, mesg//"(u)", G%HI, halos, unscale=unscale)
8100 call hchksum(v_comp, mesg//"(v)", G%HI, halos, unscale=unscale)
811 endif
8120 if (debug_redundant) then
8130 if (are_scalars) then
8140 call check_redundant_T(mesg, u_comp, v_comp, G, direction=To_All+Scalar_Pair, unscale=unscale)
815 else
8160 call check_redundant_T(mesg, u_comp, v_comp, G, unscale=unscale)
817 endif
818 endif
819
8200end subroutine chksum_vec_A2d
821
822!> This function returns the sum over computational domain of all
823!! processors of hThick*stuff, where stuff is a 3-d array at tracer points.
8240function totalStuff(HI, hThick, areaT, stuff, unscale)
825 type(hor_index_type), intent(in) :: HI !< A horizontal index type
826 real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: hThick !< The array of thicknesses to use as weights
827 !! [H ~> m or kg m-2] or [m] or [kg m-2]
828 real, dimension(HI%isd:,HI%jsd:), intent(in) :: areaT !< The array of cell areas [L2 ~> m2] or [m2]
829 real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: stuff !< The array of stuff to be summed in arbitrary
830 !! units [A ~> a] or [a]
831 real, optional, intent(in) :: unscale !< A factor that is used to undo scaling of the array
832 !! and the cell mass or volume before it is summed in
833 !! [a m3 A-1 H-1 L-2 ~> 1] or [a kg A-1 H-1 L-2 ~> 1]
834 real :: totalStuff !< the globally integrated amount of stuff
835 !! [A H L2 ~> a m3 or a kg] or [a m3]
836 ! Local variables
8370 real :: tmp_for_sum(HI%isc:HI%iec, HI%jsc:HI%jec) ! The column integrated amount of stuff in a
838 ! cell [A H L2 ~> a m3 or a kg] or [a m3]
839 integer :: i, j, k, nz
840
8410 nz = size(hThick,3)
8420 tmp_for_sum(:,:) = 0.0
8430 do k=1,nz ; do j=HI%jsc,HI%jec ; do i=HI%isc,HI%iec
8440 tmp_for_sum(i,j) = tmp_for_sum(i,j) + hThick(i,j,k) * stuff(i,j,k) * areaT(i,j)
845 enddo ; enddo ; enddo
8460 totalStuff = reproducing_sum(tmp_for_sum, unscale=unscale)
847
8480end function totalStuff
849
850!> This subroutine display the total thickness, temperature and salinity
851!! as well as the change since the last call.
8520subroutine totalTandS(HI, hThick, areaT, temperature, salinity, mesg, US, H_to_mks)
853 type(hor_index_type), intent(in) :: HI !< A horizontal index type
854 real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: hThick !< The array of thicknesses to use as weights
855 !! [H ~> m or kg m-2] or [m] or [kg m-2]
856 real, dimension(HI%isd:,HI%jsd:), intent(in) :: areaT !< The array of cell areas [L2 ~> m2] or [m2]
857 real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: temperature !< The temperature field to sum [C ~> degC] or [degC]
858 real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: salinity !< The salinity field to sum [S ~> ppt] or [ppt]
859 character(len=*), intent(in) :: mesg !< An identifying message
860 type(unit_scale_type), optional, intent(in) :: US !< A dimensional unit scaling type
861 real, optional, intent(in) :: H_to_MKS !< A constant that translates thickness units to its
862 !! MKS units (m or kg m-2) based on whether the model is
863 !! Boussinesq [m H-1 ~> 1] or not [kg m-2 H-1 ~> 1]
864 ! NOTE: This subroutine uses "save" data which is not thread safe and is purely for
865 ! extreme debugging without a proper debugger.
866 real, save :: totalH = 0. ! The total ocean volume or mass, saved for the next
867 ! call [H L2 ~> m3 or kg] or [m3] or [kg]
868 real, save :: totalT = 0. ! The total volume integrated ocean temperature, saved for the next
869 ! call [C H L2 ~> degC m3 or degC kg] or [degC m3] or [degC kg]
870 real, save :: totalS = 0. ! The total volume integrated ocean salinity, saved for the next
871 ! call [S H L2 ~> ppt m3 or ppt kg] or [ppt m3] or [ppt kg]
872 ! Local variables
873 logical, save :: firstCall = .true.
8740 real :: tmp_for_sum(HI%isc:HI%iec, HI%jsc:HI%jec) ! The volume of each column [H L2 ~> m3 or kg] or [m3] or [kg]
875 real :: thisH, delH ! The total ocean volume and the change from the last call [H L2 ~> m3 or kg] or [m3] or [kg]
876 real :: thisT, delT ! The current total volume integrated temperature and the change from the last
877 ! call [C H L2 ~> degC m3 or degC kg] or [degC m3] or [degC kg]
878 real :: thisS, delS ! The current total volume integrated salinity and the change from the last
879 ! call [S H L2 ~> ppt m3 or ppt kg] or [ppt m3] or [ppt kg]
880 real :: H_unscale ! A constant that translates thickness units to its MKS units (m or kg m-2) based on
881 ! whether the model is Boussinesq [m H-1 ~> 1] or non-Boussinesq [kg m-2 H-1 ~> 1]
882 real :: HL2_unscale ! An overall unscaling factor for cell mass or volume [m3 H-1 L-2 ~> 1] or [kg H-1 L-2 ~> 1]
883 real :: T_unscale ! An overall unscaling factor for cell-integrated temperature [degC m3 C-1 H-1 L-2 ~> 1] or
884 ! [degC kg C-1 H-1 L-2 ~> 1]
885 real :: S_unscale ! An overall unscaling factor for cell-integrated salinity [ppt m3 S-1 H-1 L-2 ~> 1] or
886 ! [ppt kg S-1 H-1 L-2 ~> 1]
887 integer :: i, j, k, nz
888
8890 H_unscale = 1.0 ; if (present(H_to_mks)) H_unscale = H_to_mks
8900 if (present(US)) then
8910 HL2_unscale = US%L_to_m**2 * H_unscale
8920 T_unscale = US%C_to_degC * HL2_unscale ; S_unscale = US%S_to_ppt * HL2_unscale
893 else
8940 HL2_unscale = H_unscale
8950 T_unscale = HL2_unscale ; S_unscale = HL2_unscale
896 endif
897
8980 nz = size(hThick,3)
8990 tmp_for_sum(:,:) = 0.0
9000 do k=1,nz ; do j=HI%jsc,HI%jec ; do i=HI%isc,HI%iec
9010 tmp_for_sum(i,j) = tmp_for_sum(i,j) + hThick(i,j,k) * areaT(i,j)
902 enddo ; enddo ; enddo
9030 thisH = reproducing_sum(tmp_for_sum, unscale=HL2_unscale)
9040 thisT = totalStuff(HI, hThick, areaT, temperature, unscale=T_unscale)
9050 thisS = totalStuff(HI, hThick, areaT, salinity, unscale=S_unscale)
906
9070 if (is_root_pe()) then
9080 if (firstCall) then
9090 totalH = thisH ; totalT = thisT ; totalS = thisS
9100 write(stdout,*) 'Totals H,T,S:', thisH*HL2_unscale, thisT*T_unscale, thisS*S_unscale, ' ', mesg
9110 firstCall = .false.
912 else
9130 delH = thisH - totalH
9140 delT = thisT - totalT
9150 delS = thisS - totalS
9160 totalH = thisH ; totalT = thisT ; totalS = thisS
9170 write(0,*) 'Tot/del H,T,S:', thisH*HL2_unscale, thisT*T_unscale, thisS*S_unscale, &
9180 delH*HL2_unscale, delT*T_unscale, delS*S_unscale, ' ', mesg
919 endif
920 endif
921
9220end subroutine totalTandS
923
924!> Returns false if the column integral of a given quantity is within roundoff
9250logical function check_column_integral(nk, field, known_answer)
926 integer, intent(in) :: nk !< Number of levels in column
927 real, dimension(nk), intent(in) :: field !< Field to be summed [arbitrary]
928 real, optional, intent(in) :: known_answer !< If present is the expected sum [arbitrary],
929 !! If missing, assumed zero
930 ! Local variables
931 real :: u_sum ! The vertical sum of the field [arbitrary]
932 real :: error ! An estimate of the roundoff error in the sum [arbitrary]
933 real :: expected ! The expected vertical sum [arbitrary]
934 integer :: k
935
9360 u_sum = field(1)
9370 error = 0.
938
939 ! Reintegrate and sum roundoff errors
9400 do k=2,nk
9410 u_sum = u_sum + field(k)
9420 error = error + EPSILON(u_sum)*MAX(ABS(u_sum),ABS(field(k)))
943 enddo
944
945 ! Assign expected answer to either the optional input or 0
9460 if (present(known_answer)) then
9470 expected = known_answer
948 else
9490 expected = 0.
950 endif
951
952 ! Compare the column integrals against calculated roundoff error
9530 if (abs(u_sum-expected) > error) then
9540 check_column_integral = .true.
955 else
9560 check_column_integral = .false.
957 endif
958
9590end function check_column_integral
960
961!> Returns false if the column integrals of two given quantities are within roundoff of each other
9620logical function check_column_integrals(nk_1, field_1, nk_2, field_2, missing_value)
963 integer, intent(in) :: nk_1 !< Number of levels in field 1
964 integer, intent(in) :: nk_2 !< Number of levels in field 2
965 real, dimension(nk_1), intent(in) :: field_1 !< First field to be summed [arbitrary]
966 real, dimension(nk_2), intent(in) :: field_2 !< Second field to be summed [arbitrary]
967 real, optional, intent(in) :: missing_value !< If column contains missing values,
968 !! mask them from the sum [arbitrary]
969 ! Local variables
970 real :: u1_sum, u2_sum ! The vertical sums of the two fields [arbitrary]
971 real :: error1, error2 ! Estimates of the roundoff errors in the sums [arbitrary]
972 real :: misval ! The missing value flag, indicating elements that are to be omitted
973 ! from the sums [arbitrary]
974 integer :: k
975
976 ! Assign missing value
9770 if (present(missing_value)) then
9780 misval = missing_value
979 else
9800 misval = 0.
981 endif
982
9830 u1_sum = field_1(1)
9840 error1 = 0.
985
986 ! Reintegrate and sum roundoff errors
9870 do k=2,nk_1
9880 if (field_1(k) /= misval) then
9890 u1_sum = u1_sum + field_1(k)
9900 error1 = error1 + EPSILON(u1_sum)*MAX(ABS(u1_sum),ABS(field_1(k)))
991 endif
992 enddo
993
9940 u2_sum = field_2(1)
9950 error2 = 0.
996
997 ! Reintegrate and sum roundoff errors
9980 do k=2,nk_2
9990 if (field_2(k) /= misval) then
10000 u2_sum = u2_sum + field_2(k)
10010 error2 = error2 + EPSILON(u2_sum)*MAX(ABS(u2_sum),ABS(field_2(k)))
1002 endif
1003 enddo
1004
1005 ! Compare the column integrals against calculated roundoff error
10060 if (abs(u1_sum-u2_sum) > (error1+error2)) then
10070 check_column_integrals = .true.
1008 else
10090 check_column_integrals = .false.
1010 endif
1011
10120end function check_column_integrals
1013
1014end module MOM_debugging