MOM6
MOM_regularize_layers.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
22 !********+*********+*********+*********+*********+*********+*********+**
23 !* *
24 !* By Robert Hallberg and Alistair Adcroft, 2011. *
25 !* *
26 !* This file contains the code to do vertical remapping of mass, *
27 !* temperature and salinity in MOM. Other tracers and the horizontal *
28 !* velocity components will be remapped outside of this subroutine *
29 !* using the values that are stored in ea and eb. *
30 !* The code that is here now only applies in very limited cases *
31 !* where the mixed- and buffer-layer structures are problematic, but *
32 !* future additions will include the ability to emulate arbitrary *
33 !* vertical coordinates. *
34 !* *
35 !* Macros written all in capital letters are defined in MOM_memory.h. *
36 !* *
37 !* A small fragment of the grid is shown below: *
38 !* *
39 !* j+1 x ^ x ^ x At x: q *
40 !* j+1 > o > o > At ^: v *
41 !* j x ^ x ^ x At >: u *
42 !* j > o > o > At o: h, T, S, ea, eb, etc. *
43 !* j-1 x ^ x ^ x *
44 !* i-1 i i+1 At x & ^: *
45 !* i i+1 At > & o: *
46 !* *
47 !* The boundaries always run through q grid points (x). *
48 !* *
49 !********+*********+*********+*********+*********+*********+*********+**
50 
51 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
52 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
53 use mom_diag_mediator, only : time_type, diag_ctrl
55 use mom_domains, only : group_pass_type
56 use mom_error_handler, only : mom_error, fatal, warning
58 use mom_grid, only : ocean_grid_type
62 
63 implicit none ; private
64 
65 #include <MOM_memory.h>
66 #undef DEBUG_CODE
67 
69 
70 type, public :: regularize_layers_cs ; private
71  logical :: regularize_surface_layers ! If true, vertically restructure the
72  ! near-surface layers when they have too much
73  ! lateral variations to allow for sensible lateral
74  ! barotropic transports.
75  logical :: reg_sfc_detrain
76  real :: h_def_tol1 ! The value of the relative thickness deficit at
77  ! which to start modifying the structure, 0.5 by
78  ! default (or a thickness ratio of 5.83).
79  real :: h_def_tol2 ! The value of the relative thickness deficit at
80  ! which to the structure modification is in full
81  ! force, now 20% of the way from h_def_tol1 to 1.
82  real :: h_def_tol3 ! The values of the relative thickness defitic at
83  real :: h_def_tol4 ! which to start detrainment from the buffer layers
84  ! to the interior, and at which to do this at full
85  ! intensity. Now 30% and 50% of the way from
86  ! h_def_tol1 to 1.
87  real :: hmix_min ! The minimum mixed layer thickness in m.
88  type(time_type), pointer :: time ! A pointer to the ocean model's clock.
89  type(diag_ctrl), pointer :: diag ! A structure that is used to regulate the
90  ! timing of diagnostic output.
91  logical :: debug ! If true, do more thorough checks for debugging purposes.
92 
93  type(group_pass_type) :: pass_h ! For group pass
94 
95  integer :: id_def_rat = -1
96  logical :: allow_clocks_in_omp_loops ! If true, clocks can be called
97  ! from inside loops that can be threaded.
98  ! To run with multiple threads, set to False.
99 #ifdef DEBUG_CODE
100  integer :: id_def_rat_2 = -1, id_def_rat_3 = -1
101  integer :: id_def_rat_u = -1, id_def_rat_v = -1
102  integer :: id_e1 = -1, id_e2 = -1, id_e3 = -1
103  integer :: id_def_rat_u_1b = -1, id_def_rat_v_1b = -1
104  integer :: id_def_rat_u_2 = -1, id_def_rat_u_2b = -1
105  integer :: id_def_rat_v_2 = -1, id_def_rat_v_2b = -1
106  integer :: id_def_rat_u_3 = -1, id_def_rat_u_3b = -1
107  integer :: id_def_rat_v_3 = -1, id_def_rat_v_3b = -1
108 #endif
109 end type regularize_layers_cs
110 
112 
113 contains
114 
115 !> This subroutine partially steps the bulk mixed layer model.
116 !! The following processes are executed, in the order listed.
117 subroutine regularize_layers(h, tv, dt, ea, eb, G, GV, CS)
118  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
119  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
120  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
121  intent(inout) :: h !< Layer thicknesses, in H (usually m or kg m-2).
122  type(thermo_var_ptrs), intent(inout) :: tv !< A structure containing pointers to any
123  !! available thermodynamic fields. Absent fields
124  !! have NULL ptrs.
125  real, intent(in) :: dt !< Time increment, in s.
126  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
127  intent(inout) :: ea !< The amount of fluid moved downward into a
128  !! layer; this should be increased due to mixed
129  !! layer detrainment, in the same units as
130  !! h - usually m or kg m-2 (i.e., H).
131  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
132  intent(inout) :: eb !< The amount of fluid moved upward into a layer;
133  !! this should be increased due to mixed layer
134  !! entrainment, in the same units as h - usually
135  !! m or kg m-2 (i.e., H).
136  type(regularize_layers_cs), pointer :: CS !< The control structure returned by a previous
137  !! call to regularize_layers_init.
138 
139 ! This subroutine partially steps the bulk mixed layer model.
140 ! The following processes are executed, in the order listed.
141 
142 ! Arguments: h - Layer thickness, in m or kg m-2. (Intent in/out)
143 ! The units of h are referred to as H below.
144 ! (in/out) tv - A structure containing pointers to any available
145 ! thermodynamic fields. Absent fields have NULL ptrs.
146 ! (in) dt - Time increment, in s.
147 ! (in/out) ea - The amount of fluid moved downward into a layer; this should
148 ! be increased due to mixed layer detrainment, in the same units
149 ! as h - usually m or kg m-2 (i.e., H).
150 ! (in/out) eb - The amount of fluid moved upward into a layer; this should
151 ! be increased due to mixed layer entrainment, in the same units
152 ! as h - usually m or kg m-2 (i.e., H).
153 ! (in) G - The ocean's grid structure.
154 ! (in) GV - The ocean's vertical grid structure.
155 ! (in) CS - The control structure returned by a previous call to
156 ! regularize_layers_init.
157 
158  integer :: i, j, k, is, ie, js, je, nz
159 
160  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
161 
162  if (.not. associated(cs)) call mom_error(fatal, "MOM_regularize_layers: "//&
163  "Module must be initialized before it is used.")
164 
165  if (cs%regularize_surface_layers) then
166  call cpu_clock_begin(id_clock_pass)
167  call create_group_pass(cs%pass_h,h,g%Domain)
168  call do_group_pass(cs%pass_h,g%Domain)
169  call cpu_clock_end(id_clock_pass)
170  endif
171 
172  if (cs%regularize_surface_layers) then
173  call regularize_surface(h, tv, dt, ea, eb, g, gv, cs)
174  endif
175 
176 end subroutine regularize_layers
177 
178 !> This subroutine ensures that there is a degree of horizontal smoothness
179 !! in the depths of the near-surface interfaces.
180 subroutine regularize_surface(h, tv, dt, ea, eb, G, GV, CS)
181  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
182  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
183  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
184  intent(inout) :: h !< Layer thicknesses, in H (usually m or kg m-2).
185  type(thermo_var_ptrs), intent(inout) :: tv !< A structure containing pointers to any
186  !! available thermodynamic fields. Absent fields
187  !! have NULL ptrs.
188  real, intent(in) :: dt !< Time increment, in s.
189  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
190  intent(inout) :: ea !< The amount of fluid moved downward into a
191  !! layer; this should be increased due to mixed
192  !! layer detrainment, in the same units as h -
193  !! usually m or kg m-2 (i.e., H).
194  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
195  intent(inout) :: eb !< The amount of fluid moved upward into a layer;
196  !! this should be increased due to mixed layer
197  !! entrainment, in the same units as h - usually
198  !! m or kg m-2 (i.e., H).
199  type(regularize_layers_cs), pointer :: CS !< The control structure returned by a previous
200  !! call to regularize_layers_init.
201 
202 ! This subroutine ensures that there is a degree of horizontal smoothness
203 ! in the depths of the near-surface interfaces.
204 
205 ! Arguments: h - Layer thickness, in m or kg m-2. (Intent in/out)
206 ! The units of h are referred to as H below.
207 ! (in/out) tv - A structure containing pointers to any available
208 ! thermodynamic fields. Absent fields have NULL ptrs.
209 ! (in) dt - Time increment, in s.
210 ! (in/out) ea - The amount of fluid moved downward into a layer; this should
211 ! be increased due to mixed layer detrainment, in the same units
212 ! as h - usually m or kg m-2 (i.e., H).
213 ! (in/out) eb - The amount of fluid moved upward into a layer; this should
214 ! be increased due to mixed layer entrainment, in the same units
215 ! as h - usually m or kg m-2 (i.e., H).
216 ! (in) G - The ocean's grid structure.
217 ! (in) GV - The ocean's vertical grid structure.
218 ! (in) CS - The control structure returned by a previous call to
219 ! regularize_layers_init.
220 
221  real, dimension(SZIB_(G),SZJ_(G)) :: &
222  def_rat_u ! The ratio of the thickness deficit to the minimum depth, ND.
223  real, dimension(SZI_(G),SZJB_(G)) :: &
224  def_rat_v ! The ratio of the thickness deficit to the minimum depth, ND.
225  real, dimension(SZI_(G),SZJ_(G)) :: &
226  def_rat_h ! The ratio of the thickness deficit to the minimum depth, ND.
227  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: &
228  e ! The interface depths, in H, positive upward.
229 
230 #ifdef DEBUG_CODE
231  real, dimension(SZIB_(G),SZJ_(G)) :: &
232  def_rat_u_1b, def_rat_u_2, def_rat_u_2b, def_rat_u_3, def_rat_u_3b
233  real, dimension(SZI_(G),SZJB_(G)) :: &
234  def_rat_v_1b, def_rat_v_2, def_rat_v_2b, def_rat_v_3, def_rat_v_3b
235  real, dimension(SZI_(G),SZJB_(G)) :: &
236  def_rat_h2, def_rat_h3
237  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: &
238  ef ! The filtered interface depths, in H, positive upward.
239 #endif
240 
241  real, dimension(SZI_(G),SZK_(G)+1) :: &
242  e_filt, e_2d ! The interface depths, in H, positive upward.
243  real, dimension(SZI_(G),SZK_(G)) :: &
244  h_2d, & ! A 2-d version of h, in H.
245  T_2d, & ! A 2-d version of tv%T, in deg C.
246  S_2d, & ! A 2-d version of tv%S, in PSU.
247  Rcv, & ! A 2-d version of the coordinate density, in kg m-3.
248  h_2d_init, & ! The initial value of h_2d, in H.
249  T_2d_init, & ! THe initial value of T_2d, in deg C.
250  S_2d_init, & ! The initial value of S_2d, in PSU.
251  d_eb, & ! The downward increase across a layer in the entrainment from
252  ! below, in H. The sign convention is that positive values of
253  ! d_eb correspond to a gain in mass by a layer by upward motion.
254  d_ea ! The upward increase across a layer in the entrainment from
255  ! above, in H. The sign convention is that positive values of
256  ! d_ea mean a net gain in mass by a layer from downward motion.
257  real, dimension(SZI_(G)) :: &
258  p_ref_cv, & ! Reference pressure for the potential density which defines
259  ! the coordinate variable, set to P_Ref, in Pa.
260  rcv_tol, & ! A tolerence, relative to the target density differences
261  ! between layers, for detraining into the interior, ND.
262  h_add_tgt, h_add_tot, &
263  h_tot1, th_tot1, sh_tot1, &
264  h_tot3, th_tot3, sh_tot3, &
265  h_tot2, th_tot2, sh_tot2
266  real, dimension(SZK_(G)) :: &
267  h_prev_1d ! The previous thicknesses, in H.
268  real :: I_dtol ! The inverse of the tolerance changes, nondim.
269  real :: I_dtol34 ! The inverse of the tolerance changes, nondim.
270  real :: h1, h2 ! Temporary thicknesses, in H.
271  real :: e_e, e_w, e_n, e_s ! Temporary interface heights, in H.
272  real :: wt ! The weight of the filted interfaces in setting the targets, ND.
273  real :: scale ! A scaling factor, ND.
274  real :: h_neglect ! A thickness that is so small it is usually lost
275  ! in roundoff and can be neglected, in H.
276  real, dimension(SZK_(G)+1) :: &
277  int_flux, int_Tflux, int_Sflux, int_Rflux
278  real :: h_add
279  real :: h_det_tot
280  real :: max_def_rat
281  real :: Rcv_min_det ! The lightest (min) and densest (max) coordinate density
282  real :: Rcv_max_det ! that can detrain into a layer, in kg m-3.
283 
284  real :: int_top, int_bot
285  real :: h_predicted
286  real :: h_prev
287  real :: h_deficit
288 
289  logical :: cols_left, ent_any, more_ent_i(szi_(g)), ent_i(szi_(g))
290  logical :: det_any, det_i(szi_(g))
291  logical :: do_j(szj_(g)), do_i(szi_(g)), find_i(szi_(g))
292  logical :: debug = .false.
293  logical :: fatal_error
294  character(len=256) :: mesg ! Message for error messages.
295  integer :: i, j, k, is, ie, js, je, nz, nkmb, nkml, k1, k2, k3, ks, nz_filt
296 
297  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
298 
299  if (.not. associated(cs)) call mom_error(fatal, "MOM_regularize_layers: "//&
300  "Module must be initialized before it is used.")
301 
302  if (gv%nkml<1) return
303  nkmb = gv%nk_rho_varies ; nkml = gv%nkml
304  if (.not.ASSOCIATED(tv%eqn_of_state)) call mom_error(fatal, &
305  "MOM_regularize_layers: This module now requires the use of temperature and "//&
306  "an equation of state.")
307 
308  h_neglect = gv%H_subroundoff
309  debug = (debug .or. cs%debug)
310 #ifdef DEBUG_CODE
311  debug = .true.
312  if (cs%id_def_rat_2 > 0) then ! Calculate over a slightly larger domain.
313  is = g%isc-1 ; ie = g%iec+1 ; js = g%jsc-1 ; je = g%jec+1
314  endif
315 #endif
316 
317  i_dtol = 1.0 / max(cs%h_def_tol2 - cs%h_def_tol1, 1e-40)
318  i_dtol34 = 1.0 / max(cs%h_def_tol4 - cs%h_def_tol3, 1e-40)
319 
320  p_ref_cv(:) = tv%P_Ref
321 
322  do j=js-1,je+1 ; do i=is-1,ie+1
323  e(i,j,1) = 0.0
324  enddo ; enddo
325  do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
326  e(i,j,k+1) = e(i,j,k) - h(i,j,k)
327  enddo ; enddo ; enddo
328 
329 #ifdef DEBUG_CODE
330  call find_deficit_ratios(e, def_rat_u, def_rat_v, g, gv, cs, def_rat_u_1b, def_rat_v_1b, 1, h)
331 #else
332  call find_deficit_ratios(e, def_rat_u, def_rat_v, g, gv, cs, h=h)
333 #endif
334  ! Determine which columns are problematic
335  do j=js,je ; do_j(j) = .false. ; enddo
336  do j=js,je ; do i=is,ie
337  def_rat_h(i,j) = max(def_rat_u(i-1,j), def_rat_u(i,j), &
338  def_rat_v(i,j-1), def_rat_v(i,j))
339  if (def_rat_h(i,j) > cs%h_def_tol1) do_j(j) = .true.
340  enddo ; enddo
341 
342 #ifdef DEBUG_CODE
343  if ((cs%id_def_rat_3 > 0) .or. (cs%id_e3 > 0) .or. &
344  (cs%id_def_rat_u_3 > 0) .or. (cs%id_def_rat_u_3b > 0) .or. &
345  (cs%id_def_rat_v_3 > 0) .or. (cs%id_def_rat_v_3b > 0) ) then
346  do j=js-1,je+1 ; do i=is-1,ie+1
347  ef(i,j,1) = 0.0
348  enddo ; enddo
349  do k=2,nz+1 ; do j=js,je ; do i=is,ie
350  if (g%mask2dCu(i,j) <= 0.0) then ; e_e = e(i,j,k) ; else
351  e_e = max(e(i+1,j,k) + min(e(i,j,k) - e(i+1,j,nz+1), 0.0), e(i,j,nz+1))
352  endif
353  if (g%mask2dCu(i-1,j) <= 0.0) then ; e_w = e(i,j,k) ; else
354  e_w = max(e(i-1,j,k) + min(e(i,j,k) - e(i-1,j,nz+1), 0.0), e(i,j,nz+1))
355  endif
356  if (g%mask2dCv(i,j) <= 0.0) then ; e_n = e(i,j,k) ; else
357  e_n = max(e(i,j+1,k) + min(e(i,j,k) - e(i,j+1,nz+1), 0.0), e(i,j,nz+1))
358  endif
359  if (g%mask2dCv(i,j-1) <= 0.0) then ; e_s = e(i,j,k) ; else
360  e_s = max(e(i,j-1,k) + min(e(i,j,k) - e(i,j-1,nz+1), 0.0), e(i,j,nz+1))
361  endif
362 
363  wt = 1.0
364  ef(i,j,k) = (1.0 - 0.5*wt) * e(i,j,k) + &
365  wt * 0.125 * ((e_e + e_w) + (e_n + e_s))
366  enddo ; enddo ; enddo
367  call find_deficit_ratios(ef, def_rat_u_3, def_rat_v_3, g, gv, cs, def_rat_u_3b, def_rat_v_3b)
368 
369  ! Determine which columns are problematic
370  do j=js,je ; do i=is,ie
371  def_rat_h3(i,j) = max(def_rat_u_3(i-1,j), def_rat_u_3(i,j), &
372  def_rat_v_3(i,j-1), def_rat_v_3(i,j))
373  enddo ; enddo
374 
375  if (cs%id_e3 > 0) call post_data(cs%id_e3, ef, cs%diag)
376  if (cs%id_def_rat_3 > 0) call post_data(cs%id_def_rat_3, def_rat_h3, cs%diag)
377  if (cs%id_def_rat_u_3 > 0) call post_data(cs%id_def_rat_u_3, def_rat_u_3, cs%diag)
378  if (cs%id_def_rat_u_3b > 0) call post_data(cs%id_def_rat_u_3b, def_rat_u_3b, cs%diag)
379  if (cs%id_def_rat_v_3 > 0) call post_data(cs%id_def_rat_v_3, def_rat_v_3, cs%diag)
380  if (cs%id_def_rat_v_3b > 0) call post_data(cs%id_def_rat_v_3b, def_rat_v_3b, cs%diag)
381  endif
382 #endif
383 
384 
385  ! Now restructure the layers.
386 !$OMP parallel do default(none) shared(is,ie,js,je,nz,do_j,def_rat_h,CS,nkmb,G,GV,&
387 !$OMP e,I_dtol,h,tv,debug,h_neglect,p_ref_cv,ea, &
388 !$OMP eb,id_clock_EOS,nkml) &
389 !$OMP private(d_ea,d_eb,max_def_rat,do_i,nz_filt,e_e,e_w,&
390 !$OMP e_n,e_s,wt,e_filt,e_2d,h_2d,T_2d,S_2d, &
391 !$OMP h_2d_init,T_2d_init,S_2d_init,ent_any, &
392 !$OMP more_ent_i,ent_i,h_add_tgt,h_add_tot, &
393 !$OMP cols_left,h_add,h_prev,ks,det_any,det_i, &
394 !$OMP Rcv_tol,Rcv,k1,k2,h_det_tot,Rcv_min_det, &
395 !$OMP Rcv_max_det,h_deficit,h_tot3,Th_tot3, &
396 !$OMP Sh_tot3,scale,int_top,int_flux,int_Rflux, &
397 !$OMP int_Tflux,int_Sflux,int_bot,h_prev_1d, &
398 !$OMP h_tot1,Th_tot1,Sh_tot1,h_tot2,Th_tot2, &
399 !$OMP Sh_tot2,h_predicted,fatal_error,mesg )
400  do j=js,je ; if (do_j(j)) then
401 
402 ! call cpu_clock_begin(id_clock_EOS)
403 ! call calculate_density_derivs(T(:,1), S(:,1), p_ref_cv, dRcv_dT, dRcv_dS, &
404 ! is, ie-is+1, tv%eqn_of_state)
405 ! call cpu_clock_end(id_clock_EOS)
406 
407  do k=1,nz ; do i=is,ie ; d_ea(i,k) = 0.0 ; d_eb(i,k) = 0.0 ; enddo ; enddo
408 
409  max_def_rat = 0.0
410  do i=is,ie
411  do_i(i) = def_rat_h(i,j) > cs%h_def_tol1
412  if (def_rat_h(i,j) > max_def_rat) max_def_rat = def_rat_h(i,j)
413  enddo
414  nz_filt = nkmb+1 ; if (max_def_rat > cs%h_def_tol3) nz_filt = nz+1
415 
416  ! Find a 2-D 1-2-1 filtered version of e to target. Area weights are
417  ! deliberately omitted here. This is slightly more complicated than a
418  ! simple filter so that the effects of topography are eliminated.
419  do k=1,nz_filt ; do i=is,ie ; if (do_i(i)) then
420  if (g%mask2dCu(i,j) <= 0.0) then ; e_e = e(i,j,k) ; else
421  e_e = max(e(i+1,j,k) + min(e(i,j,k) - e(i+1,j,nz+1), 0.0), &
422  e(i,j,nz+1) + (nz+1-k)*gv%Angstrom)
423 
424  endif
425  if (g%mask2dCu(i-1,j) <= 0.0) then ; e_w = e(i,j,k) ; else
426  e_w = max(e(i-1,j,k) + min(e(i,j,k) - e(i-1,j,nz+1), 0.0), &
427  e(i,j,nz+1) + (nz+1-k)*gv%Angstrom)
428  endif
429  if (g%mask2dCv(i,j) <= 0.0) then ; e_n = e(i,j,k) ; else
430  e_n = max(e(i,j+1,k) + min(e(i,j,k) - e(i,j+1,nz+1), 0.0), &
431  e(i,j,nz+1) + (nz+1-k)*gv%Angstrom)
432  endif
433  if (g%mask2dCv(i,j-1) <= 0.0) then ; e_s = e(i,j,k) ; else
434  e_s = max(e(i,j-1,k) + min(e(i,j,k) - e(i,j-1,nz+1), 0.0), &
435  e(i,j,nz+1) + (nz+1-k)*gv%Angstrom)
436  endif
437 
438  wt = max(0.0, min(1.0, i_dtol*(def_rat_h(i,j)-cs%h_def_tol1)))
439 
440  e_filt(i,k) = (1.0 - 0.5*wt) * e(i,j,k) + &
441  wt * 0.125 * ((e_e + e_w) + (e_n + e_s))
442  e_2d(i,k) = e(i,j,k)
443  endif ; enddo ; enddo
444  do k=1,nz ; do i=is,ie
445  h_2d(i,k) = h(i,j,k)
446  t_2d(i,k) = tv%T(i,j,k) ; s_2d(i,k) = tv%S(i,j,k)
447  enddo ; enddo
448 
449  if (debug) then
450  do k=1,nz ; do i=is,ie ; if (do_i(i)) then
451  h_2d_init(i,k) = h(i,j,k)
452  t_2d_init(i,k) = tv%T(i,j,k) ; s_2d_init(i,k) = tv%S(i,j,k)
453  endif ; enddo ; enddo
454  endif
455 
456  ! First, try to entrain from the interior.
457  ent_any = .false.
458  do i=is,ie
459  more_ent_i(i) = .false. ; ent_i(i) = .false.
460  h_add_tgt(i) = 0.0 ; h_add_tot(i) = 0.0
461  if (do_i(i) .and. (e_2d(i,nkmb+1) > e_filt(i,nkmb+1))) then
462  more_ent_i(i) = .true. ; ent_i(i) = .true. ; ent_any = .true.
463  h_add_tgt(i) = e_2d(i,nkmb+1) - e_filt(i,nkmb+1)
464  endif
465  enddo
466 
467  if (ent_any) then
468  do k=nkmb+1,nz
469  cols_left = .false.
470  do i=is,ie ; if (more_ent_i(i)) then
471  if (h_2d(i,k) - gv%Angstrom > h_neglect) then
472  if (e_2d(i,nkmb+1)-e_filt(i,nkmb+1) > h_2d(i,k) - gv%Angstrom) then
473  h_add = h_2d(i,k) - gv%Angstrom
474  h_2d(i,k) = gv%Angstrom
475  else
476  h_add = e_2d(i,nkmb+1)-e_filt(i,nkmb+1)
477  h_2d(i,k) = h_2d(i,k) - h_add
478  endif
479  d_eb(i,k-1) = d_eb(i,k-1) + h_add
480  h_add_tot(i) = h_add_tot(i) + h_add
481  e_2d(i,nkmb+1) = e_2d(i,nkmb+1) - h_add
482  h_prev = h_2d(i,nkmb)
483  h_2d(i,nkmb) = h_2d(i,nkmb) + h_add
484 
485  t_2d(i,nkmb) = (h_prev*t_2d(i,nkmb) + h_add*t_2d(i,k)) / h_2d(i,nkmb)
486  s_2d(i,nkmb) = (h_prev*s_2d(i,nkmb) + h_add*s_2d(i,k)) / h_2d(i,nkmb)
487 
488  if ((e_2d(i,nkmb+1) <= e_filt(i,nkmb+1)) .or. &
489  (h_add_tot(i) > 0.6*h_add_tgt(i))) then !### 0.6 is adjustable?.
490  more_ent_i(i) = .false.
491  else
492  cols_left = .true.
493  endif
494  else
495  cols_left = .true.
496  endif
497  endif ; enddo
498  if (.not.cols_left) exit
499  enddo
500 
501  ks = min(k-1,nz-1)
502  do k=ks,nkmb,-1 ; do i=is,ie ; if (ent_i(i)) then
503  d_eb(i,k) = d_eb(i,k) + d_eb(i,k+1)
504  endif ; enddo ; enddo
505  endif ! ent_any
506 
507  ! This is where code to detrain to the interior will go.
508  ! The buffer layers can only detrain water into layers when the buffer
509  ! layer potential density is between (c*Rlay(k-1) + (1-c)*Rlay(k)) and
510  ! (c*Rlay(k+1) + (1-c)*Rlay(k)), where 0.5 <= c < 1.0.
511  ! Do not detrain if the 2-layer deficit ratio is not significant.
512  ! Detrainment must be able to come from all mixed and buffer layers.
513  ! All water is moved out of the buffer layers below before moving from
514  ! a shallower layer (characteristics do not cross).
515  det_any = .false.
516  if ((max_def_rat > cs%h_def_tol3) .and. (cs%reg_sfc_detrain)) then
517  do i=is,ie
518  det_i(i) = .false. ; rcv_tol(i) = 0.0
519  if (do_i(i) .and. (e_2d(i,nkmb+1) < e_filt(i,nkmb+1)) .and. &
520  (def_rat_h(i,j) > cs%h_def_tol3)) then
521  det_i(i) = .true. ; det_any = .true.
522  rcv_tol(i) = min((def_rat_h(i,j) - cs%h_def_tol3), 1.0)
523  endif
524  enddo
525  endif
526  if (det_any) then
527  call cpu_clock_begin(id_clock_eos)
528  do k=1,nkmb
529  call calculate_density(t_2d(:,k),s_2d(:,k),p_ref_cv,rcv(:,k), &
530  is,ie-is+1,tv%eqn_of_state)
531  enddo
532  call cpu_clock_end(id_clock_eos)
533 
534  do i=is,ie ; if (det_i(i)) then
535  k1 = nkmb ; k2 = nz
536  h_det_tot = 0.0
537  do ! This loop is terminated by exits.
538  if (k1 <= 1) exit
539  if (k2 <= nkmb) exit
540  ! ### The 0.6 here should be adjustable? It gives 20% overlap for now.
541  rcv_min_det = gv%Rlay(k2) + 0.6*rcv_tol(i)*(gv%Rlay(k2-1)-gv%Rlay(k2))
542  if (k2 < nz) then
543  rcv_max_det = gv%Rlay(k2) + 0.6*rcv_tol(i)*(gv%Rlay(k2+1)-gv%Rlay(k2))
544  else
545  rcv_max_det = gv%Rlay(nz) + 0.6*rcv_tol(i)*(gv%Rlay(nz)-gv%Rlay(nz-1))
546  endif
547  if (rcv(i,k1) > rcv_max_det) &
548  exit ! All shallower interior layers are too light for detrainment.
549 
550  h_deficit = (e_filt(i,k2)-e_filt(i,k2+1)) - h_2d(i,k2)
551  if ((e_filt(i,k2) > e_2d(i,k1+1)) .and. (h_deficit > 0.0) .and. &
552  (rcv(i,k1) < rcv_max_det) .and. (rcv(i,k1) > rcv_min_det)) then
553  ! Detrainment will occur.
554  h_add = min(e_filt(i,k2) - e_2d(i,k2), h_deficit )
555  if (h_add < h_2d(i,k1)) then
556  ! Only part of layer k1 detrains.
557  if (h_add > 0.0) then
558  h_prev = h_2d(i,k2)
559  h_2d(i,k2) = h_2d(i,k2) + h_add
560  e_2d(i,k2) = e_2d(i,k2+1) + h_2d(i,k2)
561  d_ea(i,k2) = d_ea(i,k2) + h_add
562  ! ### THIS IS UPWIND. IT SHOULD BE HIGHER ORDER...
563  t_2d(i,k2) = (h_prev*t_2d(i,k2) + h_add*t_2d(i,k1)) / h_2d(i,k2)
564  s_2d(i,k2) = (h_prev*s_2d(i,k2) + h_add*s_2d(i,k1)) / h_2d(i,k2)
565  h_det_tot = h_det_tot + h_add
566 
567  h_2d(i,k1) = h_2d(i,k1) - h_add
568  do k3=k1,nkmb ; e_2d(i,k3+1) = e_2d(i,k3) - h_2d(i,k3) ; enddo
569  do k3=k1+1,nkmb ; d_ea(i,k3) = d_ea(i,k3) + h_add ; enddo
570  else
571  if (h_add < 0.0) &
572  call mom_error(fatal, "h_add is negative. Some logic is wrong.")
573  h_add = 0.0 ! This usually should not happen...
574  endif
575 
576  ! Move up to the next target layer.
577  k2 = k2-1
578  if (k2>nkmb+1) e_2d(i,k2) = e_2d(i,k2) + h_det_tot
579  else
580  h_add = h_2d(i,k1)
581  h_prev = h_2d(i,k2)
582  h_2d(i,k2) = h_2d(i,k2) + h_add
583  e_2d(i,k2) = e_2d(i,k2+1) + h_2d(i,k2)
584  d_ea(i,k2) = d_ea(i,k2) + h_add
585  t_2d(i,k2) = (h_prev*t_2d(i,k2) + h_add*t_2d(i,k1)) / h_2d(i,k2)
586  s_2d(i,k2) = (h_prev*s_2d(i,k2) + h_add*s_2d(i,k1)) / h_2d(i,k2)
587  h_det_tot = h_det_tot + h_add
588 
589  h_2d(i,k1) = 0.0
590  do k3=k1,nkmb ; e_2d(i,k3+1) = e_2d(i,k3) - h_2d(i,k3) ; enddo
591  do k3=k1+1,nkmb ; d_ea(i,k3) = d_ea(i,k3) + h_add ; enddo
592 
593  ! Move up to the next source layer.
594  k1 = k1-1
595  endif
596 
597  else
598  ! Move up to the next target layer.
599  k2 = k2-1
600  if (k2>nkmb+1) e_2d(i,k2) = e_2d(i,k2) + h_det_tot
601  endif
602 
603  enddo ! exit terminated loop.
604  endif ; enddo
605  ! ### This could be faster if the deepest k with nonzero d_ea were kept.
606  do k=nz-1,nkmb+1,-1 ; do i=is,ie ; if (det_i(i)) then
607  d_ea(i,k) = d_ea(i,k) + d_ea(i,k+1)
608  endif ; enddo ; enddo
609  endif ! Detrainment to the interior.
610  if (debug) then
611  do i=is,ie ; h_tot3(i) = 0.0 ; th_tot3(i) = 0.0 ; sh_tot3(i) = 0.0 ; enddo
612  do k=1,nz ; do i=is,ie ; if (do_i(i)) then
613  h_tot3(i) = h_tot3(i) + h_2d(i,k)
614  th_tot3(i) = th_tot3(i) + h_2d(i,k) * t_2d(i,k)
615  sh_tot3(i) = sh_tot3(i) + h_2d(i,k) * s_2d(i,k)
616  endif ; enddo ; enddo
617  endif
618 
619  do i=is,ie ; if (do_i(i)) then
620  ! Rescale the interface targets so the depth at the bottom of the deepest
621  ! buffer layer matches.
622  scale = e_2d(i,nkmb+1) / e_filt(i,nkmb+1)
623  do k=2,nkmb+1 ; e_filt(i,k) = e_filt(i,k) * scale ; enddo
624 
625  ! Ensure that layer 1 only has water from layers 1 to nkml and rescale
626  ! the remaining layer thicknesses if necessary.
627  if (e_filt(i,2) < e_2d(i,nkml)) then
628  scale = (e_2d(i,nkml) - e_filt(i,nkmb+1)) / &
629  ((e_filt(i,2) - e_filt(i,nkmb+1)) + h_neglect)
630  do k=3,nkmb
631  e_filt(i,k) = e_filt(i,nkmb+1) + scale * (e_filt(i,k) - e_filt(i,nkmb+1))
632  enddo
633  e_filt(i,2) = e_2d(i,nkml)
634  endif
635 
636  ! Map the water back into the layers.
637  k1 = 1 ; k2 = 1
638  int_top = 0.0
639  do k=1,nkmb+1
640  int_flux(k) = 0.0 ; int_rflux(k) = 0.0
641  int_tflux(k) = 0.0 ; int_sflux(k) = 0.0
642  enddo
643  do k=1,2*nkmb
644  int_bot = max(e_2d(i,k1+1),e_filt(i,k2+1))
645  h_add = int_top - int_bot
646 
647  if (k2 > k1) then
648  do k3=k1+1,k2
649  d_ea(i,k3) = d_ea(i,k3) + h_add
650  int_flux(k3) = int_flux(k3) + h_add
651  int_tflux(k3) = int_tflux(k3) + h_add*t_2d(i,k1)
652  int_sflux(k3) = int_sflux(k3) + h_add*s_2d(i,k1)
653  enddo
654  elseif (k1 > k2) then
655  do k3=k2,k1-1
656  d_eb(i,k3) = d_eb(i,k3) + h_add
657  int_flux(k3+1) = int_flux(k3+1) - h_add
658  int_tflux(k3+1) = int_tflux(k3+1) - h_add*t_2d(i,k1)
659  int_sflux(k3+1) = int_sflux(k3+1) - h_add*s_2d(i,k1)
660  enddo
661  endif
662 
663  if (int_bot <= e_filt(i,k2+1)) then
664  ! Increment the target layer.
665  k2 = k2 + 1
666  elseif (int_bot <= e_2d(i,k1+1)) then
667  ! Increment the source layer.
668  k1 = k1 + 1
669  else
670  call mom_error(fatal, &
671  "Regularize_surface: Could not increment target or source.")
672  endif
673  if ((k1 > nkmb) .or. (k2 > nkmb)) exit
674  int_top = int_bot
675  enddo
676  if (k2 < nkmb) &
677  call mom_error(fatal, "Regularize_surface: Did not assign fluid to layer nkmb.")
678 
679  ! Note that movement of water across the base of the bottommost buffer
680  ! layer has already been dealt with separately.
681  do k=1,nkmb ; h_prev_1d(k) = h_2d(i,k) ; enddo
682  h_2d(i,1) = h_2d(i,1) - int_flux(2)
683  do k=2,nkmb-1
684  h_2d(i,k) = h_2d(i,k) + (int_flux(k) - int_flux(k+1))
685  enddo
686  ! Note that movement of water across the base of the bottommost buffer
687  ! layer has already been dealt with separately.
688  h_2d(i,nkmb) = h_2d(i,nkmb) + int_flux(nkmb)
689 
690  t_2d(i,1) = (t_2d(i,1)*h_prev_1d(1) - int_tflux(2)) / h_2d(i,1)
691  s_2d(i,1) = (s_2d(i,1)*h_prev_1d(1) - int_sflux(2)) / h_2d(i,1)
692  do k=2,nkmb-1
693  t_2d(i,k) = (t_2d(i,k)*h_prev_1d(k) + (int_tflux(k) - int_tflux(k+1))) / h_2d(i,k)
694  s_2d(i,k) = (s_2d(i,k)*h_prev_1d(k) + (int_sflux(k) - int_sflux(k+1))) / h_2d(i,k)
695  enddo
696  t_2d(i,nkmb) = (t_2d(i,nkmb)*h_prev_1d(nkmb) + int_tflux(nkmb) ) / h_2d(i,nkmb)
697  s_2d(i,nkmb) = (s_2d(i,nkmb)*h_prev_1d(nkmb) + int_sflux(nkmb) ) / h_2d(i,nkmb)
698 
699  endif ; enddo ! i-loop
700 
701  ! Copy the interior thicknesses and other fields back to the 3-d arrays.
702  do k=1,nz ; do i=is,ie ; if (do_i(i)) then
703  h(i,j,k) = h_2d(i,k)
704  tv%T(i,j,k) = t_2d(i,k) ; tv%S(i,j,k) = s_2d(i,k)
705  ea(i,j,k) = ea(i,j,k) + d_ea(i,k)
706  eb(i,j,k) = eb(i,j,k) + d_eb(i,k)
707  endif ; enddo ; enddo
708 
709  if (debug) then
710  do i=is,ie ; h_tot1(i) = 0.0 ; th_tot1(i) = 0.0 ; sh_tot1(i) = 0.0 ; enddo
711  do i=is,ie ; h_tot2(i) = 0.0 ; th_tot2(i) = 0.0 ; sh_tot2(i) = 0.0 ; enddo
712 
713  do k=1,nz ; do i=is,ie ; if (do_i(i)) then
714  h_tot1(i) = h_tot1(i) + h_2d_init(i,k)
715  h_tot2(i) = h_tot2(i) + h(i,j,k)
716 
717  th_tot1(i) = th_tot1(i) + h_2d_init(i,k) * t_2d_init(i,k)
718  th_tot2(i) = th_tot2(i) + h(i,j,k) * tv%T(i,j,k)
719  sh_tot1(i) = sh_tot1(i) + h_2d_init(i,k) * s_2d_init(i,k)
720  sh_tot2(i) = sh_tot2(i) + h(i,j,k) * tv%S(i,j,k)
721  if (h(i,j,k) < 0.0) &
722  call mom_error(fatal,"regularize_surface: Negative thicknesses.")
723  if (k==1) then ; h_predicted = h_2d_init(i,k) + (d_eb(i,k) - d_ea(i,k+1))
724  elseif (k==nz) then ; h_predicted = h_2d_init(i,k) + (d_ea(i,k) - d_eb(i,k-1))
725  else
726  h_predicted = h_2d_init(i,k) + ((d_ea(i,k) - d_eb(i,k-1)) + &
727  (d_eb(i,k) - d_ea(i,k+1)))
728  endif
729  if (abs(h(i,j,k) - h_predicted) > max(1e-9*abs(h_predicted),gv%Angstrom)) &
730  call mom_error(fatal, "regularize_surface: d_ea mismatch.")
731  endif ; enddo ; enddo
732  do i=is,ie ; if (do_i(i)) then
733  fatal_error = .false.
734  if (abs(h_tot1(i) - h_tot2(i)) > 1e-12*h_tot1(i)) then
735  write(mesg,'(ES11.4," became ",ES11.4," diff ",ES11.4)') &
736  h_tot1(i), h_tot2(i), (h_tot1(i) - h_tot2(i))
737  call mom_error(warning, "regularize_surface: Mass non-conservation."//&
738  trim(mesg), .true.)
739  fatal_error = .true.
740  endif
741  if (abs(th_tot1(i) - th_tot2(i)) > 1e-12*(th_tot1(i)+10.0*h_tot1(i))) then
742  write(mesg,'(ES11.4," became ",ES11.4," diff ",ES11.4," int diff ",ES11.4)') &
743  th_tot1(i), th_tot2(i), (th_tot1(i) - th_tot2(i)), (th_tot1(i) - th_tot3(i))
744  call mom_error(warning, "regularize_surface: Heat non-conservation."//&
745  trim(mesg), .true.)
746  fatal_error = .true.
747  endif
748  if (abs(sh_tot1(i) - sh_tot2(i)) > 1e-12*(sh_tot1(i)+10.0*h_tot1(i))) then
749  write(mesg,'(ES11.4," became ",ES11.4," diff ",ES11.4," int diff ",ES11.4)') &
750  sh_tot1(i), sh_tot2(i), (sh_tot1(i) - sh_tot2(i)), (sh_tot1(i) - sh_tot3(i))
751  call mom_error(warning, "regularize_surface: Salinity non-conservation."//&
752  trim(mesg), .true.)
753  fatal_error = .true.
754  endif
755  if (fatal_error) then
756  write(mesg,'("Error at lat/lon ",2(ES11.4))') g%geoLatT(i,j), g%geoLonT(i,j)
757  call mom_error(fatal, "regularize_surface: Terminating with fatal error. "//&
758  trim(mesg))
759  endif
760  endif ; enddo
761  endif
762 
763  endif ; enddo ! j-loop.
764 
765  if (cs%id_def_rat > 0) call post_data(cs%id_def_rat, def_rat_h, cs%diag)
766 
767 #ifdef DEBUG_CODE
768  if (cs%id_e1 > 0) call post_data(cs%id_e1, e, cs%diag)
769  if (cs%id_def_rat_u > 0) call post_data(cs%id_def_rat_u, def_rat_u, cs%diag)
770  if (cs%id_def_rat_u_1b > 0) call post_data(cs%id_def_rat_u_1b, def_rat_u_1b, cs%diag)
771  if (cs%id_def_rat_v > 0) call post_data(cs%id_def_rat_v, def_rat_v, cs%diag)
772  if (cs%id_def_rat_v_1b > 0) call post_data(cs%id_def_rat_v_1b, def_rat_v_1b, cs%diag)
773 
774  if ((cs%id_def_rat_2 > 0) .or. &
775  (cs%id_def_rat_u_2 > 0) .or. (cs%id_def_rat_u_2b > 0) .or. &
776  (cs%id_def_rat_v_2 > 0) .or. (cs%id_def_rat_v_2b > 0) ) then
777  do j=js-1,je+1 ; do i=is-1,ie+1
778  e(i,j,1) = 0.0
779  enddo ; enddo
780  do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
781  e(i,j,k+1) = e(i,j,k) - h(i,j,k)
782  enddo ; enddo ; enddo
783 
784  call find_deficit_ratios(e, def_rat_u_2, def_rat_v_2, g, gv, cs, def_rat_u_2b, def_rat_v_2b, h=h)
785 
786  ! Determine which columns are problematic
787  do j=js,je ; do i=is,ie
788  def_rat_h2(i,j) = max(def_rat_u_2(i-1,j), def_rat_u_2(i,j), &
789  def_rat_v_2(i,j-1), def_rat_v_2(i,j))
790  enddo ; enddo
791 
792  if (cs%id_def_rat_2 > 0) call post_data(cs%id_def_rat_2, def_rat_h2, cs%diag)
793  if (cs%id_e2 > 0) call post_data(cs%id_e2, e, cs%diag)
794  if (cs%id_def_rat_u_2 > 0) call post_data(cs%id_def_rat_u_2, def_rat_u_2, cs%diag)
795  if (cs%id_def_rat_u_2b > 0) call post_data(cs%id_def_rat_u_2b, def_rat_u_2b, cs%diag)
796  if (cs%id_def_rat_v_2 > 0) call post_data(cs%id_def_rat_v_2, def_rat_v_2, cs%diag)
797  if (cs%id_def_rat_v_2b > 0) call post_data(cs%id_def_rat_v_2b, def_rat_v_2b, cs%diag)
798  endif
799 #endif
800 
801 end subroutine regularize_surface
802 
803 !> This subroutine determines the amount by which the harmonic mean
804 !! thickness at velocity points differ from the arithmetic means, relative to
805 !! the the arithmetic means, after eliminating thickness variations that are
806 !! solely due to topography and aggregating all interior layers into one.
807 subroutine find_deficit_ratios(e, def_rat_u, def_rat_v, G, GV, CS, &
808  def_rat_u_2lay, def_rat_v_2lay, halo, h)
809  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
810  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
811  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), &
812  intent(in) :: e !< Interface depths, in m or kg m-2.
813  real, dimension(SZIB_(G),SZJ_(G)), &
814  intent(out) :: def_rat_u !< The thickness deficit ratio at u points,
815  !! nondim.
816  real, dimension(SZI_(G),SZJB_(G)), &
817  intent(out) :: def_rat_v !< The thickness deficit ratio at v points,
818  !! nondim.
819  type(regularize_layers_cs), pointer :: CS !< The control structure returned by a
820  !! previous call to regularize_layers_init.
821  real, dimension(SZIB_(G),SZJ_(G)), &
822  optional, intent(out) :: def_rat_u_2lay !< The thickness deficit ratio at u
823  !! points when the mixed and buffer layers
824  !! are aggregated into 1 layer, nondim.
825  real, dimension(SZI_(G),SZJB_(G)), &
826  optional, intent(out) :: def_rat_v_2lay !< The thickness deficit ratio at v
827  !! pointswhen the mixed and buffer layers
828  !! are aggregated into 1 layer, nondim.
829  integer, optional, intent(in) :: halo !< An extra-wide halo size, 0 by default.
830  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
831  optional, intent(in) :: h !< Layer thicknesses, in H (usually m or kg
832  !! m-2); if h is not present, vertical
833  !! differences in interface heights are used
834  !! instead.
835 
836 ! This subroutine determines the amount by which the harmonic mean
837 ! thickness at velocity points differ from the arithmetic means, relative to
838 ! the the arithmetic means, after eliminating thickness variations that are
839 ! solely due to topography and aggregating all interior layers into one.
840 
841 ! Arguments: e - Interface depths, in m or kg m-2.
842 ! (out) def_rat_u - The thickness deficit ratio at u points, nondim.
843 ! (out) def_rat_v - The thickness deficit ratio at v points, nondim.
844 ! (in) G - The ocean's grid structure.
845 ! (in) GV - The ocean's vertical grid structure.
846 ! (in) CS - The control structure returned by a previous call to
847 ! regularize_layers_init.
848 ! (out,opt) def_rat_u_2lay - The thickness deficit ratio at u points when the
849 ! mixed and buffer layers are aggregated into 1 layer, nondim.
850 ! (out,opt) def_rat_v_2lay - The thickness deficit ratio at v pointswhen the
851 ! mixed and buffer layers are aggregated into 1 layer, nondim.
852 ! (in,opt) halo - An extra-wide halo size, 0 by default.
853 ! (in,opt) h - The layer thicknesse; if not present take vertical differences of e.
854  real, dimension(SZIB_(G),SZJ_(G)) :: &
855  h_def_u, & ! The vertically summed thickness deficits at u-points, in H.
856  h_norm_u, & ! The vertically summed arithmetic mean thickness by which
857  ! h_def_u is normalized, in H.
858  h_def2_u
859  real, dimension(SZI_(G),SZJB_(G)) :: &
860  h_def_v, & ! The vertically summed thickness deficits at v-points, in H.
861  h_norm_v, & ! The vertically summed arithmetic mean thickness by which
862  ! h_def_v is normalized, in H.
863  h_def2_v
864  real :: h_neglect ! A thickness that is so small it is usually lost
865  ! in roundoff and can be neglected, in H.
866  real :: h1, h2 ! Temporary thicknesses, in H.
867  integer :: i, j, k, is, ie, js, je, nz, nkmb
868 
869  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
870  if (present(halo)) then
871  is = g%isc-halo ; ie = g%iec+halo ; js = g%jsc-halo ; je = g%jec+halo
872  endif
873  nkmb = gv%nk_rho_varies
874  h_neglect = gv%H_subroundoff
875 
876  ! Determine which zonal faces are problematic.
877  do j=js,je ; do i=is-1,ie
878  ! Aggregate all water below the mixed and buffer layers for the purposes of
879  ! this diagnostic.
880  h1 = e(i,j,nkmb+1)-e(i,j,nz+1) ; h2 = e(i+1,j,nkmb+1)-e(i+1,j,nz+1)
881  if (e(i,j,nz+1) < e(i+1,j,nz+1)) then
882  if (h1 > h2) h1 = max(e(i,j,nkmb+1)-e(i+1,j,nz+1), h2)
883  elseif (e(i+1,j,nz+1) < e(i,j,nz+1)) then
884  if (h2 > h1) h2 = max(e(i+1,j,nkmb+1)-e(i,j,nz+1), h1)
885  endif
886  h_def_u(i,j) = 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
887  h_norm_u(i,j) = 0.5*(h1+h2)
888  enddo ; enddo
889  if (present(def_rat_u_2lay)) then ; do j=js,je ; do i=is-1,ie
890  ! This is a particular metric of the aggregation into two layers.
891  h1 = e(i,j,1)-e(i,j,nkmb+1) ; h2 = e(i+1,j,1)-e(i+1,j,nkmb+1)
892  if (e(i,j,nkmb+1) < e(i+1,j,nz+1)) then
893  if (h1 > h2) h1 = max(e(i,j,1)-e(i+1,j,nz+1), h2)
894  elseif (e(i+1,j,nkmb+1) < e(i,j,nz+1)) then
895  if (h2 > h1) h2 = max(e(i+1,j,1)-e(i,j,nz+1), h1)
896  endif
897  h_def2_u(i,j) = h_def_u(i,j) + 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
898  enddo ; enddo ; endif
899  do k=1,nkmb ; do j=js,je ; do i=is-1,ie
900  if (present(h)) then
901  h1 = h(i,j,k) ; h2 = h(i+1,j,k)
902  else
903  h1 = e(i,j,k)-e(i,j,k+1) ; h2 = e(i+1,j,k)-e(i+1,j,k+1)
904  endif
905  ! Thickness deficits can not arise simply because a layer's bottom is bounded
906  ! by the bathymetry.
907  if (e(i,j,k+1) < e(i+1,j,nz+1)) then
908  if (h1 > h2) h1 = max(e(i,j,k)-e(i+1,j,nz+1), h2)
909  elseif (e(i+1,j,k+1) < e(i,j,nz+1)) then
910  if (h2 > h1) h2 = max(e(i+1,j,k)-e(i,j,nz+1), h1)
911  endif
912  h_def_u(i,j) = h_def_u(i,j) + 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
913  h_norm_u(i,j) = h_norm_u(i,j) + 0.5*(h1+h2)
914  enddo ; enddo ; enddo
915  if (present(def_rat_u_2lay)) then ; do j=js,je ; do i=is-1,ie
916  def_rat_u(i,j) = g%mask2dCu(i,j) * h_def_u(i,j) / &
917  (max(cs%Hmix_min, h_norm_u(i,j)) + h_neglect)
918  def_rat_u_2lay(i,j) = g%mask2dCu(i,j) * h_def2_u(i,j) / &
919  (max(cs%Hmix_min, h_norm_u(i,j)) + h_neglect)
920  enddo ; enddo ; else ; do j=js,je ; do i=is-1,ie
921  def_rat_u(i,j) = g%mask2dCu(i,j) * h_def_u(i,j) / &
922  (max(cs%Hmix_min, h_norm_u(i,j)) + h_neglect)
923  enddo ; enddo ; endif
924 
925  ! Determine which meridional faces are problematic.
926  do j=js-1,je ; do i=is,ie
927  ! Aggregate all water below the mixed and buffer layers for the purposes of
928  ! this diagnostic.
929  h1 = e(i,j,nkmb+1)-e(i,j,nz+1) ; h2 = e(i,j+1,nkmb+1)-e(i,j+1,nz+1)
930  if (e(i,j,nz+1) < e(i,j+1,nz+1)) then
931  if (h1 > h2) h1 = max(e(i,j,nkmb+1)-e(i,j+1,nz+1), h2)
932  elseif (e(i,j+1,nz+1) < e(i,j,nz+1)) then
933  if (h2 > h1) h2 = max(e(i,j+1,nkmb+1)-e(i,j,nz+1), h1)
934  endif
935  h_def_v(i,j) = 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
936  h_norm_v(i,j) = 0.5*(h1+h2)
937  enddo ; enddo
938  if (present(def_rat_v_2lay)) then ; do j=js-1,je ; do i=is,ie
939  ! This is a particular metric of the aggregation into two layers.
940  h1 = e(i,j,1)-e(i,j,nkmb+1) ; h2 = e(i,j+1,1)-e(i,j+1,nkmb+1)
941  if (e(i,j,nkmb+1) < e(i,j+1,nz+1)) then
942  if (h1 > h2) h1 = max(e(i,j,1)-e(i,j+1,nz+1), h2)
943  elseif (e(i,j+1,nkmb+1) < e(i,j,nz+1)) then
944  if (h2 > h1) h2 = max(e(i,j+1,1)-e(i,j,nz+1), h1)
945  endif
946  h_def2_v(i,j) = h_def_v(i,j) + 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
947  enddo ; enddo ; endif
948  do k=1,nkmb ; do j=js-1,je ; do i=is,ie
949  if (present(h)) then
950  h1 = h(i,j,k) ; h2 = h(i,j+1,k)
951  else
952  h1 = e(i,j,k)-e(i,j,k+1) ; h2 = e(i,j+1,k)-e(i,j+1,k+1)
953  endif
954  ! Thickness deficits can not arise simply because a layer's bottom is bounded
955  ! by the bathymetry.
956  if (e(i,j,k+1) < e(i,j+1,nz+1)) then
957  if (h1 > h2) h1 = max(e(i,j,k)-e(i,j+1,nz+1), h2)
958  elseif (e(i,j+1,k+1) < e(i,j,nz+1)) then
959  if (h2 > h1) h2 = max(e(i,j+1,k)-e(i,j,nz+1), h1)
960  endif
961  h_def_v(i,j) = h_def_v(i,j) + 0.5*(h1-h2)**2 / ((h1 + h2) + h_neglect)
962  h_norm_v(i,j) = h_norm_v(i,j) + 0.5*(h1+h2)
963  enddo ; enddo ; enddo
964  if (present(def_rat_v_2lay)) then ; do j=js-1,je ; do i=is,ie
965  def_rat_v(i,j) = g%mask2dCv(i,j) * h_def_v(i,j) / &
966  (max(cs%Hmix_min, h_norm_v(i,j)) + h_neglect)
967  def_rat_v_2lay(i,j) = g%mask2dCv(i,j) * h_def2_v(i,j) / &
968  (max(cs%Hmix_min, h_norm_v(i,j)) + h_neglect)
969  enddo ; enddo ; else ; do j=js-1,je ; do i=is,ie
970  def_rat_v(i,j) = g%mask2dCv(i,j) * h_def_v(i,j) / &
971  (max(cs%Hmix_min, h_norm_v(i,j)) + h_neglect)
972  enddo ; enddo ; endif
973 
974 end subroutine find_deficit_ratios
975 
976 subroutine regularize_layers_init(Time, G, param_file, diag, CS)
977  type(time_type), target, intent(in) :: Time !< The current model time.
978  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
979  type(param_file_type), intent(in) :: param_file !< A structure to parse for
980  !! run-time parameters.
981  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate
982  !! diagnostic output.
983  type(regularize_layers_cs), pointer :: CS !< A pointer that is set to point to the
984  !! control structure for this module.
985 ! Arguments: Time - The current model time.
986 ! (in) G - The ocean's grid structure.
987 ! (in) param_file - A structure indicating the open file to parse for
988 ! model parameter values.
989 ! (in) diag - A structure that is used to regulate diagnostic output.
990 ! (in/out) CS - A pointer that is set to point to the control structure
991 ! for this module
992 ! This include declares and sets the variable "version".
993 #include "version_variable.h"
994  character(len=40) :: mdl = "MOM_regularize_layers" ! This module's name.
995  logical :: use_temperature
996  integer :: isd, ied, jsd, jed
997  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
998 
999  if (associated(cs)) then
1000  call mom_error(warning, "regularize_layers_init called with an associated"// &
1001  "associated control structure.")
1002  return
1003  else ; allocate(cs) ; endif
1004 
1005  cs%diag => diag
1006  cs%Time => time
1007 
1008 ! Set default, read and log parameters
1009  call log_version(param_file, mdl, version, "")
1010  call get_param(param_file, mdl, "REGULARIZE_SURFACE_LAYERS", cs%regularize_surface_layers, &
1011  "If defined, vertically restructure the near-surface \n"//&
1012  "layers when they have too much lateral variations to \n"//&
1013  "allow for sensible lateral barotropic transports.", &
1014  default=.false.)
1015  if (cs%regularize_surface_layers) then
1016  call get_param(param_file, mdl, "REGULARIZE_SURFACE_DETRAIN", cs%reg_sfc_detrain, &
1017  "If true, allow the buffer layers to detrain into the \n"//&
1018  "interior as a part of the restructuring when \n"//&
1019  "REGULARIZE_SURFACE_LAYERS is true.", default=.true.)
1020  endif
1021 
1022  call get_param(param_file, mdl, "HMIX_MIN", cs%Hmix_min, &
1023  "The minimum mixed layer depth if the mixed layer depth \n"//&
1024  "is determined dynamically.", units="m", default=0.0)
1025  call get_param(param_file, mdl, "REG_SFC_DEFICIT_TOLERANCE", cs%h_def_tol1, &
1026  "The value of the relative thickness deficit at which \n"//&
1027  "to start modifying the layer structure when \n"//&
1028  "REGULARIZE_SURFACE_LAYERS is true.", units="nondim", &
1029  default=0.5)
1030  cs%h_def_tol2 = 0.2 + 0.8*cs%h_def_tol1
1031  cs%h_def_tol3 = 0.3 + 0.7*cs%h_def_tol1
1032  cs%h_def_tol4 = 0.5 + 0.5*cs%h_def_tol1
1033 
1034  call get_param(param_file, mdl, "DEBUG", cs%debug, default=.false.)
1035 ! if (.not. CS%debug) &
1036 ! call get_param(param_file, mdl, "DEBUG_CONSERVATION", CS%debug, &
1037 ! "If true, monitor conservation and extrema.", default=.false.)
1038 
1039  call get_param(param_file, mdl, "ALLOW_CLOCKS_IN_OMP_LOOPS", &
1040  cs%allow_clocks_in_omp_loops, &
1041  "If true, clocks can be called from inside loops that can \n"//&
1042  "be threaded. To run with multiple threads, set to False.", &
1043  default=.true.)
1044 
1045  cs%id_def_rat = register_diag_field('ocean_model', 'deficit_ratio', diag%axesT1, &
1046  time, 'Max face thickness deficit ratio', 'Nondim')
1047 
1048 #ifdef DEBUG_CODE
1049  cs%id_def_rat_2 = register_diag_field('ocean_model', 'deficit_rat2', diag%axesT1, &
1050  time, 'Corrected thickness deficit ratio', 'Nondim')
1051  cs%id_def_rat_3 = register_diag_field('ocean_model', 'deficit_rat3', diag%axesT1, &
1052  time, 'Filtered thickness deficit ratio', 'Nondim')
1053  cs%id_e1 = register_diag_field('ocean_model', 'er_1', diag%axesTi, &
1054  time, 'Intial interface depths before remapping', 'm')
1055  cs%id_e2 = register_diag_field('ocean_model', 'er_2', diag%axesTi, &
1056  time, 'Intial interface depths after remapping', 'm')
1057  cs%id_e3 = register_diag_field('ocean_model', 'er_3', diag%axesTi, &
1058  time, 'Intial interface depths filtered', 'm')
1059 
1060  cs%id_def_rat_u = register_diag_field('ocean_model', 'defrat_u', diag%axesCu1, &
1061  time, 'U-point thickness deficit ratio', 'Nondim')
1062  cs%id_def_rat_u_1b = register_diag_field('ocean_model', 'defrat_u_1b', diag%axesCu1, &
1063  time, 'U-point 2-layer thickness deficit ratio', 'Nondim')
1064  cs%id_def_rat_u_2 = register_diag_field('ocean_model', 'defrat_u_2', diag%axesCu1, &
1065  time, 'U-point corrected thickness deficit ratio', 'Nondim')
1066  cs%id_def_rat_u_2b = register_diag_field('ocean_model', 'defrat_u_2b', diag%axesCu1, &
1067  time, 'U-point corrected 2-layer thickness deficit ratio', 'Nondim')
1068  cs%id_def_rat_u_3 = register_diag_field('ocean_model', 'defrat_u_3', diag%axesCu1, &
1069  time, 'U-point filtered thickness deficit ratio', 'Nondim')
1070  cs%id_def_rat_u_3b = register_diag_field('ocean_model', 'defrat_u_3b', diag%axesCu1, &
1071  time, 'U-point filtered 2-layer thickness deficit ratio', 'Nondim')
1072 
1073  cs%id_def_rat_v = register_diag_field('ocean_model', 'defrat_v', diag%axesCv1, &
1074  time, 'V-point thickness deficit ratio', 'Nondim')
1075  cs%id_def_rat_v_1b = register_diag_field('ocean_model', 'defrat_v_1b', diag%axesCv1, &
1076  time, 'V-point 2-layer thickness deficit ratio', 'Nondim')
1077  cs%id_def_rat_v_2 = register_diag_field('ocean_model', 'defrat_v_2', diag%axesCv1, &
1078  time, 'V-point corrected thickness deficit ratio', 'Nondim')
1079  cs%id_def_rat_v_2b = register_diag_field('ocean_model', 'defrat_v_2b', diag%axesCv1, &
1080  time, 'V-point corrected 2-layer thickness deficit ratio', 'Nondim')
1081  cs%id_def_rat_v_3 = register_diag_field('ocean_model', 'defrat_v_3', diag%axesCv1, &
1082  time, 'V-point filtered thickness deficit ratio', 'Nondim')
1083  cs%id_def_rat_v_3b = register_diag_field('ocean_model', 'defrat_v_3b', diag%axesCv1, &
1084  time, 'V-point filtered 2-layer thickness deficit ratio', 'Nondim')
1085 #endif
1086 
1087  if(cs%allow_clocks_in_omp_loops) then
1088  id_clock_eos = cpu_clock_id('(Ocean regularize_layers EOS)', grain=clock_routine)
1089  endif
1090  id_clock_pass = cpu_clock_id('(Ocean regularize_layers halo updates)', grain=clock_routine)
1091 
1092 end subroutine regularize_layers_init
1093 
1094 end module mom_regularize_layers
subroutine regularize_surface(h, tv, dt, ea, eb, G, GV, CS)
This subroutine ensures that there is a degree of horizontal smoothness in the depths of the near-sur...
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides the ocean grid type.
Definition: MOM_grid.F90:2
subroutine, public do_group_pass(group, MOM_dom)
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Definition: MOM_EOS.F90:214
subroutine find_deficit_ratios(e, def_rat_u, def_rat_v, G, GV, CS, def_rat_u_2lay, def_rat_v_2lay, halo, h)
This subroutine determines the amount by which the harmonic mean thickness at velocity points differ ...
subroutine, public regularize_layers_init(Time, G, param_file, diag, CS)
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
subroutine, public regularize_layers(h, tv, dt, ea, eb, G, GV, CS)
This subroutine partially steps the bulk mixed layer model. The following processes are executed...
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
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)