MOM6
mom_diag_to_z Module Reference

Data Types

type  diag_to_z_cs
 

Functions/Subroutines

real function, dimension(cs%nk_zspace) global_z_mean (var, G, CS, tracer)
 
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. More...
 
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. More...
 
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 between Z_top and Z_bot, and the fractional weights of each layer. It also calculates the normalized relative depths of the range of each layer that overlaps that depth range. More...
 
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. More...
 
subroutine, public calc_zint_diags (h, in_ptrs, ids, num_diags, G, GV, CS)
 
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. More...
 
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. More...
 
subroutine, public mom_diag_to_z_init (Time, G, GV, param_file, diag, CS)
 
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. If no appropriate file is found, -1 is returned as the number of layers in the output file. Also, a diag_manager axis is set up with the same information as this axis. More...
 
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. More...
 
integer function register_z_diag (var_desc, CS, day, missing)
 
integer function, public register_zint_diag (var_desc, CS, day)
 

Variables

integer, parameter no_zspace = -1
 

Function/Subroutine Documentation

◆ calc_zint_diags()

subroutine, public mom_diag_to_z::calc_zint_diags ( real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
type(p3d), dimension(:), intent(in)  in_ptrs,
integer, dimension(:), intent(in)  ids,
integer, intent(in)  num_diags,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(diag_to_z_cs), pointer  CS 
)
Parameters
[in]gThe ocean's grid structure.
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]gvThe ocean's vertical grid structure.

Definition at line 811 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error().

Referenced by mom_diabatic_driver::diabatic(), and mom_set_diffusivity::set_diffusivity().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_z_diag_fields()

subroutine, public mom_diag_to_z::calculate_z_diag_fields ( real, dimension(szib_(g),szj_(g),szk_(g)), intent(in)  u,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
real, dimension(szi_(g),szj_(g)), intent(in)  ssh_in,
real, dimension(:,:), pointer  frac_shelf_h,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(diag_to_z_cs), pointer  CS 
)

This subroutine maps tracers and velocities into depth space for diagnostics.

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]uThe zonal velocity, in m s-1.
[in]vThe meridional velocity, in m s-1.
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]ssh_inSea surface height (meter or kg/m2).
csControl structure returned by previous call to diagnostics_init.

Definition at line 167 of file MOM_diag_to_Z.F90.

References find_limited_slope(), find_overlap(), global_z_mean(), and mom_error_handler::mom_error().

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 
Here is the call graph for this function:

◆ calculate_z_transport()

subroutine, public mom_diag_to_z::calculate_z_transport ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  uh_int,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(in)  vh_int,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(diag_to_z_cs), pointer  CS 
)

This subroutine maps horizontal transport into depth space for diagnostic output.

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]uh_intTime integrated zonal transport (m3 or kg).
[in]vh_intTime integrated meridional transport (m3 or kg).
[in]hLayer thicknesses, in H (usually m or kg m-2).
[in]dtThe time difference in s since the last call to this subroutine.
csControl structure returned by previous call to diagnostics_init.

Definition at line 528 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error().

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 
Here is the call graph for this function:

◆ find_limited_slope()

subroutine, public mom_diag_to_z::find_limited_slope ( real, dimension(:), intent(in)  val,
real, dimension(:), intent(in)  e,
real, intent(out)  slope,
integer, intent(in)  k 
)

This subroutine determines a limited slope for val to be advected with a piecewise limited scheme.

Parameters
[in]valA column of values that are being interpolated.
[in]eColumn interface heights (meter or kg/m2).
[out]slopeNormalized slope in the intracell distribution of val.
[in]kLayer whose slope is being determined.

Definition at line 777 of file MOM_diag_to_Z.F90.

Referenced by calculate_z_diag_fields(), and mom_tracer_z_init::tracer_z_init().

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 
Here is the caller graph for this function:

◆ find_overlap()

subroutine, public mom_diag_to_z::find_overlap ( real, dimension(:), intent(in)  e,
real, intent(in)  Z_top,
real, intent(in)  Z_bot,
integer, intent(in)  k_max,
integer, intent(in)  k_start,
integer, intent(inout)  k_top,
integer, intent(inout)  k_bot,
real, dimension(:), intent(out)  wt,
real, dimension(:), intent(out)  z1,
real, dimension(:), intent(out)  z2 
)

