MOM6
MOM_diagnostics.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 !* *
25 !* By Robert Hallberg, February 2001 *
26 !* *
27 !* This subroutine calculates any requested diagnostic quantities *
28 !* that are not calculated in the various subroutines. Diagnostic *
29 !* quantities are requested by allocating them memory. *
30 !* *
31 !* Macros written all in capital letters are defined in MOM_memory.h. *
32 !* *
33 !* A small fragment of the grid is shown below: *
34 !* *
35 !* j+1 x ^ x ^ x At x: q, CoriolisBu *
36 !* j+1 > o > o > At ^: v *
37 !* j x ^ x ^ x At >: u *
38 !* j > o > o > At o: h, bathyT *
39 !* j-1 x ^ x ^ x *
40 !* i-1 i i+1 At x & ^: *
41 !* i i+1 At > & o: *
42 !* *
43 !* The boundaries always run through q grid points (x). *
44 !* *
45 !********+*********+*********+*********+*********+*********+*********+**
46 
47 use mom_coms, only : reproducing_sum
50 use mom_diag_mediator, only : diag_ctrl, time_type, safe_alloc_ptr
51 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
52 use mom_domains, only : to_north, to_east
54 use mom_error_handler, only : mom_error, fatal, warning
56 use mom_forcing_type, only : forcing
57 use mom_grid, only : ocean_grid_type
64 
65 implicit none ; private
66 
67 #include <MOM_memory.h>
68 
71 public find_eta
74 
75 
76 type, public :: diagnostics_cs ; private
77  real :: mono_n2_column_fraction = 0. !< The lower fraction of water column over which N2 is limited as
78  !! monotonic for the purposes of calculating the equivalent barotropic wave speed.
79  real :: mono_n2_depth = -1. !< The depth below which N2 is limited as monotonic for the purposes of
80  !! calculating the equivalent barotropic wave speed. (m)
81 
82  type(diag_ctrl), pointer :: diag ! structure to regulate diagnostics timing
83 
84  ! following arrays store diagnostics calculated here and unavailable outside.
85 
86  ! following fields have nz+1 levels.
87  real, pointer, dimension(:,:,:) :: &
88  e => null(), & ! interface height (metre)
89  e_d => null() ! interface height above bottom (metre)
90 
91  ! following fields have nz layers.
92  real, pointer, dimension(:,:,:) :: &
93  du_dt => null(), & ! net i-acceleration in m/s2
94  dv_dt => null(), & ! net j-acceleration in m/s2
95  dh_dt => null(), & ! thickness rate of change in (m/s) or kg/(m2*s)
96 
97  h_rlay => null(), & ! layer thicknesses in layered potential density
98  ! coordinates, in m (Bouss) or kg/m2 (non-Bouss)
99  uh_rlay => null(), & ! zonal and meridional transports in layered
100  vh_rlay => null(), & ! potential rho coordinates: m3/s(Bouss) kg/s(non-Bouss)
101  uhgm_rlay => null(), & ! zonal and meridional Gent-McWilliams transports in layered
102  vhgm_rlay => null(), & ! potential density coordinates, m3/s (Bouss) kg/s(non-Bouss)
103  p_ebt => null() ! Equivalent barotropic modal structure
104 
105  ! following fields are 2-D.
106  real, pointer, dimension(:,:) :: &
107  cg1 => null(), & ! first baroclinic gravity wave speed, in m s-1
108  rd1 => null(), & ! first baroclinic deformation radius, in m
109  cfl_cg1 => null(), & ! CFL for first baroclinic gravity wave speed, nondim
110  cfl_cg1_x => null(), & ! i-component of CFL for first baroclinic gravity wave speed, nondim
111  cfl_cg1_y => null() ! j-component of CFL for first baroclinic gravity wave speed, nondim
112 
113  ! arrays to hold diagnostics in the layer-integrated energy budget.
114  ! all except KE have units of m3 s-3 (when Boussinesq).
115  real, pointer, dimension(:,:,:) :: &
116  ke => null(), & ! KE per unit mass, in m2 s-2
117  dke_dt => null(), & ! time derivative of the layer KE
118  pe_to_ke => null(), & ! potential energy to KE term
119  ke_coradv => null(), & ! KE source from the combined Coriolis and
120  ! advection terms. The Coriolis source should be
121  ! zero, but is not due to truncation errors. There
122  ! should be near-cancellation of the global integral
123  ! of this spurious Coriolis source.
124  ke_adv => null(),& ! KE source from along-layer advection
125  ke_visc => null(),& ! KE source from vertical viscosity
126  ke_horvisc => null(),& ! KE source from horizontal viscosity
127  ke_dia => null(),& ! KE source from diapycnal diffusion
128  diag_tmp3d => null() ! 3D re-usable arrays for diagnostics
129 
130  ! diagnostic IDs
131  integer :: id_e = -1, id_e_d = -1
132  integer :: id_du_dt = -1, id_dv_dt = -1
133  integer :: id_col_ht = -1, id_dh_dt = -1
134  integer :: id_ke = -1, id_dkedt = -1
135  integer :: id_pe_to_ke = -1, id_ke_coradv = -1
136  integer :: id_ke_adv = -1, id_ke_visc = -1
137  integer :: id_ke_horvisc = -1, id_ke_dia = -1
138  integer :: id_uh_rlay = -1, id_vh_rlay = -1
139  integer :: id_uhgm_rlay = -1, id_vhgm_rlay = -1
140  integer :: id_h_rlay = -1, id_rd1 = -1
141  integer :: id_rml = -1, id_rcv = -1
142  integer :: id_cg1 = -1, id_cfl_cg1 = -1
143  integer :: id_cfl_cg1_x = -1, id_cfl_cg1_y = -1
144  integer :: id_cg_ebt = -1, id_rd_ebt = -1
145  integer :: id_p_ebt = -1
146  integer :: id_temp_int = -1, id_salt_int = -1
147  integer :: id_mass_wt = -1, id_col_mass = -1
148  integer :: id_masscello = -1, id_masso = -1
149  integer :: id_thetaoga = -1, id_soga = -1
150  integer :: id_sosga = -1, id_tosga = -1
151  integer :: id_temp_layer_ave = -1, id_salt_layer_ave = -1
152  integer :: id_pbo = -1
153  integer :: id_thkcello = -1, id_rhoinsitu = -1
154  integer :: id_rhopot0 = -1, id_rhopot2 = -1
155 
156  type(wave_speed_cs), pointer :: wave_speed_csp => null()
157 
158  ! pointers used in calculation of time derivatives
159  type(p3d) :: var_ptr(max_fields_)
160  type(p3d) :: deriv(max_fields_)
161  type(p3d) :: prev_val(max_fields_)
162  integer :: nlay(max_fields_)
163  integer :: num_time_deriv = 0
164 
165  ! for group halo pass
166  type(group_pass_type) :: pass_ke_uv
167 
168 end type diagnostics_cs
169 
170 contains
171 !> Diagnostics not more naturally calculated elsewhere are computed here.
172 subroutine calculate_diagnostic_fields(u, v, h, uh, vh, tv, ADp, CDp, fluxes, &
173  dt, G, GV, CS, eta_bt)
174  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
175  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid
176  !! structure.
177  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1.
178  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity,
179  !! in m s-1.
180  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
181  !! (usually m or kg m-2).
182  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: uh !< Transport through zonal faces
183  !! = u*h*dy, m3/s(Bouss)
184  !! kg/s(non-Bouss).
185  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: vh !< transport through meridional
186  !! faces = v*h*dx, m3/s(Bouss)
187  !! kg/s(non-Bouss).
188  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to
189  !! various thermodynamic
190  !! variables.
191  type(accel_diag_ptrs), intent(in) :: ADp !< structure with pointers to
192  !! accelerations in momentum
193  !! equation.
194  type(cont_diag_ptrs), intent(in) :: CDp !< structure with pointers to
195  !! terms in continuity equation.
196  type(forcing), intent(in) :: fluxes !< A structure containing the
197  !! surface fluxes.
198  real, intent(in) :: dt !< The time difference in s since
199  !! the last call to this
200  !! subroutine.
201  type(diagnostics_cs), intent(inout) :: CS !< Control structure returned by
202  !! a previous call to
203  !! diagnostics_init.
204  real, dimension(SZI_(G),SZJ_(G)), optional, intent(in) :: eta_bt !< An optional barotropic
205  !! variable that gives the "correct" free surface height (Boussinesq) or total water column
206  !! mass per unit area (non-Boussinesq). This is used to dilate the layer thicknesses when
207  !! calculating interface heights, in m or kg m-2.
208 
209 ! Diagnostics not more naturally calculated elsewhere are computed here.
210 
211 ! Arguments:
212 ! (in) u - zonal velocity component (m/s).
213 ! (in) v - meridional velocity component (m/s).
214 ! (in) h - layer thickness, meter(Bouss) kg/m^2(non-Bouss).
215 ! (in) uh - transport through zonal faces = u*h*dy, m3/s(Bouss) kg/s(non-Bouss).
216 ! (in) vh - transport through meridional faces = v*h*dx, m3/s(Bouss) kg/s(non-Bouss).
217 ! (in) tv - structure pointing to various thermodynamic variables.
218 ! (in) ADp - structure with pointers to accelerations in momentum equation.
219 ! (in) CDp - structure with pointers to terms in continuity equation.
220 ! (in) dt - time difference in s since the last call to this subroutine.
221 ! (in) G - ocean grid structure.
222 ! (in) GV - The ocean's vertical grid structure.
223 ! (in) CS - control structure returned by a previous call to diagnostics_init.
224 ! (in,opt) eta_bt - An optional barotropic variable that gives the "correct"
225 ! free surface height (Boussinesq) or total water column
226 ! mass per unit area (non-Boussinesq). This is used to
227 ! dilate the layer thicknesses when calculating interface
228 ! heights, in m or kg m-2.
229 
230  integer i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb
231 
232  ! coordinate variable potential density, in kg m-3.
233  real :: Rcv(szi_(g),szj_(g),szk_(g))
234 
235  ! tmp array for surface properties
236  real :: surface_field(szi_(g),szj_(g))
237  real :: pressure_1d(szi_(g)) ! Temporary array for pressure when calling EOS
238  real :: wt, wt_p
239 
240  ! squared Coriolis parameter at to h-points (1/s2)
241  real :: f2_h
242 
243  ! magnitude of the gradient of f (1/(m*s))
244  real :: mag_beta
245 
246  ! frequency squared used to avoid division by 0 (1/s2)
247  ! value is roughly (pi / (the age of the universe) )^2.
248  real, parameter :: absurdly_small_freq2 = 1e-34
249 
250  integer :: k_list
251 
252  real, dimension(SZK_(G)) :: temp_layer_ave, salt_layer_ave
253  real :: thetaoga, soga, masso, tosga, sosga
254 
255  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
256  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
257  nz = g%ke ; nkmb = gv%nk_rho_varies
258 
259  ! smg: is the following robust to ALE? It seems a bit opaque.
260  ! If the model is NOT in isopycnal mode then nkmb=0. But we need all the
261  ! following diagnostics to treat all layers as variable density, so we set
262  ! nkmb = nz, on the expectation that loops nkmb+1,nz will not iterate.
263  ! This behavior is ANSI F77 but some compiler options can force at least
264  ! one iteration that would break the following one-line workaround!
265  if (nkmb==0) nkmb = nz
266 
267  if (loc(cs)==0) call mom_error(fatal, &
268  "calculate_diagnostic_fields: Module must be initialized before used.")
269 
270  call calculate_derivs(dt, g, cs)
271 
272  if (ASSOCIATED(cs%e)) then
273  call find_eta(h, tv, gv%g_Earth, g, gv, cs%e, eta_bt)
274  if (cs%id_e > 0) call post_data(cs%id_e, cs%e, cs%diag)
275  endif
276 
277  if (ASSOCIATED(cs%e_D)) then
278  if (ASSOCIATED(cs%e)) then
279  do k=1,nz+1 ; do j=js,je ; do i=is,ie
280  cs%e_D(i,j,k) = cs%e(i,j,k) + g%bathyT(i,j)
281  enddo ; enddo ; enddo
282  else
283  call find_eta(h, tv, gv%g_Earth, g, gv, cs%e_D, eta_bt)
284  do k=1,nz+1 ; do j=js,je ; do i=is,ie
285  cs%e_D(i,j,k) = cs%e_D(i,j,k) + g%bathyT(i,j)
286  enddo ; enddo ; enddo
287  endif
288 
289  if (cs%id_e_D > 0) call post_data(cs%id_e_D, cs%e_D, cs%diag)
290  endif
291 
292  ! mass per area of grid cell (for Bouss, use Rho0)
293  if (cs%id_masscello > 0) then
294  do k=1,nz; do j=js,je ; do i=is,ie
295  cs%diag_tmp3d(i,j,k) = gv%H_to_kg_m2*h(i,j,k)
296  enddo ; enddo ; enddo
297  call post_data(cs%id_masscello, cs%diag_tmp3d, cs%diag)
298  endif
299 
300  ! mass of liquid ocean (for Bouss, use Rho0)
301  if (cs%id_masso > 0) then
302  do k=1,nz; do j=js,je ; do i=is,ie
303  cs%diag_tmp3d(i,j,k) = gv%H_to_kg_m2*h(i,j,k)*g%areaT(i,j)
304  enddo ; enddo ; enddo
305  masso = (reproducing_sum(sum(cs%diag_tmp3d,3)))
306  call post_data(cs%id_masso, masso, cs%diag)
307  endif
308 
309  ! diagnose thickness of grid cells (meter)
310  if (cs%id_thkcello > 0) then
311 
312  ! thkcello = h for Boussinesq
313  if (gv%Boussinesq) then
314  call post_data(cs%id_thkcello, gv%H_to_m*h, cs%diag)
315 
316  ! thkcello = dp/(rho*g) for non-Boussinesq
317  else
318  do j=js,je
319 
320  ! pressure loading at top of surface layer (Pa)
321  if(ASSOCIATED(fluxes%p_surf)) then
322  do i=is,ie
323  pressure_1d(i) = fluxes%p_surf(i,j)
324  enddo
325  else
326  do i=is,ie
327  pressure_1d(i) = 0.0
328  enddo
329  endif
330 
331  do k=1,nz
332  ! pressure for EOS at the layer center (Pa)
333  do i=is,ie
334  pressure_1d(i) = pressure_1d(i) + 0.5*(gv%g_Earth*gv%H_to_kg_m2)*h(i,j,k)
335  enddo
336  ! store in-situ density (kg/m3) in diag_tmp3d
337  call calculate_density(tv%T(:,j,k),tv%S(:,j,k), pressure_1d, &
338  cs%diag_tmp3d(:,j,k), is, ie-is+1, tv%eqn_of_state)
339  ! cell thickness = dz = dp/(g*rho) (meter); store in diag_tmp3d
340  do i=is,ie
341  cs%diag_tmp3d(i,j,k) = (gv%H_to_kg_m2*h(i,j,k))/cs%diag_tmp3d(i,j,k)
342  enddo
343  ! pressure for EOS at the bottom interface (Pa)
344  do i=is,ie
345  pressure_1d(i) = pressure_1d(i) + 0.5*(gv%g_Earth*gv%H_to_kg_m2)*h(i,j,k)
346  enddo
347  enddo ! k
348 
349  enddo ! j
350  call post_data(cs%id_thkcello, cs%diag_tmp3d, cs%diag)
351  endif
352  endif
353 
354  ! volume mean potential temperature
355  if (cs%id_thetaoga>0) then
356  thetaoga = global_volume_mean(tv%T, h, g, gv)
357  call post_data(cs%id_thetaoga, thetaoga, cs%diag)
358  endif
359 
360  ! area mean SST
361  if (cs%id_tosga > 0) then
362  do j=js,je ; do i=is,ie
363  surface_field(i,j) = tv%T(i,j,1)
364  enddo ; enddo
365  tosga = global_area_mean(surface_field, g)
366  call post_data(cs%id_tosga, tosga, cs%diag)
367  endif
368 
369  ! volume mean salinity
370  if (cs%id_soga>0) then
371  soga = global_volume_mean(tv%S, h, g, gv)
372  call post_data(cs%id_soga, soga, cs%diag)
373  endif
374 
375  ! area mean SSS
376  if (cs%id_sosga > 0) then
377  do j=js,je ; do i=is,ie
378  surface_field(i,j) = tv%S(i,j,1)
379  enddo ; enddo
380  sosga = global_area_mean(surface_field, g)
381  call post_data(cs%id_sosga, sosga, cs%diag)
382  endif
383 
384  ! layer mean potential temperature
385  if (cs%id_temp_layer_ave>0) then
386  temp_layer_ave = global_layer_mean(tv%T, h, g, gv)
387  call post_data_1d_k(cs%id_temp_layer_ave, temp_layer_ave, cs%diag)
388  endif
389 
390  ! layer mean salinity
391  if (cs%id_salt_layer_ave>0) then
392  salt_layer_ave = global_layer_mean(tv%S, h, g, gv)
393  call post_data_1d_k(cs%id_salt_layer_ave, salt_layer_ave, cs%diag)
394  endif
395 
396  call calculate_vertical_integrals(h, tv, fluxes, g, gv, cs)
397 
398  if ((cs%id_Rml > 0) .or. (cs%id_Rcv > 0) .or. ASSOCIATED(cs%h_Rlay) .or. &
399  ASSOCIATED(cs%uh_Rlay) .or. ASSOCIATED(cs%vh_Rlay) .or. &
400  ASSOCIATED(cs%uhGM_Rlay) .or. ASSOCIATED(cs%vhGM_Rlay)) then
401 
402  if (associated(tv%eqn_of_state)) then
403  pressure_1d(:) = tv%P_Ref
404 !$OMP parallel do default(none) shared(tv,Rcv,is,ie,js,je,nz,pressure_1d)
405  do k=1,nz ; do j=js-1,je+1
406  call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pressure_1d, &
407  rcv(:,j,k), is-1, ie-is+3, tv%eqn_of_state)
408  enddo ; enddo
409  else ! Rcv should not be used much in this case, so fill in sensible values.
410  do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
411  rcv(i,j,k) = gv%Rlay(k)
412  enddo ; enddo ; enddo
413  endif
414  if (cs%id_Rml > 0) call post_data(cs%id_Rml, rcv, cs%diag)
415  if (cs%id_Rcv > 0) call post_data(cs%id_Rcv, rcv, cs%diag)
416 
417  if (ASSOCIATED(cs%h_Rlay)) then
418  k_list = nz/2
419 !$OMP parallel do default(none) shared(is,ie,js,je,nz,nkmb,CS,Rcv,h,GV) &
420 !$OMP private(wt,wt_p) firstprivate(k_list)
421  do j=js,je
422  do k=1,nkmb ; do i=is,ie
423  cs%h_Rlay(i,j,k) = 0.0
424  enddo ; enddo
425  do k=nkmb+1,nz ; do i=is,ie
426  cs%h_Rlay(i,j,k) = h(i,j,k)
427  enddo ; enddo
428  do k=1,nkmb ; do i=is,ie
429  call find_weights(gv%Rlay, rcv(i,j,k), k_list, nz, wt, wt_p)
430  cs%h_Rlay(i,j,k_list) = cs%h_Rlay(i,j,k_list) + h(i,j,k)*wt
431  cs%h_Rlay(i,j,k_list+1) = cs%h_Rlay(i,j,k_list+1) + h(i,j,k)*wt_p
432  enddo ; enddo
433  enddo
434 
435  if (cs%id_h_Rlay > 0) call post_data(cs%id_h_Rlay, cs%h_Rlay, cs%diag)
436  endif
437 
438  if (ASSOCIATED(cs%uh_Rlay)) then
439  k_list = nz/2
440 !$OMP parallel do default(none) shared(Isq,Ieq,js,je,nz,nkmb,Rcv,CS,GV,uh) &
441 !$OMP private(wt,wt_p) firstprivate(k_list)
442  do j=js,je
443  do k=1,nkmb ; do i=isq,ieq
444  cs%uh_Rlay(i,j,k) = 0.0
445  enddo ; enddo
446  do k=nkmb+1,nz ; do i=isq,ieq
447  cs%uh_Rlay(i,j,k) = uh(i,j,k)
448  enddo ; enddo
449  k_list = nz/2
450  do k=1,nkmb ; do i=isq,ieq
451  call find_weights(gv%Rlay, 0.5*(rcv(i,j,k)+rcv(i+1,j,k)), k_list, nz, wt, wt_p)
452  cs%uh_Rlay(i,j,k_list) = cs%uh_Rlay(i,j,k_list) + uh(i,j,k)*wt
453  cs%uh_Rlay(i,j,k_list+1) = cs%uh_Rlay(i,j,k_list+1) + uh(i,j,k)*wt_p
454  enddo ; enddo
455  enddo
456 
457  if (cs%id_uh_Rlay > 0) call post_data(cs%id_uh_Rlay, cs%uh_Rlay, cs%diag)
458  endif
459 
460  if (ASSOCIATED(cs%vh_Rlay)) then
461  k_list = nz/2
462 !$OMP parallel do default(none) shared(Jsq,Jeq,is,ie,nz,nkmb,Rcv,CS,GV,vh) &
463 !$OMP private(wt,wt_p) firstprivate(k_list)
464  do j=jsq,jeq
465  do k=1,nkmb ; do i=is,ie
466  cs%vh_Rlay(i,j,k) = 0.0
467  enddo ; enddo
468  do k=nkmb+1,nz ; do i=is,ie
469  cs%vh_Rlay(i,j,k) = vh(i,j,k)
470  enddo ; enddo
471  do k=1,nkmb ; do i=is,ie
472  call find_weights(gv%Rlay, 0.5*(rcv(i,j,k)+rcv(i,j+1,k)), k_list, nz, wt, wt_p)
473  cs%vh_Rlay(i,j,k_list) = cs%vh_Rlay(i,j,k_list) + vh(i,j,k)*wt
474  cs%vh_Rlay(i,j,k_list+1) = cs%vh_Rlay(i,j,k_list+1) + vh(i,j,k)*wt_p
475  enddo ; enddo
476  enddo
477 
478  if (cs%id_vh_Rlay > 0) call post_data(cs%id_vh_Rlay, cs%vh_Rlay, cs%diag)
479  endif
480 
481  if (ASSOCIATED(cs%uhGM_Rlay) .and. ASSOCIATED(cdp%uhGM)) then
482  k_list = nz/2
483 !$OMP parallel do default(none) shared(Isq,Ieq,js,je,nz,nkmb,Rcv,CDP,CS,GV) &
484 !$OMP private(wt,wt_p) firstprivate(k_list)
485  do j=js,je
486  do k=1,nkmb ; do i=isq,ieq
487  cs%uhGM_Rlay(i,j,k) = 0.0
488  enddo ; enddo
489  do k=nkmb+1,nz ; do i=isq,ieq
490  cs%uhGM_Rlay(i,j,k) = cdp%uhGM(i,j,k)
491  enddo ; enddo
492  do k=1,nkmb ; do i=isq,ieq
493  call find_weights(gv%Rlay, 0.5*(rcv(i,j,k)+rcv(i+1,j,k)), k_list, nz, wt, wt_p)
494  cs%uhGM_Rlay(i,j,k_list) = cs%uhGM_Rlay(i,j,k_list) + cdp%uhGM(i,j,k)*wt
495  cs%uhGM_Rlay(i,j,k_list+1) = cs%uhGM_Rlay(i,j,k_list+1) + cdp%uhGM(i,j,k)*wt_p
496  enddo ; enddo
497  enddo
498 
499  if (cs%id_uh_Rlay > 0) call post_data(cs%id_uhGM_Rlay, cs%uhGM_Rlay, cs%diag)
500  endif
501 
502  if (ASSOCIATED(cs%vhGM_Rlay) .and. ASSOCIATED(cdp%vhGM)) then
503  k_list = nz/2
504 !$OMP parallel do default(none) shared(is,ie,Jsq,Jeq,nz,nkmb,CS,CDp,Rcv,GV) &
505 !$OMP private(wt,wt_p) firstprivate(k_list)
506  do j=jsq,jeq
507  do k=1,nkmb ; do i=is,ie
508  cs%vhGM_Rlay(i,j,k) = 0.0
509  enddo ; enddo
510  do k=nkmb+1,nz ; do i=is,ie
511  cs%vhGM_Rlay(i,j,k) = cdp%vhGM(i,j,k)
512  enddo ; enddo
513  do k=1,nkmb ; do i=is,ie
514  call find_weights(gv%Rlay, 0.5*(rcv(i,j,k)+rcv(i,j+1,k)), k_list, nz, wt, wt_p)
515  cs%vhGM_Rlay(i,j,k_list) = cs%vhGM_Rlay(i,j,k_list) + cdp%vhGM(i,j,k)*wt
516  cs%vhGM_Rlay(i,j,k_list+1) = cs%vhGM_Rlay(i,j,k_list+1) + cdp%vhGM(i,j,k)*wt_p
517  enddo ; enddo
518  enddo
519 
520  if (cs%id_vhGM_Rlay > 0) call post_data(cs%id_vhGM_Rlay, cs%vhGM_Rlay, cs%diag)
521  endif
522  endif
523 
524  if (associated(tv%eqn_of_state)) then
525  if (cs%id_rhopot0 > 0) then
526  pressure_1d(:) = 0.
527 !$OMP parallel do default(none) shared(tv,Rcv,is,ie,js,je,nz,pressure_1d)
528  do k=1,nz ; do j=js,je
529  call calculate_density(tv%T(:,j,k),tv%S(:,j,k),pressure_1d, &
530  rcv(:,j,k),is,ie-is+1, tv%eqn_of_state)
531  enddo ; enddo
532  if (cs%id_rhopot0 > 0) call post_data(cs%id_rhopot0, rcv, cs%diag)
533  endif
534  if (cs%id_rhopot2 > 0) then
535  pressure_1d(:) = 2.e7 ! 2000 dbars
536 !$OMP parallel do default(none) shared(tv,Rcv,is,ie,js,je,nz,pressure_1d)
537  do k=1,nz ; do j=js,je
538  call calculate_density(tv%T(:,j,k),tv%S(:,j,k),pressure_1d, &
539  rcv(:,j,k),is,ie-is+1, tv%eqn_of_state)
540  enddo ; enddo
541  if (cs%id_rhopot2 > 0) call post_data(cs%id_rhopot2, rcv, cs%diag)
542  endif
543  if (cs%id_rhoinsitu > 0) then
544 !$OMP parallel do default(none) shared(tv,Rcv,is,ie,js,je,nz,pressure_1d,h,GV)
545  do j=js,je
546  pressure_1d(:) = 0. ! Start at p=0 Pa at surface
547  do k=1,nz
548  pressure_1d(:) = pressure_1d(:) + 0.5 * h(:,j,k) * gv%H_to_Pa ! Pressure in middle of layer k
549  call calculate_density(tv%T(:,j,k),tv%S(:,j,k),pressure_1d, &
550  rcv(:,j,k),is,ie-is+1, tv%eqn_of_state)
551  pressure_1d(:) = pressure_1d(:) + 0.5 * h(:,j,k) * gv%H_to_Pa ! Pressure at bottom of layer k
552  enddo
553  enddo
554  if (cs%id_rhoinsitu > 0) call post_data(cs%id_rhoinsitu, rcv, cs%diag)
555  endif
556  endif
557 
558  if ((cs%id_cg1>0) .or. (cs%id_Rd1>0) .or. (cs%id_cfl_cg1>0) .or. &
559  (cs%id_cfl_cg1_x>0) .or. (cs%id_cfl_cg1_y>0)) then
560  call wave_speed(h, tv, g, gv, cs%cg1, cs%wave_speed_CSp)
561  if (cs%id_cg1>0) call post_data(cs%id_cg1, cs%cg1, cs%diag)
562  if (cs%id_Rd1>0) then
563 !$OMP parallel do default(none) shared(is,ie,js,je,G,CS) &
564 !$OMP private(f2_h,mag_beta)
565  do j=js,je ; do i=is,ie
566  ! Blend the equatorial deformation radius with the standard one.
567  f2_h = absurdly_small_freq2 + 0.25 * &
568  ((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
569  (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2))
570  mag_beta = sqrt(0.5 * ( &
571  (((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2 + &
572  ((g%CoriolisBu(i,j-1)-g%CoriolisBu(i-1,j-1)) * g%IdxCv(i,j-1))**2) + &
573  (((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 + &
574  ((g%CoriolisBu(i-1,j)-g%CoriolisBu(i-1,j-1)) * g%IdyCu(i-1,j))**2) ))
575  cs%Rd1(i,j) = cs%cg1(i,j) / sqrt(f2_h + cs%cg1(i,j) * mag_beta)
576 
577  enddo ; enddo
578  call post_data(cs%id_Rd1, cs%Rd1, cs%diag)
579  endif
580  if (cs%id_cfl_cg1>0) then
581  do j=js,je ; do i=is,ie
582  cs%cfl_cg1(i,j) = (dt*cs%cg1(i,j)) * (g%IdxT(i,j) + g%IdyT(i,j))
583  enddo ; enddo
584  call post_data(cs%id_cfl_cg1, cs%cfl_cg1, cs%diag)
585  endif
586  if (cs%id_cfl_cg1_x>0) then
587  do j=js,je ; do i=is,ie
588  cs%cfl_cg1_x(i,j) = (dt*cs%cg1(i,j)) * g%IdxT(i,j)
589  enddo ; enddo
590  call post_data(cs%id_cfl_cg1_x, cs%cfl_cg1_x, cs%diag)
591  endif
592  if (cs%id_cfl_cg1_y>0) then
593  do j=js,je ; do i=is,ie
594  cs%cfl_cg1_y(i,j) = (dt*cs%cg1(i,j)) * g%IdyT(i,j)
595  enddo ; enddo
596  call post_data(cs%id_cfl_cg1_y, cs%cfl_cg1_y, cs%diag)
597  endif
598  endif
599  if ((cs%id_cg_ebt>0) .or. (cs%id_Rd_ebt>0) .or. (cs%id_p_ebt>0)) then
600  if (cs%id_p_ebt>0) then
601  call wave_speed(h, tv, g, gv, cs%cg1, cs%wave_speed_CSp, use_ebt_mode=.true., &
602  mono_n2_column_fraction=cs%mono_N2_column_fraction, &
603  mono_n2_depth=cs%mono_N2_depth, modal_structure=cs%p_ebt)
604  call post_data(cs%id_p_ebt, cs%p_ebt, cs%diag)
605  else
606  call wave_speed(h, tv, g, gv, cs%cg1, cs%wave_speed_CSp, use_ebt_mode=.true., &
607  mono_n2_column_fraction=cs%mono_N2_column_fraction, &
608  mono_n2_depth=cs%mono_N2_depth)
609  endif
610  if (cs%id_cg_ebt>0) call post_data(cs%id_cg_ebt, cs%cg1, cs%diag)
611  if (cs%id_Rd_ebt>0) then
612 !$OMP parallel do default(none) shared(is,ie,js,je,G,CS) &
613 !$OMP private(f2_h,mag_beta)
614  do j=js,je ; do i=is,ie
615  ! Blend the equatorial deformation radius with the standard one.
616  f2_h = absurdly_small_freq2 + 0.25 * &
617  ((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
618  (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2))
619  mag_beta = sqrt(0.5 * ( &
620  (((g%CoriolisBu(i,j)-g%CoriolisBu(i-1,j)) * g%IdxCv(i,j))**2 + &
621  ((g%CoriolisBu(i,j-1)-g%CoriolisBu(i-1,j-1)) * g%IdxCv(i,j-1))**2) + &
622  (((g%CoriolisBu(i,j)-g%CoriolisBu(i,j-1)) * g%IdyCu(i,j))**2 + &
623  ((g%CoriolisBu(i-1,j)-g%CoriolisBu(i-1,j-1)) * g%IdyCu(i-1,j))**2) ))
624  cs%Rd1(i,j) = cs%cg1(i,j) / sqrt(f2_h + cs%cg1(i,j) * mag_beta)
625 
626  enddo ; enddo
627  call post_data(cs%id_Rd_ebt, cs%Rd1, cs%diag)
628  endif
629  endif
630 
631  if (dt > 0.0) then
632  if (cs%id_du_dt>0) call post_data(cs%id_du_dt, cs%du_dt, cs%diag)
633 
634  if (cs%id_dv_dt>0) call post_data(cs%id_dv_dt, cs%dv_dt, cs%diag)
635 
636  if (cs%id_dh_dt>0) call post_data(cs%id_dh_dt, cs%dh_dt, cs%diag)
637 
638  call calculate_energy_diagnostics(u, v, h, uh, vh, adp, cdp, g, cs)
639  endif
640 
641 end subroutine calculate_diagnostic_fields
642 
643 !> This subroutine finds location of R_in in an increasing ordered
644 !! list, Rlist, returning as k the element such that
645 !! Rlist(k) <= R_in < Rlist(k+1), and where wt and wt_p are the linear
646 !! weights that should be assigned to elements k and k+1.
647 subroutine find_weights(Rlist, R_in, k, nz, wt, wt_p)
648  real, intent(in) :: Rlist(:), R_in
649  integer, intent(inout) :: k
650  integer, intent(in) :: nz
651  real, intent(out) :: wt, wt_p
652 
653  ! This subroutine finds location of R_in in an increasing ordered
654  ! list, Rlist, returning as k the element such that
655  ! Rlist(k) <= R_in < Rlist(k+1), and where wt and wt_p are the linear
656  ! weights that should be assigned to elements k and k+1.
657 
658  integer :: k_upper, k_lower, k_new, inc
659 
660  ! First, bracket the desired point.
661  if ((k < 1) .or. (k > nz)) k = nz/2
662 
663  k_upper = k ; k_lower = k ; inc = 1
664  if (r_in < rlist(k)) then
665  do
666  k_lower = max(k_lower-inc, 1)
667  if ((k_lower == 1) .or. (r_in >= rlist(k_lower))) exit
668  k_upper = k_lower
669  inc = inc*2
670  end do
671  else
672  do
673  k_upper = min(k_upper+inc, nz)
674  if ((k_upper == nz) .or. (r_in < rlist(k_upper))) exit
675  k_lower = k_upper
676  inc = inc*2
677  end do
678  endif
679 
680  if ((k_lower == 1) .and. (r_in <= rlist(k_lower))) then
681  k = 1 ; wt = 1.0 ; wt_p = 0.0
682  else if ((k_upper == nz) .and. (r_in >= rlist(k_upper))) then
683  k = nz-1 ; wt = 0.0 ; wt_p = 1.0
684  else
685  do
686  if (k_upper <= k_lower+1) exit
687  k_new = (k_upper + k_lower) / 2
688  if (r_in < rlist(k_new)) then
689  k_upper = k_new
690  else
691  k_lower = k_new
692  endif
693  end do
694 
695 ! Uncomment this as a code check
696 ! if ((R_in < Rlist(k_lower)) .or. (R_in >= Rlist(k_upper)) .or. (k_upper-k_lower /= 1)) &
697 ! write (*,*) "Error: ",R_in," is not between R(",k_lower,") = ", &
698 ! Rlist(k_lower)," and R(",k_upper,") = ",Rlist(k_upper),"."
699  k = k_lower
700  wt = (rlist(k_upper) - r_in) / (rlist(k_upper) - rlist(k_lower))
701  wt_p = 1.0 - wt
702 
703  endif
704 
705 end subroutine find_weights
706 
707 !> Subroutine calculates vertical integrals of several tracers, along
708 !! with the mass-weight of these tracers, the total column mass, and the
709 !! carefully calculated column height.
710 subroutine calculate_vertical_integrals(h, tv, fluxes, G, GV, CS)
711  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
712  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid
713  !! structure.
714  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
715  !! (usually m or kg m-2).
716  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
717  !! thermodynamic variables.
718  type(forcing), intent(in) :: fluxes !< A structure containing the
719  !! surface fluxes.
720  type(diagnostics_cs), intent(inout) :: CS !< A control structure returned
721  !! by a previous call to
722  !! diagnostics_init.
723 
724 ! Subroutine calculates vertical integrals of several tracers, along
725 ! with the mass-weight of these tracers, the total column mass, and the
726 ! carefully calculated column height.
727 
728 ! Arguments:
729 ! (in) h - layer thickness: metre (Bouss) or kg/ m2 (non-Bouss)
730 ! (in) tv - structure pointing to thermodynamic variables
731 ! (in) fluxes - a structure containing the surface fluxes.
732 ! (in) G - ocean grid structure
733 ! (in) GV - The ocean's vertical grid structure.
734 ! (in) CS - control structure returned by a previous call to diagnostics_init
735 
736  real, dimension(SZI_(G), SZJ_(G)) :: &
737  z_top, & ! Height of the top of a layer or the ocean, in m.
738  z_bot, & ! Height of the bottom of a layer (for id_mass) or the
739  ! (positive) depth of the ocean (for id_col_ht), in m.
740  mass, & ! integrated mass of the water column, in kg m-2. For
741  ! non-Boussinesq models this is rho*dz. For Boussiensq
742  ! models, this is either the integral of in-situ density
743  ! (rho*dz for col_mass) or reference dens (Rho_0*dz for mass_wt).
744  btm_pres,&! The pressure at the ocean bottom, or CMIP variable 'pbo'.
745  ! This is the column mass multiplied by gravity plus the pressure
746  ! at the ocean surface.
747  dpress, & ! Change in hydrostatic pressure across a layer, in Pa.
748  tr_int ! vertical integral of a tracer times density,
749  ! (Rho_0 in a Boussinesq model) in TR kg m-2.
750  real :: IG_Earth ! Inverse of gravitational acceleration, in s2 m-1.
751 
752  integer :: i, j, k, is, ie, js, je, nz
753  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
754 
755  if (cs%id_mass_wt > 0) then
756  do j=js,je ; do i=is,ie ; mass(i,j) = 0.0 ; enddo ; enddo
757  do k=1,nz ; do j=js,je ; do i=is,ie
758  mass(i,j) = mass(i,j) + gv%H_to_kg_m2*h(i,j,k)
759  enddo ; enddo ; enddo
760  call post_data(cs%id_mass_wt, mass, cs%diag)
761  endif
762 
763  if (cs%id_temp_int > 0) then
764  do j=js,je ; do i=is,ie ; tr_int(i,j) = 0.0 ; enddo ; enddo
765  do k=1,nz ; do j=js,je ; do i=is,ie
766  tr_int(i,j) = tr_int(i,j) + (gv%H_to_kg_m2*h(i,j,k))*tv%T(i,j,k)
767  enddo ; enddo ; enddo
768  call post_data(cs%id_temp_int, tr_int, cs%diag)
769  endif
770 
771  if (cs%id_salt_int > 0) then
772  do j=js,je ; do i=is,ie ; tr_int(i,j) = 0.0 ; enddo ; enddo
773  do k=1,nz ; do j=js,je ; do i=is,ie
774  tr_int(i,j) = tr_int(i,j) + (gv%H_to_kg_m2*h(i,j,k))*tv%S(i,j,k)
775  enddo ; enddo ; enddo
776  call post_data(cs%id_salt_int, tr_int, cs%diag)
777  endif
778 
779  if (cs%id_col_ht > 0) then
780  call find_eta(h, tv, gv%g_Earth, g, gv, z_top)
781  do j=js,je ; do i=is,ie
782  z_bot(i,j) = z_top(i,j) + g%bathyT(i,j)
783  enddo ; enddo
784  call post_data(cs%id_col_ht, z_bot, cs%diag)
785  endif
786 
787  if (cs%id_col_mass > 0 .or. cs%id_pbo > 0) then
788  do j=js,je ; do i=is,ie ; mass(i,j) = 0.0 ; enddo ; enddo
789  if (gv%Boussinesq) then
790  if (associated(tv%eqn_of_state)) then
791  ig_earth = 1.0 / gv%g_Earth
792 ! do j=js,je ; do i=is,ie ; z_bot(i,j) = -P_SURF(i,j)/GV%H_to_Pa ; enddo ; enddo
793  do j=js,je ; do i=is,ie ; z_bot(i,j) = 0.0 ; enddo ; enddo
794  do k=1,nz
795  do j=js,je ; do i=is,ie
796  z_top(i,j) = z_bot(i,j)
797  z_bot(i,j) = z_top(i,j) - gv%H_to_m*h(i,j,k)
798  enddo ; enddo
799  call int_density_dz(tv%T(:,:,k), tv%S(:,:,k), &
800  z_top, z_bot, 0.0, gv%H_to_kg_m2, gv%g_Earth, &
801  g%HI, g%HI, tv%eqn_of_state, dpress)
802  do j=js,je ; do i=is,ie
803  mass(i,j) = mass(i,j) + dpress(i,j) * ig_earth
804  enddo ; enddo
805  enddo
806  else
807  do k=1,nz ; do j=js,je ; do i=is,ie
808  mass(i,j) = mass(i,j) + (gv%H_to_m*gv%Rlay(k))*h(i,j,k)
809  enddo ; enddo ; enddo
810  endif
811  else
812  do k=1,nz ; do j=js,je ; do i=is,ie
813  mass(i,j) = mass(i,j) + gv%H_to_kg_m2*h(i,j,k)
814  enddo ; enddo ; enddo
815  endif
816  if (cs%id_col_mass > 0) then
817  call post_data(cs%id_col_mass, mass, cs%diag)
818  endif
819  if (cs%id_pbo > 0) then
820  do j=js,je ; do i=is,ie ; btm_pres(i,j) = 0.0 ; enddo ; enddo
821  ! 'pbo' is defined as the sea water pressure at the sea floor
822  ! pbo = (mass * g) + pso
823  ! where pso is the sea water pressure at sea water surface
824  ! note that pso is equivalent to fluxes%p_surf
825  do j=js,je ; do i=is,ie
826  btm_pres(i,j) = mass(i,j) * gv%g_Earth
827  if (ASSOCIATED(fluxes%p_surf)) then
828  btm_pres(i,j) = btm_pres(i,j) + fluxes%p_surf(i,j)
829  endif
830  enddo ; enddo
831  call post_data(cs%id_pbo, btm_pres, cs%diag)
832  endif
833  endif
834 
835 end subroutine calculate_vertical_integrals
836 
837 !> This subroutine calculates terms in the mechanical energy budget.
838 subroutine calculate_energy_diagnostics(u, v, h, uh, vh, ADp, CDp, G, CS)
839  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
840  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1.
841  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity,
842  !! in m s-1.
843  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
844  !! (usually m or kg m-2).
845  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: uh !< Transport through zonal
846  !! faces=u*h*dy: m3/s (Bouss)
847  !! kg/s(non-Bouss).
848  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: vh !< Transport through merid
849  !! faces=v*h*dx: m3/s (Bouss)
850  !! kg/s(non-Bouss).
851  type(accel_diag_ptrs), intent(in) :: ADp !< Structure pointing to
852  !! accelerations in momentum
853  !! equation.
854  type(cont_diag_ptrs), intent(in) :: CDp !< Structure pointing to terms
855  !! in continuity equations.
856  type(diagnostics_cs), intent(inout) :: CS !< Control structure returned by
857  !! a previous call to
858  !! diagnostics_init.
859 
860 ! This subroutine calculates terms in the mechanical energy budget.
861 
862 ! Arguments:
863 ! (in) u - zonal velocity component (m/s)
864 ! (in) v - meridional velocity componnent (m/s)
865 ! (in) h - layer thickness: metre(Bouss) of kg/m2(non-Bouss)
866 ! (in) uh - transport through zonal faces=u*h*dy: m3/s (Bouss) kg/s(non-Bouss)
867 ! (in) vh - transport through merid faces=v*h*dx: m3/s (Bouss) kg/s(non-Bouss)
868 ! (in) ADp - structure pointing to accelerations in momentum equation
869 ! (in) CDp - structure pointing to terms in continuity equations
870 ! (in) G - ocean grid structure
871 ! (in) CS - control structure returned by a previous call to diagnostics_init
872 
873  real :: KE_u(szib_(g),szj_(g))
874  real :: KE_v(szi_(g),szjb_(g))
875  real :: KE_h(szi_(g),szj_(g))
876 
877  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
878  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
879  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
880 
881  do j=js-1,je ; do i=is-1,ie
882  ke_u(i,j) = 0.0 ; ke_v(i,j) = 0.0
883  enddo ; enddo
884 
885  if (ASSOCIATED(cs%KE)) then
886  do k=1,nz ; do j=js,je ; do i=is,ie
887  cs%KE(i,j,k) = ((u(i,j,k)*u(i,j,k) + u(i-1,j,k)*u(i-1,j,k)) + &
888  (v(i,j,k)*v(i,j,k) + v(i,j-1,k)*v(i,j-1,k)))*0.25
889  ! DELETE THE FOLLOWING... Make this 0 to test the momentum balance,
890  ! or a huge number to test the continuity balance.
891  ! CS%KE(i,j,k) *= 1e20
892  enddo ; enddo ; enddo
893  if (cs%id_KE > 0) call post_data(cs%id_KE, cs%KE, cs%diag)
894  endif
895 
896  if(.not.g%symmetric) then
897  if(ASSOCIATED(cs%dKE_dt) .OR. ASSOCIATED(cs%PE_to_KE) .OR. ASSOCIATED(cs%KE_CorAdv) .OR. &
898  ASSOCIATED(cs%KE_adv) .OR. ASSOCIATED(cs%KE_visc) .OR. ASSOCIATED(cs%KE_horvisc).OR. &
899  ASSOCIATED(cs%KE_dia) ) then
900  call create_group_pass(cs%pass_KE_uv, ke_u, ke_v, g%Domain, to_north+to_east)
901  endif
902  endif
903 
904  if (ASSOCIATED(cs%dKE_dt)) then
905  do k=1,nz
906  do j=js,je ; do i=isq,ieq
907  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*cs%du_dt(i,j,k)
908  enddo ; enddo
909  do j=jsq,jeq ; do i=is,ie
910  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*cs%dv_dt(i,j,k)
911  enddo ; enddo
912  do j=js,je ; do i=is,ie
913  ke_h(i,j) = cs%KE(i,j,k)*cs%dh_dt(i,j,k)
914  enddo ; enddo
915  if (.not.g%symmetric) &
916  call do_group_pass(cs%pass_KE_uv, g%domain)
917  do j=js,je ; do i=is,ie
918  cs%dKE_dt(i,j,k) = ke_h(i,j) + 0.5 * g%IareaT(i,j) * &
919  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
920  enddo ; enddo
921  enddo
922  if (cs%id_dKEdt > 0) call post_data(cs%id_dKEdt, cs%dKE_dt, cs%diag)
923  endif
924 
925  if (ASSOCIATED(cs%PE_to_KE)) then
926  do k=1,nz
927  do j=js,je ; do i=isq,ieq
928  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%PFu(i,j,k)
929  enddo ; enddo
930  do j=jsq,jeq ; do i=is,ie
931  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%PFv(i,j,k)
932  enddo ; enddo
933  if (.not.g%symmetric) &
934  call do_group_pass(cs%pass_KE_uv, g%domain)
935  do j=js,je ; do i=is,ie
936  cs%PE_to_KE(i,j,k) = 0.5 * g%IareaT(i,j) * &
937  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
938  enddo ; enddo
939  enddo
940  if (cs%id_PE_to_KE > 0) call post_data(cs%id_PE_to_KE, cs%PE_to_KE, cs%diag)
941  endif
942 
943  if (ASSOCIATED(cs%KE_CorAdv)) then
944  do k=1,nz
945  do j=js,je ; do i=isq,ieq
946  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%CAu(i,j,k)
947  enddo ; enddo
948  do j=jsq,jeq ; do i=is,ie
949  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%CAv(i,j,k)
950  enddo ; enddo
951  do j=js,je ; do i=is,ie
952  ke_h(i,j) = -cs%KE(i,j,k) * g%IareaT(i,j) * &
953  (uh(i,j,k) - uh(i-1,j,k) + vh(i,j,k) - vh(i,j-1,k))
954  enddo ; enddo
955  if (.not.g%symmetric) &
956  call do_group_pass(cs%pass_KE_uv, g%domain)
957  do j=js,je ; do i=is,ie
958  cs%KE_CorAdv(i,j,k) = ke_h(i,j) + 0.5 * g%IareaT(i,j) * &
959  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
960  enddo ; enddo
961  enddo
962  if (cs%id_KE_Coradv > 0) call post_data(cs%id_KE_Coradv, cs%KE_Coradv, cs%diag)
963  endif
964 
965  if (ASSOCIATED(cs%KE_adv)) then
966  do k=1,nz
967  do j=js,je ; do i=isq,ieq
968  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%gradKEu(i,j,k)
969  enddo ; enddo
970  do j=jsq,jeq ; do i=is,ie
971  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%gradKEv(i,j,k)
972  enddo ; enddo
973  do j=js,je ; do i=is,ie
974  ke_h(i,j) = -cs%KE(i,j,k) * g%IareaT(i,j) * &
975  (uh(i,j,k) - uh(i-1,j,k) + vh(i,j,k) - vh(i,j-1,k))
976  enddo ; enddo
977  if (.not.g%symmetric) &
978  call do_group_pass(cs%pass_KE_uv, g%domain)
979  do j=js,je ; do i=is,ie
980  cs%KE_adv(i,j,k) = ke_h(i,j) + 0.5 * g%IareaT(i,j) * &
981  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
982  enddo ; enddo
983  enddo
984  if (cs%id_KE_adv > 0) call post_data(cs%id_KE_adv, cs%KE_adv, cs%diag)
985  endif
986 
987  if (ASSOCIATED(cs%KE_visc)) then
988  do k=1,nz
989  do j=js,je ; do i=isq,ieq
990  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%du_dt_visc(i,j,k)
991  enddo ; enddo
992  do j=jsq,jeq ; do i=is,ie
993  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%dv_dt_visc(i,j,k)
994  enddo ; enddo
995  if (.not.g%symmetric) &
996  call do_group_pass(cs%pass_KE_uv, g%domain)
997  do j=js,je ; do i=is,ie
998  cs%KE_visc(i,j,k) = 0.5 * g%IareaT(i,j) * &
999  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
1000  enddo ; enddo
1001  enddo
1002  if (cs%id_KE_visc > 0) call post_data(cs%id_KE_visc, cs%KE_visc, cs%diag)
1003  endif
1004 
1005  if (ASSOCIATED(cs%KE_horvisc)) then
1006  do k=1,nz
1007  do j=js,je ; do i=isq,ieq
1008  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%diffu(i,j,k)
1009  enddo ; enddo
1010  do j=jsq,jeq ; do i=is,ie
1011  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%diffv(i,j,k)
1012  enddo ; enddo
1013  if (.not.g%symmetric) &
1014  call do_group_pass(cs%pass_KE_uv, g%domain)
1015  do j=js,je ; do i=is,ie
1016  cs%KE_horvisc(i,j,k) = 0.5 * g%IareaT(i,j) * &
1017  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
1018  enddo ; enddo
1019  enddo
1020  if (cs%id_KE_horvisc > 0) call post_data(cs%id_KE_horvisc, cs%KE_horvisc, cs%diag)
1021  endif
1022 
1023  if (ASSOCIATED(cs%KE_dia)) then
1024  do k=1,nz
1025  do j=js,je ; do i=isq,ieq
1026  ke_u(i,j) = uh(i,j,k)*g%dxCu(i,j)*adp%du_dt_dia(i,j,k)
1027  enddo ; enddo
1028  do j=jsq,jeq ; do i=is,ie
1029  ke_v(i,j) = vh(i,j,k)*g%dyCv(i,j)*adp%dv_dt_dia(i,j,k)
1030  enddo ; enddo
1031  do j=js,je ; do i=is,ie
1032  ke_h(i,j) = cs%KE(i,j,k) * &
1033  (cdp%diapyc_vel(i,j,k) - cdp%diapyc_vel(i,j,k+1))
1034  enddo ; enddo
1035  if (.not.g%symmetric) &
1036  call do_group_pass(cs%pass_KE_uv, g%domain)
1037  do j=js,je ; do i=is,ie
1038  cs%KE_dia(i,j,k) = ke_h(i,j) + 0.5 * g%IareaT(i,j) * &
1039  (ke_u(i,j) + ke_u(i-1,j) + ke_v(i,j) + ke_v(i,j-1))
1040  enddo ; enddo
1041  enddo
1042  if (cs%id_KE_dia > 0) call post_data(cs%id_KE_dia, cs%KE_dia, cs%diag)
1043  endif
1044 
1045 end subroutine calculate_energy_diagnostics
1046 
1047 !> This subroutine registers fields to calculate a diagnostic time derivative.
1048 subroutine register_time_deriv(f_ptr, deriv_ptr, CS)
1049  real, dimension(:,:,:), target :: f_ptr !< Field whose derivative is taken.
1050  real, dimension(:,:,:), target :: deriv_ptr !< Field in which the calculated time derivatives
1051  !! placed.
1052  type(diagnostics_cs), pointer :: CS !< Control structure returned by previous call to
1053  !! diagnostics_init.
1054 
1055 ! This subroutine registers fields to calculate a diagnostic time derivative.
1056 ! Arguments:
1057 ! (target) f_ptr - field whose derivative is taken
1058 ! (in) deriv_ptr - field in which the calculated time derivatives placed
1059 ! (in) num_lay - number of layers in this field
1060 ! (in) CS - control structure returned by previous call to diagnostics_init
1061 
1062  integer :: m
1063 
1064  if (.not.associated(cs)) call mom_error(fatal, &
1065  "register_time_deriv: Module must be initialized before it is used.")
1066 
1067  if (cs%num_time_deriv >= max_fields_) then
1068  call mom_error(warning,"MOM_diagnostics: Attempted to register more than " // &
1069  "MAX_FIELDS_ diagnostic time derivatives via register_time_deriv.")
1070  return
1071  endif
1072 
1073  m = cs%num_time_deriv+1 ; cs%num_time_deriv = m
1074 
1075  cs%nlay(m) = size(f_ptr(:,:,:),3)
1076  cs%deriv(m)%p => deriv_ptr
1077  allocate(cs%prev_val(m)%p(size(f_ptr(:,:,:),1), size(f_ptr(:,:,:),2), cs%nlay(m)) )
1078 
1079  cs%var_ptr(m)%p => f_ptr
1080  cs%prev_val(m)%p(:,:,:) = f_ptr(:,:,:)
1081 
1082 end subroutine register_time_deriv
1083 
1084 !> This subroutine calculates all registered time derivatives.
1085 subroutine calculate_derivs(dt, G, CS)
1086  real, intent(in) :: dt !< The time interval over which differences occur,
1087  !! in s.
1088  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
1089  type(diagnostics_cs), intent(inout) :: CS !< Control structure returned by previous call to
1090  !! diagnostics_init.
1091 
1092 ! This subroutine calculates all registered time derivatives.
1093 ! Arguments:
1094 ! (in) dt - time interval in s over which differences occur
1095 ! (in) G - ocean grid structure.
1096 ! (in) CS - control structure returned by previous call to diagnostics_init
1097 
1098  integer i, j, k, m
1099  real Idt
1100 
1101  if (dt > 0.0) then ; idt = 1.0/dt
1102  else ; return ; endif
1103 
1104  do m=1,cs%num_time_deriv
1105  do k=1,cs%nlay(m) ; do j=g%jsc,g%jec ; do i=g%isc,g%iec
1106  cs%deriv(m)%p(i,j,k) = (cs%var_ptr(m)%p(i,j,k) - cs%prev_val(m)%p(i,j,k)) * idt
1107  cs%prev_val(m)%p(i,j,k) = cs%var_ptr(m)%p(i,j,k)
1108  enddo ; enddo ; enddo
1109  enddo
1110 
1111 end subroutine calculate_derivs
1112 
1113 ! #@# This subroutine needs a doxygen description
1114 subroutine mom_diagnostics_init(MIS, ADp, CDp, Time, G, GV, param_file, diag, CS)
1115  type(ocean_internal_state), intent(in) :: MIS !< For "MOM Internal State" a set of pointers to
1116  !! the fields and accelerations that make up the
1117  !! ocean's internal physical state.
1118  type(accel_diag_ptrs), intent(inout) :: ADp !< Structure with pointers to momentum equation
1119  !! terms.
1120  type(cont_diag_ptrs), intent(inout) :: CDp !< Structure with pointers to continuity
1121  !! equation terms.
1122  type(time_type), intent(in) :: Time !< Current model time.
1123  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1124  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1125  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
1126  !! parameters.
1127  type(diag_ctrl), target, intent(inout) :: diag !< Structure to regulate diagnostic output.
1128  type(diagnostics_cs), pointer :: CS !< Pointer set to point to control structure
1129  !! for this module.
1130 
1131 ! Arguments
1132 ! (in) MIS - For "MOM Internal State" a set of pointers to the fields and
1133 ! accelerations that make up the ocean's internal physical
1134 ! state.
1135 ! (inout) ADp - structure with pointers to momentum equation terms
1136 ! (inout) CDp - structure with pointers to continuity equation terms
1137 ! (in) Time - current model time
1138 ! (in) G - ocean grid structure
1139 ! (in) GV - The ocean's vertical grid structure.
1140 ! (in) param_file - structure indicating the open file to parse for
1141 ! model parameter values
1142 ! (in) diag - structure to regulate diagnostic output
1143 ! (in/out) CS - pointer set to point to control structure for this module
1144 
1145 ! This include declares and sets the variable "version".
1146 #include "version_variable.h"
1147 
1148  character(len=40) :: mdl = "MOM_diagnostics" ! This module's name.
1149  real :: omega, f2_min
1150  character(len=48) :: thickness_units, flux_units
1151  integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz, nkml, nkbl
1152  integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, i, j
1153 
1154  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
1155  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
1156  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
1157  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1158 
1159  if (associated(cs)) then
1160  call mom_error(warning, "MOM_diagnostics_init called with an associated "// &
1161  "control structure.")
1162  return
1163  endif
1164  allocate(cs)
1165 
1166  cs%diag => diag
1167 
1168  ! Read all relevant parameters and write them to the model log.
1169  call log_version(param_file, mdl, version)
1170  call get_param(param_file, mdl, "DIAG_EBT_MONO_N2_COLUMN_FRACTION", cs%mono_N2_column_fraction, &
1171  "The lower fraction of water column over which N2 is limited as monotonic\n"// &
1172  "for the purposes of calculating the equivalent barotropic wave speed.", &
1173  units='nondim', default=0.)
1174  call get_param(param_file, mdl, "DIAG_EBT_MONO_N2_DEPTH", cs%mono_N2_depth, &
1175  "The depth below which N2 is limited as monotonic for the\n"// &
1176  "purposes of calculating the equivalent barotropic wave speed.", &
1177  units='m', default=-1.)
1178 
1179  if (gv%Boussinesq) then
1180  thickness_units = "meter" ; flux_units = "meter3 second-1"
1181  else
1182  thickness_units = "kilogram meter-2" ; flux_units = "kilogram second-1"
1183  endif
1184 
1185  cs%id_temp_layer_ave = register_diag_field('ocean_model', 'temp_layer_ave', diag%axesZL, time, &
1186  'Layer Average Ocean Temperature', 'Celsius')
1187 
1188  cs%id_salt_layer_ave = register_diag_field('ocean_model', 'salt_layer_ave', diag%axesZL, time, &
1189  'Layer Average Ocean Salinity', 'ppt')
1190 
1191  cs%id_masscello = register_diag_field('ocean_model', 'masscello', diag%axesTL,&
1192  time, 'Mass per unit area of liquid ocean grid cell', 'kg m-2', &
1193  standard_name='sea_water_mass_per_unit_area', v_extensive=.true.)
1194 
1195  cs%id_masso = register_scalar_field('ocean_model', 'masso', time, &
1196  diag, 'Mass of liquid ocean', 'kg', standard_name='sea_water_mass')
1197 
1198  cs%id_thkcello = register_diag_field('ocean_model', 'thkcello', diag%axesTL, time, &
1199  long_name = 'Cell Thickness', standard_name='cell_thickness', units='m', v_extensive=.true.)
1200 
1201  if (((cs%id_masscello>0) .or. (cs%id_masso>0) .or. (cs%id_thkcello>0.and..not.gv%Boussinesq)) &
1202  .and. .not.ASSOCIATED(cs%diag_tmp3d)) then
1203  call safe_alloc_ptr(cs%diag_tmp3d,isd,ied,jsd,jed,nz)
1204  endif
1205 
1206  cs%id_thetaoga = register_scalar_field('ocean_model', 'thetaoga', &
1207  time, diag, 'Global Mean Ocean Potential Temperature', 'Celsius',&
1208  standard_name='sea_water_potential_temperature')
1209 
1210  cs%id_soga = register_scalar_field('ocean_model', 'soga', &
1211  time, diag, 'Global Mean Ocean Salinity', 'ppt', &
1212  standard_name='sea_water_salinity')
1213 
1214  cs%id_tosga = register_scalar_field('ocean_model', 'sst_global', time, diag,&
1215  long_name='Global Area Average Sea Surface Temperature', &
1216  units='degC', standard_name='sea_surface_temperature', &
1217  cmor_field_name='tosga', cmor_standard_name='sea_surface_temperature', &
1218  cmor_units='degC', cmor_long_name='Sea Surface Temperature')
1219 
1220  cs%id_sosga = register_scalar_field('ocean_model', 'sss_global', time, diag,&
1221  long_name='Global Area Average Sea Surface Salinity', &
1222  units='ppt', standard_name='sea_surface_salinity', &
1223  cmor_field_name='sosga', cmor_standard_name='sea_surface_salinity', &
1224  cmor_units='ppt', cmor_long_name='Sea Surface Salinity')
1225 
1226  cs%id_e = register_diag_field('ocean_model', 'e', diag%axesTi, time, &
1227  'Interface Height Relative to Mean Sea Level', 'meter')
1228  if (cs%id_e>0) call safe_alloc_ptr(cs%e,isd,ied,jsd,jed,nz+1)
1229 
1230  cs%id_e_D = register_diag_field('ocean_model', 'e_D', diag%axesTi, time, &
1231  'Interface Height above the Seafloor', 'meter')
1232  if (cs%id_e_D>0) call safe_alloc_ptr(cs%e_D,isd,ied,jsd,jed,nz+1)
1233 
1234  cs%id_Rml = register_diag_field('ocean_model', 'Rml', diag%axesTL, time, &
1235  'Mixed Layer Coordinate Potential Density', 'kg meter-3')
1236 
1237  cs%id_Rcv = register_diag_field('ocean_model', 'Rho_cv', diag%axesTL, time, &
1238  'Coordinate Potential Density', 'kg meter-3')
1239 
1240  cs%id_rhopot0 = register_diag_field('ocean_model', 'rhopot0', diag%axesTL, time, &
1241  'Potential density referenced to surface', 'kg meter-3')
1242  cs%id_rhopot2 = register_diag_field('ocean_model', 'rhopot2', diag%axesTL, time, &
1243  'Potential density referenced to 2000 dbar', 'kg meter-3')
1244  cs%id_rhoinsitu = register_diag_field('ocean_model', 'rhoinsitu', diag%axesTL, time, &
1245  'In situ density', 'kg meter-3')
1246 
1247  cs%id_du_dt = register_diag_field('ocean_model', 'dudt', diag%axesCuL, time, &
1248  'Zonal Acceleration', 'meter second-2')
1249  if ((cs%id_du_dt>0) .and. .not.ASSOCIATED(cs%du_dt)) then
1250  call safe_alloc_ptr(cs%du_dt,isdb,iedb,jsd,jed,nz)
1251  call register_time_deriv(mis%u, cs%du_dt, cs)
1252  endif
1253 
1254  cs%id_dv_dt = register_diag_field('ocean_model', 'dvdt', diag%axesCvL, time, &
1255  'Meridional Acceleration', 'meter second-2')
1256  if ((cs%id_dv_dt>0) .and. .not.ASSOCIATED(cs%dv_dt)) then
1257  call safe_alloc_ptr(cs%dv_dt,isd,ied,jsdb,jedb,nz)
1258  call register_time_deriv(mis%v, cs%dv_dt, cs)
1259  endif
1260 
1261  cs%id_dh_dt = register_diag_field('ocean_model', 'dhdt', diag%axesTL, time, &
1262  'Thickness tendency', trim(thickness_units)//" second-1")
1263  if ((cs%id_dh_dt>0) .and. .not.ASSOCIATED(cs%dh_dt)) then
1264  call safe_alloc_ptr(cs%dh_dt,isd,ied,jsd,jed,nz)
1265  call register_time_deriv(mis%h, cs%dh_dt, cs)
1266  endif
1267 
1268  ! layer thickness variables
1269  !if (GV%nk_rho_varies > 0) then
1270  cs%id_h_Rlay = register_diag_field('ocean_model', 'h_rho', diag%axesTL, time, &
1271  'Layer thicknesses in pure potential density coordinates', thickness_units)
1272  if (cs%id_h_Rlay>0) call safe_alloc_ptr(cs%h_Rlay,isd,ied,jsd,jed,nz)
1273 
1274  cs%id_uh_Rlay = register_diag_field('ocean_model', 'uh_rho', diag%axesCuL, time, &
1275  'Zonal volume transport in pure potential density coordinates', flux_units)
1276  if (cs%id_uh_Rlay>0) call safe_alloc_ptr(cs%uh_Rlay,isdb,iedb,jsd,jed,nz)
1277 
1278  cs%id_vh_Rlay = register_diag_field('ocean_model', 'vh_rho', diag%axesCvL, time, &
1279  'Meridional volume transport in pure potential density coordinates', flux_units)
1280  if (cs%id_vh_Rlay>0) call safe_alloc_ptr(cs%vh_Rlay,isd,ied,jsdb,jedb,nz)
1281 
1282  cs%id_uhGM_Rlay = register_diag_field('ocean_model', 'uhGM_rho', diag%axesCuL, time, &
1283  'Zonal volume transport due to interface height diffusion in pure potential &
1284  &density coordinates', flux_units)
1285  if (cs%id_uhGM_Rlay>0) call safe_alloc_ptr(cs%uhGM_Rlay,isdb,iedb,jsd,jed,nz)
1286 
1287  cs%id_vhGM_Rlay = register_diag_field('ocean_model', 'vhGM_rho', diag%axesCvL, time, &
1288  'Meridional volume transport due to interface height diffusion in pure &
1289  &potential density coordinates', flux_units)
1290  if (cs%id_vhGM_Rlay>0) call safe_alloc_ptr(cs%vhGM_Rlay,isd,ied,jsdb,jedb,nz)
1291  !endif
1292 
1293 
1294  ! terms in the kinetic energy budget
1295  cs%id_KE = register_diag_field('ocean_model', 'KE', diag%axesTL, time, &
1296  'Layer kinetic energy per unit mass', 'meter2 second-2')
1297  if (cs%id_KE>0) call safe_alloc_ptr(cs%KE,isd,ied,jsd,jed,nz)
1298 
1299  cs%id_dKEdt = register_diag_field('ocean_model', 'dKE_dt', diag%axesTL, time, &
1300  'Kinetic Energy Tendency of Layer', 'meter3 second-3')
1301  if (cs%id_dKEdt>0) call safe_alloc_ptr(cs%dKE_dt,isd,ied,jsd,jed,nz)
1302 
1303  cs%id_PE_to_KE = register_diag_field('ocean_model', 'PE_to_KE', diag%axesTL, time, &
1304  'Potential to Kinetic Energy Conversion of Layer', 'meter3 second-3')
1305  if (cs%id_PE_to_KE>0) call safe_alloc_ptr(cs%PE_to_KE,isd,ied,jsd,jed,nz)
1306 
1307  cs%id_KE_Coradv = register_diag_field('ocean_model', 'KE_Coradv', diag%axesTL, time, &
1308  'Kinetic Energy Source from Coriolis and Advection', 'meter3 second-3')
1309  if (cs%id_KE_Coradv>0) call safe_alloc_ptr(cs%KE_Coradv,isd,ied,jsd,jed,nz)
1310 
1311  cs%id_KE_adv = register_diag_field('ocean_model', 'KE_adv', diag%axesTL, time, &
1312  'Kinetic Energy Source from Advection', 'meter3 second-3')
1313  if (cs%id_KE_adv>0) call safe_alloc_ptr(cs%KE_adv,isd,ied,jsd,jed,nz)
1314 
1315  cs%id_KE_visc = register_diag_field('ocean_model', 'KE_visc', diag%axesTL, time, &
1316  'Kinetic Energy Source from Vertical Viscosity and Stresses', 'meter3 second-3')
1317  if (cs%id_KE_visc>0) call safe_alloc_ptr(cs%KE_visc,isd,ied,jsd,jed,nz)
1318 
1319  cs%id_KE_horvisc = register_diag_field('ocean_model', 'KE_horvisc', diag%axesTL, time, &
1320  'Kinetic Energy Source from Horizontal Viscosity', 'meter3 second-3')
1321  if (cs%id_KE_horvisc>0) call safe_alloc_ptr(cs%KE_horvisc,isd,ied,jsd,jed,nz)
1322 
1323  cs%id_KE_dia = register_diag_field('ocean_model', 'KE_dia', diag%axesTL, time, &
1324  'Kinetic Energy Source from Diapycnal Diffusion', 'meter3 second-3')
1325  if (cs%id_KE_dia>0) call safe_alloc_ptr(cs%KE_dia,isd,ied,jsd,jed,nz)
1326 
1327 
1328  ! gravity wave CFLs
1329  cs%id_cg1 = register_diag_field('ocean_model', 'cg1', diag%axesT1, time, &
1330  'First baroclinic gravity wave speed', 'meter second-1')
1331  cs%id_Rd1 = register_diag_field('ocean_model', 'Rd1', diag%axesT1, time, &
1332  'First baroclinic deformation radius', 'meter')
1333  cs%id_cfl_cg1 = register_diag_field('ocean_model', 'CFL_cg1', diag%axesT1, time, &
1334  'CFL of first baroclinic gravity wave = dt*cg1*(1/dx+1/dy)', 'nondim')
1335  cs%id_cfl_cg1_x = register_diag_field('ocean_model', 'CFL_cg1_x', diag%axesT1, time, &
1336  'i-component of CFL of first baroclinic gravity wave = dt*cg1*/dx', 'nondim')
1337  cs%id_cfl_cg1_y = register_diag_field('ocean_model', 'CFL_cg1_y', diag%axesT1, time, &
1338  'j-component of CFL of first baroclinic gravity wave = dt*cg1*/dy', 'nondim')
1339  cs%id_cg_ebt = register_diag_field('ocean_model', 'cg_ebt', diag%axesT1, time, &
1340  'Equivalent barotropic gravity wave speed', 'meter second-1')
1341  cs%id_Rd_ebt = register_diag_field('ocean_model', 'Rd_ebt', diag%axesT1, time, &
1342  'Equivalent barotropic deformation radius', 'meter')
1343  cs%id_p_ebt = register_diag_field('ocean_model', 'p_ebt', diag%axesTL, time, &
1344  'Equivalent barotropic modal strcuture', 'nondim')
1345 
1346  if ((cs%id_cg1>0) .or. (cs%id_Rd1>0) .or. (cs%id_cfl_cg1>0) .or. &
1347  (cs%id_cfl_cg1_x>0) .or. (cs%id_cfl_cg1_y>0) .or. &
1348  (cs%id_cg_ebt>0) .or. (cs%id_Rd_ebt>0) .or. (cs%id_p_ebt>0)) then
1349  call wave_speed_init(cs%wave_speed_CSp)
1350  call safe_alloc_ptr(cs%cg1,isd,ied,jsd,jed)
1351  if (cs%id_Rd1>0) call safe_alloc_ptr(cs%Rd1,isd,ied,jsd,jed)
1352  if (cs%id_Rd_ebt>0) call safe_alloc_ptr(cs%Rd1,isd,ied,jsd,jed)
1353  if (cs%id_cfl_cg1>0) call safe_alloc_ptr(cs%cfl_cg1,isd,ied,jsd,jed)
1354  if (cs%id_cfl_cg1_x>0) call safe_alloc_ptr(cs%cfl_cg1_x,isd,ied,jsd,jed)
1355  if (cs%id_cfl_cg1_y>0) call safe_alloc_ptr(cs%cfl_cg1_y,isd,ied,jsd,jed)
1356  if (cs%id_p_ebt>0) call safe_alloc_ptr(cs%p_ebt,isd,ied,jsd,jed,nz)
1357  endif
1358 
1359  cs%id_mass_wt = register_diag_field('ocean_model', 'mass_wt', diag%axesT1, time, &
1360  'The column mass for calculating mass-weighted average properties', 'kg m-2')
1361 
1362  cs%id_temp_int = register_diag_field('ocean_model', 'temp_int', diag%axesT1, time, &
1363  'Density weighted column integrated potential temperature', 'degC kg m-2', &
1364  cmor_field_name='opottempmint', &
1365  cmor_long_name='integral_wrt_depth_of_product_of_sea_water_density_and_potential_temperature',&
1366  cmor_units='degC kg m-2', cmor_standard_name='Depth integrated density times potential temperature')
1367 
1368  cs%id_salt_int = register_diag_field('ocean_model', 'salt_int', diag%axesT1, time, &
1369  'Density weighted column integrated salinity', 'ppt kg m-2', &
1370  cmor_field_name='somint', &
1371  cmor_long_name='integral_wrt_depth_of_product_of_sea_water_density_and_salinity',&
1372  cmor_units='ppt kg m-2', cmor_standard_name='Depth integrated density times salinity')
1373 
1374  cs%id_col_mass = register_diag_field('ocean_model', 'col_mass', diag%axesT1, time, &
1375  'The column integrated in situ density', 'kg m-2')
1376 
1377  cs%id_col_ht = register_diag_field('ocean_model', 'col_height', diag%axesT1, time, &
1378  'The height of the water column', 'm')
1379  cs%id_pbo = register_diag_field('ocean_model', 'pbo', diag%axesT1, time, &
1380  long_name='Sea Water Pressure at Sea Floor', standard_name='sea_water_pressure_at_sea_floor', &
1381  units='Pa')
1382 
1383  call set_dependent_diagnostics(mis, adp, cdp, g, cs)
1384 
1385 end subroutine mom_diagnostics_init
1386 
1387 !> This subroutine sets up diagnostics upon which other diagnostics depend.
1388 subroutine set_dependent_diagnostics(MIS, ADp, CDp, G, CS)
1389  type(ocean_internal_state), intent(in) :: MIS !< For "MOM Internal State" a set of pointers to
1390  !! the fields and accelerations making up ocean
1391  !! internal physical state.
1392  type(accel_diag_ptrs), intent(inout) :: ADp !< Structure pointing to accelerations in
1393  !! momentum equation.
1394  type(cont_diag_ptrs), intent(inout) :: CDp !< Structure pointing to terms in continuity
1395  !! equation.
1396  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1397  type(diagnostics_cs), pointer :: CS !< Pointer to the control structure for this
1398  !! module.
1399 
1400 ! This subroutine sets up diagnostics upon which other diagnostics depend.
1401 ! Arguments:
1402 ! (in) MIS - For "MOM Internal State" a set of pointers to the fields and
1403 ! accelerations making up ocean internal physical state.
1404 ! (inout) ADp - structure pointing to accelerations in momentum equation
1405 ! (inout) CDp - structure pointing to terms in continuity equation
1406 ! (in) G - ocean grid structure
1407 ! (in) CS - pointer to the control structure for this module
1408 
1409  integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz
1410  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
1411  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1412 
1413  if (ASSOCIATED(cs%dKE_dt) .or. ASSOCIATED(cs%PE_to_KE) .or. &
1414  ASSOCIATED(cs%KE_CorAdv) .or. ASSOCIATED(cs%KE_adv) .or. &
1415  ASSOCIATED(cs%KE_visc) .or. ASSOCIATED(cs%KE_horvisc) .or. &
1416  ASSOCIATED(cs%KE_dia)) &
1417  call safe_alloc_ptr(cs%KE,isd,ied,jsd,jed,nz)
1418 
1419  if (ASSOCIATED(cs%dKE_dt)) then
1420  if (.not.ASSOCIATED(cs%du_dt)) then
1421  call safe_alloc_ptr(cs%du_dt,isdb,iedb,jsd,jed,nz)
1422  call register_time_deriv(mis%u, cs%du_dt, cs)
1423  endif
1424  if (.not.ASSOCIATED(cs%dv_dt)) then
1425  call safe_alloc_ptr(cs%dv_dt,isd,ied,jsdb,jedb,nz)
1426  call register_time_deriv(mis%v, cs%dv_dt, cs)
1427  endif
1428  if (.not.ASSOCIATED(cs%dh_dt)) then
1429  call safe_alloc_ptr(cs%dh_dt,isd,ied,jsd,jed,nz)
1430  call register_time_deriv(mis%h, cs%dh_dt, cs)
1431  endif
1432  endif
1433 
1434  if (ASSOCIATED(cs%KE_adv)) then
1435  call safe_alloc_ptr(adp%gradKEu,isdb,iedb,jsd,jed,nz)
1436  call safe_alloc_ptr(adp%gradKEv,isd,ied,jsdb,jedb,nz)
1437  endif
1438 
1439  if (ASSOCIATED(cs%KE_visc)) then
1440  call safe_alloc_ptr(adp%du_dt_visc,isdb,iedb,jsd,jed,nz)
1441  call safe_alloc_ptr(adp%dv_dt_visc,isd,ied,jsdb,jedb,nz)
1442  endif
1443 
1444  if (ASSOCIATED(cs%KE_dia)) then
1445  call safe_alloc_ptr(adp%du_dt_dia,isdb,iedb,jsd,jed,nz)
1446  call safe_alloc_ptr(adp%dv_dt_dia,isd,ied,jsdb,jedb,nz)
1447  endif
1448 
1449  if (ASSOCIATED(cs%uhGM_Rlay)) call safe_alloc_ptr(cdp%uhGM,isdb,iedb,jsd,jed,nz)
1450  if (ASSOCIATED(cs%vhGM_Rlay)) call safe_alloc_ptr(cdp%vhGM,isd,ied,jsdb,jedb,nz)
1451 
1452 end subroutine set_dependent_diagnostics
1453 
1454 
1455 subroutine mom_diagnostics_end(CS, ADp)
1456  type(diagnostics_cs), pointer :: CS
1457  type(accel_diag_ptrs), intent(inout) :: ADp
1458  integer :: m
1459 
1460  if (ASSOCIATED(cs%e)) deallocate(cs%e)
1461  if (ASSOCIATED(cs%e_D)) deallocate(cs%e_D)
1462  if (ASSOCIATED(cs%KE)) deallocate(cs%KE)
1463  if (ASSOCIATED(cs%dKE_dt)) deallocate(cs%dKE_dt)
1464  if (ASSOCIATED(cs%PE_to_KE)) deallocate(cs%PE_to_KE)
1465  if (ASSOCIATED(cs%KE_Coradv)) deallocate(cs%KE_Coradv)
1466  if (ASSOCIATED(cs%KE_adv)) deallocate(cs%KE_adv)
1467  if (ASSOCIATED(cs%KE_visc)) deallocate(cs%KE_visc)
1468  if (ASSOCIATED(cs%KE_horvisc)) deallocate(cs%KE_horvisc)
1469  if (ASSOCIATED(cs%KE_dia)) deallocate(cs%KE_dia)
1470  if (ASSOCIATED(cs%dv_dt)) deallocate(cs%dv_dt)
1471  if (ASSOCIATED(cs%dh_dt)) deallocate(cs%dh_dt)
1472  if (ASSOCIATED(cs%du_dt)) deallocate(cs%du_dt)
1473  if (ASSOCIATED(cs%h_Rlay)) deallocate(cs%h_Rlay)
1474  if (ASSOCIATED(cs%uh_Rlay)) deallocate(cs%uh_Rlay)
1475  if (ASSOCIATED(cs%vh_Rlay)) deallocate(cs%vh_Rlay)
1476  if (ASSOCIATED(cs%uhGM_Rlay)) deallocate(cs%uhGM_Rlay)
1477  if (ASSOCIATED(cs%vhGM_Rlay)) deallocate(cs%vhGM_Rlay)
1478  if (ASSOCIATED(cs%diag_tmp3d)) deallocate(cs%diag_tmp3d)
1479 
1480  if (ASSOCIATED(adp%gradKEu)) deallocate(adp%gradKEu)
1481  if (ASSOCIATED(adp%gradKEu)) deallocate(adp%gradKEu)
1482  if (ASSOCIATED(adp%du_dt_visc)) deallocate(adp%du_dt_visc)
1483  if (ASSOCIATED(adp%dv_dt_visc)) deallocate(adp%dv_dt_visc)
1484  if (ASSOCIATED(adp%du_dt_dia)) deallocate(adp%du_dt_dia)
1485  if (ASSOCIATED(adp%dv_dt_dia)) deallocate(adp%dv_dt_dia)
1486  if (ASSOCIATED(adp%du_other)) deallocate(adp%du_other)
1487  if (ASSOCIATED(adp%dv_other)) deallocate(adp%dv_other)
1488 
1489  do m=1,cs%num_time_deriv ; deallocate(cs%prev_val(m)%p) ; enddo
1490 
1491  deallocate(cs)
1492 
1493 end subroutine mom_diagnostics_end
1494 
1495 end module mom_diagnostics
subroutine find_weights(Rlist, R_in, k, nz, wt, wt_p)
This subroutine finds location of R_in in an increasing ordered list, Rlist, returning as k the eleme...
subroutine, public calculate_diagnostic_fields(u, v, h, uh, vh, tv, ADp, CDp, fluxes, dt, G, GV, CS, eta_bt)
Diagnostics not more naturally calculated elsewhere are computed here.
Control structure for MOM_wave_speed.
subroutine, public wave_speed_init(CS, use_ebt_mode, mono_N2_column_fraction, mono_N2_depth)
Initialize control structure for MOM_wave_speed.
subroutine, public mom_diagnostics_init(MIS, ADp, CDp, Time, G, GV, param_file, diag, CS)
This module implements boundary forcing for MOM6.
subroutine calculate_energy_diagnostics(u, v, h, uh, vh, ADp, CDp, G, CS)
This subroutine calculates terms in the mechanical energy budget.
integer function, public register_scalar_field(module_name, field_name, init_time, diag_cs, long_name, units, missing_value, range, standard_name, do_not_log, err_msg, interp_method, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name)
The module calculates interface heights, including free surface height.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides the ocean grid type.
Definition: MOM_grid.F90:2
subroutine, public do_group_pass(group, MOM_dom)
Routines for calculating baroclinic wave speeds.
The accel_diag_ptrs structure contains pointers to arrays with accelerations, which can later be used...
subroutine set_dependent_diagnostics(MIS, ADp, CDp, G, CS)
This subroutine sets up diagnostics upon which other diagnostics depend.
real function, dimension(gv %ke), public global_layer_mean(var, h, G, GV)
subroutine, public mom_diagnostics_end(CS, ADp)
The cont_diag_ptrs structure contains pointers to arrays with transports, which can later be used for...
subroutine, public register_time_deriv(f_ptr, deriv_ptr, CS)
This subroutine registers fields to calculate a diagnostic time derivative.
The ocean_internal_state structure contains pointers to all of the prognostic variables allocated in ...
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
real function, public global_volume_mean(var, h, G, GV)
subroutine, public post_data_1d_k(diag_field_id, field, diag_cs, is_static)
subroutine calculate_derivs(dt, G, CS)
This subroutine calculates all registered time derivatives.
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public wave_speed(h, tv, G, GV, cg1, CS, full_halos, use_ebt_mode, mono_N2_column_fraction, mono_N2_depth, modal_structure)
Calculates the wave speed of the first baroclinic mode.
real function, public global_area_mean(var, G)
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)
subroutine, public int_density_dz(T, S, z_t, z_b, rho_ref, rho_0, G_e, HII, HIO, EOS, dpa, intz_dpa, intx_dpa, inty_dpa)
This subroutine calculates analytical and nearly-analytical integrals of pressure anomalies across la...
Definition: MOM_EOS.F90:392
subroutine calculate_vertical_integrals(h, tv, fluxes, G, GV, CS)
Subroutine calculates vertical integrals of several tracers, along with the mass-weight of these trac...