MOM6
MOM_diag_to_Z.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, July 2006 *
26 !* *
27 !* This subroutine maps tracers and velocities into depth space *
28 !* for output as diagnostic quantities. Currently, a piecewise *
29 !* linear subgrid structure is used for tracers, while velocities can *
30 !* use either piecewise constant or piecewise linear structures. *
31 !* *
32 !* A small fragment of the grid is shown below: *
33 !* *
34 !* j+1 x ^ x ^ x At x: q, CoriolisBu *
35 !* j+1 > o > o > At ^: v *
36 !* j x ^ x ^ x At >: u *
37 !* j > o > o > At o: h, bathyT *
38 !* j-1 x ^ x ^ x *
39 !* i-1 i i+1 At x & ^: *
40 !* i i+1 At > & o: *
41 !* *
42 !* The boundaries always run through q grid points (x). *
43 !* *
44 !********+*********+*********+*********+*********+*********+*********+**
45 use mom_domains, only : pass_var
46 use mom_coms, only : reproducing_sum
48 use mom_diag_mediator, only : diag_ctrl, time_type, diag_axis_init
51 use mom_error_handler, only : mom_error, fatal, warning
53 use mom_grid, only : ocean_grid_type
54 use mom_io, only : slasher, vardesc, query_vardesc, modify_vardesc
56 use mom_variables, only : p3d, p2d
58 
59 use netcdf
60 
61 implicit none ; private
62 
63 #include <MOM_memory.h>
64 
66 public register_z_tracer
67 public mom_diag_to_z_init
69 public mom_diag_to_z_end
71 public find_overlap
72 public find_limited_slope
73 public register_zint_diag
74 public calc_zint_diags
75 
76 type, public :: diag_to_z_cs ; private
77  ! The following arrays are used to store diagnostics calculated in this
78  ! module and unavailable outside of it.
79 
80  real, pointer, dimension(:,:,:) :: &
81  u_z => null(), & ! zonal velocity remapped to depth space (m/s)
82  v_z => null(), & ! meridional velocity remapped to depth space (m/s)
83  uh_z => null(), & ! zonal transport remapped to depth space (m3/s or kg/s)
84  vh_z => null() ! meridional transport remapped to depth space (m3/s or kg/s)
85 
86  type(p3d) :: tr_z(max_fields_) ! array of tracers, remapped to depth space
87  type(p3d) :: tr_model(max_fields_) ! pointers to an array of tracers
88 
89  real :: missing_vel = -1.0e34
90  real :: missing_trans = -1.0e34
91  real :: missing_value = -1.0e34
92  real :: missing_tr(max_fields_) = -1.0e34
93 
94  integer :: id_u_z = -1
95  integer :: id_v_z = -1
96  integer :: id_uh_z = -1
97  integer :: id_vh_z = -1
98  integer :: id_tr(max_fields_) = -1
99  integer :: id_tr_xyave(max_fields_) = -1
100  integer :: num_tr_used = 0
101  integer :: nk_zspace = -1
102 
103  real, pointer :: z_int(:) => null() ! interface depths of the z-space file (meter)
104 
105  type(axes_grp) :: axesbz, axestz, axescuz, axescvz
106  type(axes_grp) :: axesbzi, axestzi, axescuzi, axescvzi
107  type(axes_grp) :: axesz
108  integer, dimension(1) :: axesz_out
109 
110  type(diag_ctrl), pointer :: diag ! structure to regulate diagnostic output timing
111 
112 end type diag_to_z_cs
113 
114 integer, parameter :: no_zspace = -1
115 
116 contains
117 
118 function global_z_mean(var,G,CS,tracer)
119  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
120  type(diag_to_z_cs), intent(in) :: CS
121  real, dimension(SZI_(G), SZJ_(G), CS%nk_zspace), intent(in) :: var
122  real, dimension(SZI_(G), SZJ_(G), CS%nk_zspace) :: tmpForSumming, weight
123  real, dimension(SZI_(G), SZJ_(G), CS%nk_zspace) :: localVar, valid_point, depth_weight
124  real, dimension(CS%nk_zspace) :: global_z_mean, scalarij, weightij
125  real, dimension(CS%nk_zspace) :: global_temp_scalar, global_weight_scalar
126  integer :: i, j, k, is, ie, js, je, nz, tracer
127  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ;
128  nz = cs%nk_zspace
129 
130  ! Initialize local arrays
131  valid_point = 1. ; depth_weight = 0.
132  tmpforsumming(:,:,:) = 0. ; weight(:,:,:) = 0.
133 
134  ! Local array copy of tracer field pointer
135  localvar = var
136 
137  do k=1, nz ; do j=js,je ; do i=is, ie
138  ! Weight factor for partial bottom cells
139  depth_weight(i,j,k) = min( max( (-1.*g%bathyT(i,j)), cs%Z_int(k+1) ) - cs%Z_int(k), 0.)
140 
141  ! Flag the point as invalid if it contains missing data, or is below the bathymetry
142  if (var(i,j,k) == cs%missing_tr(tracer)) valid_point(i,j,k) = 0.
143  if (depth_weight(i,j,k) == 0.) valid_point(i,j,k) = 0.
144 
145  ! If the point is flagged, set the variable itsef to zero to avoid NaNs
146  if (valid_point(i,j,k) == 0.) localvar(i,j,k) = 0.
147 
148  weight(i,j,k) = depth_weight(i,j,k) * ( (valid_point(i,j,k) * (g%areaT(i,j) * g%mask2dT(i,j))) )
149  tmpforsumming(i,j,k) = localvar(i,j,k) * weight(i,j,k)
150  enddo ; enddo ; enddo
151 
152  global_temp_scalar = reproducing_sum(tmpforsumming,sums=scalarij)
153  global_weight_scalar = reproducing_sum(weight,sums=weightij)
154 
155  do k=1, nz
156  if (scalarij(k) == 0) then
157  global_z_mean(k) = 0.0
158  else
159  global_z_mean(k) = scalarij(k) / weightij(k)
160  endif
161  enddo
162 
163 end function global_z_mean
164 
165 !> This subroutine maps tracers and velocities into depth space for diagnostics.
166 subroutine calculate_z_diag_fields(u, v, h, ssh_in, frac_shelf_h, G, GV, CS)
167  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
168  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid
169  !! structure.
170  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1.
171  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity,
172  !! in m s-1.
173  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
174  !! (usually m or kg m-2).
175  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: ssh_in !< Sea surface height
176  !! (meter or kg/m2).
177  real, dimension(:,:), pointer :: frac_shelf_h
178  type(diag_to_z_cs), pointer :: CS !< Control structure returned by
179  !! previous call to
180  !! diagnostics_init.
181 
182 ! This subroutine maps tracers and velocities into depth space for diagnostics.
183 
184 ! Arguments:
185 ! (in) u - zonal velocity component (m/s)
186 ! (in) v - meridional velocity component (m/s)
187 ! (in) h - layer thickness (meter or kg/m2)
188 ! (in) ssh_in - sea surface height (meter or kg/m2)
189 ! (in) G - ocean grid structure
190 ! (in) GV - The ocean's vertical grid structure.
191 ! (in) CS - control structure returned by previous call to diagnostics_init
192 
193  ! Note the deliberately reversed axes in h_f, u_f, v_f, and tr_f.
194  real :: ssh(szi_(g),szj_(g)) ! copy of ssh_in (meter or kg/m2)
195  real :: e(szk_(g)+2) ! z-star interface heights (meter or kg/m2)
196  real :: h_f(szk_(g)+1,szi_(g)) ! thicknesses of massive layers (meter or kg/m2)
197  real :: u_f(szk_(g)+1,szib_(g))! zonal velocity component in any massive layer
198  real :: v_f(szk_(g)+1,szi_(g)) ! meridional velocity component in any massive layer
199 
200  real :: tr_f(szk_(g),max(cs%num_tr_used,1),szi_(g)) ! tracer concentration in massive layers
201  integer :: nk_valid(szib_(g)) ! number of massive layers in a column
202 
203  real :: D_pt(szib_(g)) ! bottom depth (meter or kg/m2)
204  real :: shelf_depth(szib_(g)) ! ice shelf depth (meter or kg/m2)
205  real :: htot ! summed layer thicknesses (meter or kg/m2)
206  real :: dilate ! proportion by which to dilate every layer
207  real :: wt(szk_(g)+1) ! fractional weight for each layer in the
208  ! range between k_top and k_bot (nondim)
209  real :: z1(szk_(g)+1) ! z1 and z2 are the depths of the top and bottom
210  real :: z2(szk_(g)+1) ! limits of the part of a layer that contributes
211  ! to a depth level, relative to the cell center
212  ! and normalized by the cell thickness (nondim)
213  ! Note that -1/2 <= z1 < z2 <= 1/2.
214  real :: sl_tr(max(cs%num_tr_used,1)) ! normalized slope of the tracer
215  ! within the cell, in tracer units
216  real :: Angstrom ! A minimal layer thickness, in H.
217  real :: slope ! normalized slope of a variable within the cell
218 
219  real :: layer_ave(cs%nk_zspace)
220 
221  logical :: linear_velocity_profiles, ice_shelf
222 
223  integer :: k_top, k_bot, k_bot_prev
224  integer :: i, j, k, k2, kz, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nk, m, nkml
225  integer :: IsgB, IegB, JsgB, JegB
226  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nk = g%ke
227  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
228  isgb = g%IsgB ; iegb = g%IegB ; jsgb = g%JsgB ; jegb = g%JegB
229  nkml = max(gv%nkml, 1)
230  angstrom = gv%Angstrom
231  ssh(:,:) = ssh_in
232  linear_velocity_profiles = .true.
233  ! Update the halos
234  call pass_var(ssh, g%Domain)
235 
236  if (.not.associated(cs)) call mom_error(fatal, &
237  "diagnostic_fields_zstar: Module must be initialized before it is used.")
238 
239  ice_shelf = associated(frac_shelf_h)
240 
241  ! If no fields are needed, return
242  if ((cs%id_u_z <= 0) .and. (cs%id_v_z <= 0) .and. (cs%num_tr_used < 1)) return
243 
244  ! zonal velocity component
245  if (cs%id_u_z > 0) then
246 
247  do kz=1,cs%nk_zspace ; do j=js,je ; do i=isq,ieq
248  cs%u_z(i,j,kz) = cs%missing_vel
249  enddo ; enddo ; enddo
250 
251 
252  do j=js,je
253  shelf_depth(:) = 0. ! initially all is open ocean
254  ! Remove all massless layers.
255  do i=isq,ieq
256  nk_valid(i) = 0
257  d_pt(i) = 0.5*(g%bathyT(i+1,j)+g%bathyT(i,j))
258  if (ice_shelf) then
259  if (frac_shelf_h(i,j)+frac_shelf_h(i+1,j) > 0.) then ! under shelf
260  shelf_depth(i) = abs(0.5*(ssh(i+1,j)+ssh(i,j)))
261  endif
262  endif
263  enddo
264  do k=1,nk ; do i=isq,ieq
265  if ((g%mask2dCu(i,j) > 0.5) .and. (h(i,j,k)+h(i+1,j,k) > 4.0*angstrom)) then
266  nk_valid(i) = nk_valid(i) + 1 ; k2 = nk_valid(i)
267  h_f(k2,i) = 0.5*(h(i,j,k)+h(i+1,j,k)) ; u_f(k2,i) = u(i,j,k)
268  endif
269  enddo ; enddo
270  do i=isq,ieq ; if (g%mask2dCu(i,j) > 0.5) then
271  ! Add an Angstrom thick layer at the bottom with 0 velocity to impose a
272  ! no-slip BBC in the output, if anything but piecewise constant is used.
273  nk_valid(i) = nk_valid(i) + 1 ; k2 = nk_valid(i)
274  h_f(k2,i) = angstrom ; u_f(k2,i) = 0.0
275  ! GM: D_pt is always slightly larger (by 1E-6 or so) than shelf_depth, so
276  ! I consider that the ice shelf is grounded when
277  ! shelf_depth(I) + 1.0E-3 > D_pt(i)
278  if (ice_shelf .and. shelf_depth(i) + 1.0e-3 > d_pt(i)) nk_valid(i)=0
279  endif ; enddo
280 
281 
282  do i=isq,ieq ; if (nk_valid(i) > 0) then
283  ! Calculate the z* interface heights for tracers.
284  htot = 0.0 ; do k=1,nk_valid(i) ; htot = htot + h_f(k,i) ; enddo
285  dilate = 0.0
286  if (htot*gv%H_to_m > 2.0*angstrom) then
287  dilate = max((d_pt(i) - shelf_depth(i)),angstrom)/htot
288  endif
289  e(nk_valid(i)+1) = -d_pt(i)
290  do k=nk_valid(i),1,-1 ; e(k) = e(k+1) + h_f(k,i)*dilate ; enddo
291 
292  ! Interpolate each variable into depth space.
293  k_bot = 1 ; k_bot_prev = -1
294  do kz=1,cs%nk_zspace
295  call find_overlap(e, cs%Z_int(kz), cs%Z_int(kz+1), nk_valid(i), &
296  k_bot, k_top, k_bot, wt, z1, z2)
297  if (k_top>nk_valid(i)) exit
298 
299  !GM if top range that is being map is below the shelf, interpolate
300  ! otherwise keep missing_vel
301  if (cs%Z_int(kz)<=-shelf_depth(i)) then
302 
303  if (linear_velocity_profiles) then
304  k = k_top
305  if (k /= k_bot_prev) then
306  ! Calculate the intra-cell profile.
307  slope = 0.0 ! ; curv = 0.0
308  if ((k < nk_valid(i)) .and. (k > nkml)) call &
309  find_limited_slope(u_f(:,i), e, slope, k)
310  endif
311  ! This is the piecewise linear form.
312  cs%u_z(i,j,kz) = wt(k) * (u_f(k,i) + 0.5*slope*(z2(k) + z1(k)))
313  ! For the piecewise parabolic form add the following...
314  ! + C1_3*curv*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
315  do k=k_top+1,k_bot-1
316  cs%u_z(i,j,kz) = cs%u_z(i,j,kz) + wt(k)*u_f(k,i)
317  enddo
318  if (k_bot > k_top) then ; k = k_bot
319  ! Calculate the intra-cell profile.
320  slope = 0.0 ! ; curv = 0.0
321  if ((k < nk_valid(i)) .and. (k > nkml)) call &
322  find_limited_slope(u_f(:,i), e, slope, k)
323  ! This is the piecewise linear form.
324  cs%u_z(i,j,kz) = cs%u_z(i,j,kz) + wt(k) * &
325  (u_f(k,i) + 0.5*slope*(z2(k) + z1(k)))
326  ! For the piecewise parabolic form add the following...
327  ! + C1_3*curv*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
328  endif
329  k_bot_prev = k_bot
330  else ! Use piecewise constant profiles.
331  cs%u_z(i,j,kz) = wt(k_top)*u_f(k_top,i)
332  do k=k_top+1,k_bot
333  cs%u_z(i,j,kz) = cs%u_z(i,j,kz) + wt(k)*u_f(k,i)
334  enddo
335  endif ! linear profiles
336  endif ! below shelf
337  enddo ! kz-loop
338  endif ; enddo ! I-loop and mask
339  enddo ! j-loop
340 
341  call post_data(cs%id_u_z, cs%u_z, cs%diag)
342  endif
343 
344  ! meridional velocity component
345  if (cs%id_v_z > 0) then
346  do kz=1,cs%nk_zspace ; do j=jsq,jeq ; do i=is,ie
347  cs%v_z(i,j,kz) = cs%missing_vel
348  enddo ; enddo ; enddo
349 
350  do j=jsq,jeq
351  shelf_depth(:) = 0.0 ! initially all is open ocean
352  ! Remove all massless layers.
353  do i=is,ie
354  nk_valid(i) = 0 ; d_pt(i) = 0.5*(g%bathyT(i,j)+g%bathyT(i,j+1))
355  if (ice_shelf) then
356  if (frac_shelf_h(i,j)+frac_shelf_h(i,j+1) > 0.) then ! under shelf
357  shelf_depth(i) = abs(0.5*(ssh(i,j)+ssh(i,j+1)))
358  endif
359  endif
360  enddo
361  do k=1,nk ; do i=is,ie
362  if ((g%mask2dCv(i,j) > 0.5) .and. (h(i,j,k)+h(i,j+1,k) > 4.0*angstrom)) then
363  nk_valid(i) = nk_valid(i) + 1 ; k2 = nk_valid(i)
364  h_f(k2,i) = 0.5*(h(i,j,k)+h(i,j+1,k)) ; v_f(k2,i) = v(i,j,k)
365  endif
366  enddo ; enddo
367  do i=is,ie ; if (g%mask2dCv(i,j) > 0.5) then
368  ! Add an Angstrom thick layer at the bottom with 0 velocity to impose a
369  ! no-slip BBC in the output, if anything but piecewise constant is used.
370  nk_valid(i) = nk_valid(i) + 1 ; k2 = nk_valid(i)
371  h_f(k2,i) = angstrom ; v_f(k2,i) = 0.0
372  if (ice_shelf .and. shelf_depth(i) + 1.0e-3 > d_pt(i)) nk_valid(i)=0
373  endif ; enddo
374 
375  do i=is,ie ; if (nk_valid(i) > 0) then
376  ! Calculate the z* interface heights for tracers.
377  htot = 0.0 ; do k=1,nk_valid(i) ; htot = htot + h_f(k,i) ; enddo
378  dilate = 0.0
379  if (htot > 2.0*angstrom) then
380  dilate = max((d_pt(i) - shelf_depth(i)),angstrom)/htot
381  endif
382  e(nk_valid(i)+1) = -d_pt(i)
383  do k=nk_valid(i),1,-1 ; e(k) = e(k+1) + h_f(k,i)*dilate ; enddo
384 
385  ! Interpolate each variable into depth space.
386  k_bot = 1 ; k_bot_prev = -1
387  do kz=1,cs%nk_zspace
388  call find_overlap(e, cs%Z_int(kz), cs%Z_int(kz+1), nk_valid(i), &
389  k_bot, k_top, k_bot, wt, z1, z2)
390  if (k_top>nk_valid(i)) exit
391  !GM if top range that is being map is below the shelf, interpolate
392  ! otherwise keep missing_vel
393  if (cs%Z_int(kz)<=-shelf_depth(i)) then
394  if (linear_velocity_profiles) then
395  k = k_top
396  if (k /= k_bot_prev) then
397  ! Calculate the intra-cell profile.
398  slope = 0.0 ! ; curv = 0.0
399  if ((k < nk_valid(i)) .and. (k > nkml)) call &
400  find_limited_slope(v_f(:,i), e, slope, k)
401  endif
402  ! This is the piecewise linear form.
403  cs%v_z(i,j,kz) = wt(k) * (v_f(k,i) + 0.5*slope*(z2(k) + z1(k)))
404  ! For the piecewise parabolic form add the following...
405  ! + C1_3*curv*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
406  do k=k_top+1,k_bot-1
407  cs%v_z(i,j,kz) = cs%v_z(i,j,kz) + wt(k)*v_f(k,i)
408  enddo
409  if (k_bot > k_top) then ; k = k_bot
410  ! Calculate the intra-cell profile.
411  slope = 0.0 ! ; curv = 0.0
412  if ((k < nk_valid(i)) .and. (k > nkml)) call &
413  find_limited_slope(v_f(:,i), e, slope, k)
414  ! This is the piecewise linear form.
415  cs%v_z(i,j,kz) = cs%v_z(i,j,kz) + wt(k) * &
416  (v_f(k,i) + 0.5*slope*(z2(k) + z1(k)))
417  ! For the piecewise parabolic form add the following...
418  ! + C1_3*curv*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
419  endif
420  k_bot_prev = k_bot
421  else ! Use piecewise constant profiles.
422  cs%v_z(i,j,kz) = wt(k_top)*v_f(k_top,i)
423  do k=k_top+1,k_bot
424  cs%v_z(i,j,kz) = cs%v_z(i,j,kz) + wt(k)*v_f(k,i)
425  enddo
426  endif ! linear profiles
427  endif ! below shelf
428  enddo ! kz-loop
429  endif ; enddo ! i-loop and mask
430  enddo ! J-loop
431 
432  call post_data(cs%id_v_z, cs%v_z, cs%diag)
433  endif
434 
435  ! tracer concentrations
436  if (cs%num_tr_used > 0) then
437 
438  do m=1,cs%num_tr_used ; do kz=1,cs%nk_zspace ; do j=js,je ; do i=is,ie
439  cs%tr_z(m)%p(i,j,kz) = cs%missing_tr(m)
440  enddo ; enddo ; enddo ; enddo
441 
442  do j=js,je
443  shelf_depth(:) = 0.0 ! initially all is open ocean
444  ! Remove all massless layers.
445  do i=is,ie
446  nk_valid(i) = 0 ; d_pt(i) = g%bathyT(i,j)
447  if (ice_shelf) then
448  if (frac_shelf_h(i,j) > 0.) then ! under shelf
449  shelf_depth(i) = abs(ssh(i,j))
450  endif
451  endif
452  enddo
453  do k=1,nk ; do i=is,ie
454  if ((g%mask2dT(i,j) > 0.5) .and. (h(i,j,k) > 2.0*angstrom)) then
455  nk_valid(i) = nk_valid(i) + 1 ; k2 = nk_valid(i)
456  h_f(k2,i) = h(i,j,k)
457  if (ice_shelf .and. shelf_depth(i) + 1.0e-3 > d_pt(i)) nk_valid(i)=0
458  do m=1,cs%num_tr_used ; tr_f(k2,m,i) = cs%tr_model(m)%p(i,j,k) ; enddo
459  endif
460  enddo ; enddo
461 
462  do i=is,ie ; if (nk_valid(i) > 0) then
463  ! Calculate the z* interface heights for tracers.
464  htot = 0.0 ; do k=1,nk_valid(i) ; htot = htot + h_f(k,i) ; enddo
465  dilate = 0.0
466  if (htot > 2.0*angstrom) then
467  dilate = max((d_pt(i) - shelf_depth(i)),angstrom)/htot
468  endif
469  e(nk_valid(i)+1) = -d_pt(i)
470  do k=nk_valid(i),1,-1 ; e(k) = e(k+1) + h_f(k,i)*dilate ; enddo
471 
472  ! Interpolate each variable into depth space.
473  k_bot = 1 ; k_bot_prev = -1
474  do kz=1,cs%nk_zspace
475  call find_overlap(e, cs%Z_int(kz), cs%Z_int(kz+1), nk_valid(i), &
476  k_bot, k_top, k_bot, wt, z1, z2)
477  if (k_top>nk_valid(i)) exit
478  if (cs%Z_int(kz)<=-shelf_depth(i)) then
479  do m=1,cs%num_tr_used
480  k = k_top
481  if (k /= k_bot_prev) then
482  ! Calculate the intra-cell profile.
483  sl_tr(m) = 0.0 ! ; cur_tr(m) = 0.0
484  if ((k < nk_valid(i)) .and. (k > nkml)) call &
485  find_limited_slope(tr_f(:,m,i), e, sl_tr(m), k)
486  endif
487  ! This is the piecewise linear form.
488  cs%tr_z(m)%p(i,j,kz) = wt(k) * &
489  (tr_f(k,m,i) + 0.5*sl_tr(m)*(z2(k) + z1(k)))
490  ! For the piecewise parabolic form add the following...
491  ! + C1_3*cur_tr(m)*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
492  do k=k_top+1,k_bot-1
493  cs%tr_z(m)%p(i,j,kz) = cs%tr_z(m)%p(i,j,kz) + wt(k)*tr_f(k,m,i)
494  enddo
495  if (k_bot > k_top) then
496  k = k_bot
497  ! Calculate the intra-cell profile.
498  sl_tr(m) = 0.0 ! ; cur_tr(m) = 0.0
499  if ((k < nk_valid(i)) .and. (k > nkml)) call &
500  find_limited_slope(tr_f(:,m,i), e, sl_tr(m), k)
501  ! This is the piecewise linear form.
502  cs%tr_z(m)%p(i,j,kz) = cs%tr_z(m)%p(i,j,kz) + wt(k) * &
503  (tr_f(k,m,i) + 0.5*sl_tr(m)*(z2(k) + z1(k)))
504  ! For the piecewise parabolic form add the following...
505  ! + C1_3*cur_tr(m)*(z2(k)**2 + z2(k)*z1(k) + z1(k)**2))
506  endif
507  enddo
508  k_bot_prev = k_bot
509  endif ! below shelf
510  enddo ! kz-loop
511  endif ; enddo ! i-loop and mask
512 
513  enddo ! j-loop
514 
515  do m=1,cs%num_tr_used
516  if (cs%id_tr(m) > 0) call post_data(cs%id_tr(m), cs%tr_z(m)%p, cs%diag)
517  if (cs%id_tr_xyave(m) > 0) then
518  layer_ave = global_z_mean(cs%tr_z(m)%p,g,cs,m)
519  call post_data_1d_k(cs%id_tr_xyave(m), layer_ave, cs%diag)
520  endif
521  enddo
522  endif
523 
524 end subroutine calculate_z_diag_fields
525 
526 !> This subroutine maps horizontal transport into depth space for diagnostic output.
527 subroutine calculate_z_transport(uh_int, vh_int, h, dt, G, GV, CS)
528  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
529  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid
530  !! structure.
531  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: uh_int !< Time integrated zonal
532  !! transport (m3 or kg).
533  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: vh_int !< Time integrated meridional
534  !! transport (m3 or kg).
535  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
536  !! (usually m or kg m-2).
537  real, intent(in) :: dt !< The time difference in s since
538  !! the last call to this
539  !! subroutine.
540  type(diag_to_z_cs), pointer :: CS !< Control structure returned by
541  !! previous call to
542  !! diagnostics_init.
543 
544 ! This subroutine maps horizontal transport into depth space for diagnostic output.
545 
546 ! Arguments:
547 ! (in) uh_int - time integrated zonal transport (m3 or kg)
548 ! (in) vh_int - time integrated meridional transport (m3 or kg)
549 ! (in) h - layer thickness (meter or kg/m2)
550 ! (in) dt - time difference (sec) since last call to this routine
551 ! (in) G - ocean grid structure
552 ! (in) GV - The ocean's vertical grid structure
553 ! (in) CS - control structure returned by previous call to diagnostics_init
554 
555  real, dimension(SZI_(G), SZJ_(G)) :: &
556  htot, & ! total layer thickness (meter or kg/m2)
557  dilate ! nondimensional factor by which to dilate layers to
558  ! convert them into z* space. (-G%D < z* < 0)
559 
560  real, dimension(SZI_(G), max(CS%nk_zspace,1)) :: &
561  uh_Z ! uh_int interpolated into depth space (m3 or kg)
562  real, dimension(SZIB_(G), max(CS%nk_zspace,1)) :: &
563  vh_Z ! vh_int interpolated into depth space (m3 or kg)
564 
565  real :: h_rem ! dilated thickness of a layer that has yet to be mapped
566  ! into depth space (meter or kg/m2)
567  real :: uh_rem ! integrated zonal transport of a layer that has yet to be
568  ! mapped into depth space (m3 or kg)
569  real :: vh_rem ! integrated meridional transport of a layer that has yet
570  ! to be mapped into depth space (m3 or kg)
571  real :: h_here ! thickness of a layer that is within the range of the
572  ! current depth level (meter or kg/m2)
573  real :: h_above ! thickness of a layer that is above the current depth
574  ! level (meter or kg.m2)
575  real :: uh_here ! zonal transport of a layer that is attributed to the
576  ! current depth level (m3 or kg)
577  real :: vh_here ! meridional transport of a layer that is attributed to
578  ! the current depth level (m3 or kg)
579  real :: Idt ! inverse of the time step (sec)
580 
581  real :: Z_int_above(szib_(g)) ! height of the interface atop a layer (meter or kg/m2)
582 
583  integer :: kz(szib_(g)) ! index of depth level that is being contributed to
584 
585  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nk, nk_z
586  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nk = g%ke
587  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
588 
589  if (.not.associated(cs)) call mom_error(fatal, &
590  "calculate_Z_transport: Module must be initialized before it is used.")
591  if ((cs%id_uh_Z <= 0) .and. (cs%id_vh_Z <= 0)) return
592 
593  idt = 1.0 ; if (dt > 0.0) idt = 1.0 / dt
594  nk_z = cs%nk_zspace
595 
596  if (nk_z <= 0) return
597 
598  ! Determine how much the layers will be dilated in recasting them into z*
599  ! coordiantes. (-G%D < z* < 0).
600  do j=jsq,jeq+1 ; do i=isq,ieq+1
601  htot(i,j) = gv%H_subroundoff
602  enddo ; enddo
603  do k=1,nk ; do j=jsq,jeq+1 ; do i=isq,ieq+1
604  htot(i,j) = htot(i,j) + h(i,j,k)
605  enddo ; enddo ; enddo
606  do j=jsq,jeq+1 ; do i=isq,ieq+1
607  dilate(i,j) = g%bathyT(i,j) / htot(i,j)
608  enddo ; enddo
609 
610  ! zonal transport
611  if (cs%id_uh_Z > 0) then ; do j=js,je
612  do i=isq,ieq
613  kz(i) = nk_z ; z_int_above(i) = -0.5*(g%bathyT(i,j)+g%bathyT(i+1,j))
614  enddo
615  do k=nk_z,1,-1 ; do i=isq,ieq
616  uh_z(i,k) = 0.0
617  if (cs%Z_int(k) < z_int_above(i)) kz(i) = k-1
618  enddo ; enddo
619  do k=nk,1,-1 ; do i=isq,ieq
620  h_rem = 0.5*(dilate(i,j)*h(i,j,k) + dilate(i+1,j)*h(i+1,j,k))
621  uh_rem = uh_int(i,j,k)
622  z_int_above(i) = z_int_above(i) + h_rem
623 
624  do ! Distribute this layer's transport into the depth-levels.
625  h_above = z_int_above(i) - cs%Z_int(kz(i))
626  if ((kz(i) == 1) .or. (h_above <= 0.0) .or. (h_rem <= 0.0)) then
627  ! The entire remaining transport is on this level.
628  uh_z(i,kz(i)) = uh_z(i,kz(i)) + uh_rem ; exit
629  else
630  h_here = h_rem - h_above
631  uh_here = uh_rem * (h_here / h_rem)
632 
633  h_rem = h_rem - h_here ! = h_above
634  uh_z(i,kz(i)) = uh_z(i,kz(i)) + uh_here
635  uh_rem = uh_rem - uh_here
636  kz(i) = kz(i) - 1
637  endif
638  enddo ! End of loop through the target depth-space levels.
639  enddo ; enddo
640  do k=1,nk_z ; do i=isq,ieq
641  cs%uh_z(i,j,k) = uh_z(i,k)*idt
642  enddo ; enddo
643  enddo ; endif
644 
645  ! meridional transport
646  if (cs%id_vh_Z > 0) then ; do j=jsq,jeq
647  do i=is,ie
648  kz(i) = nk_z ; z_int_above(i) = -0.5*(g%bathyT(i,j)+g%bathyT(i,j+1))
649  enddo
650  do k=nk_z,1,-1 ; do i=is,ie
651  vh_z(i,k) = 0.0
652  if (cs%Z_int(k) < z_int_above(i)) kz(i) = k-1
653  enddo ; enddo
654  do k=nk,1,-1 ; do i=is,ie
655  h_rem = 0.5*(dilate(i,j)*h(i,j,k) + dilate(i,j+1)*h(i,j+1,k))
656  vh_rem = vh_int(i,j,k)
657  z_int_above(i) = z_int_above(i) + h_rem
658 
659  do ! Distribute this layer's transport into the depth-levels.
660  h_above = z_int_above(i) - cs%Z_int(kz(i))
661  if ((kz(i) == 1) .or. (h_above <= 0.0) .or. (h_rem <= 0.0)) then
662  ! The entire remaining transport is on this level.
663  vh_z(i,kz(i)) = vh_z(i,kz(i)) + vh_rem ; exit
664  else
665  h_here = h_rem - h_above
666  vh_here = vh_rem * (h_here / h_rem)
667 
668  h_rem = h_rem - h_here ! = h_above
669  vh_z(i,kz(i)) = vh_z(i,kz(i)) + vh_here
670  vh_rem = vh_rem - vh_here
671  kz(i) = kz(i) - 1
672  endif
673  enddo ! End of loop through the target depth-space levels.
674  enddo ; enddo
675  do k=1,nk_z ; do i=is,ie
676  cs%vh_z(i,j,k) = vh_z(i,k)*idt
677  enddo ; enddo
678  enddo ; endif
679 
680  if (cs%id_uh_Z > 0) then
681  do k=1,nk_z ; do j=js,je ; do i=isq,ieq
682  cs%uh_z(i,j,k) = cs%uh_z(i,j,k)*gv%H_to_kg_m2
683  enddo ; enddo ; enddo
684  call post_data(cs%id_uh_Z, cs%uh_z, cs%diag)
685  endif
686 
687  if (cs%id_vh_Z > 0) then
688  do k=1,nk_z ; do j=jsq,jeq ; do i=is,ie
689  cs%vh_z(i,j,k) = cs%vh_z(i,j,k)*gv%H_to_kg_m2
690  enddo ; enddo ; enddo
691  call post_data(cs%id_vh_Z, cs%vh_z, cs%diag)
692  endif
693 
694 end subroutine calculate_z_transport
695 
696 !> This subroutine determines the layers bounded by interfaces e that overlap
697 !! with the depth range between Z_top and Z_bot, and the fractional weights
698 !! of each layer. It also calculates the normalized relative depths of the range
699 !! of each layer that overlaps that depth range.
700 subroutine find_overlap(e, Z_top, Z_bot, k_max, k_start, k_top, k_bot, wt, z1, z2)
701  real, dimension(:), intent(in) :: e !< Column interface heights (meter or kg/m2).
702  real, intent(in) :: Z_top !< Top of range being mapped to (meter or kg/m2).
703  real, intent(in) :: Z_bot !< Bottom of range being mapped to (meter or kg/m2).
704  integer, intent(in) :: k_max !< Number of valid layers.
705  integer, intent(in) :: k_start !< Layer at which to start searching.
706  integer, intent(inout) :: k_top !< Indices of top layers that overlap with the depth
707  !! range.
708  integer, intent(inout) :: k_bot !< Indices of bottom layers that overlap with the
709  !! depth range.
710  real, dimension(:), intent(out) :: wt !< Relative weights of each layer from k_top to k_bot.
711  real, dimension(:), intent(out) :: z1, z2 !< Depths of the top and bottom limits of the part of
712  !! a layer that contributes to a depth level, relative to the cell center and normalized
713  !! by the cell thickness (nondim). Note that -1/2 <= z1 < z2 <= 1/2.
714 
715 ! This subroutine determines the layers bounded by interfaces e that overlap
716 ! with the depth range between Z_top and Z_bot, and the fractional weights
717 ! of each layer. It also calculates the normalized relative depths of the range
718 ! of each layer that overlaps that depth range.
719 
720 ! Note that by convention, e decreases with increasing k and Z_top > Z_bot.
721 !
722 ! Arguments:
723 ! (in) e - column interface heights (meter or kg/m2)
724 ! (in) Z_top - top of range being mapped to (meter or kg/m2)
725 ! (in) Z_bot - bottom of range being mapped to (meter or kg/m2)
726 ! (in) k_max - number of valid layers
727 ! (in) k_start - layer at which to start searching
728 ! (out) k_top, k_bot - indices of top and bottom layers that
729 ! overlap with the depth range
730 ! (out) wt - relative weights of each layer from k_top to k_bot
731 ! (out) z1, z2 - depths of the top and bottom limits of
732 ! the part of a layer that contributes to a depth level,
733 ! relative to the cell center and normalized by the cell
734 ! thickness (nondim). Note that -1/2 <= z1 < z2 <= 1/2.
735 
736  real :: Ih, e_c, tot_wt, I_totwt
737  integer :: k
738 
739  do k=k_start,k_max ; if (e(k+1)<z_top) exit ; enddo
740  k_top = k
741  if (k>k_max) return
742 
743  ! Determine the fractional weights of each layer.
744  ! Note that by convention, e and Z_int decrease with increasing k.
745  if (e(k+1)<=z_bot) then
746  wt(k) = 1.0 ; k_bot = k
747  ih = 1.0 / (e(k)-e(k+1))
748  e_c = 0.5*(e(k)+e(k+1))
749  z1(k) = (e_c - min(e(k),z_top)) * ih
750  z2(k) = (e_c - z_bot) * ih
751  else
752  wt(k) = min(e(k),z_top) - e(k+1) ; tot_wt = wt(k) ! These are always > 0.
753  z1(k) = (0.5*(e(k)+e(k+1)) - min(e(k),z_top)) / (e(k)-e(k+1))
754  z2(k) = 0.5
755  k_bot = k_max
756  do k=k_top+1,k_max
757  if (e(k+1)<=z_bot) then
758  k_bot = k
759  wt(k) = e(k) - z_bot ; z1(k) = -0.5
760  z2(k) = (0.5*(e(k)+e(k+1)) - z_bot) / (e(k)-e(k+1))
761  else
762  wt(k) = e(k) - e(k+1) ; z1(k) = -0.5 ; z2(k) = 0.5
763  endif
764  tot_wt = tot_wt + wt(k) ! wt(k) is always > 0.
765  if (k>=k_bot) exit
766  enddo
767 
768  i_totwt = 1.0 / tot_wt
769  do k=k_top,k_bot ; wt(k) = i_totwt*wt(k) ; enddo
770  endif
771 
772 end subroutine find_overlap
773 
774 !> This subroutine determines a limited slope for val to be advected with
775 !! a piecewise limited scheme.
776 subroutine find_limited_slope(val, e, slope, k)
777  real, dimension(:), intent(in) :: val !< A column of values that are being interpolated.
778  real, dimension(:), intent(in) :: e !< Column interface heights (meter or kg/m2).
779  real, intent(out) :: slope !< Normalized slope in the intracell distribution of val.
780  integer, intent(in) :: k !< Layer whose slope is being determined.
781 
782 ! This subroutine determines a limited slope for val to be advected with
783 ! a piecewise limited scheme.
784 
785 ! Arguments:
786 ! (in) val - a column of values that are being interpolated
787 ! (in) e - column interface heights (meter or kg/m2)
788 ! (in) slope - normalized slope in the intracell distribution of val
789 ! (in) k - layer whose slope is being determined
790 
791  real :: d1, d2
792 
793  if ((val(k)-val(k-1)) * (val(k)-val(k+1)) >= 0.0) then
794  slope = 0.0 ! ; curvature = 0.0
795  else
796  d1 = 0.5*(e(k-1)-e(k+1)) ; d2 = 0.5*(e(k)-e(k+2))
797  slope = (d1**2*(val(k+1) - val(k)) + d2**2*(val(k) - val(k-1))) * &
798  ((e(k) - e(k+1)) / (d1*d2*(d1+d2)))
799  ! slope = 0.5*(val(k+1) - val(k-1))
800  ! This is S.J. Lin's form of the PLM limiter.
801  slope = sign(1.0,slope) * min(abs(slope), &
802  2.0*(max(val(k-1),val(k),val(k+1)) - val(k)), &
803  2.0*(val(k) - min(val(k-1),val(k),val(k+1))))
804  ! curvature = 0.0
805  endif
806 
807 end subroutine find_limited_slope
808 
809 ! #@# This subroutine needs a doxygen description
810 subroutine calc_zint_diags(h, in_ptrs, ids, num_diags, G, GV, CS)
811  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
812  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H
813  !! (usually m or kg m-2).
814  type(p3d), dimension(:), intent(in) :: in_ptrs
815  integer, dimension(:), intent(in) :: ids
816  integer, intent(in) :: num_diags
817  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid
818  !! structure.
819  type(diag_to_z_cs), pointer :: CS
820 
821  real, dimension(SZI_(G),SZJ_(G),max(CS%nk_zspace+1,1),max(num_diags,1)) :: &
822  diag_on_Z ! diagnostics interpolated to depth space
823  real, dimension(SZI_(G),SZK_(G)+1) :: e
824  real, dimension(max(num_diags,1),SZI_(G),SZK_(G)+1) :: diag2d
825 
826  real, dimension(SZI_(G)) :: &
827  htot, & ! summed layer thicknesses (meter or kg/m2)
828  dilate ! proportion by which to dilate every layer
829  real :: wt ! weighting of the interface above in the
830  ! interpolation to target depths
831  integer :: kL(szi_(g)) ! layer-space index of shallowest interface
832  ! below the target depth
833 
834  integer :: i, j, k, k2, kz, is, ie, js, je, nk, m
835  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nk = g%ke
836 
837  if (num_diags < 1) return
838  if (.not.associated(cs)) call mom_error(fatal, &
839  "calc_Zint_diags: Module must be initialized before it is used.")
840 
841  do j=js,je
842  ! Calculate the stretched z* interface depths.
843  do i=is,ie ; htot(i) = 0.0 ; kl(i) = 1 ; enddo
844  do k=1,nk ; do i=is,ie ; htot(i) = htot(i) + h(i,j,k) ; enddo ; enddo
845  do i=is,ie
846  dilate(i) = 0.0
847  if (htot(i)*gv%H_to_m > 0.5) dilate(i) = (g%bathyT(i,j) - 0.0) / htot(i)
848  e(i,nk+1) = -g%bathyT(i,j)
849  enddo
850  do k=nk,1,-1 ; do i=is,ie
851  e(i,k) = e(i,k+1) + h(i,j,k) * dilate(i)
852  enddo ; enddo
853  ! e(i,1) should be 0 as a consistency check.
854 
855  do k=1,nk+1 ; do i=is,ie ; do m=1,num_diags
856  diag2d(m,i,k) = in_ptrs(m)%p(i,j,k)
857  enddo ; enddo ; enddo
858 
859  do kz=1,cs%nk_zspace+1 ; do i=is,ie
860  ! Find the interface below the target Z-file depth, kL.
861  if (cs%Z_int(kz) < e(i,nk+1)) then
862  kl(i) = nk+2
863  else
864  do k=kl(i),nk+1 ; if (cs%Z_int(kz) > e(i,k)) exit ; enddo
865  kl(i) = k
866  endif
867  if (kl(i)>1) then
868  if (cs%Z_int(kz) > e(i,kl(i)-1)) call mom_error(fatal, &
869  "calc_Zint_diags: Interface depth mapping is incorrect.")
870  endif
871  if ((kl(i)>1) .and. (kl(i)<=nk+1)) then
872  if (e(i,kl(i)-1) == e(i,kl(i))) call mom_error(warning, &
873  "calc_Zint_diags: Interface depths equal.", all_print=.true.)
874  if (e(i,kl(i)-1) - e(i,kl(i)) < 0.0) call mom_error(fatal, &
875  "calc_Zint_diags: Interface depths inverted.")
876  endif
877 
878  if (kl(i) <= 1) then
879  do m=1,num_diags
880  diag_on_z(i,j,kz,m) = diag2d(m,i,1)
881  enddo
882  elseif (kl(i) > nk+1) then
883  do m=1,num_diags
884  diag_on_z(i,j,kz,m) = cs%missing_value
885  enddo
886  else
887  wt = 0.0 ! This probably should not happen?
888  if (e(i,kl(i)-1) - e(i,kl(i)) > 0.0) &
889  wt = (cs%Z_int(kz) - e(i,kl(i))) / (e(i,kl(i)-1) - e(i,kl(i)))
890  if ((wt < 0.0) .or. (wt > 1.0)) call mom_error(fatal, &
891  "calc_Zint_diags: Bad value of wt found.")
892  do m=1,num_diags
893  diag_on_z(i,j,kz,m) = wt * diag2d(m,i,kl(i)-1) + &
894  (1.0-wt) * diag2d(m,i,kl(i))
895  enddo
896  endif
897  enddo ; enddo
898 
899  enddo
900 
901  do m=1,num_diags
902  if (ids(m) > 0) call post_data(ids(m), diag_on_z(:,:,:,m), cs%diag)
903  enddo
904 
905 end subroutine calc_zint_diags
906 
907 !> This subroutine registers a tracer to be output in depth space.
908 subroutine register_z_tracer(tr_ptr, name, long_name, units, Time, G, CS, standard_name, &
909  cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name)
910  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
911  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
912  target, intent(in) :: tr_ptr !< Tracer for translation to Z-space.
913  character(len=*), intent(in) :: name !< name for the output tracer.
914  character(len=*), intent(in) :: long_name !< Long name for the output tracer.
915  character(len=*), intent(in) :: units !< Units of output tracer.
916  character(len=*), optional, intent(in) :: standard_name
917  type(time_type), intent(in) :: Time !< Current model time.
918  type(diag_to_z_cs), pointer :: CS !< Control struct returned by previous
919  !! call to diagnostics_init.
920  character(len=*), optional, intent(in) :: cmor_field_name !< cmor name of a field.
921  character(len=*), optional, intent(in) :: cmor_long_name !< cmor long name of a field.
922  character(len=*), optional, intent(in) :: cmor_units !< cmor units of a field.
923  character(len=*), optional, intent(in) :: cmor_standard_name !< cmor standardized name
924  !! associated with a field.
925 
926 ! This subroutine registers a tracer to be output in depth space.
927 ! Arguments:
928 ! (in) tr_ptr - tracer for translation to Z-space
929 ! (in) name - name for the output tracer
930 ! (in) long_name - long name for the output tracer
931 ! (in) units - units of output tracer
932 ! (in) Time - current model time
933 ! (in) G - ocean grid structure
934 ! (in) CS - control struct returned by previous call to diagnostics_init
935 ! (in,opt) cmor_field_name - cmor name of a field
936 ! (in,opt) cmor_long_name - cmor long name of a field
937 ! (in,opt) cmor_units - cmor units of a field
938 ! (in,opt) cmor_standard_name - cmor standardized name associated with a field
939 
940  character(len=256) :: posted_standard_name
941  character(len=256) :: posted_cmor_units
942  character(len=256) :: posted_cmor_standard_name
943  character(len=256) :: posted_cmor_long_name
944 
945  if (cs%nk_zspace<1) return
946 
947  if (present(standard_name)) then
948  posted_standard_name = standard_name
949  else
950  posted_standard_name = 'not provided'
951  endif
952 
953  call register_z_tracer_low(tr_ptr, name, long_name, units, trim(posted_standard_name), time, g, cs)
954 
955  if (present(cmor_field_name)) then
956  ! Fallback values for strings set to "NULL"
957  posted_cmor_units = "not provided" !
958  posted_cmor_standard_name = "not provided" ! values might be replaced with a CS%missing field?
959  posted_cmor_long_name = "not provided" !
960 
961  ! If attributes are present for MOM variable names, use them first for the register_diag_field
962  ! call for CMOR verison of the variable
963  posted_cmor_units = units
964  posted_cmor_long_name = long_name
965  posted_cmor_standard_name = posted_standard_name
966 
967  ! If specified in the call to register_diag_field, override attributes with the CMOR versions
968  if (present(cmor_units)) posted_cmor_units = cmor_units
969  if (present(cmor_standard_name)) posted_cmor_standard_name = cmor_standard_name
970  if (present(cmor_long_name)) posted_cmor_long_name = cmor_long_name
971 
972  call register_z_tracer_low(tr_ptr, trim(cmor_field_name), trim(posted_cmor_long_name),&
973  trim(posted_cmor_units), trim(posted_cmor_standard_name), time, g, cs)
974 
975  endif
976 
977 end subroutine register_z_tracer
978 
979 !> This subroutine registers a tracer to be output in depth space.
980 subroutine register_z_tracer_low(tr_ptr, name, long_name, units, standard_name, Time, G, CS)
981  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
982  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
983  target, intent(in) :: tr_ptr !< Tracer for translation to Z-space.
984  character(len=*), intent(in) :: name !< Name for the output tracer.
985  character(len=*), intent(in) :: long_name !< Long name for output tracer.
986  character(len=*), intent(in) :: units !< Units of output tracer.
987  character(len=*), intent(in) :: standard_name
988  type(time_type), intent(in) :: Time !< Current model time.
989  type(diag_to_z_cs), pointer :: CS !< Control struct returned by previous call to
990  !! diagnostics_init.
991 
992 ! This subroutine registers a tracer to be output in depth space.
993 
994 ! Arguments:
995 ! (in) tr_ptr - tracer for translation to Z-space
996 ! (in) name - name for the output tracer
997 ! (in) long_name - long name for output tracer
998 ! (in) units - units of output tracer
999 ! (in) Time - current model time
1000 ! (in) G - ocean grid structure
1001 ! (in) CS - control struct returned by previous call to diagnostics_init
1002 
1003  character(len=256) :: posted_standard_name
1004  integer :: isd, ied, jsd, jed, nk, m, id_test
1005  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nk = g%ke
1006 
1007  if (.not.associated(cs)) call mom_error(fatal, &
1008  "register_Z_tracer: Module must be initialized before it is used.")
1009 
1010  if (cs%num_tr_used >= max_fields_) then
1011  call mom_error(warning,"MOM_diag_to_Z: Attempted to register and use "//&
1012  "more than MAX_FIELDS_ z-space tracers via register_Z_tracer.")
1013  return
1014  endif
1015 
1016  m = cs%num_tr_used + 1
1017 
1018  cs%missing_tr(m) = cs%missing_value ! This could be changed later, if desired.
1019  if (cs%nk_zspace > 0) then
1020  cs%id_tr(m) = register_diag_field('ocean_model_zold', name, cs%axesTz, time, &
1021  long_name, units, missing_value=cs%missing_tr(m), &
1022  standard_name=standard_name)
1023  cs%id_tr_xyave(m) = register_diag_field('ocean_model_zold', name//'_xyave', cs%axesZ, time, &
1024  long_name, units, missing_value=cs%missing_tr(m), &
1025  standard_name=standard_name)
1026  else
1027  id_test = register_diag_field('ocean_model_zold', name, cs%diag%axesT1, time, &
1028  long_name, units, missing_value=cs%missing_tr(m), &
1029  standard_name=standard_name)
1030  if (id_test>0) call mom_error(warning, &
1031  "MOM_diag_to_Z_init: "//trim(name)// &
1032  " cannot be output without an appropriate depth-space target file.")
1033  endif
1034 
1035  if (cs%id_tr(m) <= 0) cs%id_tr(m) = -1
1036  if (cs%id_tr_xyave(m) <= 0) cs%id_tr_xyave(m) = -1
1037  if (cs%id_tr(m) > 0 .or. cs%id_tr_xyave(m) > 0) then
1038  cs%num_tr_used = m
1039  call safe_alloc_ptr(cs%tr_z(m)%p,isd,ied,jsd,jed,cs%nk_zspace)
1040  cs%tr_model(m)%p => tr_ptr
1041  endif
1042 
1043 end subroutine register_z_tracer_low
1044 
1045 ! #@# This subroutine needs a doxygen comment.
1046 subroutine mom_diag_to_z_init(Time, G, GV, param_file, diag, CS)
1047  type(time_type), intent(in) :: Time !< Current model time.
1048  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1049  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1050  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
1051  !! parameters.
1052  type(diag_ctrl), target, intent(inout) :: diag !< Struct to regulate diagnostic output.
1053  type(diag_to_z_cs), pointer :: CS !< Pointer to point to control structure for
1054  !! this module.
1055 
1056 ! Arguments:
1057 ! (in) Time - current model time
1058 ! (in) G - ocean grid structure
1059 ! (in) GV - The ocean's vertical grid structure.
1060 ! (in) param_file - struct indicating open file to parse for model param values
1061 ! (in) diag - struct to regulate diagnostic output
1062 ! (in/out) CS - pointer to point to control structure for this module
1063 
1064 ! This include declares and sets the variable "version".
1065 #include "version_variable.h"
1066 
1067  character(len=40) :: mdl = "MOM_diag_to_Z" ! module name
1068  character(len=200) :: in_dir, zgrid_file ! strings for directory/file
1069  character(len=48) :: flux_units, string
1070  integer :: z_axis, zint_axis
1071  integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nk, id_test
1072  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nk = g%ke
1073  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1074 
1075  if (associated(cs)) then
1076  call mom_error(warning, "MOM_diag_to_Z_init called with an associated "// &
1077  "control structure.")
1078  return
1079  endif
1080  allocate(cs)
1081 
1082  if (gv%Boussinesq) then ; flux_units = "meter3 second-1"
1083  else ; flux_units = "kilogram second-1" ; endif
1084 
1085  cs%diag => diag
1086 
1087  ! Read parameters and write them to the model log.
1088  call log_version(param_file, mdl, version, "")
1089  ! Read in z-space info from a NetCDF file.
1090  call get_param(param_file, mdl, "Z_OUTPUT_GRID_FILE", zgrid_file, &
1091  "The file that specifies the vertical grid for \n"//&
1092  "depth-space diagnostics, or blank to disable \n"//&
1093  "depth-space output.", default="")
1094 
1095  if (len_trim(zgrid_file) > 0) then
1096  call get_param(param_file, mdl, "INPUTDIR", in_dir, &
1097  "The directory in which input files are found.", default=".")
1098  in_dir = slasher(in_dir)
1099  call get_z_depths(trim(in_dir)//trim(zgrid_file), "zw", cs%Z_int, "zt", &
1100  z_axis, zint_axis, cs%nk_zspace)
1101  call log_param(param_file, mdl, "!INPUTDIR/Z_OUTPUT_GRID_FILE", &
1102  trim(in_dir)//trim(zgrid_file))
1103  call log_param(param_file, mdl, "!NK_ZSPACE (from file)", cs%nk_zspace, &
1104  "The number of depth-space levels. This is determined \n"//&
1105  "from the size of the variable zw in the output grid file.", &
1106  units="nondim")
1107  else
1108  cs%nk_zspace = -1
1109  endif
1110 
1111  if (cs%nk_zspace > 0) then
1112 
1113  call define_axes_group(diag, (/ diag%axesB1%handles(1), diag%axesB1%handles(2), z_axis /), cs%axesBz)
1114  call define_axes_group(diag, (/ diag%axesT1%handles(1), diag%axesT1%handles(2), z_axis /), cs%axesTz)
1115  call define_axes_group(diag, (/ diag%axesCu1%handles(1), diag%axesCu1%handles(2), z_axis /), cs%axesCuz)
1116  call define_axes_group(diag, (/ diag%axesCv1%handles(1), diag%axesCv1%handles(2), z_axis /), cs%axesCvz)
1117  call define_axes_group(diag, (/ diag%axesB1%handles(1), diag%axesB1%handles(2), zint_axis /), cs%axesBzi)
1118  call define_axes_group(diag, (/ diag%axesT1%handles(1), diag%axesT1%handles(2), zint_axis /), cs%axesTzi)
1119  call define_axes_group(diag, (/ diag%axesCu1%handles(1), diag%axesCu1%handles(2), zint_axis /), cs%axesCuzi)
1120  call define_axes_group(diag, (/ diag%axesCv1%handles(1), diag%axesCv1%handles(2), zint_axis /), cs%axesCvzi)
1121  call define_axes_group(diag, (/ z_axis /), cs%axesZ)
1122 
1123  cs%id_u_z = register_diag_field('ocean_model_zold', 'u', cs%axesCuz, time, &
1124  'Zonal Velocity in Depth Space', 'meter second-1', &
1125  missing_value=cs%missing_vel, cmor_field_name='uo', cmor_units='m s-1',&
1126  cmor_standard_name='sea_water_x_velocity', cmor_long_name='Sea Water X Velocity')
1127  if (cs%id_u_z>0) call safe_alloc_ptr(cs%u_z,isdb,iedb,jsd,jed,cs%nk_zspace)
1128 
1129  cs%id_v_z = register_diag_field('ocean_model_zold', 'v', cs%axesCvz, time, &
1130  'Meridional Velocity in Depth Space', 'meter second-1', &
1131  missing_value=cs%missing_vel, cmor_field_name='vo', cmor_units='m s-1',&
1132  cmor_standard_name='sea_water_y_velocity', cmor_long_name='Sea Water Y Velocity')
1133  if (cs%id_v_z>0) call safe_alloc_ptr(cs%v_z,isd,ied,jsdb,jedb,cs%nk_zspace)
1134 
1135  cs%id_uh_z = register_diag_field('ocean_model_zold', 'uh', cs%axesCuz, time, &
1136  'Zonal Mass Transport (including SGS param) in Depth Space', flux_units, &
1137  missing_value=cs%missing_trans)
1138  if (cs%id_uh_z>0) call safe_alloc_ptr(cs%uh_z,isdb,iedb,jsd,jed,cs%nk_zspace)
1139 
1140  cs%id_vh_z = register_diag_field('ocean_model_zold', 'vh', cs%axesCvz, time, &
1141  'Meridional Mass Transport (including SGS param) in Depth Space', flux_units,&
1142  missing_value=cs%missing_trans)
1143  if (cs%id_vh_z>0) call safe_alloc_ptr(cs%vh_z,isd,ied,jsdb,jedb,cs%nk_zspace)
1144 
1145  endif
1146 
1147 end subroutine mom_diag_to_z_init
1148 
1149 !> This subroutine reads the depths of the interfaces bounding the intended
1150 !! layers from a NetCDF file. If no appropriate file is found, -1 is returned
1151 !! as the number of layers in the output file. Also, a diag_manager axis is set
1152 !! up with the same information as this axis.
1153 subroutine get_z_depths(depth_file, int_depth_name, int_depth, cell_depth_name, &
1154  z_axis_index, edge_index, nk_out)
1155  character(len=*), intent(in) :: depth_file
1156  character(len=*), intent(in) :: int_depth_name
1157  real, dimension(:), pointer :: int_depth
1158  character(len=*), intent(in) :: cell_depth_name
1159  integer, intent(out) :: z_axis_index
1160  integer, intent(out) :: edge_index
1161  integer, intent(out) :: nk_out
1162 
1163 ! This subroutine reads the depths of the interfaces bounding the intended
1164 ! layers from a NetCDF file. If no appropriate file is found, -1 is returned
1165 ! as the number of layers in the output file. Also, a diag_manager axis is set
1166 ! up with the same information as this axis.
1167 
1168  real, allocatable :: cell_depth(:)
1169  character (len=200) :: units, long_name
1170  integer :: ncid, status, intid, intvid, layid, layvid, k, ni
1171 
1172  nk_out = -1
1173 
1174  status = nf90_open(depth_file, nf90_nowrite, ncid);
1175  if (status /= nf90_noerr) then
1176  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1177  " Difficulties opening "//trim(depth_file)//" - "//&
1178  trim(nf90_strerror(status)))
1179  nk_out = -1 ; return
1180  endif
1181 
1182  status = nf90_inq_dimid(ncid, int_depth_name, intid)
1183  if (status /= nf90_noerr) then
1184  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1185  trim(nf90_strerror(status))//" Getting ID of dimension "//&
1186  trim(int_depth_name)//" in "//trim(depth_file))
1187  nk_out = -1 ; return
1188  endif
1189 
1190  status = nf90_inquire_dimension(ncid, intid, len=ni)
1191  if (status /= nf90_noerr) then
1192  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1193  trim(nf90_strerror(status))//" Getting number of interfaces of "//&
1194  trim(int_depth_name)//" in "//trim(depth_file))
1195  nk_out = -1 ; return
1196  endif
1197 
1198  if (ni < 2) then
1199  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1200  "At least two interface depths must be specified in "//trim(depth_file))
1201  nk_out = -1 ; return
1202  endif
1203 
1204  status = nf90_inq_dimid(ncid, cell_depth_name, layid)
1205  if (status /= nf90_noerr) call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1206  trim(nf90_strerror(status))//" Getting ID of dimension "//&
1207  trim(cell_depth_name)//" in "//trim(depth_file))
1208 
1209  status = nf90_inquire_dimension(ncid, layid, len=nk_out)
1210  if (status /= nf90_noerr) call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1211  trim(nf90_strerror(status))//" Getting number of interfaces of "//&
1212  trim(cell_depth_name)//" in "//trim(depth_file))
1213 
1214  if (ni /= nk_out+1) then
1215  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1216  "The interface depths must have one more point than cell centers in "//&
1217  trim(depth_file))
1218  nk_out = -1 ; return
1219  endif
1220 
1221  allocate(int_depth(nk_out+1))
1222  allocate(cell_depth(nk_out))
1223 
1224  status = nf90_inq_varid(ncid, int_depth_name, intvid)
1225  if (status /= nf90_noerr) call mom_error(fatal,"MOM_diag_to_Z get_Z_depths: "//&
1226  trim(nf90_strerror(status))//" Getting ID of variable "//&
1227  trim(int_depth_name)//" in "//trim(depth_file))
1228  status = nf90_get_var(ncid, intvid, int_depth)
1229  if (status /= nf90_noerr) call mom_error(fatal,"MOM_diag_to_Z get_Z_depths: "//&
1230  trim(nf90_strerror(status))//" Reading variable "//&
1231  trim(int_depth_name)//" in "//trim(depth_file))
1232  status = nf90_get_att(ncid, intvid, "units", units)
1233  if (status /= nf90_noerr) units = "meters"
1234  status = nf90_get_att(ncid, intvid, "long_name", long_name)
1235  if (status /= nf90_noerr) long_name = "Depth of edges"
1236  edge_index = diag_axis_init(int_depth_name, int_depth, units, 'z', &
1237  long_name, direction=-1)
1238 
1239 ! Create an fms axis with the same data as the cell_depth array in the input file.
1240  status = nf90_inq_varid(ncid, cell_depth_name, layvid)
1241  if (status /= nf90_noerr) call mom_error(fatal,"MOM_diag_to_Z get_Z_depths: "//&
1242  trim(nf90_strerror(status))//" Getting ID of variable "//&
1243  trim(cell_depth_name)//" in "//trim(depth_file))
1244  status = nf90_get_var(ncid, layvid, cell_depth)
1245  if (status /= nf90_noerr) call mom_error(fatal,"MOM_diag_to_Z get_Z_depths: "//&
1246  trim(nf90_strerror(status))//" Reading variable "//&
1247  trim(cell_depth_name)//" in "//trim(depth_file))
1248  status = nf90_get_att(ncid, layvid, "units", units)
1249  if (status /= nf90_noerr) units = "meters"
1250  status = nf90_get_att(ncid, layvid, "long_name", long_name)
1251  if (status /= nf90_noerr) long_name = "Depth of cell center"
1252 
1253  z_axis_index = diag_axis_init(cell_depth_name, cell_depth, units, 'z',&
1254  long_name, edges = edge_index, direction=-1)
1255 
1256  deallocate(cell_depth)
1257 
1258  status = nf90_close(ncid)
1259 
1260  ! Check the sign convention and change to the MOM "height" convention.
1261  if (int_depth(1) < int_depth(2)) then
1262  do k=1,nk_out+1 ; int_depth(k) = -1*int_depth(k) ; enddo
1263  endif
1264 
1265  ! Check for inversions in grid.
1266  do k=1,nk_out ; if (int_depth(k) < int_depth(k+1)) then
1267  call mom_error(warning,"MOM_diag_to_Z get_Z_depths: "//&
1268  "Inverted interface depths in output grid in "//depth_file)
1269  nk_out = -1 ; deallocate(int_depth) ; return
1270  endif ; enddo
1271 
1272 end subroutine get_z_depths
1273 
1274 subroutine mom_diag_to_z_end(CS)
1275  type(diag_to_z_cs), pointer :: CS
1276  integer :: m
1277 
1278  if (ASSOCIATED(cs%u_z)) deallocate(cs%u_z)
1279  if (ASSOCIATED(cs%v_z)) deallocate(cs%v_z)
1280  if (ASSOCIATED(cs%Z_int)) deallocate(cs%Z_int)
1281  do m=1,cs%num_tr_used ; deallocate(cs%tr_z(m)%p) ; enddo
1282 
1283  deallocate(cs)
1284 
1285 end subroutine mom_diag_to_z_end
1286 
1287 !> This subroutine registers a tracer to be output in depth space.
1288 function ocean_register_diag_with_z(tr_ptr, vardesc_tr, G, Time, CS)
1289  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1290  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1291  target, intent(in) :: tr_ptr !< Tracer for translation to Z-space.
1292  type(vardesc), intent(in) :: vardesc_tr !< Variable descriptor.
1293  type(time_type), intent(in) :: Time !< Current model time.
1294  type(diag_to_z_cs), pointer :: CS !< Control struct returned by a previous
1295  !! call to diagnostics_init.
1296  integer :: ocean_register_diag_with_z
1297 
1298 ! This subroutine registers a tracer to be output in depth space.
1299 ! Arguments:
1300 ! (in) tr_ptr - tracer for translation to Z-space
1301 ! (in) vardesc_tr - variable descriptor
1302 ! (in) Time - current model time
1303 ! (in) G - ocean grid structure
1304 ! (in) CS - control struct returned by a previous call to diagnostics_init
1305 
1306  type(vardesc) :: vardesc_z
1307  character(len=64) :: var_name ! A variable's name.
1308  integer :: isd, ied, jsd, jed, nk, m, id_test
1309  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nk = g%ke
1310  if (.not.associated(cs)) call mom_error(fatal, &
1311  "register_Z_tracer: Module must be initialized before it is used.")
1312  if (cs%nk_zspace<1) return
1313 
1314  if (cs%num_tr_used >= max_fields_) then
1315  call mom_error(warning,"ocean_register_diag_with_z: Attempted to register and use "//&
1316  "more than MAX_FIELDS_ z-space tracers via ocean_register_diag_with_z.")
1317  return
1318  endif
1319 
1320  ! register the layer tracer
1321  ocean_register_diag_with_z = ocean_register_diag(vardesc_tr, g, cs%diag, time)
1322 
1323  ! copy layer tracer variable descriptor to a z-tracer descriptor;
1324  ! change the name and layer information.
1325  vardesc_z = vardesc_tr
1326  call modify_vardesc(vardesc_z, z_grid="z", caller="ocean_register_diag_with_z")
1327  m = cs%num_tr_used + 1
1328  cs%missing_tr(m) = cs%missing_value ! This could be changed later, if desired.
1329  cs%id_tr(m) = register_z_diag(vardesc_z, cs, time, cs%missing_tr(m))
1330 
1331  if (cs%nk_zspace > no_zspace) then
1332 ! There is a depth-space target file.
1333  if (cs%id_tr(m)>0) then
1334 ! Only allocate the tr_z field id there is a diag_table entry looking
1335 ! for it.
1336  cs%num_tr_used = m
1337  call safe_alloc_ptr(cs%tr_z(m)%p,isd,ied,jsd,jed,cs%nk_zspace)
1338 !Can we do the following at this point?
1339 ! tr_ptr might not be allocated yet
1340  cs%tr_model(m)%p => tr_ptr
1341  endif
1342  else
1343 ! There is no depth-space target file but warn if a diag_table entry is
1344 ! present.
1345  call query_vardesc(vardesc_z, name=var_name, caller="ocean_register_diag_with_z")
1346  if (cs%id_tr(m)>0) call mom_error(warning, &
1347  "ocean_register_diag_with_z: "//trim(var_name)// &
1348  " cannot be output without an appropriate depth-space target file.")
1349  endif
1350 
1351 end function ocean_register_diag_with_z
1352 
1353 function register_z_diag(var_desc, CS, day, missing)
1354  integer :: register_Z_diag
1355  type(vardesc), intent(in) :: var_desc
1356  type(diag_to_z_cs), pointer :: CS
1357  type(time_type), intent(in) :: day
1358  real, intent(in) :: missing
1359 
1360  character(len=64) :: var_name ! A variable's name.
1361  character(len=48) :: units ! A variable's units.
1362  character(len=240) :: longname ! A variable's longname.
1363  character(len=8) :: hor_grid, z_grid ! Variable grid info.
1364  type(axes_grp), pointer :: axes
1365 
1366  call query_vardesc(var_desc, name=var_name, units=units, longname=longname, &
1367  hor_grid=hor_grid, z_grid=z_grid, caller="register_Zint_diag")
1368 
1369  ! Use the hor_grid and z_grid components of vardesc to determine the
1370  ! desired axes to register the diagnostic field for.
1371  select case (z_grid)
1372 
1373  case ("z")
1374  select case (hor_grid)
1375  case ("q")
1376  axes => cs%axesBz
1377  case ("h")
1378  axes => cs%axesTz
1379  case ("u")
1380  axes => cs%axesCuz
1381  case ("v")
1382  axes => cs%axesCvz
1383  case ("Bu")
1384  axes => cs%axesBz
1385  case ("T")
1386  axes => cs%axesTz
1387  case ("Cu")
1388  axes => cs%axesCuz
1389  case ("Cv")
1390  axes => cs%axesCvz
1391  case default
1392  call mom_error(fatal,&
1393  "register_Z_diag: unknown hor_grid component "//trim(hor_grid))
1394  end select
1395 
1396  case default
1397  call mom_error(fatal,&
1398  "register_Z_diag: unknown z_grid component "//trim(z_grid))
1399  end select
1400 
1401  register_z_diag = register_diag_field("ocean_model_zold", trim(var_name), axes, &
1402  day, trim(longname), trim(units), missing_value=missing)
1403 
1404 end function register_z_diag
1405 
1406 function register_zint_diag(var_desc, CS, day)
1407  integer :: register_Zint_diag
1408  type(vardesc), intent(in) :: var_desc
1409  type(diag_to_z_cs), pointer :: CS
1410  type(time_type), intent(in) :: day
1411 
1412  character(len=64) :: var_name ! A variable's name.
1413  character(len=48) :: units ! A variable's units.
1414  character(len=240) :: longname ! A variable's longname.
1415  character(len=8) :: hor_grid ! Variable grid info.
1416  type(axes_grp), pointer :: axes
1417 
1418  call query_vardesc(var_desc, name=var_name, units=units, longname=longname, &
1419  hor_grid=hor_grid, caller="register_Zint_diag")
1420 
1421  if (cs%nk_zspace < 0) then
1422  register_zint_diag = -1 ; return
1423  endif
1424 
1425  ! Use the hor_grid and z_grid components of vardesc to determine the
1426  ! desired axes to register the diagnostic field for.
1427  select case (hor_grid)
1428  case ("h")
1429  axes => cs%axesTzi
1430  case ("q")
1431  axes => cs%axesBzi
1432  case ("u")
1433  axes => cs%axesCuzi
1434  case ("v")
1435  axes => cs%axesCvzi
1436  case default
1437  call mom_error(fatal,&
1438  "register_Z_diag: unknown hor_grid component "//trim(hor_grid))
1439  end select
1440 
1441  register_zint_diag = register_diag_field("ocean_model_zold", trim(var_name),&
1442  axes, day, trim(longname), trim(units), missing_value=cs%missing_value)
1443 
1444 end function register_zint_diag
1445 
1446 
1447 end module mom_diag_to_z
subroutine, public find_limited_slope(val, e, slope, k)
This subroutine determines a limited slope for val to be advected with a piecewise limited scheme...
integer function, public ocean_register_diag(var_desc, G, diag_CS, day)
Registers a diagnostic using the information encapsulated in the vardesc type argument and returns an...
subroutine register_z_tracer_low(tr_ptr, name, long_name, units, standard_name, Time, G, CS)
This subroutine registers a tracer to be output in depth space.
subroutine, public find_overlap(e, Z_top, Z_bot, k_max, k_start, k_top, k_bot, wt, z1, z2)
This subroutine determines the layers bounded by interfaces e that overlap with the depth range betwe...
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...
Provides the ocean grid type.
Definition: MOM_grid.F90:2
subroutine, public define_axes_group(diag_cs, handles, axes, nz, vertical_coordinate_number, x_cell_method, y_cell_method, v_cell_method, is_h_point, is_q_point, is_u_point, is_v_point, is_layer, is_interface, is_native, needs_remapping, needs_interpolating, xyave_axes)
Defines a group of "axes" from list of handles.
This module contains I/O framework code.
Definition: MOM_io.F90:2
subroutine, public mom_diag_to_z_end(CS)
integer function, public ocean_register_diag_with_z(tr_ptr, vardesc_tr, G, Time, CS)
This subroutine registers a tracer to be output in depth space.
subroutine get_z_depths(depth_file, int_depth_name, int_depth, cell_depth_name, z_axis_index, edge_index, nk_out)
This subroutine reads the depths of the interfaces bounding the intended layers from a NetCDF file...
A group of 1D axes that comprise a 1D/2D/3D mesh.
real function, dimension(gv %ke), public global_layer_mean(var, h, G, GV)
subroutine, public calculate_z_diag_fields(u, v, h, ssh_in, frac_shelf_h, G, GV, CS)
This subroutine maps tracers and velocities into depth space for diagnostics.
subroutine, public register_z_tracer(tr_ptr, name, long_name, units, Time, G, CS, standard_name, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name)
This subroutine registers a tracer to be output in depth space.
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
subroutine, public calculate_z_transport(uh_int, vh_int, h, dt, G, GV, CS)
This subroutine maps horizontal transport into depth space for diagnostic output. ...
subroutine, public post_data_1d_k(diag_field_id, field, diag_cs, is_static)
real function, dimension(cs%nk_zspace) global_z_mean(var, G, CS, tracer)
integer function, public register_zint_diag(var_desc, CS, day)
subroutine, public mom_diag_to_z_init(Time, G, GV, param_file, diag, CS)
subroutine, public query_vardesc(vd, name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
This routine queries vardesc.
Definition: MOM_io.F90:664
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 calc_zint_diags(h, in_ptrs, ids, num_diags, G, GV, CS)
subroutine, public modify_vardesc(vd, name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
This routine modifies the named elements of a vardesc type. All arguments are optional, except the vardesc type to be modified.
Definition: MOM_io.F90:623
integer, parameter no_zspace
integer function register_z_diag(var_desc, CS, day, missing)