This subroutine determines the layers bounded by interfaces e that overlap with the depth range between Z_top and Z_bot, and the fractional weights of each layer. It also calculates the normalized relative depths of the range of each layer that overlaps that depth range.

Parameters
[in]eColumn interface heights (meter or kg/m2).
[in]z_topTop of range being mapped to (meter or kg/m2).
[in]z_botBottom of range being mapped to (meter or kg/m2).
[in]k_maxNumber of valid layers.
[in]k_startLayer at which to start searching.
[in,out]k_topIndices of top layers that overlap with the depth range.
[in,out]k_botIndices of bottom layers that overlap with the depth range.
[out]wtRelative weights of each layer from k_top to k_bot.
[out]z2Depths of the top and bottom limits of the part of a layer that contributes to a depth level, relative to the cell center and normalized by the cell thickness (nondim). Note that -1/2 <= z1 < z2 <= 1/2.

Definition at line 701 of file MOM_diag_to_Z.F90.

Referenced by calculate_z_diag_fields(), and mom_tracer_z_init::tracer_z_init().

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 
Here is the caller graph for this function:

◆ get_z_depths()

subroutine mom_diag_to_z::get_z_depths ( character(len=*), intent(in)  depth_file,
character(len=*), intent(in)  int_depth_name,
real, dimension(:), pointer  int_depth,
character(len=*), intent(in)  cell_depth_name,
integer, intent(out)  z_axis_index,
integer, intent(out)  edge_index,
integer, intent(out)  nk_out 
)
private

This subroutine reads the depths of the interfaces bounding the intended layers from a NetCDF file. If no appropriate file is found, -1 is returned as the number of layers in the output file. Also, a diag_manager axis is set up with the same information as this axis.

Definition at line 1155 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error().

Referenced by mom_diag_to_z_init().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ global_z_mean()

real function, dimension(cs%nk_zspace) mom_diag_to_z::global_z_mean ( real, dimension(szi_(g), szj_(g), cs%nk_zspace), intent(in)  var,
type(ocean_grid_type), intent(in)  G,
type(diag_to_z_cs), intent(in)  CS,
integer  tracer 
)
private
Parameters
[in]gThe ocean's grid structure

Definition at line 119 of file MOM_diag_to_Z.F90.

Referenced by calculate_z_diag_fields().

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 
Here is the caller graph for this function:

◆ mom_diag_to_z_end()

subroutine, public mom_diag_to_z::mom_diag_to_z_end ( type(diag_to_z_cs), pointer  CS)

Definition at line 1275 of file MOM_diag_to_Z.F90.

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 

◆ mom_diag_to_z_init()

subroutine, public mom_diag_to_z::mom_diag_to_z_init ( type(time_type), intent(in)  Time,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(inout), target  diag,
type(diag_to_z_cs), pointer  CS 
)
Parameters
[in]timeCurrent model time.
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]param_fileA structure to parse for run-time parameters.
[in,out]diagStruct to regulate diagnostic output.
csPointer to point to control structure for this module.

Definition at line 1047 of file MOM_diag_to_Z.F90.

References get_z_depths(), and mom_error_handler::mom_error().

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 
Here is the call graph for this function:

◆ ocean_register_diag_with_z()

integer function, public mom_diag_to_z::ocean_register_diag_with_z ( real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in), target  tr_ptr,
type(vardesc), intent(in)  vardesc_tr,
type(ocean_grid_type), intent(in)  G,
type(time_type), intent(in)  Time,
type(diag_to_z_cs), pointer  CS 
)

This subroutine registers a tracer to be output in depth space.

Parameters
[in]gThe ocean's grid structure.
[in]tr_ptrTracer for translation to Z-space.
[in]vardesc_trVariable descriptor.
[in]timeCurrent model time.
csControl struct returned by a previous call to diagnostics_init.

Definition at line 1289 of file MOM_diag_to_Z.F90.

