MOM6
MOM_debugging.F90
Go to the documentation of this file.
2 
3 !***********************************************************************
4 !* GNU General Public License *
5 !* This file is a part of MOM. *
6 !* *
7 !* MOM is free software; you can redistribute it and/or modify it and *
8 !* are expected to follow the terms of the GNU General Public License *
9 !* as published by the Free Software Foundation; either version 2 of *
10 !* the License, or (at your option) any later version. *
11 !* *
12 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
13 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
14 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
15 !* License for more details. *
16 !* *
17 !* For the full text of the GNU General Public License, *
18 !* write to: Free Software Foundation, Inc., *
19 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
20 !* or see: http://www.gnu.org/licenses/gpl.html *
21 !***********************************************************************
22 
23 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
24 ! This module contains subroutines that perform various error checking and !
25 ! debugging functions for MOM6. This routine is similar to it counterpart in !
26 ! the SIS2 code, except for the use of the ocean_grid_type and by keeping them !
27 ! separate we retain the ability to set up MOM6 and SIS2 debugging separately. !
28 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
29 
32 use mom_coms, only : pe_here, root_pe, num_pes, sum_across_pes
33 use mom_coms, only : min_across_pes, max_across_pes, reproducing_sum
34 use mom_domains, only : pass_vector, pass_var, pe_here
35 use mom_domains, only : bgrid_ne, agrid, to_all, scalar_pair
36 use mom_error_handler, only : mom_error, fatal, warning, is_root_pe
38 use mom_grid, only : ocean_grid_type
39 use mom_hor_index, only : hor_index_type
40 
41 implicit none ; private
42 
47 
48 ! These interfaces come from MOM_checksums.
49 public :: hchksum, bchksum, qchksum, is_nan, chksum
50 public :: uvchksum
51 
52 interface check_redundant
54 end interface check_redundant
57 end interface check_redundant_c
61 end interface check_redundant_b
65 end interface check_redundant_t
66 
67 interface vec_chksum
68  module procedure chksum_vec_c3d, chksum_vec_c2d
69 end interface vec_chksum
70 interface vec_chksum_c
71  module procedure chksum_vec_c3d, chksum_vec_c2d
72 end interface vec_chksum_c
73 interface vec_chksum_b
74  module procedure chksum_vec_b3d, chksum_vec_b2d
75 end interface vec_chksum_b
76 interface vec_chksum_a
77  module procedure chksum_vec_a3d, chksum_vec_a2d
78 end interface vec_chksum_a
79 
80 integer :: max_redundant_prints = 100
81 integer :: redundant_prints(3) = 0
82 logical :: debug = .false.
83 logical :: debug_chksums = .true.
84 logical :: debug_redundant = .true.
85 
86 contains
87 
88 ! =====================================================================
89 
90 !> MOM_debugging_init initializes the MOM_debugging module, and sets
91 !! the parameterts that control which checks are active for MOM6.
92 subroutine mom_debugging_init(param_file)
93  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
94 ! This include declares and sets the variable "version".
95 #include "version_variable.h"
96  character(len=40) :: mdl = "MOM_debugging" ! This module's name.
97 
98  call log_version(param_file, mdl, version)
99  call get_param(param_file, mdl, "DEBUG", debug, &
100  "If true, write out verbose debugging data.", default=.false.)
101  call get_param(param_file, mdl, "DEBUG_CHKSUMS", debug_chksums, &
102  "If true, checksums are performed on arrays in the \n"//&
103  "various vec_chksum routines.", default=debug)
104  call get_param(param_file, mdl, "DEBUG_REDUNDANT", debug_redundant, &
105  "If true, debug redundant data points during calls to \n"//&
106  "the various vec_chksum routines.", default=debug)
107 
108  call mom_checksums_init(param_file)
109 
110 end subroutine mom_debugging_init
111 
112 subroutine check_redundant_vc3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
113  direction)
114  character(len=*), intent(in) :: mesg
115  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
116  real, dimension(G%IsdB:,G%jsd:,:), intent(in) :: u_comp
117  real, dimension(G%isd:,G%JsdB:,:), intent(in) :: v_comp
118  integer, optional, intent(in) :: is, ie, js, je
119  integer, optional, intent(in) :: direction
120 ! Arguments: u_comp - The u-component of the vector being checked.
121 ! (in) v_comp - The v-component of the vector being checked.
122 ! (in) mesg - A message indicating what is being checked.
123 ! (in) G - The ocean's grid structure.
124 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
125 ! (in/opt) direction - the direction flag to be passed to pass_vector.
126 
127  character(len=24) :: mesg_k
128  integer :: k
129 
130  do k=1,size(u_comp,3)
131  if (k < 10) then ; write(mesg_k,'(" Layer",i2," ")') k
132  elseif (k < 100) then ; write(mesg_k,'(" Layer",i3," ")') k
133  elseif (k < 1000) then ; write(mesg_k,'(" Layer",i4," ")') k
134  else ; write(mesg_k,'(" Layer",i9," ")') k ; endif
135 
136  call check_redundant_vc2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
137  v_comp(:,:,k), g, is, ie, js, je, direction)
138  enddo
139 end subroutine check_redundant_vc3d
140 
141 subroutine check_redundant_vc2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
142  direction)
143  character(len=*), intent(in) :: mesg
144  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
145  real, dimension(G%IsdB:,G%jsd:), intent(in) :: u_comp
146  real, dimension(G%isd:,G%JsdB:), intent(in) :: v_comp
147  integer, optional, intent(in) :: is, ie, js, je
148  integer, optional, intent(in) :: direction
149 ! Arguments: u_comp - The u-component of the vector being checked.
150 ! (in) v_comp - The v-component of the vector being checked.
151 ! (in) mesg - A message indicating what is being checked.
152 ! (in) G - The ocean's grid structure.
153 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
154 ! (in/opt) direction - the direction flag to be passed to pass_vector.
155 
156  real :: u_nonsym(g%isd:g%ied,g%jsd:g%jed)
157  real :: v_nonsym(g%isd:g%ied,g%jsd:g%jed)
158  real :: u_resym(g%isdb:g%iedb,g%jsd:g%jed)
159  real :: v_resym(g%isd:g%ied,g%jsdb:g%jedb)
160  character(len=128) :: mesg2
161 
162  integer :: i, j, is_ch, ie_ch, js_ch, je_ch
163  integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
164  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
165  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
166  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
167 
168  if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
169  ! This only works with symmetric memory, so otherwise return.
170  if ((isd == isdb) .and. (jsd == jsdb)) return
171  endif
172 
173  do i=isd,ied ; do j=jsd,jed
174  u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
175  enddo ; enddo
176 
177  if (.not.associated(g%Domain_aux)) call mom_error(fatal," check_redundant"//&
178  " called with a non-associated auxiliary domain the grid type.")
179  call pass_vector(u_nonsym, v_nonsym, g%Domain_aux, direction)
180 
181  do i=isdb,iedb ; do j=jsd,jed ; u_resym(i,j) = u_comp(i,j) ; enddo ; enddo
182  do i=isd,ied ; do j=jsdb,jedb ; v_resym(i,j) = v_comp(i,j) ; enddo ; enddo
183  do i=isd,ied ; do j=jsd,jed
184  u_resym(i,j) = u_nonsym(i,j) ; v_resym(i,j) = v_nonsym(i,j)
185  enddo ; enddo
186  call pass_vector(u_resym, v_resym, g%Domain, direction)
187 
188  is_ch = isq ; ie_ch = ieq ; js_ch = jsq ; je_ch = jeq
189  if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
190  if (present(js)) js_ch = js ; if (present(js)) je_ch = je
191 
192  do i=is_ch,ie_ch ; do j=js_ch+1,je_ch
193  if (u_resym(i,j) /= u_comp(i,j) .and. &
195  write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
196  & 1pe12.4," at i,j = ",2i4," on pe ",i4)') &
197  u_comp(i,j), u_resym(i,j),u_comp(i,j)-u_resym(i,j),i,j,pe_here()
198  write(0,'(A130)') trim(mesg)//trim(mesg2)
200  endif
201  enddo ; enddo
202  do i=is_ch+1,ie_ch ; do j=js_ch,je_ch
203  if (v_resym(i,j) /= v_comp(i,j) .and. &
205  write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
206  & 1pe12.4," at i,j = ",2i4," x,y = ",2(1pe12.4)" on pe ",i4)') &
207  v_comp(i,j), v_resym(i,j),v_comp(i,j)-v_resym(i,j),i,j, &
208  g%geoLonBu(i,j), g%geoLatBu(i,j), pe_here()
209  write(0,'(A155)') trim(mesg)//trim(mesg2)
211  endif
212  enddo ; enddo
213 
214 end subroutine check_redundant_vc2d
215 
216 subroutine check_redundant_sb3d(mesg, array, G, is, ie, js, je)
217  character(len=*), intent(in) :: mesg
218  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
219  real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: array
220  integer, optional, intent(in) :: is, ie, js, je
221 ! Arguments: array - The array being checked.
222 ! (in) mesg - A message indicating what is being checked.
223 ! (in) G - The ocean's grid structure.
224 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
225 
226  character(len=24) :: mesg_k
227  integer :: k
228 
229  do k=1,size(array,3)
230  if (k < 10) then ; write(mesg_k,'(" Layer",i2," ")') k
231  elseif (k < 100) then ; write(mesg_k,'(" Layer",i3," ")') k
232  elseif (k < 1000) then ; write(mesg_k,'(" Layer",i4," ")') k
233  else ; write(mesg_k,'(" Layer",i9," ")') k ; endif
234 
235  call check_redundant_sb2d(trim(mesg)//trim(mesg_k), array(:,:,k), &
236  g, is, ie, js, je)
237  enddo
238 end subroutine check_redundant_sb3d
239 
240 
241 subroutine check_redundant_sb2d(mesg, array, G, is, ie, js, je)
242  character(len=*), intent(in) :: mesg
243  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
244  real, dimension(G%IsdB:,G%JsdB:), intent(in) :: array
245  integer, optional, intent(in) :: is, ie, js, je
246 ! Arguments: array - The array being checked.
247 ! (in) mesg - A message indicating what is being checked.
248 ! (in) G - The ocean's grid structure.
249 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
250 
251  real :: a_nonsym(g%isd:g%ied,g%jsd:g%jed)
252  real :: a_resym(g%isdb:g%iedb,g%jsdb:g%jedb)
253  character(len=128) :: mesg2
254 
255  integer :: i, j, is_ch, ie_ch, js_ch, je_ch
256  integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
257  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
258  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
259  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
260 
261  if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
262  ! This only works with symmetric memory, so otherwise return.
263  if ((isd == isdb) .and. (jsd == jsdb)) return
264  endif
265 
266  do i=isd,ied ; do j=jsd,jed
267  a_nonsym(i,j) = array(i,j)
268  enddo ; enddo
269 
270  if (.not.associated(g%Domain_aux)) call mom_error(fatal," check_redundant"//&
271  " called with a non-associated auxiliary domain the grid type.")
272  call pass_vector(a_nonsym, a_nonsym, g%Domain_aux, &
273  direction=to_all+scalar_pair, stagger=bgrid_ne)
274 
275  do i=isdb,iedb ; do j=jsdb,jedb ; a_resym(i,j) = array(i,j) ; enddo ; enddo
276  do i=isd,ied ; do j=jsd,jed
277  a_resym(i,j) = a_nonsym(i,j)
278  enddo ; enddo
279  call pass_vector(a_resym, a_resym, g%Domain, direction=to_all+scalar_pair, &
280  stagger=bgrid_ne)
281 
282  is_ch = isq ; ie_ch = ieq ; js_ch = jsq ; je_ch = jeq
283  if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
284  if (present(js)) js_ch = js ; if (present(js)) je_ch = je
285 
286  do i=is_ch,ie_ch ; do j=js_ch,je_ch
287  if (a_resym(i,j) /= array(i,j) .and. &
289  write(mesg2,'(" Redundant points",2(1pe12.4)," differ by ", &
290  & 1pe12.4," at i,j = ",2i4," on pe ",i4)') &
291  array(i,j), a_resym(i,j),array(i,j)-a_resym(i,j),i,j,pe_here()
292  write(0,'(A130)') trim(mesg)//trim(mesg2)
294  endif
295  enddo ; enddo
296 
297 end subroutine check_redundant_sb2d
298 
299 
300 subroutine check_redundant_vb3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
301  direction)
302  character(len=*), intent(in) :: mesg
303  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
304  real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: u_comp
305  real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: v_comp
306  integer, optional, intent(in) :: is, ie, js, je
307  integer, optional, intent(in) :: direction
308 ! Arguments: u_comp - The u-component of the vector being checked.
309 ! (in) v_comp - The v-component of the vector being checked.
310 ! (in) mesg - A message indicating what is being checked.
311 ! (in) G - The ocean's grid structure.
312 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
313 ! (in/opt) direction - the direction flag to be passed to pass_vector.
314 
315  character(len=24) :: mesg_k
316  integer :: k
317 
318  do k=1,size(u_comp,3)
319  if (k < 10) then ; write(mesg_k,'(" Layer",i2," ")') k
320  elseif (k < 100) then ; write(mesg_k,'(" Layer",i3," ")') k
321  elseif (k < 1000) then ; write(mesg_k,'(" Layer",i4," ")') k
322  else ; write(mesg_k,'(" Layer",i9," ")') k ; endif
323 
324  call check_redundant_vb2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
325  v_comp(:,:,k), g, is, ie, js, je, direction)
326  enddo
327 end subroutine check_redundant_vb3d
328 
329 subroutine check_redundant_vb2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
330  direction)
331  character(len=*), intent(in) :: mesg
332  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
333  real, dimension(G%IsdB:,G%JsdB:), intent(in) :: u_comp
334  real, dimension(G%IsdB:,G%JsdB:), intent(in) :: v_comp
335  integer, optional, intent(in) :: is, ie, js, je
336  integer, optional, intent(in) :: direction
337 ! Arguments: u_comp - The u-component of the vector being checked.
338 ! (in) v_comp - The v-component of the vector being checked.
339 ! (in) mesg - A message indicating what is being checked.
340 ! (in) G - The ocean's grid structure.
341 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
342 ! (in/opt) direction - the direction flag to be passed to pass_vector.
343 
344  real :: u_nonsym(g%isd:g%ied,g%jsd:g%jed)
345  real :: v_nonsym(g%isd:g%ied,g%jsd:g%jed)
346  real :: u_resym(g%isdb:g%iedb,g%jsdb:g%jedb)
347  real :: v_resym(g%isdb:g%iedb,g%jsdb:g%jedb)
348  character(len=128) :: mesg2
349 
350  integer :: i, j, is_ch, ie_ch, js_ch, je_ch
351  integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
352  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
353  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
354  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
355 
356  if (.not.(present(is) .or. present(ie) .or. present(js) .or. present(je))) then
357  ! This only works with symmetric memory, so otherwise return.
358  if ((isd == isdb) .and. (jsd == jsdb)) return
359  endif
360 
361  do i=isd,ied ; do j=jsd,jed
362  u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
363  enddo ; enddo
364 
365  if (.not.associated(g%Domain_aux)) call mom_error(fatal," check_redundant"//&
366  " called with a non-associated auxiliary domain the grid type.")
367  call pass_vector(u_nonsym, v_nonsym, g%Domain_aux, direction, stagger=bgrid_ne)
368 
369  do i=isdb,iedb ; do j=jsdb,jedb
370  u_resym(i,j) = u_comp(i,j) ; v_resym(i,j) = v_comp(i,j)
371  enddo ; enddo
372  do i=isd,ied ; do j=jsd,jed
373  u_resym(i,j) = u_nonsym(i,j) ; v_resym(i,j) = v_nonsym(i,j)
374  enddo ; enddo
375  call pass_vector(u_resym, v_resym, g%Domain, direction, stagger=bgrid_ne)
376 
377  is_ch = isq ; ie_ch = ieq ; js_ch = jsq ; je_ch = jeq
378  if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
379  if (present(js)) js_ch = js ; if (present(js)) je_ch = je
380 
381  do i=is_ch,ie_ch ; do j=js_ch,je_ch
382  if (u_resym(i,j) /= u_comp(i,j) .and. &
384  write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
385  & 1pe12.4," at i,j = ",2i4," on pe ",i4)') &
386  u_comp(i,j), u_resym(i,j),u_comp(i,j)-u_resym(i,j),i,j,pe_here()
387  write(0,'(A130)') trim(mesg)//trim(mesg2)
389  endif
390  enddo ; enddo
391  do i=is_ch,ie_ch ; do j=js_ch,je_ch
392  if (v_resym(i,j) /= v_comp(i,j) .and. &
394  write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
395  & 1pe12.4," at i,j = ",2i4," x,y = ",2(1pe12.4)" on pe ",i4)') &
396  v_comp(i,j), v_resym(i,j),v_comp(i,j)-v_resym(i,j),i,j, &
397  g%geoLonBu(i,j), g%geoLatBu(i,j), pe_here()
398  write(0,'(A155)') trim(mesg)//trim(mesg2)
400  endif
401  enddo ; enddo
402 
403 end subroutine check_redundant_vb2d
404 
405 subroutine check_redundant_st3d(mesg, array, G, is, ie, js, je)
406  character(len=*), intent(in) :: mesg
407  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
408  real, dimension(G%isd:,G%jsd:,:), intent(in) :: array
409  integer, optional, intent(in) :: is, ie, js, je
410 ! Arguments: array - The array being checked.
411 ! (in) mesg - A message indicating what is being checked.
412 ! (in) G - The ocean's grid structure.
413 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
414 
415  character(len=24) :: mesg_k
416  integer :: k
417 
418  do k=1,size(array,3)
419  if (k < 10) then ; write(mesg_k,'(" Layer",i2," ")') k
420  elseif (k < 100) then ; write(mesg_k,'(" Layer",i3," ")') k
421  elseif (k < 1000) then ; write(mesg_k,'(" Layer",i4," ")') k
422  else ; write(mesg_k,'(" Layer",i9," ")') k ; endif
423 
424  call check_redundant_st2d(trim(mesg)//trim(mesg_k), array(:,:,k), &
425  g, is, ie, js, je)
426  enddo
427 end subroutine check_redundant_st3d
428 
429 
430 subroutine check_redundant_st2d(mesg, array, G, is, ie, js, je)
431  character(len=*), intent(in) :: mesg
432  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
433  real, dimension(G%isd:,G%jsd:), intent(in) :: array
434  integer, optional, intent(in) :: is, ie, js, je
435 ! Arguments: array - The array being checked.
436 ! (in) mesg - A message indicating what is being checked.
437 ! (in) G - The ocean's grid structure.
438 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
439 
440  real :: a_nonsym(g%isd:g%ied,g%jsd:g%jed)
441  character(len=128) :: mesg2
442 
443  integer :: i, j, is_ch, ie_ch, js_ch, je_ch
444  integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed
445  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
446 
447  is_ch = g%isc ; ie_ch = g%iec ; js_ch = g%jsc ; je_ch = g%jec
448  if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
449  if (present(js)) js_ch = js ; if (present(js)) je_ch = je
450 
451  ! This only works on points outside of the standard computational domain.
452  if ((is_ch == g%isc) .and. (ie_ch == g%iec) .and. &
453  (js_ch == g%jsc) .and. (je_ch == g%jec)) return
454 
455  do i=isd,ied ; do j=jsd,jed
456  a_nonsym(i,j) = array(i,j)
457  enddo ; enddo
458 
459  call pass_var(a_nonsym, g%Domain)
460 
461  do i=is_ch,ie_ch ; do j=js_ch,je_ch
462  if (a_nonsym(i,j) /= array(i,j) .and. &
464  write(mesg2,'(" Redundant points",2(1pe12.4)," differ by ", &
465  & 1pe12.4," at i,j = ",2i4," on pe ",i4)') &
466  array(i,j), a_nonsym(i,j),array(i,j)-a_nonsym(i,j),i,j,pe_here()
467  write(0,'(A130)') trim(mesg)//trim(mesg2)
469  endif
470  enddo ; enddo
471 
472 end subroutine check_redundant_st2d
473 
474 
475 subroutine check_redundant_vt3d(mesg, u_comp, v_comp, G, is, ie, js, je, &
476  direction)
477  character(len=*), intent(in) :: mesg
478  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
479  real, dimension(G%isd:,G%jsd:,:), intent(in) :: u_comp
480  real, dimension(G%isd:,G%jsd:,:), intent(in) :: v_comp
481  integer, optional, intent(in) :: is, ie, js, je
482  integer, optional, intent(in) :: direction
483 ! Arguments: u_comp - The u-component of the vector being checked.
484 ! (in) v_comp - The v-component of the vector being checked.
485 ! (in) mesg - A message indicating what is being checked.
486 ! (in) G - The ocean's grid structure.
487 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
488 ! (in/opt) direction - the direction flag to be passed to pass_vector.
489 
490  character(len=24) :: mesg_k
491  integer :: k
492 
493  do k=1,size(u_comp,3)
494  if (k < 10) then ; write(mesg_k,'(" Layer",i2," ")') k
495  elseif (k < 100) then ; write(mesg_k,'(" Layer",i3," ")') k
496  elseif (k < 1000) then ; write(mesg_k,'(" Layer",i4," ")') k
497  else ; write(mesg_k,'(" Layer",i9," ")') k ; endif
498 
499  call check_redundant_vt2d(trim(mesg)//trim(mesg_k), u_comp(:,:,k), &
500  v_comp(:,:,k), g, is, ie, js, je, direction)
501  enddo
502 end subroutine check_redundant_vt3d
503 
504 subroutine check_redundant_vt2d(mesg, u_comp, v_comp, G, is, ie, js, je, &
505  direction)
506  character(len=*), intent(in) :: mesg
507  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
508  real, dimension(G%isd:,G%jsd:), intent(in) :: u_comp
509  real, dimension(G%isd:,G%jsd:), intent(in) :: v_comp
510  integer, optional, intent(in) :: is, ie, js, je
511  integer, optional, intent(in) :: direction
512 ! Arguments: u_comp - The u-component of the vector being checked.
513 ! (in) v_comp - The v-component of the vector being checked.
514 ! (in) mesg - A message indicating what is being checked.
515 ! (in) G - The ocean's grid structure.
516 ! (in/opt) is, ie, js, je - the i- and j- range of indices to check.
517 ! (in/opt) direction - the direction flag to be passed to pass_vector.
518 
519  real :: u_nonsym(g%isd:g%ied,g%jsd:g%jed)
520  real :: v_nonsym(g%isd:g%ied,g%jsd:g%jed)
521  character(len=128) :: mesg2
522 
523  integer :: i, j, is_ch, ie_ch, js_ch, je_ch
524  integer :: Isq, Ieq, Jsq, Jeq, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
525  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
526  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
527  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
528 
529  is_ch = g%isc ; ie_ch = g%iec ; js_ch = g%jsc ; je_ch = g%jec
530  if (present(is)) is_ch = is ; if (present(ie)) ie_ch = ie
531  if (present(js)) js_ch = js ; if (present(js)) je_ch = je
532 
533  ! This only works on points outside of the standard computational domain.
534  if ((is_ch == g%isc) .and. (ie_ch == g%iec) .and. &
535  (js_ch == g%jsc) .and. (je_ch == g%jec)) return
536 
537  do i=isd,ied ; do j=jsd,jed
538  u_nonsym(i,j) = u_comp(i,j) ; v_nonsym(i,j) = v_comp(i,j)
539  enddo ; enddo
540 
541  call pass_vector(u_nonsym, v_nonsym, g%Domain, direction, stagger=agrid)
542 
543  do i=is_ch,ie_ch ; do j=js_ch+1,je_ch
544  if (u_nonsym(i,j) /= u_comp(i,j) .and. &
546  write(mesg2,'(" redundant u-components",2(1pe12.4)," differ by ", &
547  & 1pe12.4," at i,j = ",2i4," on pe ",i4)') &
548  u_comp(i,j), u_nonsym(i,j),u_comp(i,j)-u_nonsym(i,j),i,j,pe_here()
549  write(0,'(A130)') trim(mesg)//trim(mesg2)
551  endif
552  enddo ; enddo
553  do i=is_ch+1,ie_ch ; do j=js_ch,je_ch
554  if (v_nonsym(i,j) /= v_comp(i,j) .and. &
556  write(mesg2,'(" redundant v-comps",2(1pe12.4)," differ by ", &
557  & 1pe12.4," at i,j = ",2i4," x,y = ",2(1pe12.4)" on pe ",i4)') &
558  v_comp(i,j), v_nonsym(i,j),v_comp(i,j)-v_nonsym(i,j),i,j, &
559  g%geoLonBu(i,j), g%geoLatBu(i,j), pe_here()
560  write(0,'(A155)') trim(mesg)//trim(mesg2)
562  endif
563  enddo ; enddo
564 
565 end subroutine check_redundant_vt2d
566 
567 ! =====================================================================
568 
569 ! This function does a checksum and redundant point check on a 3d C-grid vector.
570 subroutine chksum_vec_c3d(mesg, u_comp, v_comp, G, halos, scalars)
571  character(len=*), intent(in) :: mesg !< An identifying message
572  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
573  real, dimension(G%IsdB:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector
574  real, dimension(G%isd:,G%JsdB:,:), intent(in) :: v_comp !< The v-component of the vector
575  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
576  logical, optional, intent(in) :: scalars !< If true this is a pair of
577  !! scalars that are being checked.
578 
579  logical :: are_scalars
580  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
581 
582  if (debug_chksums) then
583  call uvchksum(mesg, u_comp, v_comp, g%HI, halos)
584  endif
585  if (debug_redundant) then
586  if (are_scalars) then
587  call check_redundant_c(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
588  else
589  call check_redundant_c(mesg, u_comp, v_comp, g)
590  endif
591  endif
592 
593 end subroutine chksum_vec_c3d
594 
595 ! This function does a checksum and redundant point check on a 2d C-grid vector.
596 subroutine chksum_vec_c2d(mesg, u_comp, v_comp, G, halos, scalars)
597  character(len=*), intent(in) :: mesg !< An identifying message
598  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
599  real, dimension(G%IsdB:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector
600  real, dimension(G%isd:,G%JsdB:), intent(in) :: v_comp !< The v-component of the vector
601  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
602  logical, optional, intent(in) :: scalars !< If true this is a pair of
603  !! scalars that are being checked.
604 
605  logical :: are_scalars
606  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
607 
608  if (debug_chksums) then
609  call uvchksum(mesg, u_comp, v_comp, g%HI, halos)
610  endif
611  if (debug_redundant) then
612  if (are_scalars) then
613  call check_redundant_c(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
614  else
615  call check_redundant_c(mesg, u_comp, v_comp, g)
616  endif
617  endif
618 
619 end subroutine chksum_vec_c2d
620 
621 ! This function does a checksum and redundant point check on a 3d B-grid vector.
622 subroutine chksum_vec_b3d(mesg, u_comp, v_comp, G, halos, scalars)
623  character(len=*), intent(in) :: mesg !< An identifying message
624  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
625  real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: u_comp !< The u-component of the vector
626  real, dimension(G%IsdB:,G%JsdB:,:), intent(in) :: v_comp !< The v-component of the vector
627  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
628  logical, optional, intent(in) :: scalars !< If true this is a pair of
629  !! scalars that are being checked.
630 
631  logical :: are_scalars
632  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
633 
634  if (debug_chksums) then
635  call bchksum(u_comp, mesg//"(u)", g%HI, halos)
636  call bchksum(v_comp, mesg//"(v)", g%HI, halos)
637  endif
638  if (debug_redundant) then
639  if (are_scalars) then
640  call check_redundant_b(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
641  else
642  call check_redundant_b(mesg, u_comp, v_comp, g)
643  endif
644  endif
645 
646 end subroutine chksum_vec_b3d
647 
648 ! This function does a checksum and redundant point check on a 2d B-grid vector.
649 subroutine chksum_vec_b2d(mesg, u_comp, v_comp, G, halos, scalars, symmetric)
650  character(len=*), intent(in) :: mesg !< An identifying message
651  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
652  real, dimension(G%IsdB:,G%JsdB:), intent(in) :: u_comp !< The u-component of the vector
653  real, dimension(G%IsdB:,G%JsdB:), intent(in) :: v_comp !< The v-component of the vector
654  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
655  logical, optional, intent(in) :: scalars !< If true this is a pair of
656  !! scalars that are being checked.
657  logical, optional, intent(in) :: symmetric !< If true, do the checksums on the
658  !! full symmetric computational domain.
659 
660  logical :: are_scalars
661  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
662 
663  if (debug_chksums) then
664  call bchksum(u_comp, mesg//"(u)", g%HI, halos, symmetric=symmetric)
665  call bchksum(v_comp, mesg//"(v)", g%HI, halos, symmetric=symmetric)
666  endif
667  if (debug_redundant) then
668  if (are_scalars) then
669  call check_redundant_b(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
670  else
671  call check_redundant_b(mesg, u_comp, v_comp, g)
672  endif
673  endif
674 
675 end subroutine chksum_vec_b2d
676 
677 ! This function does a checksum and redundant point check on a 3d C-grid vector.
678 subroutine chksum_vec_a3d(mesg, u_comp, v_comp, G, halos, scalars)
679  character(len=*), intent(in) :: mesg !< An identifying message
680  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
681  real, dimension(G%isd:,G%jsd:,:), intent(in) :: u_comp !< The u-component of the vector
682  real, dimension(G%isd:,G%jsd:,:), intent(in) :: v_comp !< The v-component of the vector
683  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
684  logical, optional, intent(in) :: scalars !< If true this is a pair of
685  !! scalars that are being checked.
686 
687  logical :: are_scalars
688  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
689 
690  if (debug_chksums) then
691  call hchksum(u_comp, mesg//"(u)", g%HI, halos)
692  call hchksum(v_comp, mesg//"(v)", g%HI, halos)
693  endif
694  if (debug_redundant) then
695  if (are_scalars) then
696  call check_redundant_t(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
697  else
698  call check_redundant_t(mesg, u_comp, v_comp, g)
699  endif
700  endif
701 
702 end subroutine chksum_vec_a3d
703 
704 
705 ! This function does a checksum and redundant point check on a 2d C-grid vector.
706 subroutine chksum_vec_a2d(mesg, u_comp, v_comp, G, halos, scalars)
707  character(len=*), intent(in) :: mesg !< An identifying message
708  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
709  real, dimension(G%isd:,G%jsd:), intent(in) :: u_comp !< The u-component of the vector
710  real, dimension(G%isd:,G%jsd:), intent(in) :: v_comp !< The v-component of the vector
711  integer, optional, intent(in) :: halos !< The width of halos to check (default 0)
712  logical, optional, intent(in) :: scalars !< If true this is a pair of
713  !! scalars that are being checked.
714 
715  logical :: are_scalars
716  are_scalars = .false. ; if (present(scalars)) are_scalars = scalars
717 
718  if (debug_chksums) then
719  call hchksum(u_comp, mesg//"(u)", g%HI, halos)
720  call hchksum(v_comp, mesg//"(v)", g%HI, halos)
721  endif
722  if (debug_redundant) then
723  if (are_scalars) then
724  call check_redundant_t(mesg, u_comp, v_comp, g, direction=to_all+scalar_pair)
725  else
726  call check_redundant_t(mesg, u_comp, v_comp, g)
727  endif
728  endif
729 
730 end subroutine chksum_vec_a2d
731 
732 
733 ! =====================================================================
734 
735 !> This function returns the sum over computational domain of all
736 !! processors of hThick*stuff, where stuff is a 3-d array at tracer points.
737 function totalstuff(HI, hThick, areaT, stuff)
738  type(hor_index_type), intent(in) :: HI !< A horizontal index type
739  real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: hThick !< The array of thicknesses to use as weights
740  real, dimension(HI%isd:,HI%jsd:), intent(in) :: areaT !< The array of cell areas in m2
741  real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: stuff !< The array of stuff to be summed
742  real :: totalStuff
743  integer :: i, j, k, nz
744 
745  nz = size(hthick,3)
746  totalstuff = 0.
747  do k = 1, nz ; do j = hi%jsc, hi%jec ; do i = hi%isc, hi%iec
748  totalstuff = totalstuff + hthick(i,j,k) * stuff(i,j,k) * areat(i,j)
749  enddo ; enddo ; enddo
750  call sum_across_pes(totalstuff)
751 
752 end function totalstuff
753 
754 ! =====================================================================
755 
756 !> This subroutine display the total thickness, temperature and salinity
757 !! as well as the change since the last call.
758 !! NOTE: This subroutine uses "save" data which is not thread safe and is purely
759 !! for extreme debugging without a proper debugger.
760 subroutine totaltands(HI, hThick, areaT, temperature, salinity, mesg)
761  type(hor_index_type), intent(in) :: HI !< A horizontal index type
762  real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: hThick !< The array of thicknesses to use as weights
763  real, dimension(HI%isd:,HI%jsd:), intent(in) :: areaT !< The array of cell areas in m2
764  real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: temperature !< The temperature field to sum
765  real, dimension(HI%isd:,HI%jsd:,:), intent(in) :: salinity !< The salinity field to sum
766  character(len=*), intent(in) :: mesg !< An identifying message
767 
768  ! NOTE: This subroutine uses "save" data which is not thread safe and is purely for
769  ! extreme debugging without a proper debugger.
770  real, save :: totalH = 0., totalt = 0., totals = 0.
771 
772  logical, save :: firstCall = .true.
773  real :: thisH, thisT, thisS, delH, delT, delS
774  integer :: i, j, k, nz
775 
776  nz = size(hthick,3)
777  thish = 0.
778  do k = 1, nz ; do j = hi%jsc, hi%jec ; do i = hi%isc, hi%iec
779  thish = thish + hthick(i,j,k) * areat(i,j)
780  enddo ; enddo ; enddo
781  call sum_across_pes(thish)
782  thist = totalstuff(hi, hthick, areat, temperature)
783  thiss = totalstuff(hi, hthick, areat, salinity)
784 
785  if (is_root_pe()) then
786  if (firstcall) then
787  totalh = thish ; totalt = thist ; totals = thiss
788  write(0,*) 'Totals H,T,S:',thish,thist,thiss,' ',mesg
789  firstcall = .false.
790  else
791  delh = thish - totalh
792  delt = thist - totalt
793  dels = thiss - totals
794  totalh = thish ; totalt = thist ; totals = thiss
795  write(0,*) 'Tot/del H,T,S:',thish,thist,thiss,delh,delt,dels,' ',mesg
796  endif
797  endif
798 
799 end subroutine totaltands
800 
801 !> Returns false if the column integral of a given quantity is within roundoff
802 logical function check_column_integral(nk, field, known_answer)
803  integer, intent(in) :: nk !< Number of levels in column
804  real, dimension(nk), intent(in) :: field !< Field to be summed
805  real, optional, intent(in) :: known_answer !< If present is the expected sum,
806  !! If missing, assumed zero
807  ! Local variables
808  real :: u_sum, error, expected
809  integer :: k
810 
811  u_sum = field(1)
812  error = 0.
813 
814  ! Reintegrate and sum roundoff errors
815  do k=2,nk
816  u_sum = u_sum + field(k)
817  error = error + epsilon(u_sum)*max(abs(u_sum),abs(field(k)))
818  enddo
819 
820  ! Assign expected answer to either the optional input or 0
821  if (present(known_answer)) then
822  expected = known_answer
823  else
824  expected = 0.
825  endif
826 
827  ! Compare the column integrals against calculated roundoff error
828  if (abs(u_sum-expected) > error) then
829  check_column_integral = .true.
830  else
831  check_column_integral = .false.
832  endif
833 
834 end function check_column_integral
835 
836 !> Returns false if the column integrals of two given quantities are within roundoff of each other
837 logical function check_column_integrals(nk_1, field_1, nk_2, field_2, missing_value)
838  integer, intent(in) :: nk_1 !< Number of levels in field 1
839  integer, intent(in) :: nk_2 !< Number of levels in field 2
840  real, dimension(nk_1), intent(in) :: field_1 !< First field to be summed
841  real, dimension(nk_2), intent(in) :: field_2 !< Second field to be summed
842  real, optional, intent(in) :: missing_value !< If column contains missing values,
843  !! mask them from the sum
844 
845 
846  ! Local variables
847  real :: u1_sum, error1, u2_sum, error2, misval
848  integer :: k
849 
850  ! Assign missing value
851  if (present(missing_value)) then
852  misval = missing_value
853  else
854  misval = 0.
855  endif
856 
857  u1_sum = field_1(1)
858  error1 = 0.
859 
860  ! Reintegrate and sum roundoff errors
861  do k=2,nk_1
862  if (field_1(k)/=misval) then
863  u1_sum = u1_sum + field_1(k)
864  error1 = error1 + epsilon(u1_sum)*max(abs(u1_sum),abs(field_1(k)))
865  endif
866  enddo
867 
868  u2_sum = field_2(1)
869  error2 = 0.
870 
871  ! Reintegrate and sum roundoff errors
872  do k=2,nk_2
873  if (field_2(k)/=misval) then
874  u2_sum = u2_sum + field_2(k)
875  error2 = error2 + epsilon(u2_sum)*max(abs(u2_sum),abs(field_2(k)))
876  endif
877  enddo
878 
879  ! Compare the column integrals against calculated roundoff error
880  if (abs(u1_sum-u2_sum) > (error1+error2)) then
881  check_column_integrals = .true.
882  else
883  check_column_integrals = .false.
884  endif
885 
886 end function check_column_integrals
887 
888 end module mom_debugging
subroutine chksum_vec_b3d(mesg, u_comp, v_comp, G, halos, scalars)
subroutine check_redundant_sb3d(mesg, array, G, is, ie, js, je)
subroutine chksum_vec_b2d(mesg, u_comp, v_comp, G, halos, scalars, symmetric)
real function, public totalstuff(HI, hThick, areaT, stuff)
This function returns the sum over computational domain of all processors of hThick*stuff, where stuff is a 3-d array at tracer points.
logical function, public check_column_integrals(nk_1, field_1, nk_2, field_2, missing_value)
Returns false if the column integrals of two given quantities are within roundoff of each other...
subroutine, public totaltands(HI, hThick, areaT, temperature, salinity, mesg)
This subroutine display the total thickness, temperature and salinity as well as the change since the...
subroutine check_redundant_vb3d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)
integer, parameter, public to_all
subroutine check_redundant_st2d(mesg, array, G, is, ie, js, je)
subroutine check_redundant_vc2d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
Provides the ocean grid type.
Definition: MOM_grid.F90:2
logical debug_chksums
integer max_redundant_prints
subroutine chksum_vec_c2d(mesg, u_comp, v_comp, G, halos, scalars)
Defines the horizontal index type (hor_index_type) used for providing index ranges.
Container for horizontal index ranges for data, computational and global domains. ...
logical debug_redundant
logical function, public check_column_integral(nk, field, known_answer)
Returns false if the column integral of a given quantity is within roundoff.
subroutine chksum_vec_a3d(mesg, u_comp, v_comp, G, halos, scalars)
subroutine check_redundant_vt3d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)
subroutine check_redundant_vb2d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)
subroutine check_redundant_st3d(mesg, array, G, is, ie, js, je)
logical function, public is_root_pe()
subroutine check_redundant_sb2d(mesg, array, G, is, ie, js, je)
subroutine, public mom_checksums_init(param_file)
MOM_checksums_init initializes the MOM_checksums module. As it happens, the only thing that it does i...
subroutine chksum_vec_a2d(mesg, u_comp, v_comp, G, halos, scalars)
subroutine check_redundant_vc3d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)
subroutine, public mom_debugging_init(param_file)
MOM_debugging_init initializes the MOM_debugging module, and sets the parameterts that control which ...
integer, dimension(3) redundant_prints
subroutine, public mom_error(level, message, all_print)
subroutine chksum_vec_c3d(mesg, u_comp, v_comp, G, halos, scalars)
subroutine check_redundant_vt2d(mesg, u_comp, v_comp, G, is, ie, js, je, direction)