References mom_io::modify_vardesc(), mom_error_handler::mom_error(), no_zspace, mom_diag_mediator::ocean_register_diag(), mom_io::query_vardesc(), and register_z_diag().

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 
Here is the call graph for this function:

◆ register_z_diag()

integer function mom_diag_to_z::register_z_diag ( type(vardesc), intent(in)  var_desc,
type(diag_to_z_cs), pointer  CS,
type(time_type), intent(in)  day,
real, intent(in)  missing 
)
private

Definition at line 1354 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error(), and mom_io::query_vardesc().

Referenced by ocean_register_diag_with_z().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ register_z_tracer()

subroutine, public mom_diag_to_z::register_z_tracer ( real, dimension(szi_(g),szj_(g),szk_(g)), intent(in), target  tr_ptr,
character(len=*), intent(in)  name,
character(len=*), intent(in)  long_name,
character(len=*), intent(in)  units,
type(time_type), intent(in)  Time,
type(ocean_grid_type), intent(in)  G,
type(diag_to_z_cs), pointer  CS,
character(len=*), intent(in), optional  standard_name,
character(len=*), intent(in), optional  cmor_field_name,
character(len=*), intent(in), optional  cmor_long_name,
character(len=*), intent(in), optional  cmor_units,
character(len=*), intent(in), optional  cmor_standard_name 
)

This subroutine registers a tracer to be output in depth space.

Parameters
[in]gThe ocean's grid structure.
[in]tr_ptrTracer for translation to Z-space.
[in]namename for the output tracer.
[in]long_nameLong name for the output tracer.
[in]unitsUnits of output tracer.
[in]timeCurrent model time.
csControl struct returned by previous call to diagnostics_init.
[in]cmor_field_namecmor name of a field.
[in]cmor_long_namecmor long name of a field.
[in]cmor_unitscmor units of a field.
[in]cmor_standard_namecmor standardized name associated with a field.

Definition at line 910 of file MOM_diag_to_Z.F90.

References register_z_tracer_low().

Referenced by advection_test_tracer::initialize_advection_test_tracer(), boundary_impulse_tracer::initialize_boundary_impulse_tracer(), dome_tracer::initialize_dome_tracer(), regional_dyes::initialize_dye_tracer(), ideal_age_example::initialize_ideal_age_tracer(), isomip_tracer::initialize_isomip_tracer(), mom_ocmip2_cfc::initialize_ocmip2_cfc(), oil_tracer::initialize_oil_tracer(), pseudo_salt_tracer::initialize_pseudo_salt_tracer(), and user_tracer_example::user_initialize_tracer().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ register_z_tracer_low()

subroutine mom_diag_to_z::register_z_tracer_low ( real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in), target  tr_ptr,
character(len=*), intent(in)  name,
character(len=*), intent(in)  long_name,
character(len=*), intent(in)  units,
character(len=*), intent(in)  standard_name,
type(time_type), intent(in)  Time,
type(ocean_grid_type), intent(in)  G,
type(diag_to_z_cs), pointer  CS 
)
private

This subroutine registers a tracer to be output in depth space.

Parameters
[in]gThe ocean's grid structure.
[in]tr_ptrTracer for translation to Z-space.
[in]nameName for the output tracer.
[in]long_nameLong name for output tracer.
[in]unitsUnits of output tracer.
[in]timeCurrent model time.
csControl struct returned by previous call to diagnostics_init.

Definition at line 981 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error().

Referenced by register_z_tracer().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ register_zint_diag()

integer function, public mom_diag_to_z::register_zint_diag ( type(vardesc), intent(in)  var_desc,
type(diag_to_z_cs), pointer  CS,
type(time_type), intent(in)  day 
)

Definition at line 1407 of file MOM_diag_to_Z.F90.

References mom_error_handler::mom_error(), and mom_io::query_vardesc().

Referenced by mom_diabatic_driver::diabatic_driver_init().

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 
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ no_zspace

integer, parameter mom_diag_to_z::no_zspace = -1

Definition at line 114 of file MOM_diag_to_Z.F90.

Referenced by ocean_register_diag_with_z().

114 integer, parameter :: no_zspace = -1